2 # -*- coding: utf-8 -*-
4 from nepi.core.attributes import AttributesMap, Attribute
5 from nepi.util import validation
10 class ConnectorType(object):
11 """A ConnectorType defines a kind of connector that can be used in an Object.
13 def __init__(self, connector_type_id, help, name, max = -1, min = 0):
14 super(ConnectorType, self).__init__()
16 ConnectorType(name, help, display_name, max, min):
17 - connector_type_id: (unique) identifier for this type.
18 Typically: testbed_id + factory_id + name
19 - name: descriptive name for the user
21 - max: amount of connections that this type support, -1 for no limit
22 - min: minimum amount of connections to this type of connector
28 'The maximum number of connections allowed need to be more than 0')
31 'The minimum number of connections allowed needs to be at least 0')
32 self._connector_type_id = connector_type_id
37 self._allowed_connections = list()
40 def connector_type_id(self):
41 return self._connector_type_id
59 def add_allowed_connection(self, connector_type_id):
60 self._allowed_connections.append(connector_type_id)
62 def can_connect(self, connector_type_id):
63 return connector_type_id in self._allowed_connections
65 class Connector(object):
66 """A Connector sepcifies the connection points in an Object"""
67 def __init__(self, element, connector_type):
68 super(Connector, self).__init__()
69 self._element = element
70 self._connector_type = connector_type
71 self._connections = dict()
78 def connector_type(self):
79 return self._connector_type
82 def connections(self):
83 return self._connections.values()
86 """Return True if the connector has the maximum number of connections"""
87 return len(self.connections) == self.connector_type.max
89 def is_complete(self):
90 """Return True if the connector has the minimum number of connections"""
91 return len(self.connections) >= self.connector_type.min
93 def connect(self, connector):
94 if self.is_full() or connector.is_full():
95 raise RuntimeError("Connector is full")
96 if not self.can_connect(connector) or not connector.can_connect(self):
97 raise RuntimeError("Could not connect.")
98 self._connections[connector._key] = connector
99 connector._connections[self._key] = self
101 def disconnect(self, connector):
102 if connector._key not in self._connections or
103 self._key not in connector._connections:
104 raise RuntimeError("Could not disconnect.")
105 del self._connections[connector._key]
106 del connector._connections[self._key]
108 def can_connect(self, connector):
109 connector_type_id = connector.connector_type.connector_type_id
110 self.connector_type.can_connect(connector_type_id)
113 for connector in self._connections:
114 self.disconnect(connector)
115 self._element = self._connectors = None
119 return "%d_%s" % (self.element.guid,
120 self.connector_type.connector_type_id)
122 class Trace(AttributesMap):
123 def __init__(self, name, help, enabled = False):
124 super(Trace, self).__init__()
127 self.enabled = enabled
137 class Address(AttributesMap):
138 def __init__(self, family):
139 super(Address, self).__init__()
140 self.add_attribute(name = "AutoConfigure",
141 help = "If set, this address will automatically be assigned",
142 type = Attribute.BOOL,
144 validation_function = validation.is_bool)
145 self.add_attribute(name = "Family",
146 help = "Address family type: AF_INET, AFT_INET6",
147 type = Attribute.INTEGER,
150 address_validation = validation.is_ip4_address if family == AF_INET \
151 else validation.is_ip6_address
152 self.add_attribute(name = "Address",
153 help = "Address number",
154 type = Attribute.STRING,
155 validation_function = address_validation)
156 prefix_range = (0, 32) if family == AF_INET else (0, 128)
157 self.add_attribute(name = "NetPrefix",
158 help = "Network prefix for the address",
159 type = Attribute.INTEGER,
160 prefix_range = prefix_range,
161 validation_function = validation.is_integer)
162 if family == AF_INET:
163 self.add_attribute(name = "Broadcast",
164 help = "Broadcast address",
165 type = Attribute.STRING
166 validation_function = validation.is_ip4_address)
168 class Route(AttributesMap):
169 def __init__(self, family):
170 super(Route, self).__init__()
171 self.add_attribute(name = "Family",
172 help = "Address family type: AF_INET, AFT_INET6",
173 type = Attribute.INTEGER,
176 address_validation = validation.is_ip4_address if family == AF_INET \
177 else validation.is_ip6_address
178 self.add_attribute(name = "Destination",
179 help = "Network destintation",
180 type = Attribute.STRING,
181 validation_function = address_validation)
182 prefix_range = (0, 32) if family == AF_INET else (0, 128)
183 self.add_attribute(name = "NetPrefix",
184 help = "Network destination prefix",
185 type = Attribute.INTEGER,
186 prefix_range = prefix_range,
187 validation_function = validation.is_integer)
188 self.add_attribute(name = "NextHop",
189 help = "Address for the next hop",
190 type = Attribute.STRING,
191 validation_function = address_validation)
192 self.add_attribute(name = "Interface",
193 help = "Local interface address",
194 type = Attribute.STRING,
195 validation_function = address_validation)
197 class Element(AttributesMap):
198 def __init__(self, guid, factory, container = None):
199 super(Element, self).__init__()
202 # factory identifier or name
203 self._factory_id = factory.factory_id
204 # elements can be nested inside other 'container' elements
205 self._container = container
206 # traces for the element
207 self._traces = dict()
208 # connectors for the element
209 self._connectors = dict()
210 # factory attributes for element construction
211 self._factory_attributes = list()
213 for connector_type in factory.connector_types:
214 connector = Connector(self, connector_type)
215 self._connectors[connector_type.connector_id] = connector
216 for trace in factory.traces:
217 tr = Trace(trace.name, trace.help, trace.enabled)
218 self._traces[trace.name] = tr
219 for attr in factory.element_attributes:
220 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
221 attr.range, attr.allowed, attr.readonly,
222 attr.validation_function)
223 for attr in factory._attributes:
224 self._factory_attributes.append(attr)
231 def factory_id(self):
232 return self._factory_id
236 return self._container
239 def connectors(self):
240 return self._connectors.values()
244 return self._traces.values()
247 def factory_attributes(self):
248 return self._factory_attributes
258 def connector(self, name):
259 return self._connectors[name]
261 def trace(self, name):
262 return self._traces[name]
265 super(Element, self).destroy()
266 for c in self.connectors:
268 for t in self.traces:
270 self._connectors = self._traces = self._factory_attributes = None
272 class AddressableElement(Element):
273 def __init__(self, guid, factory, family, max_addresses = 1, container = None):
274 super(AddressableElement, self).__init__(guid, factory, container)
275 self._family = family
276 # maximum number of addresses this element can have
277 self._max_addresses = max_addressess
278 self._addresses = list()
282 return self._addresses
285 def max_addresses(self):
286 return self._max_addresses
288 def add_address(self):
289 if len(self._addresses) == self.max_addresses:
290 raise RuntimeError("Maximun number of addresses for this element reached.")
291 address = Address(family = self._family)
292 self._addresses.append(address)
295 def delete_address(self, address):
296 self._addresses.remove(address)
300 super(AddressableElement, self).destroy()
301 for address in self.addresses:
302 self.delete_address(address)
303 self._addresses = None
305 class RoutingTableElement(Element):
306 def __init__(self, guid, factory, container = None):
307 super(RoutingTableElement, self).__init__(guid, factory, container)
308 self._routes = list()
314 def add_route(self, family):
315 route = Route(family = family)
316 self._routes.append(route)
319 def delete_route(self, route):
320 self._route.remove(route)
324 super(RoutingTableElement, self).destroy()
325 for route in self.routes:
326 self.delete_route(route)
329 class ElementFactory(AttributesMap):
330 def __init__(self, factory_id, help = None, category = None):
331 super(ElementFactory, self).__init__()
332 self._factory_id = factory_id
334 self._category = category
335 self._connector_types = set()
336 self._traces = list()
337 self._element_attributes = list()
340 def factory_id(self):
341 return self._factory_id
349 return self._category
352 def connector_types(self):
353 return self._connector_types
360 def element_attributes(self):
361 return self._element_attributes
363 def add_connector_type(self, connector_id, help, name, max = -1, min = 0):
364 connector_type = ConnectorType(connector_id, help, name, max, min)
365 self._connector_types.add(connector_type)
367 def add_trace(self, name, help, enabled = False):
368 trace = Trace(name, help, enabled)
369 self._traces.append(trace)
371 def add_element_attribute(self, name, help, type, value = None, range = None,
372 allowed = None, readonly = False, validation_function = None):
373 attribute = Attribute(name, help, type, value, range, allowed, readonly,
375 self._element_attributes.append(attribute)
377 def create(self, guid, testbed_description):
378 return Element(guid, self)
381 super(ElementFactory, self).destroy()
382 self._connector_types = None
384 class AddressableElementFactory(ElementFactory):
385 def __init__(self, factory_id, family, max_addresses = 1, help = None, category = None):
386 super(AddressableElementFactory, self).__init__(factory_id, help, category)
387 self._family = family
388 self._max_addresses = 1
390 def create(self, guid, testbed_description):
391 return AddressableElement(guid, self, self._family, self._max_addresses)
393 class RoutingTableElementFactory(ElementFactory):
394 def create(self, guid, testbed_description):
395 return RoutingTableElement(guid, self)
397 class Provider(object):
399 super(Provider, self).__init__()
400 self._factories = dict()
402 def factory(self, factory_id):
403 return self._factories[factory_id]
405 def add_factory(self, factory):
406 self._factories[factory.factory_id] = factory
408 def remove_factory(self, factory_id):
409 del self._factories[factory_id]
411 def list_factories(self):
412 return self._factories.keys()
414 class TestbedDescription(AttributeMap):
415 def __init__(self, guid_generator, testbed_id, testbed_version, provider):
416 super(TestbedDescription, self).__init__()
417 self._guid_generator = guid_generator
418 self._guid = guid_generator.next()
419 self._testbed_id = testbed_id
420 self._testbed_version = testbed_version
421 self._provider = provider
422 self._elements = dict()
429 def testbed_id(self):
430 return self._testbed_id
433 def testbed_version(self):
434 return self._testbed_version
442 return self._elements.values()
444 def create(self, factory_id):
445 guid = self.guid_generator.next()
446 factory = self._provider.factories(factory_id)
447 element = factory.create(guid, self)
448 self._elements[guid] = element
450 def delete(self, guid):
451 element = self._elements[guid]
452 del self._elements[guid]
456 for guid, element in self._elements.iteitems():
457 del self._elements[guid]
459 self._elements = None