1 # -*- coding: utf-8 -*-
7 from nepi.core.attributes import AttributesMap, Attribute
8 from nepi.core.metadata import Metadata
9 from nepi.util import validation
10 from nepi.util.guid import GuidGenerator
11 from nepi.util.graphical_info import GraphicalInfo
12 from nepi.util.parser._xml import XmlExperimentParser
13 from nepi.util.tags import Taggable
16 class Connector(object):
17 """A Connector sepcifies the connection points in an Object"""
18 def __init__(self, box, connector_type):
19 super(Connector, self).__init__()
21 self._connector_type = connector_type
22 self._connections = list()
25 return "Connector(%s, %s)" % (self.box, self.connector_type)
32 def connector_type(self):
33 return self._connector_type
36 def connections(self):
37 return self._connections
40 """Return True if the connector has the maximum number of connections
42 return len(self.connections) == self.connector_type.max
44 def is_complete(self):
45 """Return True if the connector has the minimum number of connections
47 return len(self.connections) >= self.connector_type.min
49 def is_connected(self, connector):
50 return connector in self._connections
52 def connect(self, connector):
53 if not self.can_connect(connector) or not connector.can_connect(self):
54 raise RuntimeError("Could not connect. %s to %s" % (self, connector))
55 self._connections.append(connector)
56 connector._connections.append(self)
58 def get_connected_box(self, idx = 0):
59 if len(self._connections) == 0:
61 return self._connections[idx].box
63 def disconnect(self, connector):
64 if connector not in self._connections or\
65 self not in connector._connections:
66 raise RuntimeError("Could not disconnect.")
67 self._connections.remove(connector)
68 connector._connections.remove(self)
70 def can_connect(self, connector):
71 # can't connect with self
72 if self.box.guid == connector.box.guid:
74 if self.is_full() or connector.is_full():
76 if self.is_connected(connector):
78 (testbed_id, factory_id, name) = connector.connector_type.connector_type_id
79 testbed_guid1 = self.box.testbed_guid
80 testbed_guid2 = connector.box.testbed_guid
81 must_cross = (testbed_guid1 != testbed_guid2)
82 return self.connector_type.can_connect(testbed_id, factory_id, name,
86 for connector in self.connections:
87 self.disconnect(connector)
88 self._box = self._connectors = None
90 class Trace(AttributesMap):
91 def __init__(self, name, help, enabled = False):
92 super(Trace, self).__init__()
95 self._enabled = enabled
113 self._enabled = False
115 class Address(AttributesMap):
117 super(Address, self).__init__()
118 self.add_attribute(name = "Address",
119 help = "Address number",
120 type = Attribute.STRING,
121 flags = Attribute.NoDefaultValue,
122 validation_function = validation.is_ip_address)
123 self.add_attribute(name = "NetPrefix",
124 help = "Network prefix for the address",
125 type = Attribute.INTEGER,
128 flags = Attribute.NoDefaultValue,
129 validation_function = validation.is_integer)
130 self.add_attribute(name = "Broadcast",
131 help = "Broadcast address",
132 type = Attribute.STRING,
133 validation_function = validation.is_ip4_address)
135 class Route(AttributesMap):
137 super(Route, self).__init__()
138 self.add_attribute(name = "Destination",
139 help = "Network destintation",
140 type = Attribute.STRING,
141 validation_function = validation.is_ref_address)
142 self.add_attribute(name = "NetPrefix",
143 help = "Network destination prefix",
144 type = Attribute.INTEGER,
147 flags = Attribute.NoDefaultValue,
148 validation_function = validation.is_integer)
149 self.add_attribute(name = "NextHop",
150 help = "Address for the next hop",
151 type = Attribute.STRING,
152 flags = Attribute.NoDefaultValue,
153 validation_function = validation.is_ref_address)
154 self.add_attribute(name = "Metric",
155 help = "Routing metric",
156 type = Attribute.INTEGER,
158 flags = Attribute.NoDefaultValue,
159 validation_function = validation.is_integer)
160 self.add_attribute(name = "Device",
161 help = "Device name",
162 type = Attribute.STRING,
164 flags = Attribute.NoDefaultValue,
165 validation_function = validation.is_string)
167 class Box(AttributesMap, Taggable):
168 def __init__(self, guid, factory, testbed_guid, container = None):
169 super(Box, self).__init__()
170 # guid -- global unique identifier
172 # factory_id -- factory identifier or name
173 self._factory_id = factory.factory_id
174 # testbed_guid -- parent testbed guid
175 self._testbed_guid = testbed_guid
176 # container -- boxes can be nested inside other 'container' boxes
177 self._container = container
178 # traces -- list of available traces for the box
179 self._traces = dict()
180 # connectors -- list of available connectors for the box
181 self._connectors = dict()
182 # factory_attributes -- factory attributes for box construction
183 self._factory_attributes = dict()
184 # graphical_info -- GUI position information
185 self.graphical_info = GraphicalInfo()
187 for connector_type in factory.connector_types:
188 connector = Connector(self, connector_type)
189 self._connectors[connector_type.name] = connector
190 for (name, help, enabled) in factory.traces:
191 trace = Trace(name, help, enabled)
192 self._traces[name] = trace
193 for tag_id in factory.tags:
195 for attr in factory.box_attributes.attributes:
196 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
197 attr.range, attr.allowed, attr.flags,
198 attr.validation_function, attr.category)
199 for attr in factory.attributes:
200 if attr.modified or attr.is_metadata:
201 self._factory_attributes[attr.name] = attr.value
204 return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
211 def factory_id(self):
212 return self._factory_id
215 def testbed_guid(self):
216 return self._testbed_guid
220 return self._container
223 def connectors(self):
224 return self._connectors.values()
228 return self._traces.values()
231 def traces_list(self):
232 return self._traces.keys()
235 def factory_attributes(self):
236 return self._factory_attributes
238 def trace_help(self, trace_id):
239 return self._traces[trace_id].help
241 def enable_trace(self, trace_id):
242 self._traces[trace_id].enable()
244 def disable_trace(self, trace_id):
245 self._traces[trace_id].disable()
247 def is_trace_enabled(self, trace_id):
248 return self._traces[trace_id].enabled
250 def connector(self, name):
251 return self._connectors[name]
254 super(Box, self).destroy()
255 for c in self.connectors:
257 for t in self.traces:
259 self._connectors = self._traces = self._factory_attributes = None
261 class FactoriesProvider(object):
262 def __init__(self, testbed_id):
263 super(FactoriesProvider, self).__init__()
264 self._testbed_id = testbed_id
265 self._factories = dict()
267 metadata = Metadata(testbed_id)
268 for factory in metadata.build_factories():
269 self.add_factory(factory)
271 self._testbed_version = metadata.testbed_version
274 def testbed_id(self):
275 return self._testbed_id
278 def testbed_version(self):
279 return self._testbed_version
283 return self._factories.values()
285 def factory(self, factory_id):
286 return self._factories[factory_id]
288 def add_factory(self, factory):
289 self._factories[factory.factory_id] = factory
291 def remove_factory(self, factory_id):
292 del self._factories[factory_id]
294 class TestbedDescription(AttributesMap):
295 def __init__(self, guid_generator, provider, guid = None):
296 super(TestbedDescription, self).__init__()
297 self._guid_generator = guid_generator
298 self._guid = guid_generator.next(guid)
299 self._provider = provider
301 self.graphical_info = GraphicalInfo()
303 metadata = Metadata(provider.testbed_id)
304 for attr in metadata.testbed_attributes().attributes:
305 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
306 attr.range, attr.allowed, attr.flags,
307 attr.validation_function, attr.category)
315 return self._provider
319 return self._boxes.values()
322 return self._boxes[guid] if guid in self._boxes else None
324 def create(self, factory_id, guid = None):
325 guid = self._guid_generator.next(guid)
326 factory = self._provider.factory(factory_id)
327 box = factory.create(guid, self)
328 self._boxes[guid] = box
331 def delete(self, guid):
332 box = self._boxes[guid]
333 del self._boxes[guid]
337 for guid, box in self._boxes.iteritems():
341 class ExperimentDescription(object):
343 self._guid_generator = GuidGenerator()
344 self._testbed_descriptions = dict()
347 def testbed_descriptions(self):
348 return self._testbed_descriptions.values()
351 parser = XmlExperimentParser()
352 return parser.to_xml(self)
354 def from_xml(self, xml):
355 parser = XmlExperimentParser()
356 parser.from_xml(self, xml)
358 def testbed_description(self, guid):
359 return self._testbed_descriptions[guid] \
360 if guid in self._testbed_descriptions else None
363 for testbed_description in self._testbed_descriptions.values():
364 box = testbed_description.box(guid)
368 def get_element(self, guid):
369 if guid in self._testbed_descriptions:
370 return self._testbed_descriptions[guid]
371 for testbed_description in self._testbed_descriptions.values():
372 box = testbed_description.box(guid)
376 def get_element_by_label(self, label):
377 for tbd_desc in self._testbed_descriptions.values():
378 l = tbd_desc.get_attribute_value("label")
381 for box in tbd_desc.boxes:
382 l = box.get_attribute_value("label")
387 def add_testbed_description(self, provider, guid = None):
388 testbed_description = TestbedDescription(self._guid_generator,
390 guid = testbed_description.guid
391 self._testbed_descriptions[guid] = testbed_description
392 return testbed_description
394 def remove_testbed_description(self, guid):
395 testbed_description = self._testbed_descriptions[guid]
396 del self._testbed_descriptions[guid]
397 testbed_description.destroy()
400 for testbed_description in self.testbed_descriptions:
401 testbed_description.destroy()