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, node, internet):
25 iface.has_internet = True
27 def connect_tun_iface_node(testbed_instance, node, iface):
30 ### Creation functions ###
32 def create_node(testbed_instance, guid):
33 parameters = testbed_instance._get_parameters(guid)
35 # create element with basic attributes
36 element = testbed_instance._make_node(parameters)
38 # add constraint on number of (real) interfaces
39 # by counting connected devices
40 dev_guids = testbed_instance.get_connected(guid, "node", "devs")
41 num_open_ifaces = sum( # count True values
42 TUNEIFACE == testbed_instance._get_factory_id(guid)
43 for guid in dev_guids )
44 element.min_num_external_ifaces = num_open_ifaces
46 testbed_instance.elements[guid] = element
48 def create_nodeiface(testbed_instance, guid):
49 parameters = testbed_instance._get_parameters(guid)
50 element = testbed_instance.create_node_iface(parameters)
51 testbed_instance.elements[guid] = element
53 def create_tuniface(testbed_instance, guid):
54 parameters = testbed_instance._get_parameters(guid)
55 element = testbed_instance._make_tun_iface(parameters)
56 testbed_instance.elements[guid] = element
58 def create_application(testbed_instance, guid):
59 parameters = testbed_instance._get_parameters(guid)
60 element = testbed_instance._make_internet(parameters)
61 testbed_instance.elements[guid] = element
63 def create_internet(testbed_instance, guid):
64 parameters = testbed_instance._get_parameters(guid)
66 testbed_instance.elements[guid] = element
68 ### Start/Stop functions ###
70 def start_application(testbed_instance, guid):
71 parameters = testbed_instance._get_parameters(guid)
72 traces = testbed_instance._get_traces(guid)
73 user = parameters["user"]
74 command = parameters["command"]
75 stdout = stderr = None
76 if "stdout" in traces:
79 if "stderr" in traces:
83 node_guids = testbed_instance.get_connected(guid, "node", "apps")
85 raise RuntimeError, "Can't instantiate interface %d outside planetlab node" % (guid,)
87 node = testbed_instance.elements[node_guids[0]]
91 ### Status functions ###
93 def status_application(testbed_instance, guid):
94 if guid not in testbed_instance.elements.keys():
95 return STATUS_NOT_STARTED
96 app = testbed_instance.elements[guid]
98 return STATUS_NOT_STARTED
100 ### Configure functions ###
102 def configure_nodeiface(testbed_instance, guid):
103 element = testbed_instance._elements[guid]
104 if not guid in testbed_instance._add_address:
107 # Cannot explicitly configure addresses
108 del testbed_instance._add_address[guid]
111 node_guid = testbed_instance.get_connected(guid, "node", "devs")[0]
112 dev_guids = testbed_instance.get_connected(node_guid, "node", "devs")
113 siblings = [ self._element[dev_guid]
114 for dev_guid in dev_guids
115 if dev_guid != guid ]
117 # Fetch address from PLC api
118 element.pick_iface(siblings)
120 # Do some validations
123 def configure_tuniface(testbed_instance, guid):
124 element = testbed_instance._elements[guid]
125 if not guid in testbed_instance._add_address:
127 addresses = testbed_instance._add_address[guid]
128 for address in addresses:
129 (address, netprefix, broadcast) = address
132 # Do some validations
135 def configure_node(testbed_instance, guid):
136 element = testbed_instance._elements[guid]
138 # Do some validations
141 ### Factory information ###
143 connector_types = dict({
145 "help": "Connector from node to applications",
151 "help": "Connector from node to network interfaces",
157 "help": "Connector from network interfaces to the internet",
163 "help": "Connector to a Node",
172 "from": (TESTBED_ID, NODE, "devs"),
173 "to": (TESTBED_ID, NODEIFACE, "node"),
174 "code": connect_node_iface_node,
178 "from": (TESTBED_ID, NODE, "devs"),
179 "to": (TESTBED_ID, TUNIFACE, "node"),
180 "code": connect_tun_iface_node,
184 "from": (TESTBED_ID, NODEIFACE, "inet"),
185 "to": (TESTBED_ID, INTERNET, "devs"),
186 "code": connect_node_iface_inet,
190 "from": (TESTBED_ID, NODE, "apps"),
191 "to": (TESTBED_ID, APPLICATION, "node"),
198 "forward_X11": dict({
199 "name": "forward_X11",
200 "help": "Forward x11 from main namespace to the node",
201 "type": Attribute.BOOL,
203 "flags": Attribute.DesignOnly,
204 "validation_function": validation.is_bool,
208 "help": "Constrain hostname during resource discovery. May use wildcards.",
209 "type": Attribute.STRING,
210 "flags": Attribute.DesignOnly,
211 "validation_function": validation.is_string,
213 "architecture": dict({
214 "name": "architecture",
215 "help": "Constrain architexture during resource discovery.",
216 "type": Attribute.ENUM,
217 "flags": Attribute.DesignOnly,
218 "allowed": ["x86_64",
220 "validation_function": validation.is_enum,
222 "operating_system": dict({
223 "name": "operatingSystem",
224 "help": "Constrain operating system during resource discovery.",
225 "type": Attribute.ENUM,
226 "flags": Attribute.DesignOnly,
232 "validation_function": validation.is_enum,
236 "help": "Constrain the PlanetLab site this node should reside on.",
237 "type": Attribute.ENUM,
238 "flags": Attribute.DesignOnly,
242 "validation_function": validation.is_enum,
246 "help": "Enable emulation on this node. Enables NetfilterRoutes, bridges, and a host of other functionality.",
247 "type": Attribute.BOOL,
249 "flags": Attribute.DesignOnly,
250 "validation_function": validation.is_bool,
252 "min_reliability": dict({
253 "name": "minReliability",
254 "help": "Constrain reliability while picking PlanetLab nodes. Specifies a lower acceptable bound.",
255 "type": Attribute.DOUBLE,
257 "flags": Attribute.DesignOnly,
258 "validation_function": validation.is_double,
260 "max_reliability": dict({
261 "name": "maxReliability",
262 "help": "Constrain reliability while picking PlanetLab nodes. Specifies an upper acceptable bound.",
263 "type": Attribute.DOUBLE,
265 "flags": Attribute.DesignOnly,
266 "validation_function": validation.is_double,
268 "min_bandwidth": dict({
269 "name": "minBandwidth",
270 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies a lower acceptable bound.",
271 "type": Attribute.DOUBLE,
273 "flags": Attribute.DesignOnly,
274 "validation_function": validation.is_double,
276 "max_bandwidth": dict({
277 "name": "maxBandwidth",
278 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies an upper acceptable bound.",
279 "type": Attribute.DOUBLE,
281 "flags": Attribute.DesignOnly,
282 "validation_function": validation.is_double,
288 "type": Attribute.BOOL,
290 "validation_function": validation.is_bool
294 "help": "This is the primary interface for the attached node",
295 "type": Attribute.BOOL,
297 "validation_function": validation.is_bool
299 "device_name": dict({
301 "help": "Device name",
302 "type": Attribute.STRING,
303 "flags": Attribute.DesignOnly,
304 "validation_function": validation.is_string
308 "help": "Maximum transmition unit for device",
309 "type": Attribute.INTEGER,
311 "validation_function": validation.is_integer_range(0,1500)
315 "help": "Network mask for the device (eg: 24 for /24 network)",
316 "type": Attribute.INTEGER,
317 "validation_function": validation.is_integer_range(8,24)
321 "help": "Enable SNAT (source NAT to the internet) no this device",
322 "type": Attribute.BOOL,
324 "validation_function": validation.is_bool
329 "help": "Command line string",
330 "type": Attribute.STRING,
331 "flags": Attribute.DesignOnly,
332 "validation_function": validation.is_string
336 "help": "System user",
337 "type": Attribute.STRING,
338 "flags": Attribute.DesignOnly,
339 "validation_function": validation.is_string
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 = [ NODE, NODEIFACE, TUNIFACE, APPLICATION ]
363 configure_order = [ 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", "user"],
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 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
436 def connector_types(self):
437 return connector_types
440 def connections(self):
444 def attributes(self):
452 def create_order(self):
456 def configure_order(self):
457 return configure_order
460 def factories_info(self):
461 return factories_info
464 def testbed_attributes(self):
465 return testbed_attributes