endif
#PYPATH = $(BUILDDIR):$(TESTLIB):$(PYTHONPATH)
-PYPATH = "../nepi2/src:../nepi2/test/util:../netns/src"
+PYPATH = "../nepi2/src:../nepi2/test/lib:../netns/src"
COVERAGE = $(or $(shell which coverage), $(shell which python-coverage), \
coverage)
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 attr in factory.box_attributes.attributes:
self.add_attribute(attr.name, attr.help, attr.type, attr.value,
attr.range, attr.allowed, attr.flags,
attr.validation_function)
self._category = category
self._connector_types = list()
self._traces = list()
- self._box_attributes = list()
+ self._box_attributes = AttributesMap()
@property
def factory_id(self):
def add_box_attribute(self, name, help, type, value = None, range = None,
allowed = None, flags = Attribute.NoFlags, validation_function = None):
- attribute = Attribute(name, help, type, value, range, allowed, flags,
- validation_function)
- self._box_attributes.append(attribute)
+ self._box_attributes.add_attribute(name, help, type, value, range,
+ allowed, flags, validation_function)
def create(self, guid, testbed_description):
if self._allow_addresses:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from nepi.core.attributes import AttributesMap
+from nepi.core.attributes import Attribute, AttributesMap
+from nepi.util.constants import STATUS_FINISHED
from nepi.util.parser._xml import XmlExperimentParser
from nepi.util import validation
import sys
self._status_function = status_function
self._connector_types = dict()
self._traces = list()
+ self._box_attributes = AttributesMap()
@property
def factory_id(self):
def allow_routes(self):
return self._allow_routes
+ @property
+ def box_attributes(self):
+ return self._box_attributes
+
@property
def create_function(self):
return self._create_function
def add_trace(self, trace_id):
self._traces.append(trace_id)
+ def add_box_attribute(self, name, help, type, value = None, range = None,
+ allowed = None, flags = Attribute.NoFlags, validation_function = None):
+ self._box_attributes.add_attribute(name, help, type, value, range,
+ allowed, flags, validation_function)
+
class TestbedInstance(object):
def __init__(self, testbed_id, testbed_version):
self._testbed_id = testbed_id
raise NotImplementedError
def create_set(self, guid, name, value):
- """Instructs setting an attribute on an element"""
+ """Instructs setting an initial attribute on an element"""
+ raise NotImplementedError
+
+ def factory_set(self, guid, name, value):
+ """Instructs setting an attribute on a factory"""
raise NotImplementedError
def connect(self, guid1, connector_type_name1, guid2,
return self._testbeds[testbed_guid].trace(guid, trace_id)
def start(self):
+ self._create_testbed_instances()
+ for instance in self._testbeds.values():
+ instance.do_setup()
+ for instance in self._testbeds.values():
+ instance.do_create()
+ instance.do_connect()
+ instance.do_configure()
+ for instances in self._testbeds.values():
+ instance.do_cross_connect()
+ for instances in self._testbeds.values():
+ instance.start()
+
+ def stop(self):
+ for instance in self._testbeds.values():
+ instance.stop()
+
+ def is_finished(self, guid):
+ for instance in self._testbeds.values():
+ for guid_ in instance.guids:
+ if guid_ == guid:
+ return instance.status(guid) == STATUS_FINISHED
+ raise RuntimeError("No element exists with guid %d" % guid)
+
+ def shutdown(self):
+ for instance in self._testbeds.values():
+ instance.shutdown()
+
+ def _build_testbed_instance(self, testbed_id, testbed_version):
+ mod_name = "nepi.testbeds.%s" % (testbed_id.lower())
+ if not mod_name in sys.modules:
+ __import__(mod_name)
+ module = sys.modules[mod_name]
+ return module.TestbedInstance(testbed_version)
+
+ def _create_testbed_instances(self):
parser = XmlExperimentParser()
data = parser.from_xml_to_data(self._experiment_xml)
element_guids = list()
self._testbeds[guid] = instance
else:
element_guids.append(guid)
+ self._program_testbed_instances(element_guids, data)
+ def _program_testbed_instances(self, element_guids, data):
for guid in element_guids:
(testbed_guid, factory_id) = data.get_box_data(guid)
instance = self._testbeds[testbed_guid]
data.get_route_data(guid):
instance.add_route(guid, destination, netprefix, nexthop)
- for instance in self._testbeds.values():
- instance.do_setup()
- for instance in self._testbeds.values():
- instance.do_create()
- instance.do_connect()
- instance.do_configure()
- for instances in self._testbeds.values():
- instance.do_cross_connect()
- for instances in self._testbeds.values():
- instance.start()
-
- def stop(self):
- for instance in self._testbeds.values():
- instance.stop()
-
- def status(self, guid):
- for instance in self._testbeds.values():
- for guid_ in instance.guids:
- if guid_ == guid:
- return instance.status(guid)
- raise RuntimeError("No element exists with guid %d" % guid)
-
- def shutdown(self):
- for instance in self._testbeds.values():
- instance.shutdown()
-
- def _build_testbed_instance(self, testbed_id, testbed_version):
- mod_name = "nepi.testbeds.%s" % (testbed_id.lower())
- if not mod_name in sys.modules:
- __import__(mod_name)
- module = sys.modules[mod_name]
- return module.TestbedInstance(testbed_version)
-
stop_function, status_function, allow_addresses,
allow_routes)
self._add_attributes(factory, info, "factory_attributes")
- self._add_attributes(factory, info, "box_attributes")
+ self._add_attributes(factory, info, "box_attributes", True)
self._add_execute_traces(factory, info)
self._add_execute_connector_types(factory, info)
factories.append(factory)
# experiment construction instructions
self._create = dict()
self._create_set = dict()
+ self._factory_set = dict()
self._connect = dict()
self._cross_connect = dict()
self._add_trace = dict()
# log of set operations
self._set = dict()
- # log of actions
- self._actions = dict()
# testbed element instances
self._elements = dict()
raise RuntimeError("Element guid %d doesn't exist" % guid)
factory_id = self._create[guid]
factory = self._factories[factory_id]
- if not factory.has_attribute(name):
+ if not factory.box_attributes.has_attribute(name):
raise RuntimeError("Invalid attribute %s for element type %s" %
(name, factory_id))
- factory.set_attribute_value(name, value)
+ factory.box_attributes.set_attribute_value(name, value)
if guid not in self._create_set:
self._create_set[guid] = dict()
self._create_set[guid][name] = value
-
+
+ def factory_set(self, guid, name, value):
+ if not guid in self._create:
+ raise RuntimeError("Element guid %d doesn't exist" % guid)
+ factory_id = self._create[guid]
+ factory = self._factories[factory_id]
+ if not factory.has_attribute(name):
+ raise RuntimeError("Invalid attribute %s for element type %s" %
+ (name, factory_id))
+ factory.set_attribute_value(name, value)
+ if guid not in self._factory_set:
+ self._factory_set[guid] = dict()
+ self._factory_set[guid][name] = value
+
def connect(self, guid1, connector_type_name1, guid2,
connector_type_name2):
factory_id1 = self._create[guid1]
for guid in guids[factory_id]:
parameters = dict() if guid not in self._create_set else \
self._create_set[guid]
- factory.create_function(self, guid, parameters)
+ factory_parameters = dict() if guid not in \
+ self._factory_set else self._create_set[guid]
+ factory.create_function(self, guid, parameters,
+ factory_parameters)
for name, value in parameters.iteritems():
self.set(TIME_NOW, guid, name, value)
raise RuntimeError("Element guid %d doesn't exist" % guid)
factory_id = self._create[guid]
factory = self._factories[factory_id]
- if not factory.has_attribute(name):
+ if not factory.box_attributes.has_attribute(name):
raise RuntimeError("Invalid attribute %s for element type %s" %
(name, factory_id))
if self._started and factory.is_attribute_design_only(name):
raise RuntimeError("Attribute %s can only be modified during experiment design" % name)
- factory.set_attribute_value(name, value)
+ factory.box_attributes.set_attribute_value(name, value)
if guid not in self._set:
self._set[guid] = dict()
if time not in self._set[guid]:
from constants import TESTBED_ID
from nepi.core import testbed_impl
-from nepi.core.metadata import Metadata
-from nepi.util import validation
from nepi.util.constants import AF_INET, AF_INET6
import os
### Creation functions ###
-def create_node(testbed_instance, guid, parameters):
+def create_node(testbed_instance, guid, parameters, factory_parameters):
forward_X11 = False
if "forward_X11" in parameters:
forward_X11 = parameters["forward_X11"]
element = testbed_instance.netns.Node(forward_X11 = forward_X11)
testbed_instance.elements[guid] = element
-def create_p2piface(testbed_instance, guid, parameters):
+def create_p2piface(testbed_instance, guid, parameters, factory_parameters):
if guid in testbed_instance.elements:
# The interface pair was already instantiated
return
testbed_instance.elements[guid] = element1
testbed_instance.elements[guid2] = element2
-def create_tapiface(testbed_instance, guid, parameters):
+def create_tapiface(testbed_instance, guid, parameters, factory_parameters):
node_guid = testbed_instance.get_connected(guid, "node", "devs")
if len(node_guid) == 0:
raise RuntimeError("Can't instantiate interface %d outside netns \
element = node.add_tap()
testbed_instance.elements[guid] = element
-def create_nodeiface(testbed_instance, guid, parameters):
+def create_nodeiface(testbed_instance, guid, parameters, factory_parameters):
node_guid = testbed_instance.get_connected(guid, "node", "devs")
if len(node_guid) == 0:
raise RuntimeError("Can't instantiate interface %d outside netns \
element = node.add_if()
testbed_instance.elements[guid] = element
-def create_switch(testbed_instance, guid, parameters):
+def create_switch(testbed_instance, guid, parameters, factory_parameters):
element = testbed_instance.netns.Switch()
testbed_instance.elements[guid] = element
-def create_application(testbed_instance, guid, parameters):
+def create_application(testbed_instance, guid, parameters, factory_parameters):
testbed_instance.elements[guid] = None # Delayed construction
### Start/Stop functions ###
def traces_from_data(self, box, data):
for name in data.get_trace_data(box.guid):
- box.trace(name).enable()
+ box.enable_trace(name)
def addresses_from_data(self, box, data):
for (autoconf, address, family, netprefix, broadcast) \
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core.design import ExperimentDescription, FactoriesProvider
+import mock.metadata_v01
+import sys
+import unittest
+
+class DesignTestCase(unittest.TestCase):
+ def setUp(self):
+ sys.modules["nepi.testbeds.mock.metadata_v01"] = mock.metadata_v01
+
+ def test_design(self):
+ exp_desc = ExperimentDescription()
+ testbed_version = "01"
+ testbed_id = "mock"
+ provider = FactoriesProvider(testbed_id, testbed_version)
+ desc = exp_desc.add_testbed_description(provider)
+ desc.set_attribute_value("fake", True)
+ node1 = desc.create("Node")
+ node2 = desc.create("Node")
+ iface1 = desc.create("Interface")
+ iface1.set_attribute_value("fake", True)
+ node1.connector("devs").connect(iface1.connector("node"))
+ iface2 = desc.create("Interface")
+ iface2.set_attribute_value("fake", True)
+ node2.connector("devs").connect(iface2.connector("node"))
+ iface1.connector("iface").connect(iface2.connector("iface"))
+ app = desc.create("Application")
+ app.connector("node").connect(node1.connector("apps"))
+ app.enable_trace("fake")
+
+ xml = exp_desc.to_xml()
+ exp_desc2 = ExperimentDescription()
+ exp_desc2.from_xml(xml)
+ xml2 = exp_desc2.to_xml()
+ self.assertTrue(xml == xml2)
+
+if __name__ == '__main__':
+ unittest.main()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.util.constants import STATUS_FINISHED
+import mock
+import mock.metadata_v01
+import sys
+import time
+import unittest
+
+class ExecuteTestCase(unittest.TestCase):
+ def setUp(self):
+ sys.modules["nepi.testbeds.mock.metadata_v01"] = mock.metadata_v01
+
+ def test_execute(self):
+ testbed_version = "01"
+ testbed_id = "mock"
+ instance = mock.TestbedInstance(testbed_version)
+ instance.configure("fake", True)
+ instance.create(2, "Node")
+ instance.create(3, "Node")
+ instance.create(4, "Node")
+ instance.create(5, "Interface")
+ instance.create_set(5, "fake", True)
+ instance.connect(2, "devs", 5, "node")
+ instance.create(6, "Interface")
+ instance.create_set(6, "fake", True)
+ instance.connect(3, "devs", 6, "node")
+ instance.connect(5, "iface", 6, "iface")
+ instance.create(7, "Application")
+ instance.add_trace(7, "fake")
+ instance.connect(7, "node", 2, "apps")
+
+ instance.do_setup()
+ instance.do_create()
+ instance.do_connect()
+ instance.do_configure()
+ instance.start()
+ while instance.status(7) != STATUS_FINISHED:
+ time.sleep(0.5)
+ app_result = instance.trace(7, "fake")
+ comp_result = """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
+
+--- 10.0.0.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+"""
+
+ self.assertTrue(app_result.startswith(comp_result))
+ instance.stop()
+ instance.shutdown()
+
+if __name__ == '__main__':
+ unittest.main()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core.execute import ExperimentController
+from nepi.core.design import ExperimentDescription, FactoriesProvider
+from nepi.util.constants import STATUS_FINISHED
+import mock
+import mock.metadata_v01
+import sys
+import time
+import unittest
+
+class ExecuteTestCase(unittest.TestCase):
+ def setUp(self):
+ sys.modules["nepi.testbeds.mock.metadata_v01"] = mock.metadata_v01
+ sys.modules["nepi.testbeds.mock"] = mock
+
+ def test_integration(self):
+ exp_desc = ExperimentDescription()
+ testbed_version = "01"
+ testbed_id = "mock"
+ provider = FactoriesProvider(testbed_id, testbed_version)
+ desc = exp_desc.add_testbed_description(provider)
+ desc.set_attribute_value("fake", True)
+ node1 = desc.create("Node")
+ node2 = desc.create("Node")
+ iface1 = desc.create("Interface")
+ iface1.set_attribute_value("fake", True)
+ node1.connector("devs").connect(iface1.connector("node"))
+ iface2 = desc.create("Interface")
+ iface2.set_attribute_value("fake", True)
+ node2.connector("devs").connect(iface2.connector("node"))
+ iface1.connector("iface").connect(iface2.connector("iface"))
+ app = desc.create("Application")
+ app.connector("node").connect(node1.connector("apps"))
+ app.enable_trace("fake")
+
+ xml = exp_desc.to_xml()
+ controller = ExperimentController(xml)
+ controller.start()
+ while not controller.is_finished(app.guid):
+ time.sleep(0.5)
+ fake_result = controller.trace(desc.guid, app.guid, "fake")
+ comp_result = """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
+
+--- 10.0.0.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+"""
+ self.assertTrue(fake_result.startswith(comp_result))
+ controller.stop()
+ controller.shutdown()
+
+if __name__ == '__main__':
+ unittest.main()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from execute import TestbedInstance
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+TESTBED_ID = "mock"
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from nepi.core import testbed_impl
+
+class TestbedInstance(testbed_impl.TestbedInstance):
+ def __init__(self, testbed_version):
+ super(TestbedInstance, self).__init__(TESTBED_ID, testbed_version)
+
+ def do_setup(self):
+ pass
+
+ def do_configure(self):
+ pass
+
+ def set(self, time, guid, name, value):
+ super(TestbedInstance, self).set(time, guid, name, value)
+
+ def get(self, time, guid, name):
+ return True
+
+ def action(self, time, guid, action):
+ raise NotImplementedError
+
+ def trace(self, guid, trace_id):
+ return """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
+
+--- 10.0.0.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+"""
+
+ def shutdown(self):
+ pass
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from nepi.core import metadata
+from nepi.core.attributes import Attribute
+from nepi.util import validation
+from nepi.util.constants import STATUS_FINISHED
+
+NODE = "Node"
+IFACE = "Interface"
+APP = "Application"
+
+### Connection functions ####
+
+### Creation functions ###
+
+def create_node(testbed_instance, guid, parameters, factory_parameters):
+ element = NODE
+ testbed_instance.elements[guid] = element
+
+def create_iface(testbed_instance, guid, parameters, factory_parameters):
+ element = IFACE
+ testbed_instance.elements[guid] = element
+
+def create_application(testbed_instance, guid, parameters, factory_parameters):
+ element = APP
+ testbed_instance.elements[guid] = element
+
+### Start/Stop functions ###
+
+### Status functions ###
+
+def status_application(testbed_instance, guid):
+ return STATUS_FINISHED
+
+### Factory information ###
+
+connector_types = dict({
+ "apps": dict({
+ "help": "Connector from node to applications",
+ "name": "apps",
+ "max": -1,
+ "min": 0
+ }),
+ "devs": dict({
+ "help": "Connector from node to network interfaces",
+ "name": "devs",
+ "max": -1,
+ "min": 0
+ }),
+ "node": dict({
+ "help": "Connector to a Node",
+ "name": "node",
+ "max": 1,
+ "min": 1
+ }),
+ "iface": dict({
+ "help": "Connector to a Interface",
+ "name": "iface",
+ "max": 1,
+ "min": 0
+ }),
+ })
+
+connections = [
+ dict({
+ "from": (TESTBED_ID, NODE, "devs"),
+ "to": (TESTBED_ID, IFACE, "node"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, IFACE, "iface"),
+ "to": (TESTBED_ID, IFACE, "iface"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, NODE, "apps"),
+ "to": (TESTBED_ID, APP, "node"),
+ "code": None,
+ "can_cross": False
+ })
+]
+
+attributes = dict({
+ "fake": dict({
+ "name": "fake",
+ "help": "fake attribute",
+ "type": Attribute.BOOL,
+ "value": False,
+ "range": None,
+ "allowed": None,
+ "validation_function": validation.is_bool
+ }),
+ })
+
+traces = dict({
+ "fake": dict({
+ "name": "fake",
+ "help": "fake trace"
+ }),
+ })
+
+factories_order = [ NODE, IFACE, APP ]
+
+factories_info = dict({
+ NODE: dict({
+ "help": "Fake node",
+ "category": "topology",
+ "create_function": create_node,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "box_attributes": ["fake"],
+ "connector_types": ["devs", "apps"]
+ }),
+ IFACE: dict({
+ "help": "Fake iface",
+ "category": "devices",
+ "create_function": create_iface,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "factory_attributes": ["fake"],
+ "box_attributes": ["fake"],
+ "connector_types": ["node", "iface"]
+ }),
+ APP: dict({
+ "help": "Fake application",
+ "category": "applications",
+ "create_function": create_application,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": status_application,
+ "box_attributes": ["fake"],
+ "connector_types": ["node"],
+ "traces": ["fake"]
+ }),
+})
+
+testbed_attributes = dict({
+ "fake": dict({
+ "name": "fake",
+ "help": "fake attribute",
+ "type": Attribute.BOOL,
+ "value": False,
+ "range": None,
+ "allowed": None,
+ "validation_function": validation.is_bool
+ }),
+ })
+
+class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
+ @property
+ def connections_types(self):
+ return connection_types
+
+ @property
+ def connections(self):
+ return connections
+
+ @property
+ def attributes(self):
+ return attributes
+
+ @property
+ def traces(self):
+ return traces
+
+ @property
+ def factories_order(self):
+ return factories_order
+
+ @property
+ def factories_info(self):
+ return factories_info
+
+ @property
+ def testbed_attributes(self):
+ return testbed_attributes
+
import getpass
from nepi.core.design import ExperimentDescription, FactoriesProvider
from nepi.core.execute import ExperimentController
-from nepi.util.constants import AF_INET, STATUS_FINISHED
import os
import shutil
import test_util
controller = ExperimentController(xml)
controller.start()
- while controller.status(app.guid) != STATUS_FINISHED:
+ while not controller.is_finished(app.guid):
time.sleep(0.5)
ping_result = controller.trace(netns_desc.guid, app.guid, "stdout")
comp_result = """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.