added mock testbed for unit testing.
[nepi.git] / src / nepi / core / execute.py
index a657c53..e333940 100644 (file)
@@ -2,6 +2,8 @@
 # -*- coding: utf-8 -*-
 
 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
 
@@ -99,6 +101,7 @@ class Factory(AttributesMap):
         self._status_function = status_function
         self._connector_types = dict()
         self._traces = list()
+        self._box_attributes = AttributesMap()
 
     @property
     def factory_id(self):
@@ -112,6 +115,10 @@ class Factory(AttributesMap):
     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
@@ -141,38 +148,34 @@ class Factory(AttributesMap):
     def add_trace(self, trace_id):
         self._traces.append(trace_id)
 
-class TestbedConfiguration(AttributesMap):
-    def __init__(self):
-        super(TestbedConfiguration, self).__init__()
-        self.add_attribute("HomeDirectory", 
-                "Path to the local directory where traces and other files \
-                        will be stored",
-                Attribute.STRING, False, None, None, "", 
-                validation.is_string)
+    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, configuration):
+    def __init__(self, testbed_id, testbed_version):
         self._testbed_id = testbed_id
         self._testbed_version = testbed_version
-        self._configuration = configuration
-        self._home_directory = configuration.get_attribute_value(
-                "HomeDirectory")
 
     @property
-    def home_directory(self):
-        return self._home_directory
+    def guids(self):
+        raise NotImplementedError
+
+    def configure(self, name, value):
+        """Set a configuartion attribute for the testbed instance"""
+        raise NotImplementedError
 
     def create(self, guid, factory_id):
         """Instructs creation of element """
         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 do_create(self):
-        """After do_create all instructed elements are created and 
-        attributes setted"""
+    def factory_set(self, guid, name, value):
+        """Instructs setting an attribute on a factory"""
         raise NotImplementedError
 
     def connect(self, guid1, connector_type_name1, guid2, 
@@ -183,9 +186,6 @@ class TestbedInstance(object):
             cross_testbed_id, cross_factory_id, cross_connector_type_name):
         raise NotImplementedError
 
-    def do_connect(self):
-        raise NotImplementedError
-
     def add_trace(self, guid, trace_id):
         raise NotImplementedError
 
@@ -195,25 +195,42 @@ class TestbedInstance(object):
     def add_route(self, guid, destination, netprefix, nexthop):
         raise NotImplementedError
 
+    def do_setup(self):
+        """After do_setup the testbed initial configuration is done"""
+        raise NotImplementedError
+
+    def do_create(self):
+        """After do_create all instructed elements are created and 
+        attributes setted"""
+        raise NotImplementedError
+
+    def do_connect(self):
+        """After do_connect all internal connections between testbed elements
+        are done"""
+        raise NotImplementedError
+
     def do_configure(self):
+        """After do_configure elements are configured"""
         raise NotImplementedError
 
     def do_cross_connect(self):
+        """After do_cross_connect all external connections between different testbed 
+        elements are done"""
         raise NotImplementedError
 
-    def set(self, time, guid, name, value):
+    def start(self, time):
         raise NotImplementedError
 
-    def get(self, time, guid, name):
+    def stop(self, time):
         raise NotImplementedError
 
-    def start(self, time):
+    def set(self, time, guid, name, value):
         raise NotImplementedError
 
-    def action(self, time, guid, action):
+    def get(self, time, guid, name):
         raise NotImplementedError
 
-    def stop(self, time):
+    def action(self, time, guid, action):
         raise NotImplementedError
 
     def status(self, guid):
@@ -225,3 +242,106 @@ class TestbedInstance(object):
     def shutdown(self):
         raise NotImplementedError
 
+class ExperimentController(object):
+    def __init__(self, experiment_xml):
+        self._experiment_xml = experiment_xml
+        self._testbeds = dict()
+        self._access_config = dict()
+
+    @property
+    def experiment_xml(self):
+        return self._experiment_xml
+
+    def testbed_instance(self, guid):
+        return self._testbeds[guid]
+
+    def set_testbed_access_config(self, guid, access_config):
+        self._access_config[guid] = access_config
+
+    def trace(self, testbed_guid, guid, trace_id):
+        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()
+        for guid in data.guids:
+            if data.is_testbed_data(guid):
+                (testbed_id, testbed_version) = data.get_testbed_data(guid)
+                instance = self._build_testbed_instance(testbed_id, 
+                        testbed_version)
+                for (name, value) in data.get_attribute_data(guid):
+                    instance.configure(name, value)
+                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]
+            instance.create(guid, factory_id)
+            for (name, value) in data.get_attribute_data(guid):
+                instance.create_set(guid, name, value)
+
+        for guid in element_guids: 
+            (testbed_guid, factory_id) = data.get_box_data(guid)
+            instance = self._testbeds[testbed_guid]
+            for (connector_type_name, other_guid, other_connector_type_name) \
+                    in data.get_connection_data(guid):
+                (testbed_guid, factory_id) = data.get_box_data(guid)
+                (other_testbed_guid, other_factory_id) = data.get_box_data(
+                        other_guid)
+                if testbed_guid == other_testbed_guid:
+                    instance.connect(guid, connector_type_name, other_guid, 
+                        other_connector_type_name)
+                else:
+                    instance.cross_connect(guid, connector_type_name, other_guid, 
+                        other_testbed_id, other_factory_id, other_connector_type_name)
+            for trace_id in data.get_trace_data(guid):
+                instance.add_trace(guid, trace_id)
+            for (autoconf, address, family, netprefix, broadcast) in \
+                    data.get_address_data(guid):
+                if address != None:
+                    instance.add_adddress(guid, family, address, netprefix,
+                        broadcast)
+            for (family, destination, netprefix, nexthop) in \
+                    data.get_route_data(guid):
+                instance.add_route(guid, destination, netprefix, nexthop)
+