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.create_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]
77 sudo = parameters["sudo"]
78 command = parameters["command"]
80 app.stdout = testbed_instance.trace_filename(guid, "stdout")
81 app.stderr = testbed_instance.trace_filename(guid, "stderr")
86 ### Status functions ###
88 def status_application(testbed_instance, guid):
89 if guid not in testbed_instance.elements.keys():
90 return STATUS_NOT_STARTED
91 app = testbed_instance.elements[guid]
93 return STATUS_NOT_STARTED
95 ### Configure functions ###
97 def configure_nodeiface(testbed_instance, guid):
98 element = testbed_instance._elements[guid]
99 if not guid in testbed_instance._add_address:
102 # Cannot explicitly configure addresses
103 del testbed_instance._add_address[guid]
106 node_guid = testbed_instance.get_connected(guid, "node", "devs")[0]
107 dev_guids = testbed_instance.get_connected(node_guid, "node", "devs")
108 siblings = [ self._element[dev_guid]
109 for dev_guid in dev_guids
110 if dev_guid != guid ]
112 # Fetch address from PLC api
113 element.pick_iface(siblings)
115 # Do some validations
118 def configure_tuniface(testbed_instance, guid):
119 element = testbed_instance._elements[guid]
120 if not guid in testbed_instance._add_address:
122 addresses = testbed_instance._add_address[guid]
123 for address in addresses:
124 (address, netprefix, broadcast) = address
127 # Do some validations
130 def configure_node(testbed_instance, guid):
131 element = testbed_instance._elements[guid]
133 # Do some validations
136 ### Factory information ###
138 connector_types = dict({
140 "help": "Connector from node to applications",
146 "help": "Connector from node to network interfaces",
152 "help": "Connector from network interfaces to the internet",
158 "help": "Connector to a Node",
167 "from": (TESTBED_ID, NODE, "devs"),
168 "to": (TESTBED_ID, NODEIFACE, "node"),
169 "code": connect_node_iface_node,
173 "from": (TESTBED_ID, NODE, "devs"),
174 "to": (TESTBED_ID, TUNIFACE, "node"),
175 "code": connect_tun_iface_node,
179 "from": (TESTBED_ID, NODEIFACE, "inet"),
180 "to": (TESTBED_ID, INTERNET, "devs"),
181 "code": connect_node_iface_inet,
185 "from": (TESTBED_ID, NODE, "apps"),
186 "to": (TESTBED_ID, APPLICATION, "node"),
193 "forward_X11": dict({
194 "name": "forward_X11",
195 "help": "Forward x11 from main namespace to the node",
196 "type": Attribute.BOOL,
198 "flags": Attribute.DesignOnly,
199 "validation_function": validation.is_bool,
203 "help": "Constrain hostname during resource discovery. May use wildcards.",
204 "type": Attribute.STRING,
205 "flags": Attribute.DesignOnly,
206 "validation_function": validation.is_string,
208 "architecture": dict({
209 "name": "architecture",
210 "help": "Constrain architexture during resource discovery.",
211 "type": Attribute.ENUM,
212 "flags": Attribute.DesignOnly,
213 "allowed": ["x86_64",
215 "validation_function": validation.is_enum,
217 "operating_system": dict({
218 "name": "operatingSystem",
219 "help": "Constrain operating system during resource discovery.",
220 "type": Attribute.ENUM,
221 "flags": Attribute.DesignOnly,
227 "validation_function": validation.is_enum,
231 "help": "Constrain the PlanetLab site this node should reside on.",
232 "type": Attribute.ENUM,
233 "flags": Attribute.DesignOnly,
237 "validation_function": validation.is_enum,
241 "help": "Enable emulation on this node. Enables NetfilterRoutes, bridges, and a host of other functionality.",
242 "type": Attribute.BOOL,
244 "flags": Attribute.DesignOnly,
245 "validation_function": validation.is_bool,
247 "min_reliability": dict({
248 "name": "minReliability",
249 "help": "Constrain reliability while picking PlanetLab nodes. Specifies a lower acceptable bound.",
250 "type": Attribute.DOUBLE,
252 "flags": Attribute.DesignOnly,
253 "validation_function": validation.is_double,
255 "max_reliability": dict({
256 "name": "maxReliability",
257 "help": "Constrain reliability while picking PlanetLab nodes. Specifies an upper acceptable bound.",
258 "type": Attribute.DOUBLE,
260 "flags": Attribute.DesignOnly,
261 "validation_function": validation.is_double,
263 "min_bandwidth": dict({
264 "name": "minBandwidth",
265 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies a lower acceptable bound.",
266 "type": Attribute.DOUBLE,
268 "flags": Attribute.DesignOnly,
269 "validation_function": validation.is_double,
271 "max_bandwidth": dict({
272 "name": "maxBandwidth",
273 "help": "Constrain available bandwidth while picking PlanetLab nodes. Specifies an upper acceptable bound.",
274 "type": Attribute.DOUBLE,
276 "flags": Attribute.DesignOnly,
277 "validation_function": validation.is_double,
283 "type": Attribute.BOOL,
285 "validation_function": validation.is_bool
289 "help": "This is the primary interface for the attached node",
290 "type": Attribute.BOOL,
292 "validation_function": validation.is_bool
294 "device_name": dict({
296 "help": "Device name",
297 "type": Attribute.STRING,
298 "flags": Attribute.DesignOnly,
299 "validation_function": validation.is_string
303 "help": "Maximum transmition unit for device",
304 "type": Attribute.INTEGER,
306 "validation_function": validation.is_integer_range(0,1500)
310 "help": "Network mask for the device (eg: 24 for /24 network)",
311 "type": Attribute.INTEGER,
312 "validation_function": validation.is_integer_range(8,24)
316 "help": "Enable SNAT (source NAT to the internet) no this device",
317 "type": Attribute.BOOL,
319 "validation_function": validation.is_bool
324 "help": "Command line string",
325 "type": Attribute.STRING,
326 "flags": Attribute.DesignOnly,
327 "validation_function": validation.is_string
331 "help": "System user",
332 "type": Attribute.BOOL,
333 "flags": Attribute.DesignOnly,
335 "validation_function": validation.is_bool
339 "help": "Standard input",
340 "type": Attribute.STRING,
341 "flags": Attribute.DesignOnly,
342 "validation_function": validation.is_string
349 "help": "Standard output stream"
353 "help": "Application standard error",
357 create_order = [ NODE, NODEIFACE, TUNIFACE, APPLICATION ]
359 configure_order = [ NODE, NODEIFACE, TUNIFACE, APPLICATION ]
361 factories_info = dict({
363 "allow_routes": False,
364 "help": "Virtualized Node (V-Server style)",
365 "category": "topology",
366 "create_function": create_node,
367 "configure_function": configure_node,
380 "connector_types": ["devs", "apps"]
383 "allow_addresses": True,
384 "help": "External network interface - they cannot be brought up or down, and they MUST be connected to the internet.",
385 "category": "devices",
386 "create_function": create_nodeiface,
387 "configure_function": configure_nodeiface,
388 "box_attributes": [ ],
389 "connector_types": ["node", "inet"]
392 "allow_addresses": True,
393 "help": "Virtual TUN network interface",
394 "category": "devices",
395 "create_function": create_tuniface,
396 "configure_function": configure_tuniface,
398 "up", "device_name", "mtu", "snat",
400 "connector_types": ["node"]
403 "help": "Generic executable command line application",
404 "category": "applications",
405 "create_function": create_application,
406 "start_function": start_application,
407 "status_function": status_application,
408 "box_attributes": ["command", "sudo"],
409 "connector_types": ["node"],
410 "traces": ["stdout", "stderr"]
413 "help": "Internet routing",
414 "category": "topology",
415 "create_function": create_internet,
416 "connector_types": ["devs"],
420 testbed_attributes = dict({
423 "help": "The name of the PlanetLab slice to use",
424 "type": Attribute.STRING,
425 "flags": Attribute.DesignOnly | Attribute.HasNoDefaultValue,
426 "validation_function": validation.is_string
430 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
432 def connector_types(self):
433 return connector_types
436 def connections(self):
440 def attributes(self):
448 def create_order(self):
452 def configure_order(self):
453 return configure_order
456 def factories_info(self):
457 return factories_info
460 def testbed_attributes(self):
461 return testbed_attributes