import time
import os
import collections
+import cStringIO
+import resourcealloc
from nepi.util import server
# There are replacements that are applied with string formatting,
# so '%' has to be escaped as '%%'.
'architecture' : ('arch','value'),
- 'operating_system' : ('fcdistro','value'),
+ 'operatingSystem' : ('fcdistro','value'),
'pl_distro' : ('pldistro','value'),
- 'min_reliability' : ('reliability%(timeframe)s', ']value'),
- 'max_reliability' : ('reliability%(timeframe)s', '[value'),
- 'min_bandwidth' : ('bw%(timeframe)s', ']value'),
- 'max_bandwidth' : ('bw%(timeframe)s', '[value'),
+ 'minReliability' : ('reliability%(timeframe)s', ']value'),
+ 'maxReliability' : ('reliability%(timeframe)s', '[value'),
+ 'minBandwidth' : ('bw%(timeframe)s', ']value'),
+ 'maxBandwidth' : ('bw%(timeframe)s', '[value'),
}
DEPENDS_PIDFILE = '/tmp/nepi-depends.pid'
# Attributes
self.hostname = None
self.architecture = None
- self.operating_system = None
+ self.operatingSystem = None
self.pl_distro = None
self.site = None
self.emulation = None
- self.min_reliability = None
- self.max_reliability = None
- self.min_bandwidth = None
- self.max_bandwidth = None
+ self.minReliability = None
+ self.maxReliability = None
+ self.minBandwidth = None
+ self.maxBandwidth = None
self.min_num_external_ifaces = None
self.max_num_external_ifaces = None
self.timeframe = 'm'
# Those are filled when an actual node is allocated
self._node_id = None
+ @property
+ def _nepi_testbed_environment_setup(self):
+ command = cStringIO.StringIO()
+ command.write('export PYTHONPATH=$PYTHONPATH:%s' % (
+ ':'.join(["${HOME}/"+server.shell_escape(s) for s in self.pythonpath])
+ ))
+ command.write(' ; export PATH=$PATH:%s' % (
+ ':'.join(["${HOME}/"+server.shell_escape(s) for s in self.pythonpath])
+ ))
+ if self.env:
+ for envkey, envvals in self.env.iteritems():
+ for envval in envvals:
+ command.write(' ; export %s=%s' % (envkey, envval))
+ return command.getvalue()
+
def build_filters(self, target_filters, filter_map):
for attr, tag in filter_map.iteritems():
value = getattr(self, attr, None)
# get initial candidates (no tag filters)
basefilters = self.build_filters({}, self.BASEFILTERS)
+ rootfilters = basefilters.copy()
if filter_slice_id:
basefilters['|slice_ids'] = (filter_slice_id,)
+ # only pick healthy nodes
+ basefilters['run_level'] = 'boot'
+ basefilters['boot_state'] = 'boot'
+
# keyword-only "pseudofilters"
extra = {}
if self.site:
# don't bother if there's no filter defined
if attr in applicable:
- tagfilter = basefilters.copy()
+ tagfilter = rootfilters.copy()
tagfilter['tagname'] = tagname % replacements
tagfilter[expr % replacements] = getattr(self,attr)
tagfilter['node_id'] = list(candidates)
candidates = set(filter(predicate, candidates))
return candidates
+
+ def make_filter_description(self):
+ """
+ Makes a human-readable description of filtering conditions
+ for find_candidates.
+ """
+
+ # get initial candidates (no tag filters)
+ filters = self.build_filters({}, self.BASEFILTERS)
+
+ # keyword-only "pseudofilters"
+ if self.site:
+ filters['peer'] = self.site
+
+ # filter by tag, one tag at a time
+ applicable = self.applicable_filters
+ for tagfilter in self.TAGFILTERS.iteritems():
+ attr, (tagname, expr) = tagfilter
+
+ # don't bother if there's no filter defined
+ if attr in applicable:
+ filters[attr] = getattr(self,attr)
+
+ # filter by vsys tags - special case since it doesn't follow
+ # the usual semantics
+ if self.required_vsys:
+ filters['vsys'] = ','.join(list(self.required_vsys))
+
+ # filter by iface count
+ if self.min_num_external_ifaces is not None or self.max_num_external_ifaces is not None:
+ filters['num_ifaces'] = '-'.join([
+ str(self.min_num_external_ifaces or '0'),
+ str(self.max_num_external_ifaces or 'inf')
+ ])
+
+ return '; '.join(map('%s: %s'.__mod__,filters.iteritems()))
def assign_node_id(self, node_id):
self._node_id = node_id
return False
+ def configure_routes(self, routes, devs):
+ """
+ Add the specified routes to the node's routing table
+ """
+ rules = []
+
+ for route in routes:
+ for dev in devs:
+ if dev.routes_here(route):
+ # Schedule rule
+ dest, prefix, nexthop = route
+ rules.append(
+ "add %s%s gw %s %s" % (
+ dest,
+ (("/%d" % (prefix,)) if prefix and prefix != 32 else ""),
+ nexthop,
+ dev.if_name,
+ )
+ )
+
+ # Stop checking
+ break
+ else:
+ raise RuntimeError, "Route %s cannot be bound to any virtual interface " \
+ "- PL can only handle rules over virtual interfaces. Candidates are: %s" % (route,devs)
+
+ (out,err),proc = server.popen_ssh_command(
+ "( sudo -S bash -c 'cat /vsys/vroute.out >&2' & ) ; sudo -S bash -c 'cat > /vsys/vroute.in' ; sleep 0.1" % dict(
+ home = server.shell_escape(self.home_path)),
+ host = self.hostname,
+ port = None,
+ user = self.slicename,
+ agent = None,
+ ident_key = self.ident_path,
+ server_key = self.server_key,
+ stdin = '\n'.join(rules)
+ )
+
+ if proc.wait() or err:
+ raise RuntimeError, "Could not set routes (%s) errors: %s%s" % (rules,out,err)
+
+
+