2 # -*- coding: utf-8 -*-
4 from constants import TESTBED_ID
5 from nepi.core import metadata
6 from nepi.core.attributes import Attribute
7 from nepi.util import validation
8 from nepi.util.constants import STATUS_NOT_STARTED, STATUS_RUNNING, \
12 NODEIFACE = "NodeInterface"
13 TUNIFACE = "TunInterface"
14 APPLICATION = "Application"
17 PL_TESTBED_ID = "planetlab"
19 ### Connection functions ####
21 def connect_node_iface_node(testbed_instance, node, iface):
24 def connect_node_iface_inet(testbed_instance, iface, inet):
25 iface.has_internet = True
27 def connect_tun_iface_node(testbed_instance, node, iface):
30 def connect_app(testbed_instance, node, app):
33 ### Creation functions ###
35 def create_node(testbed_instance, guid):
36 parameters = testbed_instance._get_parameters(guid)
38 # create element with basic attributes
39 element = testbed_instance._make_node(parameters)
41 # add constraint on number of (real) interfaces
42 # by counting connected devices
43 dev_guids = testbed_instance.get_connected(guid, "node", "devs")
44 num_open_ifaces = sum( # count True values
45 TUNEIFACE == testbed_instance._get_factory_id(guid)
46 for guid in dev_guids )
47 element.min_num_external_ifaces = num_open_ifaces
49 testbed_instance.elements[guid] = element
51 def create_nodeiface(testbed_instance, guid):
52 parameters = testbed_instance._get_parameters(guid)
53 element = testbed_instance._make_node_iface(parameters)
54 testbed_instance.elements[guid] = element
56 def create_tuniface(testbed_instance, guid):
57 parameters = testbed_instance._get_parameters(guid)
58 element = testbed_instance._make_tun_iface(parameters)
59 testbed_instance.elements[guid] = element
61 def create_application(testbed_instance, guid):
62 parameters = testbed_instance._get_parameters(guid)
63 element = testbed_instance._make_application(parameters)
64 testbed_instance.elements[guid] = element
66 def create_internet(testbed_instance, guid):
67 parameters = testbed_instance._get_parameters(guid)
68 element = testbed_instance._make_internet(parameters)
69 testbed_instance.elements[guid] = element
71 ### Start/Stop functions ###
73 def start_application(testbed_instance, guid):
74 parameters = testbed_instance._get_parameters(guid)
75 traces = testbed_instance._get_traces(guid)
76 app = testbed_instance.elements[guid]
78 app.stdout = testbed_instance.trace_filename(guid, "stdout")
79 app.stderr = testbed_instance.trace_filename(guid, "stderr")
84 ### Status functions ###
86 def status_application(testbed_instance, guid):
87 if guid not in testbed_instance.elements.keys():
88 return STATUS_NOT_STARTED
89 app = testbed_instance.elements[guid]
91 return STATUS_FINISHED
93 ### Configure functions ###
95 def configure_nodeiface(testbed_instance, guid):
96 element = testbed_instance._elements[guid]
98 # Cannot explicitly configure addresses
99 if guid in testbed_instance._add_address:
100 del testbed_instance._add_address[guid]
103 node_guid = testbed_instance.get_connected(guid, "node", "devs")[0]
104 dev_guids = testbed_instance.get_connected(node_guid, "node", "devs")
105 siblings = [ self._element[dev_guid]
106 for dev_guid in dev_guids
107 if dev_guid != guid ]
109 # Fetch address from PLC api
110 element.pick_iface(siblings)
112 # Do some validations
115 def configure_tuniface(testbed_instance, guid):
116 element = testbed_instance._elements[guid]
117 if not guid in testbed_instance._add_address:
120 addresses = testbed_instance._add_address[guid]
121 for address in addresses:
122 (address, netprefix, broadcast) = address
125 # Do some validations
128 def configure_node(testbed_instance, guid):
129 element = testbed_instance._elements[guid]
131 # If we have only one candidate, simply use it
132 candidates = element.find_candidates(
133 filter_slice_id = testbed_instance.slice_id)
134 if len(candidates) == 1:
135 element.assign_node_id(iter(candidates).next())
137 # Do some validations
140 ### Factory information ###
142 connector_types = dict({
144 "help": "Connector from node to applications",
150 "help": "Connector from node to network interfaces",
156 "help": "Connector from network interfaces to the internet",
162 "help": "Connector to a Node",
171 "from": (TESTBED_ID, NODE, "devs"),
172 "to": (TESTBED_ID, NODEIFACE, "node"),
173 "code": connect_node_iface_node,
177 "from": (TESTBED_ID, NODE, "devs"),
178 "to": (TESTBED_ID, TUNIFACE, "node"),
179 "code": connect_tun_iface_node,
183 "from": (TESTBED_ID, NODEIFACE, "inet"),
184 "to": (TESTBED_ID, INTERNET, "devs"),
185 "code": connect_node_iface_inet,
189 "from": (TESTBED_ID, NODE, "apps"),
190 "to": (TESTBED_ID, APPLICATION, "node"),
197 "forward_X11": dict({
198 "name": "forward_X11",
199 "help": "Forward x11 from main namespace to the node",
200 "type": Attribute.BOOL,
202 "flags": Attribute.DesignOnly,
203 "validation_function": validation.is_bool,
207 "help": "Constrain hostname during resource discovery. May use wildcards.",
208 "type": Attribute.STRING,
209 "flags": Attribute.DesignOnly,
210 "validation_function": validation.is_string,
212 "architecture": dict({
213 "name": "architecture",
214 "help": "Constrain architexture during resource discovery.",
215 "type": Attribute.ENUM,
216 "flags": Attribute.DesignOnly,
217 "allowed": ["x86_64",
219 "validation_function": validation.is_enum,
221 "operating_system": dict({
222 "name": "operatingSystem",
223 "help": "Constrain operating system during resource discovery.",
224 "type": Attribute.ENUM,
225 "flags": Attribute.DesignOnly,
231 "validation_function": validation.is_enum,
235 "help": "Constrain the PlanetLab site this node should reside on.",
236 "type": Attribute.ENUM,
237 "flags": Attribute.DesignOnly,
241 "validation_function": validation.is_enum,
245 "help": "Enable emulation on this node. Enables NetfilterRoutes, bridges, and a host of other functionality.",
246 "type": Attribute.BOOL,
248 "flags": Attribute.DesignOnly,
249 "validation_function": validation.is_bool,
251 "min_reliability": dict({
252 "name": "minReliability",
253 "help": "Constrain reliability while picking PlanetLab nodes. Specifies a lower acceptable bound.",
254 "type": Attribute.DOUBLE,
256 "flags": Attribute.DesignOnly,
257 "validation_function": validation.is_double,
259 "max_reliability": dict({
260 "name": "maxReliability",
261 "help": "Constrain reliability while picking PlanetLab nodes. Specifies an upper acceptable bound.",
262 "type": Attribute.DOUBLE,
264 "flags": Attribute.DesignOnly,
265 "validation_function": validation.is_double,
267 "min_bandwidth": dict({
268 "name": "minBandwidth",
269 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies a lower acceptable bound.",
270 "type": Attribute.DOUBLE,
272 "flags": Attribute.DesignOnly,
273 "validation_function": validation.is_double,
275 "max_bandwidth": dict({
276 "name": "maxBandwidth",
277 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies an upper acceptable bound.",
278 "type": Attribute.DOUBLE,
280 "flags": Attribute.DesignOnly,
281 "validation_function": validation.is_double,
287 "type": Attribute.BOOL,
289 "validation_function": validation.is_bool
293 "help": "This is the primary interface for the attached node",
294 "type": Attribute.BOOL,
296 "validation_function": validation.is_bool
298 "device_name": dict({
300 "help": "Device name",
301 "type": Attribute.STRING,
302 "flags": Attribute.DesignOnly,
303 "validation_function": validation.is_string
307 "help": "Maximum transmition unit for device",
308 "type": Attribute.INTEGER,
310 "validation_function": validation.is_integer_range(0,1500)
314 "help": "Network mask for the device (eg: 24 for /24 network)",
315 "type": Attribute.INTEGER,
316 "validation_function": validation.is_integer_range(8,24)
320 "help": "Enable SNAT (source NAT to the internet) no this device",
321 "type": Attribute.BOOL,
323 "validation_function": validation.is_bool
328 "help": "Command line string",
329 "type": Attribute.STRING,
330 "flags": Attribute.DesignOnly,
331 "validation_function": validation.is_string
335 "help": "System user",
336 "type": Attribute.BOOL,
337 "flags": Attribute.DesignOnly,
339 "validation_function": validation.is_bool
343 "help": "Standard input",
344 "type": Attribute.STRING,
345 "flags": Attribute.DesignOnly,
346 "validation_function": validation.is_string
353 "help": "Standard output stream"
357 "help": "Application standard error",
361 create_order = [ INTERNET, NODE, NODEIFACE, TUNIFACE, APPLICATION ]
363 configure_order = [ INTERNET, NODE, NODEIFACE, TUNIFACE, APPLICATION ]
365 factories_info = dict({
367 "allow_routes": False,
368 "help": "Virtualized Node (V-Server style)",
369 "category": "topology",
370 "create_function": create_node,
371 "configure_function": configure_node,
384 "connector_types": ["devs", "apps"]
387 "allow_addresses": True,
388 "help": "External network interface - they cannot be brought up or down, and they MUST be connected to the internet.",
389 "category": "devices",
390 "create_function": create_nodeiface,
391 "configure_function": configure_nodeiface,
392 "box_attributes": [ ],
393 "connector_types": ["node", "inet"]
396 "allow_addresses": True,
397 "help": "Virtual TUN network interface",
398 "category": "devices",
399 "create_function": create_tuniface,
400 "configure_function": configure_tuniface,
402 "up", "device_name", "mtu", "snat",
404 "connector_types": ["node"]
407 "help": "Generic executable command line application",
408 "category": "applications",
409 "create_function": create_application,
410 "start_function": start_application,
411 "status_function": status_application,
412 "box_attributes": ["command", "sudo"],
413 "connector_types": ["node"],
414 "traces": ["stdout", "stderr"]
417 "help": "Internet routing",
418 "category": "topology",
419 "create_function": create_internet,
420 "connector_types": ["devs"],
424 testbed_attributes = dict({
427 "help": "The name of the PlanetLab slice to use",
428 "type": Attribute.STRING,
429 "flags": Attribute.DesignOnly | Attribute.HasNoDefaultValue,
430 "validation_function": validation.is_string
434 "help": "The name of the PlanetLab user to use for API calls - it must have at least a User role.",
435 "type": Attribute.STRING,
436 "flags": Attribute.DesignOnly | Attribute.HasNoDefaultValue,
437 "validation_function": validation.is_string
441 "help": "The PlanetLab user's password.",
442 "type": Attribute.STRING,
443 "flags": Attribute.DesignOnly | Attribute.HasNoDefaultValue,
444 "validation_function": validation.is_string
448 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
450 def connector_types(self):
451 return connector_types
454 def connections(self):
458 def attributes(self):
466 def create_order(self):
470 def configure_order(self):
471 return configure_order
474 def factories_info(self):
475 return factories_info
478 def testbed_attributes(self):
479 return testbed_attributes