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)
161 class Box(AttributesMap, Taggable):
162 def __init__(self, guid, factory, testbed_guid, container = None):
163 super(Box, self).__init__()
164 # guid -- global unique identifier
166 # factory_id -- factory identifier or name
167 self._factory_id = factory.factory_id
168 # testbed_guid -- parent testbed guid
169 self._testbed_guid = testbed_guid
170 # container -- boxes can be nested inside other 'container' boxes
171 self._container = container
172 # traces -- list of available traces for the box
173 self._traces = dict()
174 # connectors -- list of available connectors for the box
175 self._connectors = dict()
176 # factory_attributes -- factory attributes for box construction
177 self._factory_attributes = dict()
178 # graphical_info -- GUI position information
179 self.graphical_info = GraphicalInfo()
181 for connector_type in factory.connector_types:
182 connector = Connector(self, connector_type)
183 self._connectors[connector_type.name] = connector
184 for (name, help, enabled) in factory.traces:
185 trace = Trace(name, help, enabled)
186 self._traces[name] = trace
187 for tag_id in factory.tags:
189 for attr in factory.box_attributes.attributes:
190 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
191 attr.range, attr.allowed, attr.flags,
192 attr.validation_function, attr.category)
193 for attr in factory.attributes:
194 if attr.modified or attr.is_metadata:
195 self._factory_attributes[attr.name] = attr.value
198 return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
205 def factory_id(self):
206 return self._factory_id
209 def testbed_guid(self):
210 return self._testbed_guid
214 return self._container
217 def connectors(self):
218 return self._connectors.values()
222 return self._traces.values()
225 def traces_list(self):
226 return self._traces.keys()
229 def factory_attributes(self):
230 return self._factory_attributes
232 def trace_help(self, trace_id):
233 return self._traces[trace_id].help
235 def enable_trace(self, trace_id):
236 self._traces[trace_id].enable()
238 def disable_trace(self, trace_id):
239 self._traces[trace_id].disable()
241 def is_trace_enabled(self, trace_id):
242 return self._traces[trace_id].enabled
244 def connector(self, name):
245 return self._connectors[name]
248 super(Box, self).destroy()
249 for c in self.connectors:
251 for t in self.traces:
253 self._connectors = self._traces = self._factory_attributes = None
255 class FactoriesProvider(object):
256 def __init__(self, testbed_id):
257 super(FactoriesProvider, self).__init__()
258 self._testbed_id = testbed_id
259 self._factories = dict()
261 metadata = Metadata(testbed_id)
262 for factory in metadata.build_factories():
263 self.add_factory(factory)
265 self._testbed_version = metadata.testbed_version
268 def testbed_id(self):
269 return self._testbed_id
272 def testbed_version(self):
273 return self._testbed_version
277 return self._factories.values()
279 def factory(self, factory_id):
280 return self._factories[factory_id]
282 def add_factory(self, factory):
283 self._factories[factory.factory_id] = factory
285 def remove_factory(self, factory_id):
286 del self._factories[factory_id]
288 class TestbedDescription(AttributesMap):
289 def __init__(self, guid_generator, provider, guid = None):
290 super(TestbedDescription, self).__init__()
291 self._guid_generator = guid_generator
292 self._guid = guid_generator.next(guid)
293 self._provider = provider
295 self.graphical_info = GraphicalInfo()
297 metadata = Metadata(provider.testbed_id)
298 for attr in metadata.testbed_attributes().attributes:
299 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
300 attr.range, attr.allowed, attr.flags,
301 attr.validation_function, attr.category)
309 return self._provider
313 return self._boxes.values()
316 return self._boxes[guid] if guid in self._boxes else None
318 def create(self, factory_id, guid = None):
319 guid = self._guid_generator.next(guid)
320 factory = self._provider.factory(factory_id)
321 box = factory.create(guid, self)
322 self._boxes[guid] = box
325 def delete(self, guid):
326 box = self._boxes[guid]
327 del self._boxes[guid]
331 for guid, box in self._boxes.iteritems():
335 class ExperimentDescription(object):
337 self._guid_generator = GuidGenerator()
338 self._testbed_descriptions = dict()
341 def testbed_descriptions(self):
342 return self._testbed_descriptions.values()
345 parser = XmlExperimentParser()
346 return parser.to_xml(self)
348 def from_xml(self, xml):
349 parser = XmlExperimentParser()
350 parser.from_xml(self, xml)
352 def testbed_description(self, guid):
353 return self._testbed_descriptions[guid] \
354 if guid in self._testbed_descriptions else None
357 for testbed_description in self._testbed_descriptions.values():
358 box = testbed_description.box(guid)
362 def get_element(self, guid):
363 if guid in self._testbed_descriptions:
364 return self._testbed_descriptions[guid]
365 for testbed_description in self._testbed_descriptions.values():
366 box = testbed_description.box(guid)
370 def get_element_by_label(self, label):
371 for tbd_desc in self._testbed_descriptions.values():
372 l = tbd_desc.get_attribute_value("label")
375 for box in tbd_desc.boxes:
376 l = box.get_attribute_value("label")
381 def add_testbed_description(self, provider, guid = None):
382 testbed_description = TestbedDescription(self._guid_generator,
384 guid = testbed_description.guid
385 self._testbed_descriptions[guid] = testbed_description
386 return testbed_description
388 def remove_testbed_description(self, guid):
389 testbed_description = self._testbed_descriptions[guid]
390 del self._testbed_descriptions[guid]
391 testbed_description.destroy()
394 for testbed_description in self.testbed_descriptions:
395 testbed_description.destroy()