2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
18 # Julien Tribino <julien.tribino@inria.fr>
24 from nepi.util.logger import Logger
26 from nepi.resources.omf.omf_client import OMFClient
27 from nepi.resources.omf.messages_5_4 import MessageHandler
29 class OMF5API(Logger):
31 .. class:: Class Args :
33 :param host: Xmpp Server
35 :param slice: Xmpp Slice
37 :param port: Xmpp Port
39 :param password: Xmpp password
41 :param xmpp_root: Root of the Xmpp Topic Architecture
46 This class is the implementation of an OMF 5.4 API.
47 Since the version 5.4.1, the Topic Architecture start with OMF_5.4
48 instead of OMF used for OMF5.3
51 def __init__(self, host, slice, port, password, xmpp_root = None,
54 :param host: Xmpp Server
56 :param slice: Xmpp Slice
58 :param port: Xmpp Port
60 :param password: Xmpp password
62 :param xmpp_root: Root of the Xmpp Topic Architecture
66 super(OMF5API, self).__init__("OMF5API")
68 self._user = "%s-%s" % (slice, self._exp_id)
72 self._password = password
74 self._xmpp_root = xmpp_root or "OMF_5.4"
82 if sys.version_info < (3, 0):
84 sys.setdefaultencoding('utf8')
86 # instantiate the xmpp client
89 # register xmpp nodes for the experiment
90 self._enroll_experiment()
91 self._enroll_newexperiment()
93 # register xmpp logger for the experiment
96 def _init_client(self):
97 """ Initialize XMPP Client
100 jid = "%s@%s" % (self._user, self._host)
101 xmpp = OMFClient(jid, self._password)
102 # PROTOCOL_SSLv3 required for compatibility with OpenFire
103 xmpp.ssl_version = ssl.PROTOCOL_SSLv3
105 if xmpp.connect((self._host, self._port)):
106 xmpp.process(block=False)
107 while not xmpp.ready:
110 self._message = MessageHandler(self._slice, self._user)
112 msg = "Unable to connect to the XMPP server."
114 raise RuntimeError(msg)
116 def _enroll_experiment(self):
117 """ Create and Subscribe to the Session Topic
120 xmpp_node = self._exp_session_id
121 self._client.create(xmpp_node)
122 #print "Create experiment sesion id topics !!"
123 self._client.subscribe(xmpp_node)
124 #print "Subscribe to experiment sesion id topics !!"
127 def _enroll_newexperiment(self):
128 """ Publish New Experiment Message
131 address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice,
134 payload = self._message.newexp_function(self._user, address)
135 slice_sid = "/%s/%s" % (self._xmpp_root, self._slice)
136 self._client.publish(payload, slice_sid)
138 def _enroll_logger(self):
139 """ Create and Subscribe to the Logger Topic
142 xmpp_node = self._logger_session_id
143 self._client.create(xmpp_node)
144 self._client.subscribe(xmpp_node)
146 payload = self._message.log_function("2",
147 "nodeHandler::NodeHandler",
149 "OMF Experiment Controller 5.4 (git 529a626)")
150 self._client.publish(payload, xmpp_node)
152 def _host_session_id(self, hostname):
153 """ Return the Topic Name as /xmpp_root/slice/user/hostname
155 :param hostname: Full hrn of the node
159 return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user,
162 def _host_resource_id(self, hostname):
163 """ Return the Topic Name as /xmpp_root/slice/resources/hostname
165 :param hostname: Full hrn of the node
169 return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname)
172 def _exp_session_id(self):
173 """ Return the Topic Name as /xmpp_root/slice/user
176 return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user)
179 def _logger_session_id(self):
180 """ Return the Topic Name as /xmpp_root/slice/LOGGER
183 return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user)
185 def delete(self, hostname):
186 """ Delete the topic corresponding to the hostname for this session
188 :param hostname: Full hrn of the node
192 if not hostname in self._hostnames:
195 self._hostnames.remove(hostname)
197 xmpp_node = self._host_session_id(hostname)
198 self._client.delete(xmpp_node)
200 def enroll_host(self, hostname):
201 """ Create and Subscribe to the session topic and the resources
202 corresponding to the hostname
204 :param hostname: Full hrn of the node
208 if hostname in self._hostnames:
211 self._hostnames.append(hostname)
213 xmpp_node = self._host_session_id(hostname)
214 self._client.create(xmpp_node)
215 self._client.subscribe(xmpp_node)
217 xmpp_node = self._host_resource_id(hostname)
218 self._client.subscribe(xmpp_node)
220 payload = self._message.enroll_function("1", "*", "1", hostname)
221 self._client.publish(payload, xmpp_node)
223 def configure(self, hostname, attribute, value):
224 """ Configure attribute on the node
226 :param hostname: Full hrn of the node
228 :param attribute: Attribute that need to be configured (
229 often written as /net/wX/attribute, with X the interface number)
231 :param value: Value of the attribute
235 payload = self._message.configure_function(hostname, value, attribute)
236 xmpp_node = self._host_session_id(hostname)
237 self._client.publish(payload, xmpp_node)
240 def send_stdin(self, hostname, value, app_id):
241 """ Send to the stdin of the application the value
243 :param hostname: Full hrn of the node
245 :param appid: Application Id (Any id that represents in a unique
248 :param value: parameter to execute in the stdin of the application
252 payload = self._message.stdin_function(hostname, value, app_id)
253 xmpp_node = self._host_session_id(hostname)
254 self._client.publish(payload, xmpp_node)
257 def execute(self, hostname, app_id, arguments, path, env):
258 """ Execute command on the node
260 :param hostname: Full hrn of the node
262 :param app_id: Application Id (Any id that represents in a unique
265 :param arguments: Arguments of the application
267 :param path: Path of the application
269 :param env: Environnement values for the application
273 payload = self._message.execute_function(hostname, app_id, arguments,
275 xmpp_node = self._host_session_id(hostname)
276 self._client.publish(payload, xmpp_node)
278 def exit(self, hostname, app_id):
279 """ Kill an application started with OMF
281 :param hostname: Full hrn of the node
283 :param app_id: Application Id of the application you want to stop
287 payload = self._message.exit_function(hostname, app_id)
288 xmpp_node = self._host_session_id(hostname)
289 self._client.publish(payload, xmpp_node)
291 def release(self, hostname):
292 """ Delete the session and logger topics. Then disconnect
295 if hostname in self._hostnames:
296 self.delete(hostname)
298 def disconnect(self) :
299 """ Delete the session and logger topics. Then disconnect
302 self._client.delete(self._exp_session_id)
303 self._client.delete(self._logger_session_id)
307 # Wait the send queue to be empty before disconnect
308 self._client.disconnect(wait=True)
309 msg = " Disconnected from XMPP Server"