-#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
from nepi.core.attributes import AttributesMap, Attribute
from nepi.core.metadata import Metadata
from nepi.util import validation
-from nepi.util.constants import AF_INET, AF_INET6
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(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")
- # connector_type_id -- univoquely identifies a connector type
- # across testbeds
- self._connector_type_id = (testbed_id.lower(), factory_id.lower(),
- name.lower())
- # name -- display name for the connector type
- self._name = name
- # help -- help text
- self._help = help
- # 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
- # 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 connector_type_id(self):
- return self._connector_type_id
-
- @property
- def help(self):
- return self._help
-
- @property
- def name(self):
- return self._name
-
- @property
- def max(self):
- return self._max
-
- @property
- def min(self):
- return self._min
-
- def add_allowed_connection(self, testbed_id, factory_id, name, can_cross):
- self._allowed_connections[(testbed_id.lower(),
- factory_id.lower(), name.lower())] = can_cross
-
- def can_connect(self, connector_type_id, testbed_guid1, testbed_guid2):
- if not connector_type_id in self._allowed_connections.keys():
- return False
- can_cross = self._allowed_connections[connector_type_id]
- return can_cross or (testbed_guid1 == testbed_guid2)
-
class Connector(object):
"""A Connector sepcifies the connection points in an Object"""
def __init__(self, box, connector_type):
self._connector_type = connector_type
self._connections = list()
+ def __str__(self):
+ return "Connector(%s, %s)" % (self.box, self.connector_type)
+
@property
def box(self):
return self._box
def connect(self, connector):
if not self.can_connect(connector) or not connector.can_connect(self):
- raise RuntimeError("Could not connect.")
+ raise RuntimeError("Could not connect. %s to %s" % (self, connector))
self._connections.append(connector)
connector._connections.append(self)
+ def get_connected_box(self, idx = 0):
+ if len(self._connections) == 0:
+ return None
+ return self._connections[idx].box
+
def disconnect(self, connector):
if connector not in self._connections or\
self not in connector._connections:
connector._connections.remove(self)
def can_connect(self, connector):
+ # can't connect with self
+ 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
- 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
+ self._enabled = enabled
@property
- def trace_id(self):
- return self._trace_id
+ def name(self):
+ return self._name
@property
def help(self):
return self._help
+ @property
+ def enabled(self):
+ return self._enabled
+
+ def enable(self):
+ self._enabled = True
+
+ def disable(self):
+ self._enabled = False
+
class Address(AttributesMap):
- def __init__(self, family):
+ def __init__(self):
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)
+ flags = Attribute.NoDefaultValue,
+ validation_function = validation.is_ip_address)
self.add_attribute(name = "NetPrefix",
help = "Network prefix for the address",
type = Attribute.INTEGER,
- range = prefix_range,
- value = 24 if family == AF_INET else 64,
+ range = (0, 128),
+ value = 24,
+ flags = Attribute.NoDefaultValue,
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)
+ self.add_attribute(name = "Broadcast",
+ help = "Broadcast address",
+ type = Attribute.STRING,
+ validation_function = validation.is_ip4_address)
class Route(AttributesMap):
- def __init__(self, family):
+ def __init__(self):
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)
+ validation_function = validation.is_ref_address)
self.add_attribute(name = "NetPrefix",
help = "Network destination prefix",
type = Attribute.INTEGER,
- prefix_range = prefix_range,
+ range = (0, 128),
+ value = 24,
+ flags = Attribute.NoDefaultValue,
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",
+ flags = Attribute.NoDefaultValue,
+ validation_function = validation.is_ref_address)
+ self.add_attribute(name = "Metric",
+ help = "Routing metric",
+ type = Attribute.INTEGER,
+ value = 0,
+ flags = Attribute.NoDefaultValue,
+ validation_function = validation.is_integer)
+ self.add_attribute(name = "Device",
+ help = "Device name",
type = Attribute.STRING,
- validation_function = address_validation)
+ value = None,
+ flags = Attribute.NoDefaultValue,
+ validation_function = validation.is_string)
-class Box(AttributesMap):
+class Box(AttributesMap, Taggable):
def __init__(self, guid, factory, testbed_guid, container = None):
super(Box, self).__init__()
# guid -- global unique identifier
# connectors -- list of available connectors for the box
self._connectors = dict()
# factory_attributes -- factory attributes for box construction
- self._factory_attributes = list()
+ self._factory_attributes = dict()
# graphical_info -- GUI position information
- self.graphical_info = GraphicalInfo(str(self._guid))
+ self.graphical_info = GraphicalInfo()
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 attr in factory.box_attributes:
+ for (name, help, enabled) in factory.traces:
+ trace = Trace(name, help, enabled)
+ self._traces[name] = trace
+ for tag_id in factory.tags:
+ 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.readonly, attr.visible,
- attr.validation_function)
+ attr.range, attr.allowed, attr.flags,
+ attr.validation_function, attr.category)
for attr in factory.attributes:
- self._factory_attributes.append(attr)
+ if attr.modified or attr.is_metadata:
+ self._factory_attributes[attr.name] = attr.value
+
+ def __str__(self):
+ return "Box(%s, %s, %s)" % (self.guid, self.factory_id, self.testbed_guid)
@property
def guid(self):
def traces(self):
return self._traces.values()
+ @property
+ def traces_list(self):
+ return self._traces.keys()
+
@property
def factory_attributes(self):
return self._factory_attributes
- @property
- def addresses(self):
- return []
+ def trace_help(self, trace_id):
+ return self._traces[trace_id].help
- @property
- def routes(self):
- return []
+ def enable_trace(self, trace_id):
+ self._traces[trace_id].enable()
+
+ def disable_trace(self, trace_id):
+ self._traces[trace_id].disable()
+
+ def is_trace_enabled(self, trace_id):
+ return self._traces[trace_id].enabled
def connector(self, name):
return self._connectors[name]
- def trace(self, trace_id):
- return self._traces[trace_id]
-
def destroy(self):
super(Box, self).destroy()
for c in self.connectors:
t.destroy()
self._connectors = self._traces = self._factory_attributes = None
-class AddressableBox(Box):
- def __init__(self, guid, factory, testbed_guid, container = None):
- super(AddressableBox, self).__init__(guid, factory, testbed_guid,
- container)
- self._family = factory.get_attribute_value("Family")
- # maximum number of addresses this box can have
- self._max_addresses = factory.get_attribute_value("MaxAddresses")
- 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 box reached.")
- address = Address(family = self._family)
- self._addresses.append(address)
- return address
-
- def delete_address(self, address):
- self._addresses.remove(address)
- del address
-
- def destroy(self):
- super(AddressableBox, self).destroy()
- for address in 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)
- 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(RoutingTableBox, self).destroy()
- for route in self.routes:
- self.delete_route(route)
- self._route = None
-
-class Factory(AttributesMap):
- def __init__(self, factory_id, allow_addresses = False,
- allow_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._help = help
- self._category = category
- self._connector_types = list()
- self._traces = list()
- self._box_attributes = list()
-
- @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 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 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_box_attribute(self, name, help, type, value = None, range = None,
- allowed = None, readonly = False, visible = True,
- validation_function = None):
- attribute = Attribute(name, help, type, value, range, allowed, readonly,
- visible, validation_function)
- self._box_attributes.append(attribute)
-
- 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)
-
- def destroy(self):
- super(Factory, self).destroy()
- self._connector_types = None
-
class FactoriesProvider(object):
- def __init__(self, testbed_id, testbed_version):
+ def __init__(self, testbed_id):
super(FactoriesProvider, self).__init__()
self._testbed_id = testbed_id
- self._testbed_version = testbed_version
self._factories = dict()
- metadata = Metadata(testbed_id, testbed_version)
- for factory in metadata.build_design_factories():
+ metadata = Metadata(testbed_id)
+ for factory in metadata.build_factories():
self.add_factory(factory)
+ self._testbed_version = metadata.testbed_version
+
@property
def testbed_id(self):
return self._testbed_id
del self._factories[factory_id]
class TestbedDescription(AttributesMap):
- def __init__(self, guid_generator, provider):
+ def __init__(self, guid_generator, provider, guid = None):
super(TestbedDescription, self).__init__()
self._guid_generator = guid_generator
- self._guid = guid_generator.next()
+ self._guid = guid_generator.next(guid)
self._provider = provider
self._boxes = dict()
- self.graphical_info = GraphicalInfo(str(self._guid))
+ self.graphical_info = GraphicalInfo()
+
+ metadata = Metadata(provider.testbed_id)
+ for attr in metadata.testbed_attributes().attributes:
+ self.add_attribute(attr.name, attr.help, attr.type, attr.value,
+ attr.range, attr.allowed, attr.flags,
+ attr.validation_function, attr.category)
@property
def guid(self):
def box(self, guid):
return self._boxes[guid] if guid in self._boxes else None
- def create(self, factory_id):
- guid = self._guid_generator.next()
+ def create(self, factory_id, guid = None):
+ guid = self._guid_generator.next(guid)
factory = self._provider.factory(factory_id)
box = factory.create(guid, self)
self._boxes[guid] = box
self._boxes = None
class ExperimentDescription(object):
- def __init__(self, guid = 0):
- self._guid_generator = GuidGenerator(guid)
+ def __init__(self):
+ self._guid_generator = GuidGenerator()
self._testbed_descriptions = dict()
@property
if box: return box
return None
- def add_testbed_description(self, provider):
+ def get_element(self, guid):
+ if guid in self._testbed_descriptions:
+ return self._testbed_descriptions[guid]
+ for testbed_description in self._testbed_descriptions.values():
+ box = testbed_description.box(guid)
+ if box: return box
+ return None
+
+ def get_element_by_label(self, label):
+ for tbd_desc in self._testbed_descriptions.values():
+ l = tbd_desc.get_attribute_value("label")
+ if label == l:
+ return tbd_desc
+ for box in tbd_desc.boxes:
+ l = box.get_attribute_value("label")
+ if label == l:
+ return box
+ return None
+
+ def add_testbed_description(self, provider, guid = None):
testbed_description = TestbedDescription(self._guid_generator,
- provider)
+ provider, guid)
guid = testbed_description.guid
self._testbed_descriptions[guid] = testbed_description
return testbed_description
- def remove_testbed_description(self, testbed_description):
- guid = testbed_description.guid
+ def remove_testbed_description(self, guid):
+ testbed_description = self._testbed_descriptions[guid]
del self._testbed_descriptions[guid]
+ testbed_description.destroy()
def destroy(self):
for testbed_description in self.testbed_descriptions:
testbed_description.destroy()
-# TODO: When the experiment xml is passed to the controller to execute it
-# NetReferences in the xml need to be solved
-#
-#targets = re.findall(r"%target:(.*?)%", command)
-#for target in targets:
-# try:
-# (family, address, port) = resolve_netref(target, AF_INET,
-# self.server.experiment )
-# command = command.replace("%%target:%s%%" % target, address.address)
-# except:
-# continue