from neco.resources.omf.omf_messages_5_4 import MessageHandler
class OMFAPI(object):
+ """
+ .. class:: Class Args :
+
+ :param slice: Xmpp Slice
+ :type slice: Str
+ :param host: Xmpp Server
+ :type host: Str
+ :param port: Xmpp Port
+ :type port: Str
+ :param password: Xmpp password
+ :type password: Str
+ :param xmpp_root: Root of the Xmpp Topic Architecture
+ :type xmpp_root: Str
+
+ .. note::
+
+ This class is the implementation of an OMF 5.4 API. Since the version 5.4.1, the Topic Architecture start with OMF_5.4 instead of OMF used for OMF5.3
+
+ """
def __init__(self, slice, host, port, password, xmpp_root = None):
date = datetime.datetime.now().strftime("%Y-%m-%dt%H.%M.%S")
tz = -time.altzone if time.daylight != 0 else -time.timezone
self._enroll_logger()
def _init_client(self):
+ """ Initialize XMPP Client
+
+ """
jid = "%s@%s" % (self._user, self._host)
xmpp = OMFClient(jid, self._password)
# PROTOCOL_SSLv3 required for compatibility with OpenFire
raise RuntimeError(msg)
def _enroll_experiment(self):
+ """ Create and Subscribe to the Session Topic
+
+ """
xmpp_node = self._exp_session_id
self._client.create(xmpp_node)
#print "Create experiment sesion id topics !!"
def _enroll_newexperiment(self):
+ """ Publish New Experiment Message
+
+ """
address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice, self._user)
print address
payload = self._message.newexpfunction(self._user, address)
self._client.publish(payload, slice_sid)
def _enroll_logger(self):
+ """ Create and Subscribe to the Logger Topic
+
+ """
xmpp_node = self._logger_session_id
self._client.create(xmpp_node)
self._client.subscribe(xmpp_node)
self._client.publish(payload, xmpp_node)
def _host_session_id(self, hostname):
+ """ Return the Topic Name as /xmpp_root/slice/user/hostname
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+
+ """
return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user, hostname)
def _host_resource_id(self, hostname):
+ """ Return the Topic Name as /xmpp_root/slice/resources/hostname
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+
+ """
return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname)
@property
def _exp_session_id(self):
+ """ Return the Topic Name as /xmpp_root/slice/user
+
+ """
return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user)
@property
def _logger_session_id(self):
+ """ Return the Topic Name as /xmpp_root/slice/LOGGER
+
+ """
return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user)
def delete(self, hostname):
+ """ Delete the topic corresponding to the hostname for this session
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+
+ """
if not hostname in self._hostnames:
return
self._client.delete(xmpp_node)
def enroll_host(self, hostname):
+ """ Create and Subscribe to the session topic and the resources corresponding to the hostname
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+
+ """
if hostname in self._hostnames:
return
payload = self._message.enrollfunction("1", "*", "1", hostname)
self._client.publish(payload, xmpp_node)
- def configure(self, hostname, attribute, value):
+ def configure(self, hostname, attribute, value):
+ """ Configure attribute on the node
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+ :param attribute: Attribute that need to be configured (often written as /net/wX/attribute, with X the interface number)
+ :type attribute: str
+ :param value: Value of the attribute
+ :type value: str
+
+ """
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, env):
+ """ Execute command on the node
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+ :param app_id: Application Id (Any id that represents in a unique way the application)
+ :type app_id: str
+ :param arguments: Arguments of the application
+ :type arguments: str
+ :param path: Path of the application
+ :type path: str
+ :param env: Environnement values for the application
+ :type env: str
+
+ """
payload = self._message.executefunction(hostname, app_id, arguments, path, env)
xmpp_node = self._host_session_id(hostname)
self._client.publish(payload, xmpp_node)
def exit(self, hostname, app_id):
+ """ Kill an application started with OMF
+
+ :param hostname: Full hrn of the node
+ :type hostname: str
+ :param app_id: Application Id of the application you want to stop
+ :type app_id: str
+
+ """
payload = self._message.exitfunction(hostname, app_id)
xmpp_node = self._host_session_id(hostname)
self._client.publish(payload, xmpp_node)
def disconnect(self):
+ """ Delete the sesion and logger topic and disconnect
+
+ """
self._client.delete(self._exp_session_id)
self._client.delete(self._logger_session_id)
class OMFAPIFactory(object):
+ """
+ .. note::
+
+ It allows the different RM to use the same xmpp client if they use the same credentials. For the moment, it is focused on Xmpp.
+
+ """
+
# XXX: put '_apis' instead of '_Api'
_Api = dict()
@classmethod
def get_api(cls, slice, host, port, password):
+ """ Get an Api
+
+ :param slice: Xmpp Slice Name
+ :type slice: str
+ :param host: Xmpp Server Adress
+ :type host: str
+ :param port: Xmpp Port (Default : 5222)
+ :type port: str
+ :param password: Xmpp Password
+ :type password: str
+
+ """
if slice and host and port and password:
key = cls._hash_api(slice, host, port)
if key in cls._Api:
@classmethod
def create_api(cls, slice, host, port, password):
+ """ Create an API if this one doesn't exist yet with this credentials
+
+ :param slice: Xmpp Slice Name
+ :type slice: str
+ :param host: Xmpp Server Adress
+ :type host: str
+ :param port: Xmpp Port (Default : 5222)
+ :type port: str
+ :param password: Xmpp Password
+ :type password: str
+
+ """
OmfApi = OMFAPI(slice, host, port, password)
key = cls._hash_api(slice, host, port)
cls._Api[key] = OmfApi
# XXX: change method name for 'make_key'
@classmethod
def _hash_api(cls, slice, host, port):
+ """ Hash the credentials in order to create a key
+
+ :param slice: Xmpp Slice Name
+ :type slice: str
+ :param host: Xmpp Server Adress
+ :type host: str
+ :param port: Xmpp Port (Default : 5222)
+ :type port: str
+
+ """
res = slice + "_" + host + "_" + port
return res
#!/usr/bin/env python
-from neco.execution.resource import ResourceManager, clsinit
+
+from neco.execution.resource import Resource, clsinit
from neco.execution.attribute import Attribute
from neco.resources.omf.omf_api import OMFAPIFactory
import logging
@clsinit
-class OMFApplication(ResourceManager):
+class OMFApplication(Resource):
+ """
+ .. class:: Class Args :
+
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ .. note::
+
+ This class is used only by the Experiment Controller through the Resource Factory
+
+ """
_rtype = "OMFApplication"
_authorized_connections = ["OMFNode"]
@classmethod
def _register_attributes(cls):
+ """Register the attributes of an OMF application
+ """
+
appid = Attribute("appid", "Name of the application")
path = Attribute("path", "Path of the application")
args = Attribute("args", "Argument of the application")
def __init__(self, ec, guid, creds):
+ """
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ """
+
super(OMFApplication, self).__init__(ec, guid)
self.set('xmppSlice', creds['xmppSlice'])
self.set('xmppHost', creds['xmppHost'])
self._logger = logging.getLogger("neco.omf.omfApp ")
self._logger.setLevel(neco.LOGLEVEL)
+
def _validate_connection(self, guid):
+ """Check if the connection is available.
+
+ :param guid: Guid of the current RM
+ :type guid: int
+ :rtype: Boolean
+
+ """
rm = self.ec.resource(guid)
if rm.rtype() not in self._authorized_connections:
self._logger.debug("Connection between %s %s and %s %s refused : An Application can be connected only to a Node" % (self.rtype(), self._guid, rm.rtype(), guid))
return True
def _get_nodes(self, conn_set):
+ """Get the RM of the node to which the application is connected
+
+ :param conn_set: Connections of the current Guid
+ :type conn_set: set
+ :rtype: ResourceManager
+ """
+
for elt in conn_set:
rm = self.ec.resource(elt)
if rm.rtype() == "OMFNode":
return None
def start(self):
+ """Send Xmpp Message Using OMF protocol to execute the application
+
+ """
self._logger.debug(" " + self.rtype() + " ( Guid : " + str(self._guid) +") : " + self.get('appid') + " : " + self.get('path') + " : " + self.get('args') + " : " + self.get('env'))
#try:
if self.get('appid') and self.get('path') and self.get('args') and self.get('env'):
self._omf_api.execute(rm_node.get('hostname'),self.get('appid'), self.get('args'), self.get('path'), self.get('env'))
def stop(self):
+ """Send Xmpp Message Using OMF protocol to kill the application
+
+ """
rm_node = self._get_nodes(self._connections)
self._omf_api.exit(rm_node.get('hostname'),self.get('appid'))
#!/usr/bin/env python
-from neco.execution.resource import ResourceManager, clsinit
+from neco.execution.resource import Resource, clsinit
from neco.execution.attribute import Attribute
from neco.resources.omf.omf_api import OMFAPIFactory
import logging
@clsinit
-class OMFChannel(ResourceManager):
+class OMFChannel(Resource):
+ """
+ .. class:: Class Args :
+
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ .. note::
+
+ This class is used only by the Experiment Controller through the Resource Factory
+
+ """
_rtype = "OMFChannel"
_authorized_connections = ["OMFWifiInterface"]
@classmethod
def _register_attributes(cls):
+ """Register the attributes of an OMF channel
+ """
channel = Attribute("channel", "Name of the application")
xmppSlice = Attribute("xmppSlice","Name of the slice", flags = "0x02")
xmppHost = Attribute("xmppHost", "Xmpp Server",flags = "0x02")
cls._register_attribute(xmppPassword)
def __init__(self, ec, guid, creds):
+ """
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ """
super(OMFChannel, self).__init__(ec, guid)
self.set('xmppSlice', creds['xmppSlice'])
self.set('xmppHost', creds['xmppHost'])
self._logger.setLevel(neco.LOGLEVEL)
def _validate_connection(self, guid):
+ """Check if the connection is available.
+
+ :param guid: Guid of the current RM
+ :type guid: int
+ :rtype: Boolean
+
+ """
rm = self.ec.resource(guid)
if rm.rtype() in self._authorized_connections:
self._logger.debug("Connection between %s %s and %s %s accepted" % (self.rtype(), self._guid, rm.rtype(), guid))
self._logger.debug("Connection between %s %s and %s %s refused" % (self.rtype(), self._guid, rm.rtype(), guid))
return False
- def _get_nodes(self, conn_set):
+ def _get_target(self, conn_set):
+ """
+ Get the couples (host, interface) that used this channel
+
+ :param conn_set: Connections of the current Guid
+ :type conn_set: set
+ :rtype: list
+ :return: self._nodes_guid
+ """
for elt in conn_set:
rm_iface = self.ec.resource(elt)
for conn in rm_iface._connections:
return self._nodes_guid
def discover(self):
+ """ Discover the availables channels
+
+ """
pass
def provision(self, credential):
+ """ Provision some availables channels
+
+ """
pass
def start(self):
+ """Send Xmpp Message Using OMF protocol to configure Channel
+
+ """
if self.get('channel'):
- set_nodes = self._get_nodes(self._connections)
+ set_nodes = self._get_target(self._connections)
#print set_nodes
for couple in set_nodes:
#print "Couple node/alias : " + couple[0] + " , " + couple[1]
import neco
class OMFClient(sleekxmpp.ClientXMPP):
+ """
+ .. class:: Class Args :
+
+ :param jid: Jabber Id (= Xmpp Slice + Date)
+ :type jid: Str
+ :param password: Jabber Password (= Xmpp Password)
+ :type password: Str
+
+ .. note::
+
+ This class is an XMPP Client with customized method
+
+ """
+
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self._ready = False
#!/usr/bin/env python
-from neco.execution.resource import ResourceManager, clsinit
+from neco.execution.resource import Resource, clsinit
from neco.execution.attribute import Attribute
from neco.resources.omf.omf_api import OMFAPIFactory
import logging
@clsinit
-class OMFWifiInterface(ResourceManager):
+class OMFWifiInterface(Resource):
+ """
+ .. class:: Class Args :
+
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ .. note::
+
+ This class is used only by the Experiment Controller through the Resource Factory
+
+ """
_rtype = "OMFWifiInterface"
_authorized_connections = ["OMFNode" , "OMFChannel"]
@classmethod
def _register_attributes(cls):
+ """Register the attributes of an OMF interface
+ """
alias = Attribute("alias","Alias of the interface", default_value = "w0")
mode = Attribute("mode","Mode of the interface")
type = Attribute("type","Type of the interface")
cls._register_attribute(ip)
def __init__(self, ec, guid, creds):
+ """
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ """
super(OMFWifiInterface, self).__init__(ec, guid)
self.set('xmppSlice', creds['xmppSlice'])
self.set('xmppHost', creds['xmppHost'])
self._logger.setLevel(neco.LOGLEVEL)
def _validate_connection(self, guid):
+ """Check if the connection is available.
+
+ :param guid: Guid of the current RM
+ :type guid: int
+ :rtype: Boolean
+
+ """
rm = self.ec.resource(guid)
if rm.rtype() in self._authorized_connections:
self._logger.debug("Connection between %s %s and %s %s accepted" % (self.rtype(), self._guid, rm.rtype(), guid))
return False
def _get_nodes(self, conn_set):
+ """
+ Get the RM of the node to which the application is connected
+
+ :param conn_set: Connections of the current Guid
+ :type conn_set: set
+ :rtype: ResourceManager
+ """
for elt in conn_set:
rm = self.ec.resource(elt)
if rm.rtype() == "OMFNode":
def start(self):
+ """Send Xmpp Messages Using OMF protocol to configure Interface
+
+ """
self._logger.debug(self.rtype() + " ( Guid : " + str(self._guid) +") : " + self.get('mode') + " : " + self.get('type') + " : " + self.get('essid') + " : " + self.get('ip'))
#try:
if self.get('mode') and self.get('type') and self.get('essid') and self.get('ip'):
self._omf_api.configure(rm_node.get('hostname'), attrname, attrval)
def stop(self):
+ """Send Xmpp Message Using OMF protocol to put down the interface
+
+ """
self._omf_api.disconnect()
EXIT = "EXIT"
class MessageHandler():
- SliceID = ""
- ExpID = ""
+ """
+ .. class:: Class Args :
+
+ :param sliceid: Slice Name (= Xmpp Slice)
+ :type expid: Str
+ :param expid: Experiment ID (= Xmpp User)
+ :type expid: Str
+
+ .. note::
+
+ This class is used only for OMF 5.4 Protocol and is going to become unused
+
+ """
+
def __init__(self, sliceid, expid ):
- self.SliceID = sliceid
- self.ExpID = expid
- print "init" + self.ExpID +" "+ self.SliceID
+ self._slice_id = sliceid
+ self._exp_id = expid
+ print "init" + self._exp_id +" "+ self._slice_id
pass
def Mid(self, parent, keyword):
payload = ET.Element("omf-message")
execute = self.Mid(payload,"EXECUTE")
env = self.Mtext(execute, "ENV", env)
- sliceid = self.Mtext(execute,"SLICEID",self.SliceID)
- expid = self.Mtext(execute,"EXPID",self.ExpID)
+ sliceid = self.Mtext(execute,"SLICEID",self._slice_id)
+ expid = self.Mtext(execute,"EXPID",self._exp_id)
target = self.Mtext(execute,"TARGET",target)
appid = self.Mtext(execute,"APPID",appid)
cmdlineargs = self.Mtext(execute,"CMDLINEARGS",cmdlineargs)
def exitfunction(self, target, appid):
payload = ET.Element("omf-message")
execute = self.Mid(payload,"EXIT")
- sliceid = self.Mtext(execute,"SLICEID",self.SliceID)
- expid = self.Mtext(execute,"EXPID",self.ExpID)
+ sliceid = self.Mtext(execute,"SLICEID",self._slice_id)
+ expid = self.Mtext(execute,"EXPID",self._exp_id)
target = self.Mtext(execute,"TARGET",target)
appid = self.Mtext(execute,"APPID",appid)
return payload
def configurefunction(self, target, value, path):
payload = ET.Element("omf-message")
config = self.Mid(payload, "CONFIGURE")
- sliceid = self.Mtext(config,"SLICEID",self.SliceID)
- expid = self.Mtext(config,"EXPID",self.ExpID)
+ sliceid = self.Mtext(config,"SLICEID",self._slice_id)
+ expid = self.Mtext(config,"EXPID",self._exp_id)
target = self.Mtext(config,"TARGET",target)
value = self.Mtext(config,"VALUE",value)
path = self.Mtext(config,"PATH",path)
payload = ET.Element("omf-message")
log = self.Mid(payload, "LOGGING")
level = self.Mtext(log,"LEVEL",level)
- sliceid = self.Mtext(log,"SLICEID",self.SliceID)
+ sliceid = self.Mtext(log,"SLICEID",self._slice_id)
logger = self.Mtext(log,"LOGGER",logger)
- expid = self.Mtext(log,"EXPID",self.ExpID)
+ expid = self.Mtext(log,"EXPID",self._exp_id)
level_name = self.Mtext(log,"LEVEL_NAME",level_name)
data = self.Mtext(log,"DATA",data)
return payload
def aliasfunction(self, name, target):
payload = ET.Element("omf-message")
alias = self.Mid(payload,"ALIAS")
- sliceid = self.Mtext(alias,"SLICEID",self.SliceID)
- expid = self.Mtext(alias,"EXPID",self.ExpID)
+ sliceid = self.Mtext(alias,"SLICEID",self._slice_id)
+ expid = self.Mtext(alias,"EXPID",self._exp_id)
name = self.Mtext(alias,"NAME",name)
target = self.Mtext(alias,"TARGET",target)
return payload
payload = ET.Element("omf-message")
enroll = self.Mid(payload,"ENROLL")
enrollkey = self.Mtext(enroll,"ENROLLKEY",enrollkey)
- sliceid = self.Mtext(enroll,"SLICEID",self.SliceID)
+ sliceid = self.Mtext(enroll,"SLICEID",self._slice_id)
image = self.Mtext(enroll,"IMAGE",image)
- expid = self.Mtext(enroll,"EXPID",self.ExpID)
+ expid = self.Mtext(enroll,"EXPID",self._exp_id)
index = self.Mtext(enroll,"INDEX",index)
target = self.Mtext(enroll,"TARGET",target)
return payload
def noopfunction(self,target):
payload = ET.Element("omf-message")
noop = self.Mid(payload,"NOOP")
- sliceid = self.Mtext(noop,"SLICEID",self.SliceID)
- expid = self.Mtext(noop,"EXPID",self.ExpID)
+ sliceid = self.Mtext(noop,"SLICEID",self._slice_id)
+ expid = self.Mtext(noop,"EXPID",self._exp_id)
target = self.Mtext(noop,"TARGET",target)
return payload
payload = ET.Element("omf-message")
newexp = self.Mid(payload,"EXPERIMENT_NEW")
experimentid = self.Mtext(newexp,"EXPERIMENT_ID",experimentid)
- sliceid = self.Mtext(newexp,"SLICEID",self.SliceID)
- expid = self.Mtext(newexp,"EXPID",self.ExpID)
+ sliceid = self.Mtext(newexp,"SLICEID",self._slice_id)
+ expid = self.Mtext(newexp,"EXPID",self._exp_id)
address = self.Mtext(newexp,"ADDRESS",address)
return payload
@clsinit
class OMFNode(ResourceManager):
+ """
+ .. class:: Class Args :
+
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ .. note::
+
+ This class is used only by the Experiment Controller through the Resource Factory
+
+ """
_rtype = "OMFNode"
_authorized_connections = ["OMFApplication" , "OMFWifiInterface"]
@classmethod
def _register_attributes(cls):
+ """Register the attributes of an OMF Node
+
+ """
hostname = Attribute("hostname", "Hostname of the machine")
cpu = Attribute("cpu", "CPU of the node")
ram = Attribute("ram", "RAM of the node")
@classmethod
def _register_filters(cls):
+ """Register the filters of an OMF Node
+
+ """
hostname = Attribute("hostname", "Hostname of the machine")
gateway = Attribute("gateway", "Gateway")
granularity = Attribute("granularity", "Granularity of the reservation time")
# THE OMF API SHOULD BE CREATED ON THE DEPLOY METHOD, NOT NOW
# THIS FORCES MORE CONSTRAINES ON THE WAY WE WILL AUTHOMATE DEPLOYMENT!
def __init__(self, ec, guid, creds):
+ """
+ :param ec: The Experiment controller
+ :type ec: ExperimentController
+ :param guid: guid of the RM
+ :type guid: int
+ :param creds: Credentials to communicate with the rm (XmppClient for OMF)
+ :type creds: dict
+
+ """
super(OMFNode, self).__init__(ec, guid)
self.set('xmppSlice', creds['xmppSlice'])
self.set('xmppHost', creds['xmppHost'])
self._logger.setLevel(neco.LOGLEVEL)
def _validate_connection(self, guid):
+ """Check if the connection is available.
+
+ :param guid: Guid of the current RM
+ :type guid: int
+ :rtype: Boolean
+
+ """
rm = self.ec.resource(guid)
if rm.rtype() in self._authorized_connections:
self._logger.debug("Connection between %s %s and %s %s accepted" % (self.rtype(), self._guid, rm.rtype(), guid))
return False
def discover(self):
+ """ Discover the availables nodes
+
+ """
pass
def provision(self, credential):
+ """ Provision some availables nodes
+
+ """
pass
def start(self):
+ """Send Xmpp Message Using OMF protocol to enroll the node into the experiment
+
+ """
self._omf_api.enroll_host(self.get('hostname'))
def stop(self):
+ """Send Xmpp Message Using OMF protocol to disconnect the node
+
+ """
self._omf_api.disconnect()
def configure(self):