basic API for testbed design.
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Mon, 7 Feb 2011 13:22:31 +0000 (14:22 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Mon, 7 Feb 2011 13:22:31 +0000 (14:22 +0100)
src/nepi/core/attributes.py
src/nepi/core/backend.py [deleted file]
src/nepi/core/controller.py
src/nepi/core/protocol.py [new file with mode: 0644]
src/nepi/core/testbed.py

index 53560ba..4832cab 100644 (file)
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 # vim:ts=4:sw=4:et:ai:sts=4
 
diff --git a/src/nepi/core/backend.py b/src/nepi/core/backend.py
deleted file mode 100644 (file)
index 918eca6..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# vim:ts=4:sw=4:et:ai:sts=4
-from nepi.core.attributes import AttributesMap
-
-class Trace(AttributesMap):
-    def __init__(self, name, help, enabled=False):
-        super(Trace, self).__init__()
-        self._name = name
-        self._help = help       
-        self._enabled = enabled
-    
-    @property
-    def name(self):
-        return self._name
-
-    @property
-    def help(self):
-        return self._help
-
-    @property
-    def is_enabled(self):
-        return self._enabled
-
-    def read_trace(self):
-        raise NotImplementedError
-
-    def enable(self):
-        self._enabled = True
-
-    def disable(self):
-        self._enabled = False
-
-class Element(AttributesMap):
-    def __init__(self, guid, factory, container = None):
-        super(Element, self).__init__()
-        # general unique id
-        self._guid = guid
-        # factory identifier or name
-        self._factory_id = factory.factory_id
-        # elements can be nested inside other 'container' elements
-        self._container = container
-        # traces for the element
-        self._traces = dict()
-        # connectors for the element
-        self._connectors = dict()
-        from nepi.core.connection import Connector
-        for connector_type in factory.connector_types:
-            connector = Connector(self, connector_type)
-            self._connectors[connector_type.name] = connector
-
-    @property
-    def guid(self):
-        return self._guid
-
-    @property
-    def factory_id(self):
-        return self._factory_id
-
-    @property
-    def container(self):
-        return self._container
-
-    @property
-    def connections(self):
-        r = set()
-        for c in self.connectors:
-            r.update(c.connections)
-        return r
-
-    @property
-    def connectors(self):
-        return self._connectors.values()
-
-    @property
-    def traces(self):
-        return self._traces.values()
-
-    @property
-    def instructions(self):
-        raise NotImplementedError
-
-    def connector(self, name):
-        return self._connectors[name]
-
-    def trace(self, name):
-        return self._traces[name]
-
-    def destroy(self):
-        super(Element, self).destroy()
-        for c in self.connections:
-            c.disconnect()
-        if len(self.connections) != 0:
-            raise AttributeError('Some connections could not be disconnected')
-        for c in self.connectors:
-            c.destroy()         
-        for t in self.traces:
-            t.destroy()
-        self._connectors = self._traces = None
-
-class Factory(AttributesMap):
-    def __init__(self, factory_id, help = None, category = None):
-        super(Factory, self).__init__()
-        self._factory_id = factory_id
-        self._help = help
-        self._category = category
-        self._connector_types = set()
-
-    @property
-    def factory_id(self):
-        return self._factory_id
-
-    @property
-    def help(self):
-        return self._help
-
-    @property
-    def category(self):
-        return self._category
-
-    @property
-    def connector_types(self):
-        return self._connector_types
-
-    def add_connector_type(self, name, help, display_name, max = -1, min = 0):
-        from nepi.core.connection import ConnectorType
-        connector_type = ConnectorType(name, help, display_name, max, min)            
-        self._connector_types.add(connector_type)
-
-    def create(self, guid, backend, container = None):
-        raise NotImplementedError
-
-    def destroy(self):
-        super(Factory, self).destroy()
-        self._connector_types = None
-
-#TODO: Provide some way to identify that the providers and the factories
-# belong to a specific testbed version
-class Provider(object):
-    def __init__(self):
-        super(Provider, self).__init__()
-        self._factories = dict()
-
-    def factory(self, factory_id):
-        return self._factories[factory_id]
-
-    def add_factory(self, factory):
-        self._factories[factory.factory_id] = factory
-
-    def remove_factory(self, factory_id):
-        del self._factories[factory_id]
-
-    def list_factories(self):
-        return self._factories.keys()
-
-class Backend(AttributeMap):
-    def __init__(self, guid_generator, testbed_id, provider):
-        super(Backend, self).__init__()
-        self._guid_generator = guid_generator
-        self._guid = guid_generator.next()
-        self._testbed_id = testbed_id
-        self._provider = provider
-        self._elements = dict()
-
-    @property
-    def guid(self):
-        return self._guid
-
-    @property
-    def testbed_id(self):
-        return self._testbed_id
-
-    @property
-    def elements(self):
-        return self._elements.values()
-
-    def create(self, factory_id):
-        guid = self.guid_generator.next()
-        factory = self._provider.factories(factory_id)
-        element = factory.create(guid, self)
-        self._elements[guid] = element
-
-    def remove(self, guid):
-        element = self._elements[guid]
-        del self._elements[guid]
-        element.destroy()
-
-    def instructions(self):
-        raise NotImplementedError
-
-    def destroy(self):
-        for guid, element in self._elements.iteitems():
-            del self._elements[guid]
-            element.destroy()
-        self._elements = None
-
index d700547..cc34efd 100644 (file)
@@ -5,7 +5,7 @@
 #TODO: DEF ERRORCODES
 #TODO: DEF PROTOCOL
 
-class Testbed(object):
+class Controller(object):
     def __init__(self):
         self._testbeds = dict()
 
diff --git a/src/nepi/core/protocol.py b/src/nepi/core/protocol.py
new file mode 100644 (file)
index 0000000..c650a32
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim:ts=4:sw=4:et:ai:sts=4
+
+# PROTOCOL MESSAGES
+CREATE      = 0
+CONNECT     = 1
+SET         = 2
+GET         = 3
+START       = 4
+STOP        = 5
+STATUS      = 6
+ENABLE_TRACE    = 7
+DISABLE_TRACE   = 8
+GET_TRACE   = 9
+ADD_ADDRES  = 10
+ADD_ROUTE   = 11
+SHUTDOWN    = 12
+
+tesbed_messages = {
+        CREATE: "CREATE,%d,%d,%s,[%s]", # CREATE,time,guid,factory_id,parameters
+        CONNECT: "CONNECT,%d,%d,%d,%d,%s,%s", # CONNECT,time,object1_guid,object2_guid,connector1_id,connector2_id
+        SET: "%d,%d,%s,%s", # SET,time,guid,name,value
+        GET: "%d,%d,%s", # GET,time,guid,name
+        START: "%d,%d", # START,time,guid
+        STOP: "%d,%d", # STOP,time,guid
+        STATUS: "%d,%d", # STATUS,time,guid
+        ENABLE_TRACE: "%d,%d,%s", # ENABLE_TRACE,time,guid,trace_id
+        DISABLE_TRACE: "%d,%d,%s", # DISABLE_TRACE,time,guid,trace_id
+        GET_TRACE: "%d,%d,%s", # GET_TRACE,time,guid,trace_id
+        ADD_ADDRESSES: "%d,%d", # ADD_ADDRESSES,time,guid
+        ADD_ROUTE: "%d,%d", # ADD_ROUTE,time,guid
+        SHUTDOWN: "%d,%d" , # SHUTDOWN,time.guid
+    }
+
index dd326c5..655f7e4 100644 (file)
 # vim:ts=4:sw=4:et:ai:sts=4
 from nepi.core.attributes import AttributesMap
 
-#TODO: DEF ERRORCODES
-#TODO: DEF PROTOCOL
+class ConnectorType(object):
+    """A ConnectorType defines a kind of connector that can be used in an Object.
+    """
+    def __init__(self, connector_id, help, name, max = -1, min = 0):
+        super(ConnectorType, self).__init__()
+        """
+        ConnectorType(name, help, display_name, max, min):
+        - connector_id: (unique) identifier for this type
+        - name: descriptive name for the user
+        - help: help text
+        - max: amount of connections that this type support, -1 for no limit
+        - min: minimum amount of connections to this type of connector
+        """
+        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')
+        self._connector_id = connector_id
+        self._help = help
+        self._name = name
+        self._max = max
+        self._min = min
 
-class Configuration(AttributesMap):
+    @property
+    def connector_id(self):
+        return self._connector_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
+
+class Connector(object):
+    """A Connector sepcifies the connection points in an Object"""
+    def __init__(self, element, connector_type):
+        super(Connector, self).__init__()
+        self._element = element
+        self._connector_type = connector_type
+        self._connections = dict()
+
+    @property
+    def element(self):
+        return self._element
+
+    @property
+    def connector_type(self):
+        return self._connector_type
+
+    @property
+    def connections(self):
+        return self._connections.values()
+
+    def is_full(self):
+        """Return True if the connector has the maximum number of connections"""
+        return len(self.connections) == self.connector_type.max
+
+    def is_complete(self):
+        """Return True if the connector has the minimum number of connections"""
+        return len(self.connection) >= self.connector_type.min 
+
+    def connect(self, connector):
+        if self.is_full() or connector.is_full():
+            raise RuntimeError("Connector is full")    
+        if not self.can_connect(connector) or not connector.can_connect(self):
+            raise RuntimeError("Could not connect.")
+        self._connections[connector._key] = connector
+        connector._connections[self._key] = self
+
+    def disconnect(self, connector):
+        if connector._key not in self._connections or 
+            self._key not in connector._connections:
+                raise RuntimeError("Could not disconnect.")
+        del self._connections[connector._key]
+        del connector._connections[self._key]
+
+    def can_connect(self, connector):
+        raise NotImplementedError
+
+    def destroy(self):
+        for connector in self._connections:
+            self.disconnect(connector)
+        self._element = self._connectors = None
+
+    @property
+    def _key(self):
+        return "%d_%s" % (self.element.guid, self.connector_type.connector_id)
+
+class Trace(AttributesMap):
+    def __init__(self, name, help, enabled=False):
+        super(Trace, self).__init__()
+        self._name = name
+        self._help = help       
+        self._enabled = enabled
+    
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def help(self):
+        return self._help
+
+    @property
+    def is_enabled(self):
+        return self._enabled
+
+    def read_trace(self):
+        raise NotImplementedError
+
+    def enable(self):
+        self._enabled = True
+
+    def disable(self):
+        self._enabled = False
+
+class Element(AttributesMap):
+    def __init__(self, guid, testbed_id, factory, container = None):
+        super(Element, self).__init__()
+        # general unique id
+        self._guid = guid
+        # factory identifier or name
+        self._factory_id = factory.factory_id
+        # testbed identifier
+        self._tesbed_id = testbed_id
+        # elements can be nested inside other 'container' elements
+        self._container = container
+        # traces for the element
+        self._traces = dict()
+        # connectors for the element
+        self._connectors = dict()
+        for connector_type in factory.connector_types:
+            connector = Connector(self, connector_type)
+            self._connectors[connector_type.connector_id] = connector
+
+    @property
+    def guid(self):
+        return self._guid
+
+    @property
+    def factory_id(self):
+        return self._factory_id
+
+    @property
+    def testbed_id(self):
+        return self._testbed_id
+
+    @property
+    def container(self):
+        return self._container
+
+    @property
+    def connectors(self):
+        return self._connectors.values()
+
+    @property
+    def traces(self):
+        return self._traces.values()
+
+    def connector(self, name):
+        return self._connectors[name]
+
+    def trace(self, name):
+        return self._traces[name]
+
+    def destroy(self):
+        super(Element, self).destroy()
+        for c in self.connectors:
+            c.destroy()         
+        for t in self.traces:
+            t.destroy()
+        self._connectors = self._traces = None
+
+class Factory(AttributesMap):
+    def __init__(self, factory_id, help = None, category = None):
+        super(Factory, self).__init__()
+        self._factory_id = factory_id
+        self._help = help
+        self._category = category
+        self._connector_types = set()
+
+    @property
+    def factory_id(self):
+        return self._factory_id
+
+    @property
+    def help(self):
+        return self._help
+
+    @property
+    def category(self):
+        return self._category
+
+    @property
+    def connector_types(self):
+        return self._connector_types
+
+    def add_connector_type(self, connector_id, help, name, max = -1, min = 0):
+        connector_type = ConnectorType(connector_id, help, name, max, min)            
+        self._connector_types.add(connector_type)
+
+    def create(self, guid, testbed_design, container = None):
+        raise NotImplementedError
+
+    def destroy(self):
+        super(Factory, self).destroy()
+        self._connector_types = None
+
+#TODO: Provide some way to identify that the providers and the factories
+# belong to a specific testbed version
+class Provider(object):
+    def __init__(self):
+        super(Provider, self).__init__()
+        self._factories = dict()
+
+    def factory(self, factory_id):
+        return self._factories[factory_id]
+
+    def add_factory(self, factory):
+        self._factories[factory.factory_id] = factory
+
+    def remove_factory(self, factory_id):
+        del self._factories[factory_id]
+
+    def list_factories(self):
+        return self._factories.keys()
+
+class TestbedDesignInstance(AttributeMap):
+    def __init__(self, guid_generator, testbed_id, provider):
+        super(TestbedInstance, self).__init__()
+        self._guid_generator = guid_generator
+        self._guid = guid_generator.next()
+        self._testbed_id = testbed_id
+        self._provider = provider
+        self._elements = dict()
+
+    @property
+    def guid(self):
+        return self._guid
+
+    @property
+    def testbed_id(self):
+        return self._testbed_id
+
+    @property
+    def elements(self):
+        return self._elements.values()
+
+    def create(self, factory_id):
+        guid = self.guid_generator.next()
+        factory = self._provider.factories(factory_id)
+        element = factory.create(guid, self)
+        self._elements[guid] = element
+
+    def delete(self, guid):
+        element = self._elements[guid]
+        del self._elements[guid]
+        element.destroy()
+
+    def instructions(self):
+        raise NotImplementedError
+
+    def destroy(self):
+        for guid, element in self._elements.iteitems():
+            del self._elements[guid]
+            element.destroy()
+        self._elements = None
+
+class TestbedConfiguration(AttributesMap):
     pass
 
-class Testbed(object):
+class TestbedInstance(object):
     def __init__(self, configuration):
         pass
 
@@ -23,16 +302,10 @@ class Testbed(object):
     def create(self, time, guid, factory_id, parameters):
         raise NotImplementedError
 
-    def destroy(self, time, guid):
-        raise NotImplementedError
-
     def connect(self, time, connection_guid, 
             object1_guid, object2_guid, connetor1_id, connector2_id): 
         raise NotImplementedError
 
-    def disconnect(self, time, connection_guid): 
-        raise NotImplementedError
-
     def set(self, time, guid, name, value):
         raise NotImplementedError
 
@@ -45,13 +318,13 @@ class Testbed(object):
     def stop(self, time, guid):
         raise NotImplementedError
 
-    def state(self, time, guid):
+    def status(self, time, guid):
         raise NotImplementedError
 
-    def trace_enable(self, time, guid, trace_id):
+    def enable_trace(self, time, guid, trace_id):
         raise NotImplementedError
 
-    def trace_disable(self, time, guid, trace_id):
+    def disable_trace(self, time, guid, trace_id):
         raise NotImplementedError
 
     def get_trace(self, time, guid, trace_id):
@@ -67,3 +340,4 @@ class Testbed(object):
 
     def shutdown(self):
         raise NotImplementedError
+