Change OMF attributes during runtime
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Tue, 21 Aug 2012 16:50:21 +0000 (18:50 +0200)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Tue, 21 Aug 2012 16:50:21 +0000 (18:50 +0200)
examples/omf_vlc.py
src/nepi/testbeds/omf/execute.py
src/nepi/testbeds/omf/metadata.py
src/nepi/testbeds/omf/omf_api.py [new file with mode: 0644]
src/nepi/testbeds/omf/omf_client.py

index e5aac6c..1f92319 100644 (file)
@@ -26,7 +26,7 @@ omf_desc.set_attribute_value("enableDebug", True)
 omf_desc.set_attribute_value("xmppSlice", "default_slice")
 omf_desc.set_attribute_value("xmppHost", "xmpp-omf.onelab.eu")
 omf_desc.set_attribute_value("xmppPort", 5222)
-omf_desc.set_attribute_value("xmppPassword", "******")
+omf_desc.set_attribute_value("xmppPassword", "1234")
 
 node1 = omf_desc.create("Node")
 node1.set_attribute_value("hostname", "omf.my.wlab18")
@@ -35,39 +35,35 @@ node2.set_attribute_value("hostname", "omf.my.wlab49")
 
 iface12 = omf_desc.create("WifiInterface")
 iface12.set_attribute_value("mode", "adhoc")
-iface12.set_attribute_value("channel", "g")
+iface12.set_attribute_value("channel", "6")
 iface12.set_attribute_value("type", "g")
 iface12.set_attribute_value("essid", "cvlcmode")
+iface12.set_attribute_value("ip", "192.168.0.18")
 node1.connector("devs").connect(iface12.connector("node"))
 
 iface21 = omf_desc.create("WifiInterface")
 iface21.set_attribute_value("mode", "adhoc")
-iface21.set_attribute_value("channel", "g")
+iface21.set_attribute_value("channel", "6")
 iface21.set_attribute_value("type", "g")
 iface21.set_attribute_value("essid", "cvlcmode")
+iface21.set_attribute_value("ip", "192.168.0.49")
 node2.connector("devs").connect(iface21.connector("node"))
 
-ip12 = iface12.add_address()
-ip12.set_attribute_value("Address", "192.168.0.18")
-
-ip21 = iface21.add_address()
-ip21.set_attribute_value("Address", "192.168.0.49")
-
 channel = omf_desc.create("Channel")
 channel.set_attribute_value("mode", "adhoc")
-channel.set_attribute_value("channel", "g")
+channel.set_attribute_value("channel", "6")
 channel.set_attribute_value("type", "g")
 channel.set_attribute_value("essid", "cvlcmode")
 channel.connector("devs").connect(iface12.connector("chan"))
 channel.connector("devs").connect(iface21.connector("chan"))
 
-app2 = omf_desc.create("Application")
+app2 = omf_desc.create("OmfApplication")
 app2.set_attribute_value("appId", "Vlc#2")
 app2.set_attribute_value("arguments", "rtp://239.255.0.1:1234")
 app2.set_attribute_value("path", "/opt/vlc-1.1.13/vlc")
 app2.connector("node").connect(node2.connector("apps"))
 
-app1 = omf_desc.create("Application")
+app1 = omf_desc.create("OmfApplication")
 app1.set_attribute_value("appId", "Vlc#1")
 app1.set_attribute_value("arguments", "/opt/10-by-p0d.avi --sout '#duplicate{dst=display,dst=rtp{mux=ts,dst=239.255.0.1,port=1234}}'")
 app1.set_attribute_value("path", "/opt/vlc-1.1.13/vlc")
@@ -81,7 +77,11 @@ controller.start()
 #        controller.is_finished(app2.guid)):
 #    time.sleep(0.5)
 
-time.sleep(30)
+time.sleep(20)
+
+controller.set(iface21.guid, "channel", "1")
+
+time.sleep(15)
 
 controller.stop()
 controller.shutdown()
index dccb80c..8428dcd 100644 (file)
@@ -4,157 +4,67 @@ from constants import TESTBED_ID, TESTBED_VERSION
 from nepi.core import testbed_impl
 from nepi.util.constants import TIME_NOW
 
-import datetime
+from nepi.testbeds.omf.omf_api import OmfAPI
+
 import logging
 import os
-import sys
-import ssl
 import time
 
-from nepi.testbeds.omf.omf_client import OMFClient
-from nepi.testbeds.omf.omf_messages import MessageHandler
-
-
 class TestbedController(testbed_impl.TestbedController):
     def __init__(self):
         super(TestbedController, self).__init__(TESTBED_ID, TESTBED_VERSION)
-        self._slice = None
-        self._user = None
-        self._host = None
-        self._xmpp = None
-        self._message = None
         self._home = None
-        
+        self._api = None
         self._logger = logging.getLogger('nepi.testbeds.omf')
  
     def do_setup(self):
-        if self._attributes.get_attribute_value("enableDebug") == True:
+        debug = self._attributes.get_attribute_value("enableDebug")
+        if debug:
             self._logger.setLevel(logging.DEBUG)
 
         # create home
-        self._home = self._attributes.\
-            get_attribute_value("homeDirectory")
+        self._home = self._attributes.get_attribute_value("homeDirectory")
         home = os.path.normpath(self._home)
         if not os.path.exists(home):
             os.makedirs(home, 0755)
-    
-        # instantiate the xmpp client
-        self._init_client()
-        # register xmpp nodes for the experiment
-        self._publish_and_enroll_experiment()
-        # register xmpp logger for the experiment
-        self._publish_and_enroll_logger()
 
+        # initialize OMF xmpp client
+        slice = self._attributes.get_attribute_value("xmppSlice")
+        host = self._attributes.get_attribute_value("xmppHost")
+        port = self._attributes.get_attribute_value("xmppPort")
+        password = self._attributes.get_attribute_value("xmppPassword")
+
+        self._api = OmfAPI(slice, host, port, password, debug)
         super(TestbedController, self).do_setup()
 
+    @property
+    def api(self):
+        return self._api
+
     def set(self, guid, name, value, time = TIME_NOW):
         super(TestbedController, self).set(guid, name, value, time)
-        pass
+        element = self._elements[guid]
+        if element:
+            try:
+                setattr(element, name, value)
+            except:
+                # We ignore these errors while recovering.
+                # Some attributes are immutable, and setting
+                # them is necessary (to recover the state), but
+                # some are not (they throw an exception).
+                if not self.recovering:
+                    raise
 
     def get(self, guid, name, time = TIME_NOW):
         value = super(TestbedController, self).get(guid, name, time)
-        return "MISS"
+        element = self._elements.get(guid)
+        try:
+            return getattr(element, name)
+        except (KeyError, AttributeError):
+            return value
 
     def shutdown(self):
-        node_sid = "/OMF/%s/%s" % (self._slice, self._user)
-        self._clean_up(node_sid)
-        logger = "/OMF/%s/%s/LOGGER" % (self._slice, self._user)
-        self._clean_up(logger)
-
-        for hostname in self._elements.values():
-            if not hostname:
-                continue
-            node_sid = self._host_sid(hostname)
-            self._clean_up(node_sid)
-            #node_res = self._host_res(hostname)
-            #self._clean_up(node_res)
-
-        time.sleep(5)
-        self._xmpp.disconnect()
-
-    def _host_sid(self, hostname):
-        return "/OMF/%s/%s/%s" % (self._slice, self._user, hostname)
-
-    def _host_res(self, hostname):
-        return "/OMF/%s/resources/%s" % (self._slice, hostname)
-
-    def _init_client(self):
-        self._slice = self._attributes.get_attribute_value("xmppSlice")
-        self._host = self._attributes.get_attribute_value("xmppHost")
-        port = self._attributes.get_attribute_value("xmppPort")
-        password = self._attributes.get_attribute_value("xmppPassword")
-       
-        #date = "2012-04-18t16.06.34+02.00"
-        date = datetime.datetime.now().strftime("%Y-%m-%dt%H.%M.%S+02.00")
-        self._user = "%s-%s" % (self._slice, date)
-        jid = "%s@%s" % (self._user, self._host)
-
-        xmpp = OMFClient(jid, password)
-        # PROTOCOL_SSLv3 required for compatibility with OpenFire
-        xmpp.ssl_version = ssl.PROTOCOL_SSLv3
-
-        if xmpp.connect((self._host, port)):
-            xmpp.process(threaded=True)
-            while not xmpp.ready:
-                time.sleep(1)
-            self._xmpp = xmpp
-            self._message = MessageHandler(self._slice, self._user)
-        else:
-            msg = "Unable to connect to the XMPP server."
-            self._logger.error(msg)
-            raise RuntimeError(msg)
-
-    def _publish_and_enroll_experiment(self):
-        node_sid = "/OMF/%s/%s" % (self._slice, self._user)
-        self._create_and_subscribe(node_sid)  
-
-        node_slice = "/OMF/%s" % (self._slice)
-        address = "/%s/OMF/%s/%s" % (self._host, self._slice, self._user)
-        payload = self._message.newexpfunction(self._user, address)
-        self._xmpp.publish(payload, node_slice)
-   
-    def _publish_and_enroll_logger(self):
-        logger = "/OMF/%s/%s/LOGGER" % (self._slice, self._user)
-        self._create_and_subscribe(logger)
-
-        payload = self._message.logfunction("2", 
-                "nodeHandler::NodeHandler", 
-                "INFO", 
-                "OMF Experiment Controller 5.4 (git 529a626)")
-        self._xmpp.publish(payload, logger)
-
-    def _clean_up(self, xmpp_node):
-        self._xmpp.delete(xmpp_node)
-
-        if sys.version_info < (3, 0):
-            reload(sys)
-            sys.setdefaultencoding('utf8')
-
-    def _create_and_subscribe(self, xmpp_node):
-        self._xmpp.suscriptions()
-        self._xmpp.create(xmpp_node)
-        self._xmpp.subscribe(xmpp_node)
-        self._xmpp.nodes()
-
-    def _publish_and_enroll_host(self, hostname):
-        node_sid =  self._host_sid(hostname)
-        self._create_and_subscribe(node_sid)  
-        
-        node_res =  self._host_res(hostname)
-        self._create_and_subscribe(node_res)  
-
-        payload = self._message.enrollfunction("1", "*", "1", hostname)
-        self._xmpp.publish(payload, node_res)
-
-    def _publish_configure(self, hostname, attribute, value): 
-        payload = self._message.configurefunction(hostname, value, attribute)
-        node_sid =  self._host_sid(hostname)
-        self._xmpp.publish(payload, node_sid)
-
-    def _publish_execute(self, hostname, app_id, arguments, path):
-        payload = self._message.executefunction(hostname, app_id, arguments, path)
-        node_sid =  self._host_sid(hostname)
-        self._xmpp.publish(payload, node_sid)
-
-
+        if self.api: 
+            self.api.disconnect()
 
index 3a86db0..3c71b9a 100644 (file)
@@ -1,5 +1,8 @@
 # -*- coding: utf-8 -*-
 
+import functools
+import weakref
+
 from constants import TESTBED_ID, TESTBED_VERSION
 from nepi.core import metadata
 from nepi.core.attributes import Attribute
@@ -7,92 +10,128 @@ from nepi.util import tags, validation
 from nepi.util.constants import ApplicationStatus as AS, \
         FactoryCategories as FC, DeploymentConfiguration as DC
 
+##############################################################################
+
+class OmfResource(object):
+    def __init__(self, guid, tc):
+        super(OmfResource, self).__init__()
+        self._tc = weakref.ref(tc)
+        self._guid = guid
+
+    @property
+    def tc(self):
+        return self._tc and self._tc()
+
+    def configure(self):
+        pass
+
+    def start(self):
+        pass
+
+    def stop(self):
+        pass
+
+    def status(self):
+        pass
+
+    def shutdown(self):
+        pass
+
+## NODE #######################################################################
+
+class OmfNode(OmfResource):
+    def __init__(self, guid, tc):
+        super(OmfNode, self).__init__(guid, tc)
+        self.hostname = self.tc._get_parameters(guid)['hostname']
+        self.tc.api.enroll_host(self.hostname)
+
+## APPLICATION ################################################################
+
+class OmfApplication(OmfResource):
+    def __init__(self, guid, tc):
+        super(OmfApplication, self).__init__(guid, tc)
+        node_guids = tc.get_connected(guid, "node", "apps")
+        if len(node_guids) == 0:
+            raise RuntimeError("Can't instantiate interface %d outside node" % guid)
+
+        self._node_guid = node_guids[0] 
+        self.app_id = None
+        self.arguments = None
+        self.path = None
+
+    def start(self):
+        node = self.tc.elements.get(self._node_guid)
+        self.tc.api.execute(node.hostname, 
+                self.appId, 
+                self.arguments, 
+                self.path)
+
+    def status(self):
+        if guid not in testbed_instance.elements.keys():
+            return AS.STATUS_NOT_STARTED
+        return AS.STATUS_RUNNING
+        # TODO!!!!
+        #return AS.STATUS_FINISHED
+
+
+## WIFIIFACE ########################################################
+
+class OmfWifiInterface(OmfResource):
+    def __init__(self, guid, tc):
+        super(OmfWifiInterface, self).__init__(guid, tc)
+        node_guids = tc.get_connected(guid, "node", "devs")
+        if len(node_guids) == 0:
+            raise RuntimeError("Can't instantiate interface %d outside node" % guid)
+
+        self._node_guid = node_guids[0] 
+        self.mode = None
+        self.type = None
+        self.essid = None
+        self.channel = None
+        self.ip = None
+
+    def __setattr__(self, name, value):
+        if name in ["ip", "mode", "type", "essid", "channel"]:
+            node = self.tc.elements.get(self._node_guid)    
+            attribute = "net/w0/%s" % name
+            self._tc().api.configure(node.hostname, attribute, value)
+        else:
+            super(OmfWifiInterface, self).__setattr__(name, value)
+
 # Factories
 NODE = "Node"
 WIFIIFACE = "WifiInterface"
-ETHIFACE = "EthInterface"
 CHANNEL = "Channel"
-APPLICATION = "Application"
-
-### Connection functions ####
-
-### Creation functions ###
-
-def create_node(testbed_instance, guid):
-    parameters = testbed_instance._get_parameters(guid)
-    hostname = parameters['hostname']
-    testbed_instance._elements[guid] = hostname
-    testbed_instance._publish_and_enroll_host(hostname)
-
-def create_wifiiface(testbed_instance, guid):
-    pass
-
-def create_ethiface(testbed_instance, guid):
-    pass
-
-def create_channel(testbed_instance, guid):
-    pass
-
-def create_application(testbed_instance, guid):
-    pass
-
-### Start/Stop functions ###
-
-def start_application(testbed_instance, guid):
-    # search for the node asociated with the device
-    node_guids = testbed_instance.get_connected(guid, "node", "apps")
-    if len(node_guids) == 0:
-        raise RuntimeError("Can't instantiate interface %d outside node" % guid)
-
-    # node attributes
-    node_parameters = testbed_instance._get_parameters(node_guids[0])
-    hostname = node_parameters['hostname']
-
-    # application attributes
-    parameters = testbed_instance._get_parameters(guid)
-    app_id = parameters.get("appId")
-    arguments = parameters.get("arguments")
-    path = parameters.get("path")
-    testbed_instance._publish_execute(hostname, app_id, arguments, path)
-
-def stop_application(testbed_instance, guid):
-    pass
+OMFAPPLICATION = "OmfApplication"
 
-### Status functions ###
+def create(factory, testbed_instance, guid):
+    clazz = OmfResource
+    if factory == NODE:
+        clazz = OmfNode
+    elif factory == OMFAPPLICATION:
+        clazz = OmfApplication
+    elif factory == WIFIIFACE:
+        clazz = OmfWifiInterface
 
-def status_application(testbed_instance, guid):
-    if guid not in testbed_instance.elements.keys():
-        return AS.STATUS_NOT_STARTED
-    return AS.STATUS_RUNNING
-    # TODO!!!!
-    #return AS.STATUS_FINISHED
+    element = clazz(guid, testbed_instance)
+    #import pdb; pdb.set_trace()
+    testbed_instance._elements[guid] = element
 
-### Configure functions ###
+def start(testbed_instance, guid):
+    element = testbed_instance.elements.get(guid)
+    element.start()
 
-def configure_wifiiface(testbed_instance, guid):
-    # search for the node asociated with the device
-    node_guids = testbed_instance.get_connected(guid, "node", "devs")
-    if len(node_guids) == 0:
-        raise RuntimeError("Can't instantiate interface %d outside node" % guid)
+def stop(testbed_instance, guid):
+    element = testbed_instance.elements.get(guid)
+    element.stop()
 
-    # node attributes
-    node_parameters = testbed_instance._get_parameters(node_guids[0])
-    hostname = node_parameters['hostname']
+def status(testbed_instance, guid):
+    element = testbed_instance.elements.get(guid)
+    return element.status()
 
-    # wifi iface attributes
-    parameters = testbed_instance._get_parameters(guid)
-
-    for attr in ["mode", "type", "channel", "essid"]: 
-        attribute = "net/w0/%s" % attr
-        value = parameters.get(attr)
-        if value:
-            testbed_instance._publish_configure(hostname, attribute, value)
-
-    if guid in testbed_instance._add_address: 
-        attribute = "net/w0/ip"
-        addresses = testbed_instance._add_address[guid]
-        (value, netprefix, broadcast) = addresses[0]
-        testbed_instance._publish_configure(hostname, attribute, value)
+def configure(testbed_instance, guid):
+    element = testbed_instance.elements.get(guid)
+    return element.status()
 
 ### Factory information ###
 
@@ -129,11 +168,6 @@ connections = [
         "to":   (TESTBED_ID, WIFIIFACE, "node"),
         "can_cross": False
     }),
-    dict({
-        "from": (TESTBED_ID, NODE, "devs"),
-        "to":   (TESTBED_ID, ETHIFACE, "node"),
-        "can_cross": False
-    }),
     dict({
         "from": (TESTBED_ID, WIFIIFACE, "chan"),
         "to":   (TESTBED_ID, CHANNEL, "devs"),
@@ -141,7 +175,7 @@ connections = [
     }),
     dict({
         "from": (TESTBED_ID, NODE, "apps"),
-        "to":   (TESTBED_ID, APPLICATION, "node"),
+        "to":   (TESTBED_ID, OMFAPPLICATION, "node"),
         "can_cross": False
     }),
  ]
@@ -179,44 +213,52 @@ attributes = dict({
                 "name": "mode",
                 "help": "Corresponds to the OMF attributes net/w0/mode",
                 "type": Attribute.STRING,
-                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_string
             }),
     "type": dict({
                 "name": "type",
                 "help": "Corresponds to the OMF attributes net/w0/type",
                 "type": Attribute.STRING,
-                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_string
             }),
     "channel": dict({
                 "name": "channel",
                 "help": "Corresponds to the OMF attributes net/w0/channel",
                 "type": Attribute.STRING,
-                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_string
             }),
     "essid": dict({
                 "name": "essid",
                 "help": "Corresponds to the OMF attributes net/w0/essid",
                 "type": Attribute.STRING,
-                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_string
             }),
+    "ip": dict({
+                "name": "ip",
+                "help": "Corresponds to the OMF attributes net/w0/ip",
+                "type": Attribute.STRING,
+                "flags": Attribute.NoDefaultValue, 
+                "validation_function": validation.is_ip4_address
+            }),
+
 
 
     })
 
 traces = dict()
 
-create_order = [ NODE, WIFIIFACE, ETHIFACE, CHANNEL, APPLICATION ]
-configure_order = [ WIFIIFACE, ETHIFACE, NODE, CHANNEL, APPLICATION ]
+create_order = [ NODE, WIFIIFACE, CHANNEL, OMFAPPLICATION ]
+configure_order = [ WIFIIFACE,  NODE, CHANNEL, OMFAPPLICATION ]
 
 factories_info = dict({
     NODE: dict({
             "help": "OMF Node",
             "category": FC.CATEGORY_NODES,
-            "create_function": create_node,
+            "create_function": functools.partial(create, NODE),
             "box_attributes": ["hostname"],
             "connector_types": ["devs", "apps"],
             "tags": [tags.NODE, tags.ALLOW_ROUTES],
@@ -224,34 +266,27 @@ factories_info = dict({
     WIFIIFACE: dict({
             "help": "Wireless network interface",
             "category": FC.CATEGORY_DEVICES,
-            "create_function": create_wifiiface,
-            "configure_function": configure_wifiiface,
-            "box_attributes": ["mode", "type", "channel", "essid"],
+            "create_function": functools.partial(create, WIFIIFACE),
+            "configure_function": configure,
+            "box_attributes": ["mode", "type", "channel", "essid", "ip"],
             "connector_types": ["node", "chan"],
-            "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
-       }),
-    ETHIFACE: dict({
-            "help": "Ethernet network interface",
-            "category": FC.CATEGORY_DEVICES,
-            "create_function": create_ethiface,
-            #"box_attributes": [""],
-            "connector_types": ["node"],
-            "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
+            "tags": [tags.INTERFACE, tags.HAS_ADDRESSES],
        }),
     CHANNEL: dict({
             "help": "Wireless channel",
             "category": FC.CATEGORY_DEVICES,
-            "create_function": create_channel,
+            "create_function": create,
+            "create_function": functools.partial(create, CHANNEL),
             "box_attributes": ["mode", "type", "channel", "essid"],
             "connector_types": ["devs"],
        }),
-    APPLICATION: dict({
+    OMFAPPLICATION: dict({
             "help": "Generic executable command line application",
             "category": FC.CATEGORY_APPLICATIONS,
-            "create_function": create_application,
-            "start_function": start_application,
-            "stop_function": stop_application,
-            "status_function": status_application,
+            "create_function": functools.partial(create, OMFAPPLICATION),
+            "start_function": start,
+            "stop_function": stop,
+            "status_function": status,
             "box_attributes": ["appId", "arguments", "path"],
             "connector_types": ["node"],
             "tags": [tags.APPLICATION],
diff --git a/src/nepi/testbeds/omf/omf_api.py b/src/nepi/testbeds/omf/omf_api.py
new file mode 100644 (file)
index 0000000..ac7946d
--- /dev/null
@@ -0,0 +1,140 @@
+import datetime
+import logging
+import ssl
+import sys
+import time
+
+from nepi.testbeds.omf.omf_client import OMFClient
+from nepi.testbeds.omf.omf_messages import MessageHandler
+
+class OmfAPI(object):
+    def __init__(self, slice, host, port, password, debug):
+        date = datetime.datetime.now().strftime("%Y-%m-%dt%H.%M.%S")
+        tz = -time.altzone if time.daylight != 0 else -time.timezone
+        date += "%+06.2f" % (tz / 3600) # timezone difference is in seconds
+        self._user = "%s-%s" % (slice, date)
+        self._slice = slice
+        self._host = host
+        self._port = port
+        self._password = password
+        self._hostnames = []
+
+        self._logger = logging.getLogger('nepi.testbeds.omfapi')
+        if debug:
+            self._logger.setLevel(logging.DEBUG)
+
+        # OMF xmpp client
+        self._client = None
+        # message handler
+        self._message = None
+
+        if sys.version_info < (3, 0):
+            reload(sys)
+            sys.setdefaultencoding('utf8')
+
+        # instantiate the xmpp client
+        self._init_client()
+
+        # register xmpp nodes for the experiment
+        self._enroll_experiment()
+
+        # register xmpp logger for the experiment
+        self._enroll_logger()
+
+    def _init_client(self):
+        jid = "%s@%s" % (self._user, self._host)
+        xmpp = OMFClient(jid, self._password)
+        # PROTOCOL_SSLv3 required for compatibility with OpenFire
+        xmpp.ssl_version = ssl.PROTOCOL_SSLv3
+
+        if xmpp.connect((self._host, self._port)):
+            xmpp.process(threaded=True)
+            while not xmpp.ready:
+                time.sleep(1)
+            self._client = xmpp
+            self._message = MessageHandler(self._slice, self._user)
+        else:
+            msg = "Unable to connect to the XMPP server."
+            self._logger.error(msg)
+            raise RuntimeError(msg)
+
+    def _enroll_experiment(self):
+        xmpp_node = self._exp_session_id
+        self._client.create(xmpp_node)
+        self._client.subscribe(xmpp_node)
+
+        address = "/%s/OMF/%s/%s" % (self._host, self._slice, self._user)
+        payload = self._message.newexpfunction(self._user, address)
+        slice_sid = "/OMF/%s" % (self._slice)
+        self._client.publish(payload, slice_sid)
+
+    def _enroll_logger(self):
+        xmpp_node = self._logger_session_id
+        self._client.create(xmpp_node)
+        self._client.subscribe(xmpp_node)
+
+        payload = self._message.logfunction("2", 
+                "nodeHandler::NodeHandler", 
+                "INFO", 
+                "OMF Experiment Controller 5.4 (git 529a626)")
+        self._client.publish(payload, xmpp_node)
+
+    def _host_session_id(self, hostname):
+        return "/OMF/%s/%s/%s" % (self._slice, self._user, hostname)
+
+    def _host_resource_id(self, hostname):
+        return "/OMF/%s/resources/%s" % (self._slice, hostname)
+
+    @property
+    def _exp_session_id(self):
+        return "/OMF/%s/%s" % (self._slice, self._user)
+
+    @property
+    def _logger_session_id(self):
+        return "/OMF/%s/%s/LOGGER" % (self._slice, self._user)
+
+    def delete(self, hostname):
+        if not hostname in self._hostnames:
+            return
+
+        self._hostnames.remove(hostname)
+
+        xmpp_node = self._host_session_id(hostname)
+        self._client.delete(xmpp_node)
+
+    def enroll_host(self, hostname):
+        if hostname in self._hostnames:
+            return 
+
+        self._hostnames.append(hostname)
+
+        xmpp_node =  self._host_session_id(hostname)
+        self._client.create(xmpp_node)
+        self._client.subscribe(xmpp_node)
+
+        xmpp_node =  self._host_resource_id(hostname)
+        self._client.subscribe(xmpp_node)
+
+        payload = self._message.enrollfunction("1", "*", "1", hostname)
+        self._client.publish(payload, xmpp_node)
+
+    def configure(self, hostname, attribute, value): 
+        payload = self._message.configurefunction(hostname, value, attribute)
+        xmpp_node =  self._host_session_id(hostname)
+        self._client.publish(payload, xmpp_node)
+
+    def execute(self, hostname, app_id, arguments, path):
+        payload = self._message.executefunction(hostname, app_id, arguments, path)
+        xmpp_node =  self._host_session_id(hostname)
+        self._client.publish(payload, xmpp_node)
+
+    def disconnect(self):
+        self._client.delete(self._exp_session_id)
+        self._client.delete(self._logger_session_id)
+
+        for hostname in self._hostnames[:]:
+            self.delete(hostname)
+
+        time.sleep(5)
+        self._client.disconnect()
+
index 3100a46..e244d1b 100644 (file)
@@ -109,7 +109,7 @@ class OMFClient(sleekxmpp.ClientXMPP):
         try:
             result = self['xep_0060'].publish(self._server,node,payload=data)
             id = result['pubsub']['publish']['item']['id']
-            print('Published at item id: %s' % id)
+            #print('Published at item id: %s' % id)
         except:
             print traceback.format_exc()
             logging.error('Could not publish to: %s' % self.boundjid)