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
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.HasNoDefaultValue,
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.HasNoDefaultValue,
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.HasNoDefaultValue,
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.HasNoDefaultValue,
148 validation_function = validation.is_ref_address)
149 self.add_attribute(name = "Metric",
150 help = "Routing metric",
151 type = Attribute.INTEGER,
153 flags = Attribute.HasNoDefaultValue,
154 validation_function = validation.is_integer)
156 class Box(AttributesMap):
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 # tags -- list of tags for the box
171 # connectors -- list of available connectors for the box
172 self._connectors = dict()
173 # factory_attributes -- factory attributes for box construction
174 self._factory_attributes = dict()
175 # graphical_info -- GUI position information
176 self.graphical_info = GraphicalInfo()
178 for connector_type in factory.connector_types:
179 connector = Connector(self, connector_type)
180 self._connectors[connector_type.name] = connector
181 for (name, help, enabled) in factory.traces:
182 trace = Trace(name, help, enabled)
183 self._traces[name] = trace
184 for tag_id in factory.tags:
185 self._tags.append(tag_id)
186 for attr in factory.box_attributes.attributes:
187 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
188 attr.range, attr.allowed, attr.flags,
189 attr.validation_function, attr.category)
190 for attr in factory.attributes:
191 if attr.modified or attr.invisible:
192 self._factory_attributes[attr.name] = attr.value
195 return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
202 def factory_id(self):
203 return self._factory_id
206 def testbed_guid(self):
207 return self._testbed_guid
211 return self._container
214 def connectors(self):
215 return self._connectors.values()
219 return self._traces.values()
222 def traces_list(self):
223 return self._traces.keys()
226 def factory_attributes(self):
227 return self._factory_attributes
233 def trace_help(self, trace_id):
234 return self._traces[trace_id].help
236 def enable_trace(self, trace_id):
237 self._traces[trace_id].enable()
239 def disable_trace(self, trace_id):
240 self._traces[trace_id].disable()
242 def is_trace_enabled(self, trace_id):
243 return self._traces[trace_id].enabled
245 def connector(self, name):
246 return self._connectors[name]
249 super(Box, self).destroy()
250 for c in self.connectors:
252 for t in self.traces:
254 self._connectors = self._traces = self._factory_attributes = None
256 class FactoriesProvider(object):
257 def __init__(self, testbed_id, testbed_version):
258 super(FactoriesProvider, self).__init__()
259 self._testbed_id = testbed_id
260 self._testbed_version = testbed_version
261 self._factories = dict()
263 metadata = Metadata(testbed_id, testbed_version)
264 for factory in metadata.build_factories():
265 self.add_factory(factory)
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, provider.testbed_version)
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 add_testbed_description(self, provider, guid = None):
371 testbed_description = TestbedDescription(self._guid_generator,
373 guid = testbed_description.guid
374 self._testbed_descriptions[guid] = testbed_description
375 return testbed_description
377 def remove_testbed_description(self, guid):
378 testbed_description = self._testbed_descriptions[guid]
379 del self._testbed_descriptions[guid]
380 testbed_description.destroy()
383 for testbed_description in self.testbed_descriptions:
384 testbed_description.destroy()