2 # -*- coding: utf-8 -*-
8 from nepi.core.attributes import AttributesMap, Attribute
9 from nepi.core.metadata import Metadata
10 from nepi.util import validation
11 from nepi.util.guid import GuidGenerator
12 from nepi.util.graphical_info import GraphicalInfo
13 from nepi.util.parser._xml import XmlExperimentParser
14 from nepi.util.tags import Taggable
17 class Connector(object):
18 """A Connector sepcifies the connection points in an Object"""
19 def __init__(self, box, connector_type):
20 super(Connector, self).__init__()
22 self._connector_type = connector_type
23 self._connections = list()
26 return "Connector(%s, %s)" % (self.box, self.connector_type)
33 def connector_type(self):
34 return self._connector_type
37 def connections(self):
38 return self._connections
41 """Return True if the connector has the maximum number of connections
43 return len(self.connections) == self.connector_type.max
45 def is_complete(self):
46 """Return True if the connector has the minimum number of connections
48 return len(self.connections) >= self.connector_type.min
50 def is_connected(self, connector):
51 return connector in self._connections
53 def connect(self, connector):
54 if not self.can_connect(connector) or not connector.can_connect(self):
55 raise RuntimeError("Could not connect. %s to %s" % (self, connector))
56 self._connections.append(connector)
57 connector._connections.append(self)
59 def disconnect(self, connector):
60 if connector not in self._connections or\
61 self not in connector._connections:
62 raise RuntimeError("Could not disconnect.")
63 self._connections.remove(connector)
64 connector._connections.remove(self)
66 def can_connect(self, connector):
67 # can't connect with self
68 if self.box.guid == connector.box.guid:
70 if self.is_full() or connector.is_full():
72 if self.is_connected(connector):
74 (testbed_id, factory_id, name) = connector.connector_type.connector_type_id
75 testbed_guid1 = self.box.testbed_guid
76 testbed_guid2 = connector.box.testbed_guid
77 must_cross = (testbed_guid1 != testbed_guid2)
78 return self.connector_type.can_connect(testbed_id, factory_id, name,
82 for connector in self.connections:
83 self.disconnect(connector)
84 self._box = self._connectors = None
86 class Trace(AttributesMap):
87 def __init__(self, name, help, enabled = False):
88 super(Trace, self).__init__()
91 self._enabled = enabled
109 self._enabled = False
111 class Address(AttributesMap):
113 super(Address, self).__init__()
114 self.add_attribute(name = "Address",
115 help = "Address number",
116 type = Attribute.STRING,
117 flags = Attribute.NoDefaultValue,
118 validation_function = validation.is_ip_address)
119 self.add_attribute(name = "NetPrefix",
120 help = "Network prefix for the address",
121 type = Attribute.INTEGER,
124 flags = Attribute.NoDefaultValue,
125 validation_function = validation.is_integer)
126 self.add_attribute(name = "Broadcast",
127 help = "Broadcast address",
128 type = Attribute.STRING,
129 validation_function = validation.is_ip4_address)
131 class Route(AttributesMap):
133 super(Route, self).__init__()
134 self.add_attribute(name = "Destination",
135 help = "Network destintation",
136 type = Attribute.STRING,
137 validation_function = validation.is_ref_address)
138 self.add_attribute(name = "NetPrefix",
139 help = "Network destination prefix",
140 type = Attribute.INTEGER,
143 flags = Attribute.NoDefaultValue,
144 validation_function = validation.is_integer)
145 self.add_attribute(name = "NextHop",
146 help = "Address for the next hop",
147 type = Attribute.STRING,
148 flags = Attribute.NoDefaultValue,
149 validation_function = validation.is_ref_address)
150 self.add_attribute(name = "Metric",
151 help = "Routing metric",
152 type = Attribute.INTEGER,
154 flags = Attribute.NoDefaultValue,
155 validation_function = validation.is_integer)
157 class Box(AttributesMap, Taggable):
158 def __init__(self, guid, factory, testbed_guid, container = None):
159 super(Box, self).__init__()
160 # guid -- global unique identifier
162 # factory_id -- factory identifier or name
163 self._factory_id = factory.factory_id
164 # testbed_guid -- parent testbed guid
165 self._testbed_guid = testbed_guid
166 # container -- boxes can be nested inside other 'container' boxes
167 self._container = container
168 # traces -- list of available traces for the box
169 self._traces = dict()
170 # connectors -- list of available connectors for the box
171 self._connectors = dict()
172 # factory_attributes -- factory attributes for box construction
173 self._factory_attributes = dict()
174 # graphical_info -- GUI position information
175 self.graphical_info = GraphicalInfo()
177 for connector_type in factory.connector_types:
178 connector = Connector(self, connector_type)
179 self._connectors[connector_type.name] = connector
180 for (name, help, enabled) in factory.traces:
181 trace = Trace(name, help, enabled)
182 self._traces[name] = trace
183 for tag_id in factory.tags:
185 for attr in factory.box_attributes.attributes:
186 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
187 attr.range, attr.allowed, attr.flags,
188 attr.validation_function, attr.category)
189 for attr in factory.attributes:
190 if attr.modified or attr.is_metadata:
191 self._factory_attributes[attr.name] = attr.value
194 return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
201 def factory_id(self):
202 return self._factory_id
205 def testbed_guid(self):
206 return self._testbed_guid
210 return self._container
213 def connectors(self):
214 return self._connectors.values()
218 return self._traces.values()
221 def traces_list(self):
222 return self._traces.keys()
225 def factory_attributes(self):
226 return self._factory_attributes
228 def trace_help(self, trace_id):
229 return self._traces[trace_id].help
231 def enable_trace(self, trace_id):
232 self._traces[trace_id].enable()
234 def disable_trace(self, trace_id):
235 self._traces[trace_id].disable()
237 def is_trace_enabled(self, trace_id):
238 return self._traces[trace_id].enabled
240 def connector(self, name):
241 return self._connectors[name]
244 super(Box, self).destroy()
245 for c in self.connectors:
247 for t in self.traces:
249 self._connectors = self._traces = self._factory_attributes = None
251 class FactoriesProvider(object):
252 def __init__(self, testbed_id):
253 super(FactoriesProvider, self).__init__()
254 self._testbed_id = testbed_id
255 self._factories = dict()
257 metadata = Metadata(testbed_id)
258 for factory in metadata.build_factories():
259 self.add_factory(factory)
261 self._testbed_version = metadata.testbed_version
264 def testbed_id(self):
265 return self._testbed_id
268 def testbed_version(self):
269 return self._testbed_version
273 return self._factories.values()
275 def factory(self, factory_id):
276 return self._factories[factory_id]
278 def add_factory(self, factory):
279 self._factories[factory.factory_id] = factory
281 def remove_factory(self, factory_id):
282 del self._factories[factory_id]
284 class TestbedDescription(AttributesMap):
285 def __init__(self, guid_generator, provider, guid = None):
286 super(TestbedDescription, self).__init__()
287 self._guid_generator = guid_generator
288 self._guid = guid_generator.next(guid)
289 self._provider = provider
291 self.graphical_info = GraphicalInfo()
293 metadata = Metadata(provider.testbed_id)
294 for attr in metadata.testbed_attributes().attributes:
295 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
296 attr.range, attr.allowed, attr.flags,
297 attr.validation_function, attr.category)
305 return self._provider
309 return self._boxes.values()
312 return self._boxes[guid] if guid in self._boxes else None
314 def create(self, factory_id, guid = None):
315 guid = self._guid_generator.next(guid)
316 factory = self._provider.factory(factory_id)
317 box = factory.create(guid, self)
318 self._boxes[guid] = box
321 def delete(self, guid):
322 box = self._boxes[guid]
323 del self._boxes[guid]
327 for guid, box in self._boxes.iteritems():
331 class ExperimentDescription(object):
333 self._guid_generator = GuidGenerator()
334 self._testbed_descriptions = dict()
337 def testbed_descriptions(self):
338 return self._testbed_descriptions.values()
341 parser = XmlExperimentParser()
342 return parser.to_xml(self)
344 def from_xml(self, xml):
345 parser = XmlExperimentParser()
346 parser.from_xml(self, xml)
348 def testbed_description(self, guid):
349 return self._testbed_descriptions[guid] \
350 if guid in self._testbed_descriptions else None
353 for testbed_description in self._testbed_descriptions.values():
354 box = testbed_description.box(guid)
358 def get_element(self, guid):
359 if guid in self._testbed_descriptions:
360 return self._testbed_descriptions[guid]
361 for testbed_description in self._testbed_descriptions.values():
362 box = testbed_description.box(guid)
366 def add_testbed_description(self, provider, guid = None):
367 testbed_description = TestbedDescription(self._guid_generator,
369 guid = testbed_description.guid
370 self._testbed_descriptions[guid] = testbed_description
371 return testbed_description
373 def remove_testbed_description(self, guid):
374 testbed_description = self._testbed_descriptions[guid]
375 del self._testbed_descriptions[guid]
376 testbed_description.destroy()
379 for testbed_description in self.testbed_descriptions:
380 testbed_description.destroy()