HasNoDefaultValue = 0x08
def __init__(self, name, help, type, value = None, range = None,
- allowed = None, flags = NoFlags, validation_function = None,
+ allowed = None, flags = None, validation_function = None,
category = None):
if not type in Attribute.types:
raise AttributeError("invalid type %s " % type)
self._type = type
self._help = help
self._value = value
- self._flags = flags
+ self._flags = flags if flags != None else Attribute.NoFlags
# range: max and min possible values
self._range = range
# list of possible values
are going to be manipulated by the end-user in a script or GUI.
"""
def __init__(self):
+ super(AttributesMap, self).__init__()
self._attributes = dict()
@property
def attributes(self):
return self._attributes.values()
- @property
- def attributes_list(self):
- return self._attributes.keys()
+ def get_attribute_list(self, filter_flags = None):
+ attributes = self._attributes
+ if filter_flags != None:
+ def filter_attrs(attr):
+ (attr_id, attr_data) = attr
+ return not ((attr_data.flags & filter_flags) == filter_flags)
+ attributes = dict(filter(filter_attrs, attributes.iteritems()))
+ return attributes.keys()
def set_attribute_value(self, name, value):
self._attributes[name].value = value
# -*- coding: utf-8 -*-
"""
-Common connector base classes
+Common connector class
"""
import sys
-class ConnectorTypeBase(object):
- def __init__(self, testbed_id, factory_id, name, max = -1, min = 0):
- super(ConnectorTypeBase, self).__init__()
+class ConnectorType(object):
+ def __init__(self, testbed_id, factory_id, name, help, max = -1, min = 0):
+ super(ConnectorType, self).__init__()
+
if max == -1:
max = sys.maxint
elif max <= 0:
raise RuntimeError, "The maximum number of connections allowed need to be more than 0"
if min < 0:
raise RuntimeError, "The minimum number of connections allowed needs to be at least 0"
+ # max -- maximum amount of connections that this type support,
+ # -1 for no limit
+ self._max = max
+ # min -- minimum amount of connections required by this type of connector
+ self._min = min
+
# connector_type_id -- univoquely identifies a connector type
# across testbeds
self._connector_type_id = self.make_connector_type_id(
testbed_id, factory_id, name)
+
# name -- display name for the connector type
self._name = name
- # max -- maximum amount of connections that this type support,
- # -1 for no limit
- self._max = max
- # min -- minimum amount of connections required by this type of connector
- self._min = min
+
+ # help -- help text
+ self._help = help
+
+ # from_connections -- connections where the other connector is the "From"
+ # to_connections -- connections where the other connector is the "To"
+ # keys in the dictionary correspond to the
+ # connector_type_id for possible connections. The value is a tuple:
+ # (can_cross, connect)
+ # can_cross: indicates if the connection is allowed accros different
+ # testbed instances
+ # code: is the connection function to be invoked when the elements
+ # are connected
+ self._from_connections = dict()
+ self._to_connections = dict()
def __str__(self):
return "ConnectorType%r" % (self._connector_type_id,)
def name(self):
return self._name
+ @property
+ def help(self):
+ return self._help
+
@property
def max(self):
return self._max
if (None, None, name) != connector_type_id:
yield (None, None, name)
+ def add_from_connection(self, testbed_id, factory_id, name, can_cross,
+ init_code, compl_code):
+ type_id = self.make_connector_type_id(testbed_id, factory_id, name)
+ self._from_connections[type_id] = (can_cross, init_code, compl_code)
+
+ def add_to_connection(self, testbed_id, factory_id, name, can_cross,
+ init_code, compl_code):
+ type_id = self.make_connector_type_id(testbed_id, factory_id, name)
+ self._to_connections[type_id] = (can_cross, init_code, compl_code)
+
+ def connect_to_init_code(self, testbed_id, factory_id, name, must_cross):
+ return self._connect_to_code(testbed_id, factory_id, name, must_cross)[0]
+
+ def connect_to_compl_code(self, testbed_id, factory_id, name, must_cross):
+ return self._connect_to_code(testbed_id, factory_id, name, must_cross)[1]
+
+ def _connect_to_code(self, testbed_id, factory_id, name,
+ must_cross):
+ connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
+ for lookup_type_id in self._type_resolution_order(connector_type_id):
+ if lookup_type_id in self._to_connections:
+ (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
+ if must_cross == can_cross:
+ return (init_code, compl_code)
+ else:
+ return (False, False)
+
+ def can_connect(self, testbed_id, factory_id, name, must_cross):
+ connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
+ for lookup_type_id in self._type_resolution_order(connector_type_id):
+ if lookup_type_id in self._from_connections:
+ (can_cross, init_code, compl_code) = self._from_connections[lookup_type_id]
+ elif lookup_type_id in self._to_connections:
+ (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
+ else:
+ # keep trying
+ continue
+ return not must_cross or can_cross
+ else:
+ return False
"""
from nepi.core.attributes import AttributesMap, Attribute
-from nepi.core.connector import ConnectorTypeBase
from nepi.core.metadata import Metadata
from nepi.util import validation
from nepi.util.guid import GuidGenerator
from nepi.util.graphical_info import GraphicalInfo
from nepi.util.parser._xml import XmlExperimentParser
+from nepi.util.tags import Taggable
import sys
-class ConnectorType(ConnectorTypeBase):
- def __init__(self, testbed_id, factory_id, name, help, max = -1, min = 0):
- super(ConnectorType, self).__init__(testbed_id, factory_id, name, max, min)
-
- # help -- help text
- self._help = help
-
- # allowed_connections -- keys in the dictionary correspond to the
- # connector_type_id for possible connections. The value indicates if
- # the connection is allowed accros different testbed instances
- self._allowed_connections = dict()
-
- @property
- def help(self):
- return self._help
-
- def add_allowed_connection(self, testbed_id, factory_id, name, can_cross):
- type_id = self.make_connector_type_id(testbed_id, factory_id, name)
- self._allowed_connections[type_id] = can_cross
-
- def can_connect(self, connector_type_id, testbed_guid1, testbed_guid2):
- for lookup_type_id in self._type_resolution_order(connector_type_id):
- if lookup_type_id in self._allowed_connections:
- can_cross = self._allowed_connections[lookup_type_id]
- if can_cross or (testbed_guid1 == testbed_guid2):
- return True
- else:
- return False
-
class Connector(object):
"""A Connector sepcifies the connection points in an Object"""
def __init__(self, box, connector_type):
return False
if self.is_connected(connector):
return False
- connector_type_id = connector.connector_type.connector_type_id
+ (testbed_id, factory_id, name) = connector.connector_type.connector_type_id
testbed_guid1 = self.box.testbed_guid
testbed_guid2 = connector.box.testbed_guid
- return self.connector_type.can_connect(connector_type_id,
- testbed_guid1, testbed_guid2)
+ must_cross = (testbed_guid1 != testbed_guid2)
+ return self.connector_type.can_connect(testbed_id, factory_id, name,
+ must_cross)
def destroy(self):
for connector in self.connections:
self._box = self._connectors = None
class Trace(AttributesMap):
- def __init__(self, trace_id, help, enabled = False):
+ def __init__(self, name, help, enabled = False):
super(Trace, self).__init__()
- self._trace_id = trace_id
+ self._name = name
self._help = help
self._enabled = enabled
@property
- def trace_id(self):
- return self._trace_id
+ def name(self):
+ return self._name
@property
def help(self):
flags = Attribute.HasNoDefaultValue,
validation_function = validation.is_integer)
-class Box(AttributesMap):
+class Box(AttributesMap, Taggable):
def __init__(self, guid, factory, testbed_guid, container = None):
super(Box, self).__init__()
# guid -- global unique identifier
self._container = container
# traces -- list of available traces for the box
self._traces = dict()
- # tags -- list of tags for the box
- self._tags = list()
# connectors -- list of available connectors for the box
self._connectors = dict()
# factory_attributes -- factory attributes for box construction
for connector_type in factory.connector_types:
connector = Connector(self, connector_type)
self._connectors[connector_type.name] = connector
- for trace in factory.traces:
- tr = Trace(trace.trace_id, trace.help, trace.enabled)
- self._traces[trace.trace_id] = tr
+ for (name, help, enabled) in factory.traces:
+ trace = Trace(name, help, enabled)
+ self._traces[name] = trace
for tag_id in factory.tags:
- self._tags.append(tag_id)
+ self.add_tag(tag_id)
for attr in factory.box_attributes.attributes:
self.add_attribute(attr.name, attr.help, attr.type, attr.value,
attr.range, attr.allowed, attr.flags,
return self._traces.values()
@property
- def trace_names(self):
+ def traces_list(self):
return self._traces.keys()
@property
def factory_attributes(self):
return self._factory_attributes
- @property
- def tags(self):
- return self._tags
-
def trace_help(self, trace_id):
return self._traces[trace_id].help
t.destroy()
self._connectors = self._traces = self._factory_attributes = None
-class AddressableMixin(object):
- def __init__(self, guid, factory, testbed_guid, container = None):
- super(AddressableMixin, self).__init__(guid, factory, testbed_guid,
- container)
- max_addr = self._factory_attributes["MaxAddresses"] \
- if "MaxAddresses" in self._factory_attributes else 1
- self._max_addresses = max_addr
- self._addresses = list()
-
- @property
- def addresses(self):
- return self._addresses
-
- @property
- 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.")
- address = Address()
- self._addresses.append(address)
- return address
-
- def delete_address(self, address):
- self._addresses.remove(address)
- del address
-
- def destroy(self):
- super(UserAddressableMixin, self).destroy()
- for address in list(self.addresses):
- self.delete_address(address)
- self._addresses = None
-
-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)
- return route
-
- def delete_route(self, route):
- self._routes.remove(route)
- del route
-
- def destroy(self):
- 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):
- _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 = 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._tags = 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):
- return self._factory_id
-
- @property
- def allow_addresses(self):
- return self._allow_addresses
-
- @property
- 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
-
- @property
- def category(self):
- return self._category
-
- @property
- def connector_types(self):
- return self._connector_types
-
- @property
- def traces(self):
- return self._traces
-
- @property
- def tags(self):
- return self._tags
-
- @property
- def box_attributes(self):
- return self._box_attributes
-
- def add_connector_type(self, connector_type):
- self._connector_types.append(connector_type)
-
- def add_trace(self, trace_id, help, enabled = False):
- trace = Trace(trace_id, help, enabled)
- self._traces.append(trace)
-
- def add_tag(self, tag_id):
- self._tags.append(tag_id)
-
- def add_box_attribute(self, name, help, type, value = None, range = None,
- allowed = None, flags = Attribute.NoFlags, validation_function = None,
- category = None):
- self._box_attributes.add_attribute(name, help, type, value, range,
- allowed, flags, validation_function, category)
-
- def create(self, guid, testbed_description):
- return self._factory(guid, self, testbed_description.guid)
-
- def destroy(self):
- super(Factory, self).destroy()
- self._connector_types = None
-
class FactoriesProvider(object):
def __init__(self, testbed_id, testbed_version):
super(FactoriesProvider, self).__init__()
self._factories = dict()
metadata = Metadata(testbed_id, testbed_version)
- for factory in metadata.build_design_factories():
+ for factory in metadata.build_factories():
self.add_factory(factory)
@property
# -*- coding: utf-8 -*-
from nepi.core.attributes import Attribute, AttributesMap
-from nepi.core.connector import ConnectorTypeBase
from nepi.util import validation
from nepi.util.constants import ApplicationStatus as AS, TIME_NOW
from nepi.util.parser._xml import XmlExperimentParser
ATTRIBUTE_PATTERN_GUID_SUB = r"{#[%(guid)s]%(expr)s#}"
COMPONENT_PATTERN = re.compile(r"(?P<kind>[a-z]*)\[(?P<index>.*)\]")
-class ConnectorType(ConnectorTypeBase):
- def __init__(self, testbed_id, factory_id, name, max = -1, min = 0):
- super(ConnectorType, self).__init__(testbed_id, factory_id, name, max, min)
- # from_connections -- connections where the other connector is the "From"
- # to_connections -- connections where the other connector is the "To"
- # keys in the dictionary correspond to the
- # connector_type_id for possible connections. The value is a tuple:
- # (can_cross, connect)
- # can_cross: indicates if the connection is allowed accros different
- # testbed instances
- # code: is the connection function to be invoked when the elements
- # are connected
- self._from_connections = dict()
- self._to_connections = dict()
-
- def add_from_connection(self, testbed_id, factory_id, name, can_cross,
- init_code, compl_code):
- type_id = self.make_connector_type_id(testbed_id, factory_id, name)
- self._from_connections[type_id] = (can_cross, init_code, compl_code)
-
- def add_to_connection(self, testbed_id, factory_id, name, can_cross,
- init_code, compl_code):
- type_id = self.make_connector_type_id(testbed_id, factory_id, name)
- self._to_connections[type_id] = (can_cross, init_code, compl_code)
-
- def can_connect(self, testbed_id, factory_id, name, count,
- must_cross):
- connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
- for lookup_type_id in self._type_resolution_order(connector_type_id):
- if lookup_type_id in self._from_connections:
- (can_cross, init_code, compl_code) = self._from_connections[lookup_type_id]
- elif lookup_type_id in self._to_connections:
- (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
- else:
- # keep trying
- continue
- return not must_cross or can_cross
- else:
- return False
-
- def _connect_to_code(self, testbed_id, factory_id, name,
- must_cross):
- connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
- for lookup_type_id in self._type_resolution_order(connector_type_id):
- if lookup_type_id in self._to_connections:
- (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
- if not must_cross or can_cross:
- return (init_code, compl_code)
- else:
- return (False, False)
-
- def connect_to_init_code(self, testbed_id, factory_id, name, must_cross):
- return self._connect_to_code(testbed_id, factory_id, name, must_cross)[0]
-
- def connect_to_compl_code(self, testbed_id, factory_id, name, must_cross):
- return self._connect_to_code(testbed_id, factory_id, name, must_cross)[1]
-
-class Factory(AttributesMap):
- def __init__(self, factory_id, create_function, start_function,
- stop_function, status_function,
- configure_function, preconfigure_function,
- prestart_function,
- allow_addresses = False, has_addresses = False,
- allow_routes = False, has_routes = False):
- super(Factory, self).__init__()
- self._factory_id = factory_id
- 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
- self._status_function = status_function
- self._configure_function = configure_function
- self._preconfigure_function = preconfigure_function
- self._prestart_function = prestart_function
- self._connector_types = dict()
- self._traces = list()
- self._tags = list()
- self._box_attributes = AttributesMap()
-
- @property
- def factory_id(self):
- return self._factory_id
-
- @property
- def allow_addresses(self):
- return self._allow_addresses
-
- @property
- 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
-
- @property
- def create_function(self):
- return self._create_function
-
- @property
- def prestart_function(self):
- return self._prestart_function
-
- @property
- def start_function(self):
- return self._start_function
-
- @property
- def stop_function(self):
- return self._stop_function
-
- @property
- def status_function(self):
- return self._status_function
-
- @property
- def configure_function(self):
- return self._configure_function
-
- @property
- def preconfigure_function(self):
- return self._preconfigure_function
-
- @property
- def traces(self):
- return self._traces
-
- @property
- def tags(self):
- return self._tags
-
- def connector_type(self, name):
- return self._connector_types[name]
-
- def add_connector_type(self, connector_type):
- self._connector_types[connector_type.name] = connector_type
-
- def add_trace(self, trace_id):
- self._traces.append(trace_id)
-
- def add_tag(self, tag_id):
- self._tags.append(tag_id)
-
- def add_box_attribute(self, name, help, type, value = None, range = None,
- allowed = None, flags = Attribute.NoFlags, validation_function = None,
- category = None):
- self._box_attributes.add_attribute(name, help, type, value, range,
- allowed, flags, validation_function, category)
-
class TestbedController(object):
def __init__(self, testbed_id, testbed_version):
self._testbed_id = testbed_id
"""
raise NotImplementedError
- def get_attribute_list(self, guid):
+ def get_attribute_list(self, guid, filter_flags = None):
raise NotImplementedError
def get_factory_id(self, guid):
def start(self):
parser = XmlExperimentParser()
data = parser.from_xml_to_data(self._experiment_xml)
-
self._init_testbed_controllers(data)
# persist testbed connection data, for potential recovery
for testbed_guid, testbed_config in self._deployment_config.iteritems():
testbed_guid = str(testbed_guid)
conf.add_section(testbed_guid)
- for attr in testbed_config.attributes_list:
+ for attr in testbed_config.get_attribute_list():
if attr not in TRANSIENT:
conf.set(testbed_guid, attr,
testbed_config.get_attribute_value(attr))
testbed_guid = str(testbed_guid)
conf.add_section(testbed_guid)
- for attr in testbed_config.attributes_list:
+ for attr in testbed_config.get_attribute_list():
if attr not in TRANSIENT:
getter = getattr(conf, TYPEMAP.get(
testbed_config.get_attribute_type(attr),
_testbed_id = cross_testbed.testbed_id,
_testbed_version = cross_testbed.testbed_version)
cross_data[cross_testbed_guid][cross_guid] = elem_cross_data
- attributes_list = cross_testbed.get_attribute_list(cross_guid)
- for attr_name in attributes_list:
+ attribute_list = cross_testbed.get_attribute_list(cross_guid,
+ filter_flags = Attribute.DesignOnly)
+ for attr_name in attribute_list:
attr_value = cross_testbed.get(cross_guid, attr_name)
elem_cross_data[attr_name] = attr_value
return cross_data
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core.attributes import AttributesMap, Attribute
+from nepi.util import tags
+from nepi.util.tags import Taggable
+
+class AddressableMixin(object):
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(AddressableMixin, self).__init__(guid, factory, testbed_guid,
+ container)
+ max_addr = self._factory_attributes["maxAddresses"]
+ self._max_addresses = max_addr
+ self._addresses = list()
+
+ @property
+ def addresses(self):
+ return self._addresses
+
+ @property
+ 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.")
+ from nepi.core.design import Address
+ address = Address()
+ self._addresses.append(address)
+ return address
+
+ def delete_address(self, address):
+ self._addresses.remove(address)
+ del address
+
+ def destroy(self):
+ super(UserAddressableMixin, self).destroy()
+ for address in list(self.addresses):
+ self.delete_address(address)
+ self._addresses = None
+
+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):
+ from nepi.core.design import Route
+ route = Route()
+ self._routes.append(route)
+ return route
+
+ def delete_route(self, route):
+ self._routes.remove(route)
+ del route
+
+ def destroy(self):
+ 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, Taggable):
+ _box_class_cache = {}
+
+ def __init__(self, factory_id,
+ create_function,
+ start_function,
+ stop_function,
+ status_function,
+ configure_function,
+ preconfigure_function,
+ prestart_function,
+ help = None,
+ category = None):
+
+ super(Factory, self).__init__()
+
+ self._factory_id = factory_id
+ self._create_function = create_function
+ self._start_function = start_function
+ self._stop_function = stop_function
+ self._status_function = status_function
+ self._configure_function = configure_function
+ self._preconfigure_function = preconfigure_function
+ self._prestart_function = prestart_function
+ self._help = help
+ self._category = category
+ self._connector_types = dict()
+ self._traces = dict()
+ self._box_attributes = AttributesMap()
+ self._factory = None
+
+ @property
+ def factory(self):
+ if self._factory:
+ return self._factory
+
+ from nepi.core.design import Box
+
+ 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 self.allow_addresses:
+ MixIn(_factory, UserAddressableMixin)
+ elif self.has_addresses:
+ MixIn(_factory, AddressableMixin)
+
+ if self.allow_routes:
+ MixIn(_factory, UserRoutableMixin)
+ elif self.has_routes:
+ MixIn(_factory, RoutableMixin)
+
+ # Put into cache
+ self._box_class_cache[key] = self._factory = _factory
+ return self._factory
+
+ @property
+ def factory_id(self):
+ return self._factory_id
+
+ @property
+ def allow_addresses(self):
+ return self.has_tag(tags.ALLOW_ADDRESSES)
+
+ @property
+ def allow_routes(self):
+ return self.has_tag(tags.ALLOW_ROUTES)
+
+ @property
+ def has_addresses(self):
+ return self.has_tag(tags.HAS_ADDRESSES) or \
+ self.allow_addresses
+
+ @property
+ def has_routes(self):
+ return self.has_tag(tags.HAS_ROUTES) or \
+ self.allow_routes
+
+ @property
+ def help(self):
+ return self._help
+
+ @property
+ def category(self):
+ return self._category
+
+ @property
+ def connector_types(self):
+ return self._connector_types.values()
+
+ @property
+ def traces(self):
+ return self._traces.values()
+
+ @property
+ def traces_list(self):
+ return self._traces.keys()
+
+ @property
+ def box_attributes(self):
+ return self._box_attributes
+
+ @property
+ def create_function(self):
+ return self._create_function
+
+ @property
+ def prestart_function(self):
+ return self._prestart_function
+
+ @property
+ def start_function(self):
+ return self._start_function
+
+ @property
+ def stop_function(self):
+ return self._stop_function
+
+ @property
+ def status_function(self):
+ return self._status_function
+
+ @property
+ def configure_function(self):
+ return self._configure_function
+
+ @property
+ def preconfigure_function(self):
+ return self._preconfigure_function
+
+ def connector_type(self, name):
+ return self._connector_types[name]
+
+ def add_connector_type(self, connector_type):
+ self._connector_types[connector_type.name] = connector_type
+
+ def add_trace(self, name, help, enabled = False):
+ self._traces[name] = (name, help, enabled)
+
+ def add_box_attribute(self, name, help, type, value = None, range = None,
+ allowed = None, flags = Attribute.NoFlags, validation_function = None,
+ category = None):
+ self._box_attributes.add_attribute(name, help, type, value, range,
+ allowed, flags, validation_function, category)
+
+ def create(self, guid, testbed_description):
+ return self.factory(guid, self, testbed_description.guid)
+
+ def destroy(self):
+ super(Factory, self).destroy()
+ self._connector_types = None
+
# -*- coding: utf-8 -*-
from nepi.core.attributes import Attribute, AttributesMap
+from nepi.core.connector import ConnectorType
+from nepi.core.factory import Factory
import sys
import getpass
-from nepi.util import validation
+from nepi.util import tags, validation
from nepi.util.constants import ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP, \
DeploymentConfiguration as DC, \
AttributeCategories as AC
def factories_info(self):
""" dictionary of dictionaries of factory specific information
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,
raise NotImplementedError
class Metadata(object):
- STANDARD_BOX_ATTRIBUTES = (
- ("label", dict(
- name = "label",
- validation_function = validation.is_string,
- type = Attribute.STRING,
- flags = Attribute.DesignOnly,
- help = "A unique identifier for referring to this box",
- )),
- )
-
- STANDARD_TESTBED_ATTRIBUTES = (
- ("home_directory", dict(
- name = "homeDirectory",
- validation_function = validation.is_string,
- help = "Path to the directory where traces and other files will be stored",
- type = Attribute.STRING,
- value = "",
- flags = Attribute.DesignOnly
- )),
- ("label", dict(
- name = "label",
- validation_function = validation.is_string,
- type = Attribute.STRING,
- flags = Attribute.DesignOnly,
- help = "A unique identifier for referring to this testbed",
- )),
- )
+ # These attributes should be added to all boxes
+ STANDARD_BOX_ATTRIBUTES = dict({
+ "label" : dict({
+ "name" : "label",
+ "validation_function" : validation.is_string,
+ "type" : Attribute.STRING,
+ "flags" : Attribute.DesignOnly,
+ "help" : "A unique identifier for referring to this box",
+ }),
+ })
+
+ # These are the attribute definitions for tagged attributes
+ STANDARD_TAGGED_ATTRIBUTES_DEFINITIONS = dict({
+ "maxAddresses" : dict({
+ "name" : "maxAddresses",
+ "validation_function" : validation.is_integer,
+ "type" : Attribute.INTEGER,
+ "value" : 1,
+ "flags" : Attribute.Invisible,
+ "help" : "The maximum allowed number of addresses",
+ }),
+ })
+
+ # Attributes to be added to all boxes with specific tags
+ STANDARD_TAGGED_BOX_ATTRIBUTES = dict({
+ tags.ALLOW_ADDRESSES : ["maxAddresses"],
+ tags.HAS_ADDRESSES : ["maxAddresses"],
+ })
+
+ # These attributes should be added to all testbeds
+ STANDARD_TESTBED_ATTRIBUTES = dict({
+ "home_directory" : dict({
+ "name" : "homeDirectory",
+ "validation_function" : validation.is_string,
+ "help" : "Path to the directory where traces and other files will be stored",
+ "type" : Attribute.STRING,
+ "value" : "",
+ "flags" : Attribute.DesignOnly
+ }),
+ "label" : dict({
+ "name" : "label",
+ "validation_function" : validation.is_string,
+ "type" : Attribute.STRING,
+ "flags" : Attribute.DesignOnly,
+ "help" : "A unique identifier for referring to this testbed",
+ }),
+ })
- DEPLOYMENT_ATTRIBUTES = (
+ # These attributes should be added to all testbeds
+ DEPLOYMENT_ATTRIBUTES = dict({
# TESTBED DEPLOYMENT ATTRIBUTES
- (DC.DEPLOYMENT_ENVIRONMENT_SETUP, dict(
- name = DC.DEPLOYMENT_ENVIRONMENT_SETUP,
- validation_function = validation.is_string,
- help = "Shell commands to run before spawning TestbedController processes",
- type = Attribute.STRING,
- flags = Attribute.DesignOnly,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_MODE, dict(name = DC.DEPLOYMENT_MODE,
- help = "Instance execution mode",
- type = Attribute.ENUM,
- value = DC.MODE_SINGLE_PROCESS,
- allowed = [
+ DC.DEPLOYMENT_ENVIRONMENT_SETUP : dict({
+ "name" : DC.DEPLOYMENT_ENVIRONMENT_SETUP,
+ "validation_function" : validation.is_string,
+ "help" : "Shell commands to run before spawning TestbedController processes",
+ "type" : Attribute.STRING,
+ "flags" : Attribute.DesignOnly,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_MODE: dict({
+ "name" : DC.DEPLOYMENT_MODE,
+ "help" : "Instance execution mode",
+ "type" : Attribute.ENUM,
+ "value" : DC.MODE_SINGLE_PROCESS,
+ "allowed" : [
DC.MODE_DAEMON,
DC.MODE_SINGLE_PROCESS
],
- flags = Attribute.DesignOnly,
- validation_function = validation.is_enum,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_COMMUNICATION, dict(name = DC.DEPLOYMENT_COMMUNICATION,
- help = "Instance communication mode",
- type = Attribute.ENUM,
- value = DC.ACCESS_LOCAL,
- allowed = [
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_enum,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_COMMUNICATION : dict({
+ "name" : DC.DEPLOYMENT_COMMUNICATION,
+ "help" : "Instance communication mode",
+ "type" : Attribute.ENUM,
+ "value" : DC.ACCESS_LOCAL,
+ "allowed" : [
DC.ACCESS_LOCAL,
DC.ACCESS_SSH
],
- flags = Attribute.DesignOnly,
- validation_function = validation.is_enum,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_HOST, dict(name = DC.DEPLOYMENT_HOST,
- help = "Host where the testbed will be executed",
- type = Attribute.STRING,
- value = "localhost",
- flags = Attribute.DesignOnly,
- validation_function = validation.is_string,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_USER, dict(name = DC.DEPLOYMENT_USER,
- help = "User on the Host to execute the testbed",
- type = Attribute.STRING,
- value = getpass.getuser(),
- flags = Attribute.DesignOnly,
- validation_function = validation.is_string,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_KEY, dict(name = DC.DEPLOYMENT_KEY,
- help = "Path to SSH key to use for connecting",
- type = Attribute.STRING,
- flags = Attribute.DesignOnly,
- validation_function = validation.is_string,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.DEPLOYMENT_PORT, dict(name = DC.DEPLOYMENT_PORT,
- help = "Port on the Host",
- type = Attribute.INTEGER,
- value = 22,
- flags = Attribute.DesignOnly,
- validation_function = validation.is_integer,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.ROOT_DIRECTORY, dict(name = DC.ROOT_DIRECTORY,
- help = "Root directory for storing process files",
- type = Attribute.STRING,
- value = ".",
- flags = Attribute.DesignOnly,
- validation_function = validation.is_string, # TODO: validation.is_path
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.USE_AGENT, dict(name = DC.USE_AGENT,
- help = "Use -A option for forwarding of the authentication agent, if ssh access is used",
- type = Attribute.BOOL,
- value = False,
- flags = Attribute.DesignOnly,
- validation_function = validation.is_bool,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.LOG_LEVEL, dict(name = DC.LOG_LEVEL,
- help = "Log level for instance",
- type = Attribute.ENUM,
- value = DC.ERROR_LEVEL,
- allowed = [
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_enum,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_HOST : dict({
+ "name" : DC.DEPLOYMENT_HOST,
+ "help" : "Host where the testbed will be executed",
+ "type" : Attribute.STRING,
+ "value" : "localhost",
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_string,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_USER : dict({
+ "name" : DC.DEPLOYMENT_USER,
+ "help" : "User on the Host to execute the testbed",
+ "type" : Attribute.STRING,
+ "value" : getpass.getuser(),
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_string,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_KEY : dict({
+ "name" : DC.DEPLOYMENT_KEY,
+ "help" : "Path to SSH key to use for connecting",
+ "type" : Attribute.STRING,
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_string,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.DEPLOYMENT_PORT : dict({
+ "name" : DC.DEPLOYMENT_PORT,
+ "help" : "Port on the Host",
+ "type" : Attribute.INTEGER,
+ "value" : 22,
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_integer,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.ROOT_DIRECTORY : dict({
+ "name" : DC.ROOT_DIRECTORY,
+ "help" : "Root directory for storing process files",
+ "type" : Attribute.STRING,
+ "value" : ".",
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_string, # TODO: validation.is_path
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.USE_AGENT : dict({
+ "name" : DC.USE_AGENT,
+ "help" : "Use -A option for forwarding of the authentication agent, if ssh access is used",
+ "type" : Attribute.BOOL,
+ "value" : False,
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_bool,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.LOG_LEVEL : dict({
+ "name" : DC.LOG_LEVEL,
+ "help" : "Log level for instance",
+ "type" : Attribute.ENUM,
+ "value" : DC.ERROR_LEVEL,
+ "allowed" : [
DC.ERROR_LEVEL,
DC.DEBUG_LEVEL
],
- flags = Attribute.DesignOnly,
- validation_function = validation.is_enum,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- (DC.RECOVER, dict(name = DC.RECOVER,
- help = "Do not intantiate testbeds, rather, reconnect to already-running instances. Used to recover from a dead controller.",
- type = Attribute.BOOL,
- value = False,
- flags = Attribute.DesignOnly,
- validation_function = validation.is_bool,
- category = AC.CATEGORY_DEPLOYMENT,
- )),
- )
-
- STANDARD_TESTBED_ATTRIBUTES += DEPLOYMENT_ATTRIBUTES
-
- STANDARD_ATTRIBUTE_BUNDLES = {
- "tun_proto" : dict({
- "name": "tun_proto",
- "help": "TUNneling protocol used",
- "type": Attribute.STRING,
- "flags": Attribute.Invisible,
- "validation_function": validation.is_string,
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_enum,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ DC.RECOVER : dict({
+ "name" : DC.RECOVER,
+ "help" : "Do not intantiate testbeds, rather, reconnect to already-running instances. Used to recover from a dead controller.",
+ "type" : Attribute.BOOL,
+ "value" : False,
+ "flags" : Attribute.DesignOnly,
+ "validation_function" : validation.is_bool,
+ "category" : AC.CATEGORY_DEPLOYMENT,
+ }),
+ })
+
+ # These attributes could appear in the boxes attribute list
+ STANDARD_BOX_ATTRIBUTE_DEFINITIONS = dict({
+ "tun_proto" : dict({
+ "name" : "tun_proto",
+ "help" : "TUNneling protocol used",
+ "type" : Attribute.STRING,
+ "flags" : Attribute.Invisible,
+ "validation_function" : validation.is_string,
}),
- "tun_key" : dict({
- "name": "tun_key",
- "help": "Randomly selected TUNneling protocol cryptographic key. "
- "Endpoints must agree to use the minimum (in lexicographic order) "
- "of both the remote and local sides.",
- "type": Attribute.STRING,
- "flags": Attribute.Invisible,
- "validation_function": validation.is_string,
+ "tun_key" : dict({
+ "name" : "tun_key",
+ "help" : "Randomly selected TUNneling protocol cryptographic key. "
+ "Endpoints must agree to use the minimum (in lexicographic order) "
+ "of both the remote and local sides.",
+ "type" : Attribute.STRING,
+ "flags" :Attribute.Invisible,
+ "validation_function" : validation.is_string,
}),
- "tun_addr" : dict({
- "name": "tun_addr",
- "help": "Address (IP, unix socket, whatever) of the tunnel endpoint",
- "type": Attribute.STRING,
- "flags": Attribute.Invisible,
- "validation_function": validation.is_string,
+ "tun_addr" : dict({
+ "name": "tun_addr",
+ "help" : "Address (IP, unix socket, whatever) of the tunnel endpoint",
+ "type" : Attribute.STRING,
+ "flags" : Attribute.Invisible,
+ "validation_function" : validation.is_string,
}),
- "tun_port" : dict({
- "name": "tun_port",
- "help": "IP port of the tunnel endpoint",
- "type": Attribute.INTEGER,
- "flags": Attribute.Invisible,
- "validation_function": validation.is_integer,
+ "tun_port" : dict({
+ "name" : "tun_port",
+ "help" : "IP port of the tunnel endpoint",
+ "type" : Attribute.INTEGER,
+ "flags" : Attribute.Invisible,
+ "validation_function" : validation.is_integer,
}),
- ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP : dict({
- "name": ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
- "help": "Commands to set up the environment needed to run NEPI testbeds",
- "type": Attribute.STRING,
- "flags": Attribute.Invisible,
- "validation_function": validation.is_string
+ ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP : dict({
+ "name" : ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
+ "help" : "Commands to set up the environment needed to run NEPI testbeds",
+ "type" : Attribute.STRING,
+ "flags" : Attribute.Invisible,
+ "validation_function" : validation.is_string
}),
- }
+ })
+ STANDARD_TESTBED_ATTRIBUTES.update(DEPLOYMENT_ATTRIBUTES.copy())
def __init__(self, testbed_id, version):
self._version = version
def testbed_attributes(self):
attributes = AttributesMap()
-
- # standard attributes
- self._add_standard_attributes(attributes, None, True, False,
- self.STANDARD_TESTBED_ATTRIBUTES)
-
- # custom attributes - they override standard ones
- for attr_info in self._metadata.testbed_attributes.values():
- name = attr_info["name"]
- help = attr_info["help"]
- type = attr_info["type"]
- value = attr_info["value"] if "value" in attr_info else None
- range = attr_info["range"] if "range" in attr_info else None
- allowed = attr_info["allowed"] if "allowed" in attr_info else None
- flags = attr_info["flags"] if "flags" in attr_info \
- else Attribute.NoFlags
- validation_function = attr_info["validation_function"]
- category = attr_info["category"] if "category" in attr_info else None
- attributes.add_attribute(name, help, type, value,
- range, allowed, flags, validation_function, category)
-
+ testbed_attributes = self._testbed_attributes()
+ self._add_attributes(attributes.add_attribute, testbed_attributes)
return attributes
- def build_design_factories(self):
- from nepi.core.design import Factory
- factories = list()
- for factory_id, info in self._metadata.factories_info.iteritems():
- help = info["help"]
- category = info["category"]
- 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
- self._add_standard_attributes(factory, info, True, True,
- self.STANDARD_BOX_ATTRIBUTES)
-
- # custom attributes - they override standard ones
- self._add_attributes(factory, info, "factory_attributes")
- self._add_attributes(factory, info, "box_attributes", True)
-
- self._add_design_traces(factory, info)
- self._add_tags(factory, info)
- self._add_design_connector_types(factory, info)
- factories.append(factory)
- return factories
-
- def build_execute_factories(self):
- from nepi.core.execute import Factory
+ def build_factories(self):
factories = list()
for factory_id, info in self._metadata.factories_info.iteritems():
create_function = info.get("create_function")
configure_function = info.get("configure_function")
preconfigure_function = info.get("preconfigure_function")
prestart_function = info.get("prestart_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,
+ help = info["help"]
+ category = info["category"]
+ factory = Factory(factory_id,
+ create_function,
+ start_function,
+ stop_function,
+ status_function,
+ configure_function,
+ preconfigure_function,
prestart_function,
- allow_addresses, has_addresses,
- allow_routes, has_routes)
+ help,
+ category)
- # standard attributes
- self._add_standard_attributes(factory, info, False, True,
- self.STANDARD_BOX_ATTRIBUTES)
-
- # custom attributes - they override standard ones
- self._add_attributes(factory, info, "factory_attributes")
- self._add_attributes(factory, info, "box_attributes", True)
+ factory_attributes = self._factory_attributes(info)
+ self._add_attributes(factory.add_attribute, factory_attributes)
+ box_attributes = self._box_attributes(info)
+ self._add_attributes(factory.add_box_attribute, box_attributes)
- self._add_execute_traces(factory, info)
+ self._add_traces(factory, info)
self._add_tags(factory, info)
- self._add_execute_connector_types(factory, info)
+ self._add_connector_types(factory, info)
factories.append(factory)
return factories
__import__(mod_name)
return sys.modules[mod_name]
- def _add_standard_attributes(self, factory, info, design, box, STANDARD_ATTRIBUTES):
- if design:
- attr_bundle = STANDARD_ATTRIBUTES
+ def _testbed_attributes(self):
+ # standar attributes
+ attributes = self.STANDARD_TESTBED_ATTRIBUTES.copy()
+ # custom attributes
+ attributes.update(self._metadata.testbed_attributes.copy())
+ return attributes
+
+ def _factory_attributes(self, info):
+ tagged_attributes = self._tagged_attributes(info)
+ if "factory_attributes" in info:
+ definitions = self._metadata.attributes.copy()
+ # filter attributes corresponding to the factory_id
+ factory_attributes = self._filter_attributes(info["factory_attributes"],
+ definitions)
else:
- # Only add non-DesignOnly attributes
- def nonDesign(attr_info):
- return not (attr_info[1].get('flags',Attribute.NoFlags) & Attribute.DesignOnly)
- attr_bundle = filter(nonDesign, STANDARD_ATTRIBUTES)
- self._add_attributes(factory, info, None, box,
- attr_bundle = STANDARD_ATTRIBUTES)
-
- def _add_attributes(self, factory, info, attr_key, box_attributes = False, attr_bundle = ()):
- if not attr_bundle and info and attr_key in info:
- definitions = self.STANDARD_ATTRIBUTE_BUNDLES.copy()
+ factory_attributes = dict()
+ attributes = dict(tagged_attributes.items() + \
+ factory_attributes.items())
+ return attributes
+
+ def _box_attributes(self, info):
+ tagged_attributes = self._tagged_attributes(info)
+ if "box_attributes" in info:
+ definitions = self.STANDARD_BOX_ATTRIBUTE_DEFINITIONS.copy()
definitions.update(self._metadata.attributes)
- attr_bundle = [ (attr_id, definitions[attr_id])
- for attr_id in info[attr_key] ]
- for attr_id, attr_info in attr_bundle:
+ box_attributes = self._filter_attributes(info["box_attributes"],
+ definitions)
+ else:
+ box_attributes = dict()
+ attributes = dict(tagged_attributes.items() + \
+ box_attributes.items())
+ attributes.update(self.STANDARD_BOX_ATTRIBUTES.copy())
+ return attributes
+
+ def _tagged_attributes(self, info):
+ tagged_attributes = dict()
+ for tag_id in info.get("tags", []):
+ if tag_id in self.STANDARD_TAGGED_BOX_ATTRIBUTES:
+ attr_list = self.STANDARD_TAGGED_BOX_ATTRIBUTES[tag_id]
+ attributes = self._filter_attributes(attr_list,
+ self.STANDARD_TAGGED_ATTRIBUTES_DEFINITIONS)
+ tagged_attributes.update(attributes)
+ return tagged_attributes
+
+ def _filter_attributes(self, attr_list, definitions):
+ # filter attributes not corresponding to the factory
+ attributes = dict((attr_id, definitions[attr_id]) \
+ for attr_id in attr_list)
+ return attributes
+
+ def _add_attributes(self, add_attr_func, attributes):
+ for attr_id, attr_info in attributes.iteritems():
name = attr_info["name"]
help = attr_info["help"]
type = attr_info["type"]
- value = attr_info["value"] if "value" in attr_info else None
- range = attr_info["range"] if "range" in attr_info else None
- allowed = attr_info["allowed"] if "allowed" in attr_info \
- else None
- flags = attr_info["flags"] if "flags" in attr_info \
- and attr_info["flags"] != None \
- else Attribute.NoFlags
+ value = attr_info.get("value")
+ range = attr_info.get("range")
+ allowed = attr_info.get("allowed")
+ flags = attr_info.get("flags")
+ flags = Attribute.NoFlags if flags == None else flags
validation_function = attr_info["validation_function"]
- category = attr_info["category"] if "category" in attr_info else None
- if box_attributes:
- factory.add_box_attribute(name, help, type, value, range,
- allowed, flags, validation_function, category)
- else:
- factory.add_attribute(name, help, type, value, range,
- allowed, flags, validation_function, category)
-
- def _add_design_traces(self, factory, info):
- if "traces" in info:
- for trace in info["traces"]:
- trace_info = self._metadata.traces[trace]
- trace_id = trace_info["name"]
- help = trace_info["help"]
- factory.add_trace(trace_id, help)
-
- def _add_execute_traces(self, factory, info):
- if "traces" in info:
- for trace in info["traces"]:
- trace_info = self._metadata.traces[trace]
- trace_id = trace_info["name"]
- factory.add_trace(trace_id)
+ category = attr_info.get("category")
+ add_attr_func(name, help, type, value, range, allowed, flags,
+ validation_function, category)
- def _add_tags(self, factory, info):
- if "tags" in info:
- for tag_id in info["tags"]:
- factory.add_tag(tag_id)
+ def _add_traces(self, factory, info):
+ for trace_id in info.get("traces", []):
+ trace_info = self._metadata.traces[trace_id]
+ name = trace_info["name"]
+ help = trace_info["help"]
+ factory.add_trace(name, help)
- def _add_design_connector_types(self, factory, info):
- from nepi.core.design import ConnectorType
- if "connector_types" in info:
- connections = dict()
- for connection in self._metadata.connections:
- from_ = connection["from"]
- to = connection["to"]
- can_cross = connection["can_cross"]
- if from_ not in connections:
- connections[from_] = list()
- if to not in connections:
- connections[to] = list()
- connections[from_].append((to, can_cross))
- connections[to].append((from_, can_cross))
- for connector_id in info["connector_types"]:
- connector_type_info = self._metadata.connector_types[
- connector_id]
- name = connector_type_info["name"]
- help = connector_type_info["help"]
- max = connector_type_info["max"]
- min = connector_type_info["min"]
- testbed_id = self._testbed_id
- factory_id = factory.factory_id
- connector_type = ConnectorType(testbed_id, factory_id, name,
- help, max, min)
- for (to, can_cross) in connections[(testbed_id, factory_id,
- name)]:
- (testbed_id_to, factory_id_to, name_to) = to
- connector_type.add_allowed_connection(testbed_id_to,
- factory_id_to, name_to, can_cross)
- factory.add_connector_type(connector_type)
+ def _add_tags(self, factory, info):
+ for tag_id in info.get("tags", []):
+ factory.add_tag(tag_id)
- def _add_execute_connector_types(self, factory, info):
- from nepi.core.execute import ConnectorType
+ def _add_connector_types(self, factory, info):
if "connector_types" in info:
from_connections = dict()
to_connections = dict()
from_ = connection["from"]
to = connection["to"]
can_cross = connection["can_cross"]
- init_code = connection["init_code"] \
- if "init_code" in connection else None
- compl_code = connection["compl_code"] \
- if "compl_code" in connection else None
+ init_code = connection.get("init_code")
+ compl_code = connection.get("compl_code")
if from_ not in from_connections:
from_connections[from_] = list()
if to not in to_connections:
connector_type_info = self._metadata.connector_types[
connector_id]
name = connector_type_info["name"]
+ help = connector_type_info["help"]
max = connector_type_info["max"]
min = connector_type_info["min"]
testbed_id = self._testbed_id
factory_id = factory.factory_id
connector_type = ConnectorType(testbed_id, factory_id, name,
- max, min)
+ help, max, min)
connector_key = (testbed_id, factory_id, name)
if connector_key in to_connections:
for (from_, can_cross, init_code, compl_code) in \
self._elements = dict()
self._metadata = Metadata(self._testbed_id, self._testbed_version)
- for factory in self._metadata.build_execute_factories():
+ for factory in self._metadata.build_factories():
self._factories[factory.factory_id] = factory
self._attributes = self._metadata.testbed_attributes()
self._root_directory = None
connector_type_name2):
factory1 = self._get_factory(guid1)
factory_id2 = self._create[guid2]
- count = self._get_connection_count(guid1, connector_type_name1)
+ # TODO VALIDATE!!!
+ #if self.box.guid == connector.box.guid:
+ # return False
+ #if self.is_full() or connector.is_full():
+ # return False
+ #if self.is_connected(connector):
+ # return False
+ #count = self._get_connection_count(guid1, connector_type_name1)
connector_type = factory1.connector_type(connector_type_name1)
connector_type.can_connect(self._testbed_id, factory_id2,
- connector_type_name2, count, False)
+ connector_type_name2, False)
if not guid1 in self._connect:
self._connect[guid1] = dict()
if not connector_type_name1 in self._connect[guid1]:
cross_testbed_guid, cross_testbed_id, cross_factory_id,
cross_connector_type_name):
factory = self._get_factory(guid)
- count = self._get_connection_count(guid, connector_type_name)
+ # TODO VALIDATE!!!
+ #if self.box.guid == connector.box.guid:
+ # return False
+ #if self.is_full() or connector.is_full():
+ # return False
+ #if self.is_connected(connector):
+ # return False
+ #count = self._get_connection_count(guid, connector_type_name)
connector_type = factory.connector_type(connector_type_name)
connector_type.can_connect(cross_testbed_id, cross_factory_id,
- cross_connector_type_name, count, True)
+ cross_connector_type_name, True)
if not guid in self._cross_connect:
self._cross_connect[guid] = dict()
if not connector_type_name in self._cross_connect[guid]:
(cross_guid, cross_testbed_guid, cross_testbed_id,
cross_factory_id, cross_connector_type_name)
- def defer_add_trace(self, guid, trace_id):
+ def defer_add_trace(self, guid, trace_name):
if not guid in self._create:
raise RuntimeError("Element guid %d doesn't exist" % guid)
factory = self._get_factory(guid)
- if not trace_id in factory.traces:
+ if not trace_name in factory.traces_list:
raise RuntimeError("Element type '%s' has no trace '%s'" %
- (factory.factory_id, trace_id))
+ (factory.factory_id, trace_name))
if not guid in self._add_trace:
self._add_trace[guid] = list()
- self._add_trace[guid].append(trace_id)
+ self._add_trace[guid].append(trace_name)
def defer_add_address(self, guid, address, netprefix, broadcast):
if not guid in self._create:
return addresses[index][attribute_index]
- def get_attribute_list(self, guid):
+ def get_attribute_list(self, guid, filter_flags = None):
factory = self._get_factory(guid)
attribute_list = list()
- return factory.box_attributes.attributes_list
+ return factory.box_attributes.get_attribute_list(filter_flags)
def get_factory_id(self, guid):
factory = self._get_factory(guid)
# TODO: take on account schedule time for the task
factory_id = self._create[guid]
factory = self._factories[factory_id]
- if factory.box_attributes.is_attribute_design_only(name):
+ if factory.box_attributes.is_attribute_design_only(name) or \
+ factory.box_attributes.is_attribute_invisible(name):
return
element = self._elements.get(guid)
if element:
# TODO: take on account schedule time for the task
factory_id = self._create[guid]
factory = self._factories[factory_id]
- if factory.box_attributes.is_attribute_design_only(name):
+ if factory.box_attributes.is_attribute_design_only(name) or \
+ factory.box_attributes.is_attribute_invisible(name):
return value
element = self._elements.get(guid)
try:
from constants import TESTBED_ID
from nepi.core import metadata
from nepi.core.attributes import Attribute
-from nepi.util import validation
+from nepi.util import tags, validation
from nepi.util.constants import ApplicationStatus as AS, \
FactoryCategories as FC
factories_info = dict({
NODE: dict({
- "allow_routes": True,
"help": "Emulated Node with virtualized network stack",
"category": FC.CATEGORY_NODES,
"create_function": create_node,
"configure_function": configure_node,
"box_attributes": ["forward_X11"],
"connector_types": ["devs", "apps"],
- "traces": ["node_pcap"]
+ "traces": ["node_pcap"],
+ "tags": [tags.NODE, tags.ALLOW_ROUTES],
}),
P2PIFACE: dict({
- "allow_addresses": True,
"help": "Point to point network interface",
"category": FC.CATEGORY_DEVICES,
"create_function": create_p2piface,
"configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
- "connector_types": ["node", "p2p"]
+ "connector_types": ["node", "p2p"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
TAPIFACE: dict({
- "allow_addresses": True,
"help": "Tap device network interface",
"category": FC.CATEGORY_DEVICES,
"create_function": create_tapiface,
"configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
- "connector_types": ["node", "fd->"]
+ "connector_types": ["node", "fd->"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
NODEIFACE: dict({
- "allow_addresses": True,
"help": "Node network interface",
"category": FC.CATEGORY_DEVICES,
"create_function": create_nodeiface,
"configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
- "connector_types": ["node", "switch"]
+ "connector_types": ["node", "switch"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
SWITCH: dict({
"display_name": "Switch",
#TODO: Add attribute ("HelloTime", help, type, value, range, allowed, readonly, validation_function),
#TODO: Add attribute ("AgeingTime", help, type, value, range, allowed, readonly, validation_function),
#TODO: Add attribute ("MaxAge", help, type, value, range, allowed, readonly, validation_function)
- "connector_types": ["devs"]
+ "connector_types": ["devs"],
+ "tags": [tags.SWITCH],
}),
APPLICATION: dict({
"help": "Generic executable command line application",
"status_function": status_application,
"box_attributes": ["command", "user"],
"connector_types": ["node"],
- "traces": ["stdout", "stderr"]
+ "traces": ["stdout", "stderr"],
+ "tags": [tags.APPLICATION],
}),
TUNCHANNEL : dict({
- "category": FC.CATEGORY_TUNNELS,
- "create_function": create_tunchannel,
- "preconfigure_function": preconfigure_tunchannel,
- "configure_function": postconfigure_tunchannel,
- "prestart_function": wait_tunchannel,
- "help": "Channel to forward "+TAPIFACE+" data to "
+ "category": FC.CATEGORY_TUNNELS,
+ "create_function": create_tunchannel,
+ "preconfigure_function": preconfigure_tunchannel,
+ "configure_function": postconfigure_tunchannel,
+ "prestart_function": wait_tunchannel,
+ "help": "Channel to forward "+TAPIFACE+" data to "
"other TAP interfaces supporting the NEPI tunneling protocol.",
- "connector_types": ["->fd", "udp", "tcp"],
- "allow_addresses": False,
- "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"]
+ "connector_types": ["->fd", "udp", "tcp"],
+ "allow_addresses": False,
+ "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"],
+ "tags": [tags.TUNNEL],
}),
})
"category": FC.CATEGORY_APPLICATIONS,
"create_function": create_element,
"configure_function": configure_element,
- "help": "",
- "connector_types": [],
"stop_function": stop_application,
"start_function": start_application,
"status_function": status_application,
+ "help": "",
+ "connector_types": [],
"box_attributes": ["MaxPackets",
"Interval",
"RemoteIpv6",
"PacketSize",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::UdpL4Protocol": dict({
"category": FC.CATEGORY_PROTOCOLS,
"help": "",
"connector_types": ["node"],
"box_attributes": ["ProtocolNumber"],
+ "tags": [tags.PROTOCOL],
}),
"ns3::RandomDiscPositionAllocator": dict({
"category": FC.CATEGORY_MOBILITY_MODELS,
"configure_function": configure_node,
"help": "",
"connector_types": ["devs", "apps", "protos", "mobility"],
- "allow_routes": True,
- "box_attributes": [],
+ "tags": [tags.NODE, tags.ALLOW_ROUTES],
}),
"ns3::GridPositionAllocator": dict({
"category": FC.CATEGORY_MOBILITY_MODELS,
"DeltaX",
"DeltaY",
"LayoutType"],
- "tags": [tags.MOBILE],
}),
"ns3::TapBridge": dict({
"category": FC.CATEGORY_DEVICES,
"configure_function": configure_element,
"help": "",
"connector_types": [],
- "allow_addresses": True,
"box_attributes": ["Mtu",
"DeviceName",
"Gateway",
"Netmask",
"Start",
"Stop"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::FlowMonitor": dict({
- "category": "",
+ "category": FC.CATEGORY_SERVICE_FLOWS,
"create_function": create_element,
"configure_function": configure_element,
"help": "",
"StartTime",
"StopTime"],
"traces": ["rtt"],
+ "tags": [tags.APPLICATION],
}),
"ns3::dot11s::PeerLink": dict({
"category": "",
"configure_function": configure_device,
"help": "",
"connector_types": ["node", "err", "queue", "chan"],
- "allow_addresses": True,
"box_attributes": ["Mtu",
"Address",
"DataRate",
"InterframeGap"],
- "traces": ["p2ppcap", "p2pascii"]
+ "traces": ["p2ppcap", "p2pascii"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::NakagamiPropagationLossModel": dict({
"category": FC.CATEGORY_LOSS_MODELS,
"Protocol",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::AdhocWifiMac": dict({
"category": FC.CATEGORY_MAC_MODELS,
"configure_function": configure_device,
"help": "Network interface associated to a file descriptor",
"connector_types": ["node", "->fd"],
- "allow_addresses": True,
"box_attributes": ["Address",
"LinuxSocketAddress",
"tun_proto", "tun_addr", "tun_port", "tun_key"],
- "traces": ["fdpcap"]
+ "traces": ["fdpcap"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::Nepi::TunChannel": dict({
"category": FC.CATEGORY_TUNNELS,
"other TAP interfaces supporting the NEPI tunneling protocol.",
"connector_types": ["fd->", "udp", "tcp"],
"allow_addresses": False,
- "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"]
+ "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"],
+ "tags": [tags.TUNNEL],
+
}),
"ns3::CsmaNetDevice": dict({
"category": FC.CATEGORY_DEVICES,
"configure_function": configure_device,
"help": "CSMA (carrier sense, multiple access) interface",
"connector_types": ["node", "chan", "err", "queue"],
- "allow_addresses": True,
"box_attributes": ["Address",
"Mtu",
"SendEnable",
"ReceiveEnable"],
- "traces": ["csmapcap", "csmapcap_promisc"]
+ "traces": ["csmapcap", "csmapcap_promisc"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::UanPropModelThorp": dict({
"category": "",
"configure_function": configure_element,
"help": "",
"connector_types": ["node", "chan"],
- "allow_addresses": True,
"box_attributes": [],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::FriisPropagationLossModel": dict({
"category": FC.CATEGORY_LOSS_MODELS,
"help": "",
"connector_types": [],
"box_attributes": [],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::ConstantSpeedPropagationDelayModel": dict({
"category": FC.CATEGORY_DELAY_MODELS,
"configure_function": configure_station,
"help": "Base station for wireless mobile network",
"connector_types": ["node", "chan", "phy", "uplnk", "dwnlnk"],
- "allow_addresses": True,
"box_attributes": ["InitialRangInterval",
"DcdInterval",
"UcdInterval",
"RTG",
"TTG"],
"traces": ["wimaxpcap", "wimaxascii"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::UdpServer": dict({
"category": FC.CATEGORY_APPLICATIONS,
"Start",
"Stop",
"RxQueueSize"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::Ipv6ExtensionLooseRouting": dict({
"category": FC.CATEGORY_ROUTING,
"connector_types": [],
"box_attributes": ["Address",
"Mtu"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::MatrixPropagationLossModel": dict({
"category": FC.CATEGORY_LOSS_MODELS,
"configure_function": configure_device,
"help": "",
"connector_types": ["node", "mac", "phy", "manager"],
- "allow_addresses": True,
"box_attributes": ["Mtu"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::CsmaChannel": dict({
"category": FC.CATEGORY_CHANNELS,
"configure_function": configure_element,
"help": "",
"connector_types": ["node"],
- "allow_addresses": True,
"box_attributes": ["Mtu",
"EnableLearning",
"ExpirationTime"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::Ipv6ExtensionRouting": dict({
"category": FC.CATEGORY_ROUTING,
"PacketSize",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::UdpClient": dict({
"category": FC.CATEGORY_APPLICATIONS,
"PacketSize",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::PointToPointChannel": dict({
"category": FC.CATEGORY_CHANNELS,
"configure_function": configure_element,
"help": "",
"connector_types": [],
- "allow_addresses": True,
"box_attributes": ["Mtu"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::BasicEnergySource": dict({
"category": FC.CATEGORY_ENERGY_MODELS,
"configure_function": configure_element,
"help": "",
"connector_types": [],
- "allow_addresses": True,
"box_attributes": [],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::RateErrorModel": dict({
"category": FC.CATEGORY_ERROR_MODELS,
"configure_function": configure_element,
"help": "",
"connector_types": [],
- "allow_addresses": True,
"box_attributes": ["Mtu"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::UanPhyGen": dict({
"category": FC.CATEGORY_PHY_MODELS,
"Protocol",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::RandomDirection2dMobilityModel": dict({
"category": FC.CATEGORY_MOBILITY_MODELS,
"box_attributes": ["Port",
"StartTime",
"StopTime"],
+ "tags": [tags.APPLICATION],
}),
"ns3::AmrrWifiManager": dict({
"category": FC.CATEGORY_MANAGERS,
"configure_function": configure_station,
"help": "Subscriber station for mobile wireless network",
"connector_types": ["node", "chan", "phy", "sflows"],
- "allow_addresses": True,
"box_attributes": ["LostDlMapInterval",
"LostUlMapInterval",
"MaxDcdInterval",
"RTG",
"TTG"],
"traces": ["wimaxpcap", "wimaxascii"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
"ns3::flame::FlameRtable": dict({
"category": "",
from constants import TESTBED_ID
from nepi.core import metadata
from nepi.core.attributes import Attribute
-from nepi.util import validation
+from nepi.util import tags, validation
from nepi.util.constants import ApplicationStatus as AS, \
FactoryCategories as FC, \
ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP
factories_info = dict({
NODE: dict({
- "allow_routes": True,
"help": "Virtualized Node (V-Server style)",
"category": FC.CATEGORY_NODES,
"create_function": create_node,
# NEPI-in-NEPI attributes
ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
],
- "connector_types": ["devs", "apps", "pipes", "deps"]
+ "connector_types": ["devs", "apps", "pipes", "deps"],
+ "tags": [tags.NODE, tags.ALLOW_ROUTES],
}),
NODEIFACE: dict({
- "has_addresses": True,
"help": "External network interface - they cannot be brought up or down, and they MUST be connected to the internet.",
"category": FC.CATEGORY_DEVICES,
"create_function": create_nodeiface,
"preconfigure_function": configure_nodeiface,
"box_attributes": [ ],
- "connector_types": ["node", "inet"]
+ "connector_types": ["node", "inet"],
+ "tags": [tags.INTERFACE, tags.HAS_ADDRESSES],
}),
TUNIFACE: dict({
- "allow_addresses": True,
"help": "Virtual TUN network interface (layer 3)",
"category": FC.CATEGORY_DEVICES,
"create_function": create_tuniface,
"tun_proto", "tun_addr", "tun_port", "tun_key"
],
"traces": ["packets"],
- "connector_types": ["node","udp","tcp","fd->"]
+ "connector_types": ["node","udp","tcp","fd->"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
TAPIFACE: dict({
- "allow_addresses": True,
"help": "Virtual TAP network interface (layer 2)",
"category": FC.CATEGORY_DEVICES,
"create_function": create_tapiface,
"tun_proto", "tun_addr", "tun_port", "tun_key"
],
"traces": ["packets"],
- "connector_types": ["node","udp","tcp","fd->"]
+ "connector_types": ["node","udp","tcp","fd->"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
APPLICATION: dict({
"help": "Generic executable command line application",
"depends", "build-depends", "build", "install",
"sources", "rpm-fusion" ],
"connector_types": ["node"],
- "traces": ["stdout", "stderr", "buildlog"]
+ "traces": ["stdout", "stderr", "buildlog"],
+ "tags": [tags.APPLICATION],
}),
DEPENDENCY: dict({
"help": "Requirement for package or application to be installed on some node",
"box_attributes": ["depends", "build-depends", "build", "install",
"sources", "rpm-fusion" ],
"connector_types": ["node"],
- "traces": ["buildlog"]
+ "traces": ["buildlog"],
}),
NEPIDEPENDENCY: dict({
"help": "Requirement for NEPI inside NEPI - required to run testbed instances inside a node",
"category": FC.CATEGORY_APPLICATIONS,
"create_function": create_nepi_dependency,
"preconfigure_function": configure_dependency,
- "box_attributes": [ ],
+ "box_attributes": [],
"connector_types": ["node"],
- "traces": ["buildlog"]
+ "traces": ["buildlog"],
}),
NS3DEPENDENCY: dict({
"help": "Requirement for NS3 inside NEPI - required to run NS3 testbed instances inside a node. It also needs NepiDependency.",
"preconfigure_function": configure_dependency,
"box_attributes": [ ],
"connector_types": ["node"],
- "traces": ["buildlog"]
+ "traces": ["buildlog"],
}),
INTERNET: dict({
"help": "Internet routing",
"category": FC.CATEGORY_CHANNELS,
"create_function": create_internet,
"connector_types": ["devs"],
+ "tags": [tags.INTERNET],
}),
NETPIPE: dict({
"help": "Link emulation",
"bw_in","plr_in","delay_in",
"bw_out","plr_out","delay_out"],
"connector_types": ["node"],
- "traces": ["netpipe_stats"]
+ "traces": ["netpipe_stats"],
}),
})
data = self.data[guid]
if not "traces" in data:
return []
- return [trace_id for trace_id in data["traces"]]
+ return data["traces"]
def get_connection_data(self, guid):
data = self.data[guid]
def traces_to_data(self, data, guid, traces):
for trace in traces:
if trace.enabled:
- data.add_trace_data(guid, trace.trace_id)
+ data.add_trace_data(guid, trace.name)
def connections_to_data(self, data, guid, connectors):
for connector in connectors:
from nepi.core.metadata import Metadata
- for _,attr_info in Metadata.DEPLOYMENT_ATTRIBUTES:
+ for _,attr_info in Metadata.DEPLOYMENT_ATTRIBUTES.iteritems():
self.add_attribute(**attr_info)
if params:
return self._testbed.status(guid)
@Marshalling.handles(GET_ATTRIBUTE_LIST)
- @Marshalling.args(int)
+ @Marshalling.args(int, int)
@Marshalling.retval( Marshalling.pickled_data )
- def get_attribute_list(self, guid):
- return self._testbed.get_attribute_list(guid)
+ def get_attribute_list(self, guid, filter_flags = None):
+ return self._testbed.get_attribute_list(guid, filter_flags)
@Marshalling.handles(GET_FACTORY_ID)
@Marshalling.args(int)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-MOBILE = 0
+MOBILE = "mobile"
+NODE = "node"
+INTERFACE = "interface"
+WIRELESS = "wireless"
+APPLICATION = "application"
+NAT = "nat"
+ROUTER = "router"
+SWITCH = "switch"
+PPP = "point-to-point"
+PROTOCOL = "protocol"
+TUNNEL = "tunnel"
+INTERNET = "internet"
+HUB = "hub"
+ALLOW_ADDRESSES = "allow_addresses"
+ALLOW_ROUTES = "allow_routes"
+HAS_ADDRESSES = "has_addresses"
+HAS_ROUTES = "has_routes"
+
+class Taggable(object):
+ def __init__(self):
+ super(Taggable, self).__init__()
+ self._tags = list()
+
+ @property
+ def tags(self):
+ return self._tags
+
+ def add_tag(self, tag_id):
+ self._tags.append(tag_id)
+
+ def has_tag(self, tag_id):
+ return tag_id in self._tags
app.connector("node").connect(node1.connector("apps"))
app.enable_trace("fake")
- self.assertEquals(node1.tags, [tags.MOBILE])
+ self.assertEquals(node1.tags, [tags.MOBILE, tags.NODE, tags.ALLOW_ROUTES])
xml = exp_desc.to_xml()
exp_desc2 = ExperimentDescription()
instance.do_configure()
instance.start()
attr_list = instance.get_attribute_list(5)
- self.assertEquals(attr_list, ["test", "fake", "cross", "label"])
+ self.assertEquals(attr_list, ["test", "fake", "cross", "maxAddresses", "label"])
while instance.status(7) != AS.STATUS_FINISHED:
time.sleep(0.5)
app_result = instance.trace(7, "fake")
"value": False,
"validation_function": validation.is_bool
}),
- "MaxAddresses": dict({
- "name": "MaxAddresses",
+ "maxAddresses": dict({
+ "name": "maxAddresses",
"help": "Attribute that indicates the maximum number of addresses for an interface",
"type": Attribute.INTEGER,
"value": 3,
"status_function": None,
"box_attributes": ["fake","test"],
"connector_types": ["devs", "apps"],
- "tags": [tags.MOBILE]
+ "tags": [tags.MOBILE, tags.NODE, tags.ALLOW_ROUTES],
}),
IFACE: dict({
"help": "Fake iface",
"stop_function": None,
"status_function": None,
"allow_addresses": True,
- "factory_attributes": ["fake", "MaxAddresses"],
+ "factory_attributes": ["fake", "maxAddresses"],
"box_attributes": ["fake", "test", "cross"],
- "connector_types": ["node", "iface", "cross"]
+ "connector_types": ["node", "iface", "cross"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
APP: dict({
"help": "Fake application",
"status_function": status_application,
"box_attributes": ["fake", "test"],
"connector_types": ["node"],
- "traces": ["fake"]
+ "traces": ["fake"],
+ "tags": [tags.APPLICATION],
}),
})
from constants import TESTBED_ID
from nepi.core import metadata
from nepi.core.attributes import Attribute
-from nepi.util import validation
+from nepi.util import tags, validation
from nepi.util.constants import ApplicationStatus as AS
NODE = "Node"
"stop_function": None,
"status_function": None,
"box_attributes": ["fake","test"],
- "connector_types": ["devs", "apps"]
+ "connector_types": ["devs", "apps"],
+ "tags": [tags.NODE, tags.ALLOW_ROUTES],
}),
IFACE: dict({
"help": "Fake iface",
"allow_addresses": True,
"factory_attributes": ["fake"],
"box_attributes": ["fake", "test", "cross"],
- "connector_types": ["node", "iface", "cross"]
+ "connector_types": ["node", "iface", "cross"],
+ "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
}),
APP: dict({
"help": "Fake application",
"status_function": status_application,
"box_attributes": ["fake", "test"],
"connector_types": ["node"],
- "traces": ["fake"]
+ "traces": ["fake"],
+ "tags": [tags.APPLICATION],
}),
})