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 disconnect(self, connector):
59 if connector not in self._connections or\
60 self not in connector._connections:
61 raise RuntimeError("Could not disconnect.")
62 self._connections.remove(connector)
63 connector._connections.remove(self)
65 def can_connect(self, connector):
66 # can't connect with self
67 if self.box.guid == connector.box.guid:
69 if self.is_full() or connector.is_full():
71 if self.is_connected(connector):
73 (testbed_id, factory_id, name) = connector.connector_type.connector_type_id
74 testbed_guid1 = self.box.testbed_guid
75 testbed_guid2 = connector.box.testbed_guid
76 must_cross = (testbed_guid1 != testbed_guid2)
77 return self.connector_type.can_connect(testbed_id, factory_id, name,
81 for connector in self.connections:
82 self.disconnect(connector)
83 self._box = self._connectors = None
85 class Trace(AttributesMap):
86 def __init__(self, name, help, enabled = False):
87 super(Trace, self).__init__()
90 self._enabled = enabled
108 self._enabled = False
110 class Address(AttributesMap):
112 super(Address, self).__init__()
113 self.add_attribute(name = "Address",
114 help = "Address number",
115 type = Attribute.STRING,
116 flags = Attribute.NoDefaultValue,
117 validation_function = validation.is_ip_address)
118 self.add_attribute(name = "NetPrefix",
119 help = "Network prefix for the address",
120 type = Attribute.INTEGER,
123 flags = Attribute.NoDefaultValue,
124 validation_function = validation.is_integer)
125 self.add_attribute(name = "Broadcast",
126 help = "Broadcast address",
127 type = Attribute.STRING,
128 validation_function = validation.is_ip4_address)
130 class Route(AttributesMap):
132 super(Route, self).__init__()
133 self.add_attribute(name = "Destination",
134 help = "Network destintation",
135 type = Attribute.STRING,
136 validation_function = validation.is_ref_address)
137 self.add_attribute(name = "NetPrefix",
138 help = "Network destination prefix",
139 type = Attribute.INTEGER,
142 flags = Attribute.NoDefaultValue,
143 validation_function = validation.is_integer)
144 self.add_attribute(name = "NextHop",
145 help = "Address for the next hop",
146 type = Attribute.STRING,
147 flags = Attribute.NoDefaultValue,
148 validation_function = validation.is_ref_address)
149 self.add_attribute(name = "Metric",
150 help = "Routing metric",
151 type = Attribute.INTEGER,
153 flags = Attribute.NoDefaultValue,
154 validation_function = validation.is_integer)
156 class Box(AttributesMap, Taggable):
157 def __init__(self, guid, factory, testbed_guid, container = None):
158 super(Box, self).__init__()
159 # guid -- global unique identifier
161 # factory_id -- factory identifier or name
162 self._factory_id = factory.factory_id
163 # testbed_guid -- parent testbed guid
164 self._testbed_guid = testbed_guid
165 # container -- boxes can be nested inside other 'container' boxes
166 self._container = container
167 # traces -- list of available traces for the box
168 self._traces = dict()
169 # connectors -- list of available connectors for the box
170 self._connectors = dict()
171 # factory_attributes -- factory attributes for box construction
172 self._factory_attributes = dict()
173 # graphical_info -- GUI position information
174 self.graphical_info = GraphicalInfo()
176 for connector_type in factory.connector_types:
177 connector = Connector(self, connector_type)
178 self._connectors[connector_type.name] = connector
179 for (name, help, enabled) in factory.traces:
180 trace = Trace(name, help, enabled)
181 self._traces[name] = trace
182 for tag_id in factory.tags:
184 for attr in factory.box_attributes.attributes:
185 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
186 attr.range, attr.allowed, attr.flags,
187 attr.validation_function, attr.category)
188 for attr in factory.attributes:
189 if attr.modified or attr.is_metadata:
190 self._factory_attributes[attr.name] = attr.value
193 return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
200 def factory_id(self):
201 return self._factory_id
204 def testbed_guid(self):
205 return self._testbed_guid
209 return self._container
212 def connectors(self):
213 return self._connectors.values()
217 return self._traces.values()
220 def traces_list(self):
221 return self._traces.keys()
224 def factory_attributes(self):
225 return self._factory_attributes
227 def trace_help(self, trace_id):
228 return self._traces[trace_id].help
230 def enable_trace(self, trace_id):
231 self._traces[trace_id].enable()
233 def disable_trace(self, trace_id):
234 self._traces[trace_id].disable()
236 def is_trace_enabled(self, trace_id):
237 return self._traces[trace_id].enabled
239 def connector(self, name):
240 return self._connectors[name]
243 super(Box, self).destroy()
244 for c in self.connectors:
246 for t in self.traces:
248 self._connectors = self._traces = self._factory_attributes = None
250 class FactoriesProvider(object):
251 def __init__(self, testbed_id):
252 super(FactoriesProvider, self).__init__()
253 self._testbed_id = testbed_id
254 self._factories = dict()
256 metadata = Metadata(testbed_id)
257 for factory in metadata.build_factories():
258 self.add_factory(factory)
260 self._testbed_version = metadata.testbed_version
263 def testbed_id(self):
264 return self._testbed_id
267 def testbed_version(self):
268 return self._testbed_version
272 return self._factories.values()
274 def factory(self, factory_id):
275 return self._factories[factory_id]
277 def add_factory(self, factory):
278 self._factories[factory.factory_id] = factory
280 def remove_factory(self, factory_id):
281 del self._factories[factory_id]
283 class TestbedDescription(AttributesMap):
284 def __init__(self, guid_generator, provider, guid = None):
285 super(TestbedDescription, self).__init__()
286 self._guid_generator = guid_generator
287 self._guid = guid_generator.next(guid)
288 self._provider = provider
290 self.graphical_info = GraphicalInfo()
292 metadata = Metadata(provider.testbed_id)
293 for attr in metadata.testbed_attributes().attributes:
294 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
295 attr.range, attr.allowed, attr.flags,
296 attr.validation_function, attr.category)
304 return self._provider
308 return self._boxes.values()
311 return self._boxes[guid] if guid in self._boxes else None
313 def create(self, factory_id, guid = None):
314 guid = self._guid_generator.next(guid)
315 factory = self._provider.factory(factory_id)
316 box = factory.create(guid, self)
317 self._boxes[guid] = box
320 def delete(self, guid):
321 box = self._boxes[guid]
322 del self._boxes[guid]
326 for guid, box in self._boxes.iteritems():
330 class ExperimentDescription(object):
332 self._guid_generator = GuidGenerator()
333 self._testbed_descriptions = dict()
336 def testbed_descriptions(self):
337 return self._testbed_descriptions.values()
340 parser = XmlExperimentParser()
341 return parser.to_xml(self)
343 def from_xml(self, xml):
344 parser = XmlExperimentParser()
345 parser.from_xml(self, xml)
347 def testbed_description(self, guid):
348 return self._testbed_descriptions[guid] \
349 if guid in self._testbed_descriptions else None
352 for testbed_description in self._testbed_descriptions.values():
353 box = testbed_description.box(guid)
357 def get_element(self, guid):
358 if guid in self._testbed_descriptions:
359 return self._testbed_descriptions[guid]
360 for testbed_description in self._testbed_descriptions.values():
361 box = testbed_description.box(guid)
365 def get_element_by_label(self, label):
366 for tbd_desc in self._testbed_descriptions.values():
367 l = tbd_desc.get_attribute_value("label")
370 for box in tbd_desc.boxes:
371 l = box.get_attribute_value("label")
376 def add_testbed_description(self, provider, guid = None):
377 testbed_description = TestbedDescription(self._guid_generator,
379 guid = testbed_description.guid
380 self._testbed_descriptions[guid] = testbed_description
381 return testbed_description
383 def remove_testbed_description(self, guid):
384 testbed_description = self._testbed_descriptions[guid]
385 del self._testbed_descriptions[guid]
386 testbed_description.destroy()
389 for testbed_description in self.testbed_descriptions:
390 testbed_description.destroy()