t.destroy()
self._connectors = self._traces = self._factory_attributes = None
-class AddressableBox(Box):
+class AddressableMixin(object):
def __init__(self, guid, factory, testbed_guid, container = None):
- super(AddressableBox, self).__init__(guid, factory, testbed_guid,
+ super(AddressableMixin, self).__init__(guid, factory, testbed_guid,
container)
self._max_addresses = 1 # TODO: How to make this configurable!
self._addresses = list()
def max_addresses(self):
return self._max_addresses
+class UserAddressableMixin(AddressableMixin):
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(UserAddressableMixin, self).__init__(guid, factory, testbed_guid,
+ container)
+
def add_address(self):
if len(self._addresses) == self.max_addresses:
raise RuntimeError("Maximun number of addresses for this box reached.")
del address
def destroy(self):
- super(AddressableBox, self).destroy()
- for address in self.addresses:
+ super(UserAddressableMixin, self).destroy()
+ for address in list(self.addresses):
self.delete_address(address)
self._addresses = None
-class RoutingTableBox(Box):
- def __init__(self, guid, factory, container = None):
- super(RoutingTableBox, self).__init__(guid, factory, container)
+class RoutableMixin(object):
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(RoutableMixin, self).__init__(guid, factory, testbed_guid,
+ container)
self._routes = list()
@property
def routes(self):
return self._routes
+class UserRoutableMixin(RoutableMixin):
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(UserRoutableMixin, self).__init__(guid, factory, testbed_guid,
+ container)
+
def add_route(self):
route = Route()
self._routes.append(route)
del route
def destroy(self):
- super(RoutingTableBox, self).destroy()
- for route in self.routes:
+ super(UserRoutableMixin, self).destroy()
+ for route in list(self.routes):
self.delete_route(route)
self._route = None
+def MixIn(MyClass, MixIn):
+ # Mixins are installed BEFORE "Box" because
+ # Box inherits from non-cooperative classes,
+ # so the MRO chain gets broken when it gets
+ # to Box.
+
+ # Install mixin
+ MyClass.__bases__ = (MixIn,) + MyClass.__bases__
+
+ # Add properties
+ # Somehow it doesn't work automatically
+ for name in dir(MixIn):
+ prop = getattr(MixIn,name,None)
+ if isinstance(prop, property):
+ setattr(MyClass, name, prop)
+
+ # Update name
+ MyClass.__name__ = MyClass.__name__.replace(
+ 'Box',
+ MixIn.__name__.replace('MixIn','')+'Box',
+ 1)
+
class Factory(AttributesMap):
- def __init__(self, factory_id, allow_addresses = False,
- allow_routes = False, Help = None, category = None):
+ _box_class_cache = {}
+
+ def __init__(self, factory_id,
+ allow_addresses = False, has_addresses = False,
+ allow_routes = False, has_routes = False,
+ Help = None, category = None):
super(Factory, self).__init__()
self._factory_id = factory_id
- self._allow_addresses = (allow_addresses == True)
- self._allow_routes = (allow_routes == True)
+ self._allow_addresses = bool(allow_addresses)
+ self._allow_routes = bool(allow_routes)
+ self._has_addresses = bool(allow_addresses) or self._allow_addresses
+ self._has_routes = bool(allow_routes) or self._allow_routes
self._help = help
self._category = category
self._connector_types = list()
self._traces = list()
self._box_attributes = AttributesMap()
+
+ if not self._has_addresses and not self._has_routes:
+ self._factory = Box
+ else:
+ addresses = 'w' if self._allow_addresses else ('r' if self._has_addresses else '-')
+ routes = 'w' if self._allow_routes else ('r' if self._has_routes else '-')
+ key = addresses+routes
+
+ if key in self._box_class_cache:
+ self._factory = self._box_class_cache[key]
+ else:
+ # Create base class
+ class _factory(Box):
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(_factory, self).__init__(guid, factory, testbed_guid, container)
+
+ # Add mixins, one by one
+ if allow_addresses:
+ MixIn(_factory, UserAddressableMixin)
+ elif has_addresses:
+ MixIn(_factory, AddressableMixin)
+
+ if allow_routes:
+ MixIn(_factory, UserRoutableMixin)
+ elif has_routes:
+ MixIn(_factory, RoutableMixin)
+
+ # Put into cache
+ self._box_class_cache[key] = self._factory = _factory
@property
def factory_id(self):
def allow_routes(self):
return self._allow_routes
+ @property
+ def has_addresses(self):
+ return self._has_addresses
+
+ @property
+ def has_routes(self):
+ return self._has_routes
+
@property
def help(self):
return self._help
allowed, flags, validation_function)
def create(self, guid, testbed_description):
- if self._allow_addresses:
- return AddressableBox(guid, self, testbed_description.guid)
- elif self._allow_routes:
- return RoutingTableBox(guid, self, testbed_description.guid)
- else:
- return Box(guid, self, testbed_description.guid)
+ return self._factory(guid, self, testbed_description.guid)
def destroy(self):
super(Factory, self).destroy()
def __init__(self, factory_id, create_function, start_function,
stop_function, status_function,
configure_function, preconfigure_function,
- allow_addresses = False, allow_routes = False):
+ allow_addresses = False, has_addresses = False,
+ allow_routes = False, has_routes = False):
super(Factory, self).__init__()
self._factory_id = factory_id
- self._allow_addresses = (allow_addresses == True)
- self._allow_routes = (allow_routes == True)
+ self._allow_addresses = bool(allow_addresses)
+ self._allow_routes = bool(allow_routes)
+ self._has_addresses = bool(has_addresses) or self._allow_addresses
+ self._has_routes = bool(has_routes) or self._allow_routes
self._create_function = create_function
self._start_function = start_function
self._stop_function = stop_function
def allow_routes(self):
return self._allow_routes
+ @property
+ def has_addresses(self):
+ return self._has_addresses
+
+ @property
+ def has_routes(self):
+ return self._has_routes
+
@property
def box_attributes(self):
return self._box_attributes
factory_id: dict({
"allow_addresses": whether the box allows adding IP addresses,
"allow_routes": wether the box allows adding routes,
+ "has_addresses": whether the box allows obtaining IP addresses,
+ "has_routes": wether the box allows obtaining routes,
"help": help text,
"category": category the element belongs to,
"create_function": function for element instantiation,
for factory_id, info in self._metadata.factories_info.iteritems():
help = info["help"]
category = info["category"]
- allow_addresses = info["allow_addresses"] \
- if "allow_addresses" in info else False
- allow_routes = info["allow_routes"] \
- if "allow_routes" in info else False
- factory = Factory(factory_id, allow_addresses, allow_routes,
+ allow_addresses = info.get("allow_addresses", False)
+ allow_routes = info.get("allow_routes", False)
+ has_addresses = info.get("has_addresses", False)
+ has_routes = info.get("has_routes", False)
+ factory = Factory(factory_id,
+ allow_addresses, has_addresses,
+ allow_routes, has_routes,
help, category)
# standard attributes
preconfigure_function = info.get("preconfigure_function")
allow_addresses = info.get("allow_addresses", False)
allow_routes = info.get("allow_routes", False)
+ has_addresses = info.get("has_addresses", False)
+ has_routes = info.get("has_routes", False)
factory = Factory(factory_id, create_function, start_function,
stop_function, status_function,
configure_function, preconfigure_function,
- allow_addresses, allow_routes)
+ allow_addresses, has_addresses,
+ allow_routes, has_routes)
# standard attributes
self._add_standard_attributes(factory, info, False, True,