2 # -*- coding: utf-8 -*-
4 from constants import TESTBED_ID
5 from nepi.core import testbed_impl
6 from nepi.util.constants import TIME_NOW
10 class TestbedController(testbed_impl.TestbedController):
11 def __init__(self, testbed_version):
12 super(TestbedController, self).__init__(TESTBED_ID, testbed_version)
13 self._home_directory = None
17 import node, interfaces, application
19 self._interfaces = interfaces
20 self._app = application
23 def home_directory(self):
24 return self._home_directory
28 if not hasattr(self, '_plapi'):
32 self._plapi = plcapi.PLCAPI(
33 username = self.authUser,
34 password = self.authString)
36 # anonymous access - may not be enough for much
37 self._plapi = plcapi.PLCAPI()
42 if not hasattr(self, '_slice_id'):
43 slices = self.plapi.GetSlices(self.slicename, fields=('slice_id',))
45 self._slice_id = slices[0]['slice_id']
47 # If it wasn't found, don't remember this failure, keep trying
52 self._home_directory = self._attributes.\
53 get_attribute_value("homeDirectory")
54 self.slicename = self._attributes.\
55 get_attribute_value("slice")
56 self.authUser = self._attributes.\
57 get_attribute_value("authUser")
58 self.authString = self._attributes.\
59 get_attribute_value("authPass")
60 self.sliceSSHKey = self._attributes.\
61 get_attribute_value("sliceSSHKey")
62 super(TestbedController, self).do_setup()
64 def do_preconfigure(self):
65 # Perform resource discovery if we don't have
66 # specific resources assigned yet
67 self.do_resource_discovery()
69 # Create PlanetLab slivers
70 self.do_provisioning()
72 # Configure elements per XML data
73 super(TestbedController, self).do_preconfigure()
75 def do_resource_discovery(self):
79 # look for perfectly defined nodes
80 # (ie: those with only one candidate)
81 to_provision = self._to_provision = set()
82 for guid, node in self._elements.iteritems():
83 if isinstance(node, self._node.Node) and node._node_id is None:
84 # Try existing nodes first
85 # If we have only one candidate, simply use it
86 candidates = node.find_candidates(
87 filter_slice_id = self.slice_id)
88 if len(candidates) == 1:
89 node.assign_node_id(iter(candidates).next())
91 # Try again including unassigned nodes
92 candidates = node.find_candidates()
93 if len(candidates) > 1:
94 raise RuntimeError, "Cannot assign resources for node %s, too many candidates" % (guid,)
95 if len(candidates) == 1:
96 node_id = iter(candidates).next()
97 node.assign_node_id(node_id)
98 to_provision.add(node_id)
100 raise RuntimeError, "Cannot assign resources for node %s, no candidates" % (guid,)
102 def do_provisioning(self):
103 if self._to_provision:
104 # Add new nodes to the slice
105 cur_nodes = self.plapi.GetSlices(self.slicename, ['node_ids'])[0]['node_ids']
106 new_nodes = list(set(cur_nodes) | self._to_provision)
107 self.plapi.UpdateSlice(self.slicename, nodes=new_nodes)
110 del self._to_provision
112 def set(self, guid, name, value, time = TIME_NOW):
113 super(TestbedController, self).set(guid, name, value, time)
114 # TODO: take on account schedule time for the task
115 element = self._elements[guid]
117 setattr(element, name, value)
119 if hasattr(element, 'refresh'):
120 # invoke attribute refresh hook
123 def get(self, guid, name, time = TIME_NOW):
124 value = super(TestbedController, self).get(guid, name, time)
125 # TODO: take on account schedule time for the task
126 factory_id = self._create[guid]
127 factory = self._factories[factory_id]
128 if factory.box_attributes.is_attribute_design_only(name):
130 element = self._elements.get(guid)
132 return getattr(element, name)
133 except KeyError, AttributeError:
136 def get_address(self, guid, index, attribute='Address'):
140 iface = self._elements.get(guid)
141 if iface and index == 0:
142 if attribute == 'Address':
144 elif attribute == 'NetPrefix':
145 return iface.netprefix
146 elif attribute == 'Broadcast':
147 return iface.broadcast
149 # if all else fails, query box
150 return self.get_address(guid, index, attribute)
152 def action(self, time, guid, action):
153 raise NotImplementedError
156 for trace in self._traces.values():
158 for element in self._elements.values():
159 # invoke cleanup hooks
160 if hasattr(element, 'cleanup'):
163 def trace(self, guid, trace_id, attribute='value'):
164 app = self._elements[guid]
166 if attribute == 'value':
167 path = app.sync_trace(self.home_directory, trace_id)
174 elif attribute == 'path':
175 content = app.remote_trace_path(trace_id)
180 def follow_trace(self, trace_id, trace):
181 self._traces[trace_id] = trace
183 def _make_generic(self, parameters, kind):
184 app = kind(self.plapi)
186 # Note: there is 1-to-1 correspondence between attribute names
187 # If that changes, this has to change as well
188 for attr,val in parameters.iteritems():
189 setattr(app, attr, val)
193 def _make_node(self, parameters):
194 node = self._make_generic(parameters, self._node.Node)
196 # If emulation is enabled, we automatically need
197 # some vsys interfaces and packages
199 node.required_vsys.add('ipfw-be')
200 node.required_packages.add('ipfwslice')
204 def _make_node_iface(self, parameters):
205 return self._make_generic(parameters, self._interfaces.NodeIface)
207 def _make_tun_iface(self, parameters):
208 return self._make_generic(parameters, self._interfaces.TunIface)
210 def _make_netpipe(self, parameters):
211 return self._make_generic(parameters, self._interfaces.NetPipe)
213 def _make_internet(self, parameters):
214 return self._make_generic(parameters, self._interfaces.Internet)
216 def _make_application(self, parameters):
217 return self._make_generic(parameters, self._app.Application)
219 def _make_dependency(self, parameters):
220 return self._make_generic(parameters, self._app.Dependency)
222 def _make_nepi_dependency(self, parameters):
223 return self._make_generic(parameters, self._app.NepiDependency)