From: Alina Quereilhac Date: Mon, 7 Feb 2011 13:22:31 +0000 (+0100) Subject: basic API for testbed design. X-Git-Tag: nepi_v2~212 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=067c82590bdf256d01d5d43f5798aaab9979b4dd;p=nepi.git basic API for testbed design. --- diff --git a/src/nepi/core/attributes.py b/src/nepi/core/attributes.py index 53560ba3..4832cabd 100644 --- a/src/nepi/core/attributes.py +++ b/src/nepi/core/attributes.py @@ -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 index 918eca6f..00000000 --- a/src/nepi/core/backend.py +++ /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 - diff --git a/src/nepi/core/controller.py b/src/nepi/core/controller.py index d7005477..cc34efd2 100644 --- a/src/nepi/core/controller.py +++ b/src/nepi/core/controller.py @@ -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 index 00000000..c650a324 --- /dev/null +++ b/src/nepi/core/protocol.py @@ -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 + } + diff --git a/src/nepi/core/testbed.py b/src/nepi/core/testbed.py index dd326c5c..655f7e4c 100644 --- a/src/nepi/core/testbed.py +++ b/src/nepi/core/testbed.py @@ -3,13 +3,292 @@ # 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 +