2 # -*- coding: utf-8 -*-
4 from nepi.core.attributes import AttributesMap, Attribute
5 from nepi.util import validation
11 class ConnectorType(object):
12 """A ConnectorType defines a kind of connector that can be used in an Object.
14 def __init__(self, connector_type_id, help, name, max = -1, min = 0):
15 super(ConnectorType, self).__init__()
17 ConnectorType(name, help, display_name, max, min):
18 - connector_type_id: (unique) identifier for this type.
19 Typically: testbed_id + factory_id + name
20 - name: descriptive name for the user
22 - max: amount of connections that this type support, -1 for no limit
23 - min: minimum amount of connections to this type of connector
29 'The maximum number of connections allowed need to be more than 0')
32 'The minimum number of connections allowed needs to be at least 0')
33 self._connector_type_id = connector_type_id
38 # list of connector_type_ids with which this connector_type is allowed
40 self._allowed_connector_type_ids = list()
43 def connector_type_id(self):
44 return self._connector_type_id
62 def add_allowed_connector_type_id(self, connector_type_id):
63 self._allowed_connector_type_ids.append(connector_type_id)
65 def can_connect(self, connector_type_id):
66 return connector_type_id in self._allowed_connector_type_ids
68 class Connector(object):
69 """A Connector sepcifies the connection points in an Object"""
70 def __init__(self, box, connector_type):
71 super(Connector, self).__init__()
73 self._connector_type = connector_type
74 self._connections = dict()
81 def connector_type(self):
82 return self._connector_type
85 def connections(self):
86 return self._connections.values()
89 """Return True if the connector has the maximum number of connections"""
90 return len(self.connections) == self.connector_type.max
92 def is_complete(self):
93 """Return True if the connector has the minimum number of connections"""
94 return len(self.connections) >= self.connector_type.min
96 def connect(self, connector):
97 if self.is_full() or connector.is_full():
98 raise RuntimeError("Connector is full")
99 if not self.can_connect(connector) or not connector.can_connect(self):
100 raise RuntimeError("Could not connect.")
101 self._connections[connector._key] = connector
102 connector._connections[self._key] = self
104 def disconnect(self, connector):
105 if connector._key not in self._connections or\
106 self._key not in connector._connections:
107 raise RuntimeError("Could not disconnect.")
108 del self._connections[connector._key]
109 del connector._connections[self._key]
111 def can_connect(self, connector):
112 connector_type_id = connector.connector_type.connector_type_id
113 return self.connector_type.can_connect(connector_type_id)
116 for connector in self._connections:
117 self.disconnect(connector)
118 self._box = self._connectors = None
122 return "%d_%s" % (self.box.guid,
123 self.connector_type.connector_type_id)
125 class Trace(AttributesMap):
126 def __init__(self, name, help, enabled = False):
127 super(Trace, self).__init__()
130 self.enabled = enabled
140 class Address(AttributesMap):
141 def __init__(self, family):
142 super(Address, self).__init__()
143 self.add_attribute(name = "AutoConfigure",
144 help = "If set, this address will automatically be assigned",
145 type = Attribute.BOOL,
147 validation_function = validation.is_bool)
148 self.add_attribute(name = "Family",
149 help = "Address family type: AF_INET, AFT_INET6",
150 type = Attribute.INTEGER,
153 address_validation = validation.is_ip4_address if family == AF_INET \
154 else validation.is_ip6_address
155 self.add_attribute(name = "Address",
156 help = "Address number",
157 type = Attribute.STRING,
158 validation_function = address_validation)
159 prefix_range = (0, 32) if family == AF_INET else (0, 128)
160 self.add_attribute(name = "NetPrefix",
161 help = "Network prefix for the address",
162 type = Attribute.INTEGER,
163 range = prefix_range,
164 validation_function = validation.is_integer)
165 if family == AF_INET:
166 self.add_attribute(name = "Broadcast",
167 help = "Broadcast address",
168 type = Attribute.STRING,
169 validation_function = validation.is_ip4_address)
171 class Route(AttributesMap):
172 def __init__(self, family):
173 super(Route, self).__init__()
174 self.add_attribute(name = "Family",
175 help = "Address family type: AF_INET, AFT_INET6",
176 type = Attribute.INTEGER,
179 address_validation = validation.is_ip4_address if family == AF_INET \
180 else validation.is_ip6_address
181 self.add_attribute(name = "Destination",
182 help = "Network destintation",
183 type = Attribute.STRING,
184 validation_function = address_validation)
185 prefix_range = (0, 32) if family == AF_INET else (0, 128)
186 self.add_attribute(name = "NetPrefix",
187 help = "Network destination prefix",
188 type = Attribute.INTEGER,
189 prefix_range = prefix_range,
190 validation_function = validation.is_integer)
191 self.add_attribute(name = "NextHop",
192 help = "Address for the next hop",
193 type = Attribute.STRING,
194 validation_function = address_validation)
195 self.add_attribute(name = "Interface",
196 help = "Local interface address",
197 type = Attribute.STRING,
198 validation_function = address_validation)
200 class Box(AttributesMap):
201 def __init__(self, guid, factory, container = None):
202 super(Box, self).__init__()
205 # factory identifier or name
206 self._factory_id = factory.factory_id
207 # boxes can be nested inside other 'container' boxes
208 self._container = container
210 self._traces = dict()
211 # connectors for the box
212 self._connectors = dict()
213 # factory attributes for box construction
214 self._factory_attributes = list()
216 for connector_type in factory.connector_types:
217 connector = Connector(self, connector_type)
218 self._connectors[connector_type.name] = connector
219 for trace in factory.traces:
220 tr = Trace(trace.name, trace.help, trace.enabled)
221 self._traces[trace.name] = tr
222 for attr in factory.box_attributes:
223 self.add_attribute(attr.name, attr.help, attr.type, attr.value,
224 attr.range, attr.allowed, attr.readonly,
225 attr.validation_function)
226 for attr in factory._attributes:
227 self._factory_attributes.append(attr)
234 def factory_id(self):
235 return self._factory_id
239 return self._container
242 def connectors(self):
243 return self._connectors.values()
247 return self._traces.values()
250 def factory_attributes(self):
251 return self._factory_attributes
261 def connector(self, name):
262 return self._connectors[name]
264 def trace(self, name):
265 return self._traces[name]
268 super(Box, self).destroy()
269 for c in self.connectors:
271 for t in self.traces:
273 self._connectors = self._traces = self._factory_attributes = None
275 class AddressableBox(Box):
276 def __init__(self, guid, factory, family, max_addresses = 1, container = None):
277 super(AddressableBox, self).__init__(guid, factory, container)
278 self._family = family
279 # maximum number of addresses this box can have
280 self._max_addresses = max_addresses
281 self._addresses = list()
285 return self._addresses
288 def max_addresses(self):
289 return self._max_addresses
291 def add_address(self):
292 if len(self._addresses) == self.max_addresses:
293 raise RuntimeError("Maximun number of addresses for this box reached.")
294 address = Address(family = self._family)
295 self._addresses.append(address)
298 def delete_address(self, address):
299 self._addresses.remove(address)
303 super(AddressableBox, self).destroy()
304 for address in self.addresses:
305 self.delete_address(address)
306 self._addresses = None
308 class RoutingTableBox(Box):
309 def __init__(self, guid, factory, container = None):
310 super(RoutingTableBox, self).__init__(guid, factory, container)
311 self._routes = list()
317 def add_route(self, family):
318 route = Route(family = family)
319 self._routes.append(route)
322 def delete_route(self, route):
323 self._route.remove(route)
327 super(RoutingCapableBox, self).destroy()
328 for route in self.routes:
329 self.delete_route(route)
332 class BoxFactory(AttributesMap):
333 def __init__(self, factory_id, display_name, help = None, category = None):
334 super(BoxFactory, self).__init__()
335 self._factory_id = factory_id
337 self._category = category
338 self._display_name = display_name
339 self._connector_types = set()
340 self._traces = list()
341 self._box_attributes = list()
344 def factory_id(self):
345 return self._factory_id
353 return self._category
356 def display_name(self):
357 return self._display_name
360 def connector_types(self):
361 return self._connector_types
368 def box_attributes(self):
369 return self._box_attributes
371 def add_connector_type(self, connector_type_id, help, name, max = -1,
372 min = 0, allowed_connector_type_ids = []):
373 connector_type = ConnectorType(connector_type_id, help, name, max, min)
374 for connector_type_id in allowed_connector_type_ids:
375 connector_type.add_allowed_connector_type_id(connector_type_id)
376 self._connector_types.add(connector_type)
378 def add_trace(self, name, help, enabled = False):
379 trace = Trace(name, help, enabled)
380 self._traces.append(trace)
382 def add_box_attribute(self, name, help, type, value = None, range = None,
383 allowed = None, readonly = False, validation_function = None):
384 attribute = Attribute(name, help, type, value, range, allowed, readonly,
386 self._box_attributes.append(attribute)
388 def create(self, guid, testbed_description):
389 return Box(guid, self)
392 super(BoxFactory, self).destroy()
393 self._connector_types = None
395 class AddressableBoxFactory(BoxFactory):
396 def __init__(self, factory_id, display_name, family, max_addresses = 1,
397 help = None, category = None):
398 super(AddressableBoxFactory, self).__init__(factory_id,
399 display_name, help, category)
400 self._family = family
401 self._max_addresses = 1
403 def create(self, guid, testbed_description):
404 return AddressableBox(guid, self, self._family,
407 class RoutingTableBoxFactory(BoxFactory):
408 def create(self, guid, testbed_description):
409 return RoutingTableBox(guid, self)
411 class FactoriesProvider(object):
413 super(FactoriesProvider, self).__init__()
414 self._factories = dict()
416 def factory(self, factory_id):
417 return self._factories[factory_id]
419 def add_factory(self, factory):
420 self._factories[factory.factory_id] = factory
422 def remove_factory(self, factory_id):
423 del self._factories[factory_id]
425 def list_factories(self):
426 return self._factories.keys()
428 class TestbedDescription(AttributesMap):
429 def __init__(self, guid_generator, testbed_id, testbed_version, provider):
430 super(TestbedDescription, self).__init__()
431 self._guid_generator = guid_generator
432 self._guid = guid_generator.next()
433 self._testbed_id = testbed_id
434 self._testbed_version = testbed_version
435 self._provider = provider
443 def testbed_id(self):
444 return self._testbed_id
447 def testbed_version(self):
448 return self._testbed_version
456 return self._boxes.values()
458 def create(self, factory_id):
459 guid = self._guid_generator.next()
460 factory = self._provider.factory(factory_id)
461 box = factory.create(guid, self)
462 self._boxes[guid] = box
465 def delete(self, guid):
466 box = self._boxes[guid]
467 del self._boxes[guid]
471 for guid, box in self._boxes.iteitems():
472 del self._boxes[guid]