From caaa4be89f8384423348642f4016fefe185e51a0 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Wed, 9 Feb 2011 14:24:56 +0100 Subject: [PATCH] description: routes, addresses and validation functions --- DEPENDENCIES | 1 + src/nepi/core/attributes.py | 58 ++++-- src/nepi/core/description.py | 209 ++++++++++++++++++--- src/nepi/core/experiment.py | 2 +- src/nepi/core/models.py | 33 ---- src/nepi/{utils => util}/__init__.py | 0 src/nepi/{utils => util}/guid_generator.py | 0 src/nepi/{utils => util}/server.py | 0 src/nepi/util/validation.py | 28 +++ 9 files changed, 265 insertions(+), 66 deletions(-) create mode 100644 DEPENDENCIES delete mode 100644 src/nepi/core/models.py rename src/nepi/{utils => util}/__init__.py (100%) rename src/nepi/{utils => util}/guid_generator.py (100%) rename src/nepi/{utils => util}/server.py (100%) create mode 100644 src/nepi/util/validation.py diff --git a/DEPENDENCIES b/DEPENDENCIES new file mode 100644 index 00000000..27285a78 --- /dev/null +++ b/DEPENDENCIES @@ -0,0 +1 @@ +* ipaddr-2.1.7 : http://ipaddr-py.googlecode.com/files/ipaddr-2.1.7.tar.gz diff --git a/src/nepi/core/attributes.py b/src/nepi/core/attributes.py index 2db9f0c9..7f2d6bac 100644 --- a/src/nepi/core/attributes.py +++ b/src/nepi/core/attributes.py @@ -54,37 +54,73 @@ class AttributesMap(object): self._attributes = dict() class Attribute(object): - STRING , BOOL, ENUM, DOUBLE, INTEGER, ENDPOINT, TIME = ( - "STRING", "BOOL", "ENUM", "DOUBLE", "INTEGER", "ENDPOINT", "TIME") + STRING, BOOL, ENUM, DOUBLE, INTEGER = ( + "STRING", "BOOL", "ENUM", "DOUBLE", "INTEGER") - types = [STRING, BOOL, ENUM, DOUBLE, INTEGER, ENDPOINT, TIME] + types = [STRING, BOOL, ENUM, DOUBLE, INTEGER] def __init__(self, name, help, type, value = None, range = None, allowed = None, readonly = False, validation_function = None): if not type in Attribute.types: raise AttributeError("invalid type %s " % type) self.name = name - self.type = type - self.help = help + self._type = type + self._help = help self._value = value self._validation_function = validation_function - self.readonly = (readonly == True) - self.modified = False + self._readonly = (readonly == True) + self._modified = False # range: max and min possible values - self.range = range + self._range = range # list of possible values - self.allowed = allowed + self._allowed = allowed + + @property + def type(self): + return self._type + + @property + def help(self): + return self._help + + @property + def readornly(self): + return self._readonly + + @property + def modified(self): + return self._modified + + @property + def range(self): + return self._range + + @property + def allowed(self): + return self._allowed def get_value(self): return self._value def set_value(self, value): - func = self._validation_function - if not func or func(value): + if self._is_in_range(value) and \ + self._is_in_allowed_values(value) and \ + self._is_valid(value): self._value = value + self._modified = True else: raise RuntimeError("Invalid value %s for attribute %s" % (str(value), self.name)) value = property(get_value, set_value) + def _is_in_range(self, value): + return not self.range or + (value >= self.range[0] and value <= self.range[1]) + + def _is_in_allowed_values(self, value): + return not self.allowed or value in self._allowed + + def _is_valid(self, value): + return not self._validation_function or self._validation_function(value) + diff --git a/src/nepi/core/description.py b/src/nepi/core/description.py index d3837d08..8b736679 100644 --- a/src/nepi/core/description.py +++ b/src/nepi/core/description.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from nepi.core.attributes import AttributesMap + +from nepi.core.attributes import AttributesMap, Attribute +from nepi.util import validation + +AF_INET = 0 +AF_INET6 = 1 class ConnectorType(object): """A ConnectorType defines a kind of connector that can be used in an Object. @@ -115,11 +120,11 @@ class Connector(object): self.connector_type.connector_type_id) class Trace(AttributesMap): - def __init__(self, name, help, enabled=False): + def __init__(self, name, help, enabled = False): super(Trace, self).__init__() self._name = name self._help = help - self._enabled = enabled + self.enabled = enabled @property def name(self): @@ -129,18 +134,68 @@ class Trace(AttributesMap): def help(self): return self._help - @property - def is_enabled(self): - return self._enabled - - def enable(self): - self._enabled = True - - def disable(self): - self._enabled = False +class Address(AttributesMap): + def __init__(self, family): + super(Address, self).__init__() + self.add_attribute(name = "AutoConfigure", + help = "If set, this address will automatically be assigned", + type = Attribute.BOOL, + value = False, + validation_function = validation.is_bool) + self.add_attribute(name = "Family", + help = "Address family type: AF_INET, AFT_INET6", + type = Attribute.INTEGER, + value = family + readonly = True) + address_validation = validation.is_ip4_address if family == AF_INET \ + else validation.is_ip6_address + self.add_attribute(name = "Address", + help = "Address number", + type = Attribute.STRING, + validation_function = address_validation) + prefix_range = (0, 32) if family == AF_INET else (0, 128) + self.add_attribute(name = "NetPrefix", + help = "Network prefix for the address", + type = Attribute.INTEGER, + prefix_range = prefix_range, + validation_function = validation.is_integer) + if family == AF_INET: + self.add_attribute(name = "Broadcast", + help = "Broadcast address", + type = Attribute.STRING + validation_function = validation.is_ip4_address) + +class Route(AttributesMap): + def __init__(self, family): + super(Route, self).__init__() + self.add_attribute(name = "Family", + help = "Address family type: AF_INET, AFT_INET6", + type = Attribute.INTEGER, + value = family + readonly = True) + address_validation = validation.is_ip4_address if family == AF_INET \ + else validation.is_ip6_address + self.add_attribute(name = "Destination", + help = "Network destintation", + type = Attribute.STRING, + validation_function = address_validation) + prefix_range = (0, 32) if family == AF_INET else (0, 128) + self.add_attribute(name = "NetPrefix", + help = "Network destination prefix", + type = Attribute.INTEGER, + prefix_range = prefix_range, + validation_function = validation.is_integer) + self.add_attribute(name = "NextHop", + help = "Address for the next hop", + type = Attribute.STRING, + validation_function = address_validation) + self.add_attribute(name = "Interface", + help = "Local interface address", + type = Attribute.STRING, + validation_function = address_validation) class Element(AttributesMap): - def __init__(self, guid, testbed_id, factory, container = None): + def __init__(self, guid, factory, container = None): super(Element, self).__init__() # general unique id self._guid = guid @@ -152,9 +207,21 @@ class Element(AttributesMap): self._traces = dict() # connectors for the element self._connectors = dict() + # factory attributes for element construction + self._factory_attributes = list() + for connector_type in factory.connector_types: connector = Connector(self, connector_type) self._connectors[connector_type.connector_id] = connector + for trace in factory.traces: + tr = Trace(trace.name, trace.help, trace.enabled) + self._traces[trace.name] = tr + for attr in factory.element_attributes: + self.add_attribute(attr.name, attr.help, attr.type, attr.value, + attr.range, attr.allowed, attr.readonly, + attr.validation_function) + for attr in factory._attributes: + self._factory_attributes.append(attr) @property def guid(self): @@ -176,6 +243,18 @@ class Element(AttributesMap): def traces(self): return self._traces.values() + @property + def factory_attributes(self): + return self._factory_attributes + + @property + def addresses(self): + return [] + + @property + def routes(self): + return [] + def connector(self, name): return self._connectors[name] @@ -188,15 +267,74 @@ class Element(AttributesMap): c.destroy() for t in self.traces: t.destroy() - self._connectors = self._traces = None + self._connectors = self._traces = self._factory_attributes = None + +class AddressableElement(Element): + def __init__(self, guid, factory, family, max_addresses = 1, container = None): + super(AddressableElement, self).__init__(guid, factory, container) + self._family = family + # maximum number of addresses this element can have + self._max_addresses = max_addressess + self._addresses = list() + + @property + def addresses(self): + return self._addresses + + @property + def max_addresses(self): + return self._max_addresses + + def add_address(self): + if len(self._addresses) == self.max_addresses: + raise RuntimeError("Maximun number of addresses for this element reached.") + address = Address(family = self._family) + self._addresses.append(address) + return address + + def delete_address(self, address): + self._addresses.remove(address) + del address -class Factory(AttributesMap): + def destroy(self): + super(AddressableElement, self).destroy() + for address in self.addresses: + self.delete_address(address) + self._addresses = None + +class RoutingTableElement(Element): + def __init__(self, guid, factory, container = None): + super(RoutingTableElement, self).__init__(guid, factory, container) + self._routes = list() + + @property + def routes(self): + return self._routes + + def add_route(self, family): + route = Route(family = family) + self._routes.append(route) + return route + + def delete_route(self, route): + self._route.remove(route) + del route + + def destroy(self): + super(RoutingTableElement, self).destroy() + for route in self.routes: + self.delete_route(route) + self._route = None + +class ElementFactory(AttributesMap): def __init__(self, factory_id, help = None, category = None): - super(Factory, self).__init__() + super(ElementFactory, self).__init__() self._factory_id = factory_id self._help = help self._category = category self._connector_types = set() + self._traces = list() + self._element_attributes = list() @property def factory_id(self): @@ -214,19 +352,48 @@ class Factory(AttributesMap): def connector_types(self): return self._connector_types + @property + def traces(self): + return self._traces + + @property + def element_attributes(self): + return self._element_attributes + def add_connector_type(self, connector_id, help, name, max = -1, min = 0): connector_type = ConnectorType(connector_id, help, name, max, min) self._connector_types.add(connector_type) - def create(self, guid, testbed_design, container = None): - raise NotImplementedError + def add_trace(self, name, help, enabled = False): + trace = Trace(name, help, enabled) + self._traces.append(trace) + + def add_element_attribute(self, name, help, type, value = None, range = None, + allowed = None, readonly = False, validation_function = None): + attribute = Attribute(name, help, type, value, range, allowed, readonly, + validation_function) + self._element_attributes.append(attribute) + + def create(self, guid, testbed_description): + return Element(guid, self) def destroy(self): - super(Factory, self).destroy() + super(ElementFactory, self).destroy() self._connector_types = None -#TODO: Provide some way to identify that the providers and the factories -# belong to a specific testbed version +class AddressableElementFactory(ElementFactory): + def __init__(self, factory_id, family, max_addresses = 1, help = None, category = None): + super(AddressableElementFactory, self).__init__(factory_id, help, category) + self._family = family + self._max_addresses = 1 + + def create(self, guid, testbed_description): + return AddressableElement(guid, self, self._family, self._max_addresses) + +class RoutingTableElementFactory(ElementFactory): + def create(self, guid, testbed_description): + return RoutingTableElement(guid, self) + class Provider(object): def __init__(self): super(Provider, self).__init__() diff --git a/src/nepi/core/experiment.py b/src/nepi/core/experiment.py index 19825e49..3b8ca93b 100644 --- a/src/nepi/core/experiment.py +++ b/src/nepi/core/experiment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from nepi.utils.guid import GuidGenerator +from nepi.util.guid import GuidGenerator import sys class ExperimentDescription(object): diff --git a/src/nepi/core/models.py b/src/nepi/core/models.py deleted file mode 100644 index 1f3b5aa0..00000000 --- a/src/nepi/core/models.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# vim:ts=4:sw=4:et:ai:sts=4 - -class Mobile(object): - pass - -class RoutingTable(object): - def entries(self): - pass - - def add_entry(self): - pass - - def remove_entry(self): - pass - -class Entry(object): - pass - -class Interface(object): - pass - """ - Link encap:Local Loopback - inet addr:127.0.0.1 - Mask:255.0.0.0 - inet6 addr: ::1/128 Scope:Host - UP LOOPBACK RUNNING - MTU:16436 - Metric:1 - """ - - diff --git a/src/nepi/utils/__init__.py b/src/nepi/util/__init__.py similarity index 100% rename from src/nepi/utils/__init__.py rename to src/nepi/util/__init__.py diff --git a/src/nepi/utils/guid_generator.py b/src/nepi/util/guid_generator.py similarity index 100% rename from src/nepi/utils/guid_generator.py rename to src/nepi/util/guid_generator.py diff --git a/src/nepi/utils/server.py b/src/nepi/util/server.py similarity index 100% rename from src/nepi/utils/server.py rename to src/nepi/util/server.py diff --git a/src/nepi/util/validation.py b/src/nepi/util/validation.py new file mode 100644 index 00000000..fc8a8ecb --- /dev/null +++ b/src/nepi/util/validation.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import ipaddr + +def is_bool(value): + return isinstance(value, bool) + +def is_integer(value): + return isinstance(value, int) + +def is_string(value): + return isinstance(value, str) + +def is_ip4_address(value): + try: + ipaddr.IPv4(value) + except ipaddr.Error: + return False + return True + +def is_ip6_address(value): + try: + ipaddr.IPv6(value) + except ipaddr.Error: + return False + return True + -- 2.47.0