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):
self._home_directory = None
self.slicename = None
self._traces = dict()
-
+
import node, interfaces, application
self._node = node
self._interfaces = interfaces
@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,
# 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'):
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
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)