X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=src%2Fnepi%2Ftestbeds%2Fplanetlab%2Fexecute.py;h=7f3e3050dd76b2e572171e546e5049e6200482de;hb=ef968d674bcacf6ab6e42eaf1f6f376278645529;hp=8611834be365b27bef016e6e42957f7bbf93931c;hpb=0f6345e48f32e6080a2ed709d963722601a288ee;p=nepi.git diff --git a/src/nepi/testbeds/planetlab/execute.py b/src/nepi/testbeds/planetlab/execute.py index 8611834b..7f3e3050 100644 --- a/src/nepi/testbeds/planetlab/execute.py +++ b/src/nepi/testbeds/planetlab/execute.py @@ -3,7 +3,9 @@ from constants import TESTBED_ID from nepi.core import testbed_impl +from nepi.util.constants import TIME_NOW import os +import time class TestbedController(testbed_impl.TestbedController): def __init__(self, testbed_version): @@ -11,7 +13,7 @@ class TestbedController(testbed_impl.TestbedController): self._home_directory = None self.slicename = None self._traces = dict() - + import node, interfaces, application self._node = node self._interfaces = interfaces @@ -20,12 +22,12 @@ class TestbedController(testbed_impl.TestbedController): @property def home_directory(self): return self._home_directory - + @property def plapi(self): if not hasattr(self, '_plapi'): import plcapi - + if self.authUser: self._plapi = plcapi.PLCAPI( username = self.authUser, @@ -34,7 +36,7 @@ class TestbedController(testbed_impl.TestbedController): # anonymous access - may not be enough for much self._plapi = plcapi.PLCAPI() return self._plapi - + @property def slice_id(self): if not hasattr(self, '_slice_id'): @@ -55,68 +57,97 @@ class TestbedController(testbed_impl.TestbedController): get_attribute_value("authUser") self.authString = self._attributes.\ get_attribute_value("authPass") + self.sliceSSHKey = self._attributes.\ + get_attribute_value("sliceSSHKey") + super(TestbedController, self).do_setup() - def do_create(self): - # Create node elements per XML data - super(TestbedController, self).do_create() - + def do_preconfigure(self): # Perform resource discovery if we don't have # specific resources assigned yet self.do_resource_discovery() - + # Create PlanetLab slivers self.do_provisioning() - - # Wait for all nodes to be ready - self.wait_nodes() - + + # Configure elements per XML data + super(TestbedController, self).do_preconfigure() + def do_resource_discovery(self): # Do what? - pass + + # Provisional algo: + # look for perfectly defined nodes + # (ie: those with only one candidate) + to_provision = self._to_provision = set() + for guid, node in self._elements.iteritems(): + if isinstance(node, self._node.Node) and node._node_id is None: + # Try existing nodes first + # If we have only one candidate, simply use it + candidates = node.find_candidates( + filter_slice_id = self.slice_id) + if len(candidates) == 1: + node.assign_node_id(iter(candidates).next()) + else: + # Try again including unassigned nodes + candidates = node.find_candidates() + if len(candidates) > 1: + raise RuntimeError, "Cannot assign resources for node %s, too many candidates" % (guid,) + if len(candidates) == 1: + node_id = iter(candidates).next() + node.assign_node_id(node_id) + to_provision.add(node_id) + elif not candidates: + raise RuntimeError, "Cannot assign resources for node %s, no candidates" % (guid,) def do_provisioning(self): - # Que te recontra? - pass - - def wait_nodes(self): - # Suuure... - pass + if self._to_provision: + # Add new nodes to the slice + cur_nodes = self.plapi.GetSlices(self.slicename, ['node_ids'])[0]['node_ids'] + new_nodes = list(set(cur_nodes) | self._to_provision) + self.plapi.UpdateSlice(self.slicename, nodes=new_nodes) + + # cleanup + del self._to_provision - def set(self, time, guid, name, value): - super(TestbedController, self).set(time, guid, name, value) - # TODO: take on account schedule time for the task + def set(self, guid, name, value, time = TIME_NOW): + super(TestbedController, self).set(guid, name, value, time) + # TODO: take on account schedule time for the task element = self._elements[guid] if element: setattr(element, name, value) - def get(self, time, guid, name): + if hasattr(element, 'refresh'): + # invoke attribute refresh hook + element.refresh() + + def get(self, guid, name, time = TIME_NOW): + value = super(TestbedController, self).get(guid, name, time) # TODO: take on account schedule time for the task + factory_id = self._create[guid] + factory = self._factories[factory_id] + if factory.box_attributes.is_attribute_design_only(name): + return value element = self._elements.get(guid) - if element: - try: - if hasattr(element, name): - # Runtime attribute - return getattr(element, name) - else: - # Try design-time attributes - return self.box_get(time, guid, name) - except KeyError, AttributeError: - return None - - def get_route(self, guid, index, attribute): - # TODO: fetch real data from planetlab try: - return self.box_get_route(guid, int(index), attribute) + return getattr(element, name) except KeyError, AttributeError: - return None + return value def get_address(self, guid, index, attribute='Address'): - # TODO: fetch real data from planetlab - try: - return self.box_get_address(guid, int(index), attribute) - except KeyError, AttributeError: - return None + index = int(index) + # try the real stuff + iface = self._elements.get(guid) + if iface and index == 0: + if attribute == 'Address': + return iface.address + elif attribute == 'NetPrefix': + return iface.netprefix + elif attribute == 'Broadcast': + return iface.broadcast + + # if all else fails, query box + return self.get_address(guid, index, attribute) def action(self, time, guid, action): raise NotImplementedError @@ -125,57 +156,75 @@ class TestbedController(testbed_impl.TestbedController): for trace in self._traces.values(): trace.close() for element in self._elements.values(): - element.destroy() - - def trace_filename(self, guid, trace_id): - # TODO: Need to be defined inside a home!!!! with and experiment id_code - return os.path.join(self.home_directory, "%d_%s" % (guid, trace_id)) + # invoke cleanup hooks + if hasattr(element, 'cleanup'): + element.cleanup() + + def trace(self, guid, trace_id, attribute='value'): + app = self._elements[guid] + + if attribute == 'value': + path = app.sync_trace(self.home_directory, trace_id) + if path: + fd = open(path, "r") + content = fd.read() + fd.close() + else: + content = None + elif attribute == 'path': + content = app.remote_trace_path(trace_id) + else: + content = None + return content def follow_trace(self, trace_id, trace): self._traces[trace_id] = trace + + def _make_generic(self, parameters, kind): + app = kind(self.plapi) - def _make_node(self, parameters): - node = self._node.Node(self.plapi) - # Note: there is 1-to-1 correspondence between attribute names # If that changes, this has to change as well for attr,val in parameters.iteritems(): - setattr(node, attr, val) - + setattr(app, attr, val) + + return app + + def _make_node(self, parameters): + node = self._make_generic(parameters, self._node.Node) + + # If emulation is enabled, we automatically need + # some vsys interfaces and packages + if node.emulation: + node.required_vsys.add('ipfw-be') + node.required_packages.add('ipfwslice') + return node - + def _make_node_iface(self, parameters): - iface = self._interfaces.NodeIface(self.plapi) - - # Note: there is 1-to-1 correspondence between attribute names - # If that changes, this has to change as well - for attr,val in parameters.iteritems(): - setattr(iface, attr, val) - - return iface - + return self._make_generic(parameters, self._interfaces.NodeIface) + def _make_tun_iface(self, parameters): - iface = self._interfaces.TunIface(self.plapi) - - # Note: there is 1-to-1 correspondence between attribute names - # If that changes, this has to change as well - for attr,val in parameters.iteritems(): - setattr(iface, attr, val) - - return iface - + return self._make_generic(parameters, self._interfaces.TunIface) + + def _make_tap_iface(self, parameters): + return self._make_generic(parameters, self._interfaces.TapIface) + + def _make_netpipe(self, parameters): + return self._make_generic(parameters, self._interfaces.NetPipe) + def _make_internet(self, parameters): - return self._interfaces.Internet(self.plapi) - + return self._make_generic(parameters, self._interfaces.Internet) + def _make_application(self, parameters): - app = self._app.Application(self.plapi) - - # Note: there is 1-to-1 correspondence between attribute names - # If that changes, this has to change as well - for attr,val in parameters.iteritems(): - setattr(app, attr, val) - - return app - + return self._make_generic(parameters, self._app.Application) + + def _make_dependency(self, parameters): + return self._make_generic(parameters, self._app.Dependency) + + def _make_nepi_dependency(self, parameters): + return self._make_generic(parameters, self._app.NepiDependency) + def _make_ns3_dependency(self, parameters): + return self._make_generic(parameters, self._app.NS3Dependency)