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 as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 # Julien Tribino <julien.tribino@inria.fr>
25 from nepi.util.logger import Logger
27 from nepi.resources.omf.omf_client import OMFClient
28 from nepi.resources.omf.messages_5_4 import MessageHandler
30 class OMF5API(Logger):
32 .. class:: Class Args :
34 :param slice: Xmpp Slice
36 :param host: Xmpp Server
38 :param port: Xmpp Port
40 :param password: Xmpp password
42 :param xmpp_root: Root of the Xmpp Topic Architecture
47 This class is the implementation of an OMF 5.4 API.
48 Since the version 5.4.1, the Topic Architecture start with OMF_5.4
49 instead of OMF used for OMF5.3
52 def __init__(self, slice, host, port, password, xmpp_root = None,
56 :param slice: Xmpp Slice
58 :param host: Xmpp Server
60 :param port: Xmpp Port
62 :param password: Xmpp password
64 :param xmpp_root: Root of the Xmpp Topic Architecture
68 super(OMFAPI, self).__init__("OMFAPI")
70 self._user = "%s-%s" % (slice, self._exp_id)
74 self._password = password
76 self._xmpp_root = xmpp_root or "OMF_5.4"
84 if sys.version_info < (3, 0):
86 sys.setdefaultencoding('utf8')
88 # instantiate the xmpp client
91 # register xmpp nodes for the experiment
92 self._enroll_experiment()
93 self._enroll_newexperiment()
95 # register xmpp logger for the experiment
98 def _init_client(self):
99 """ Initialize XMPP Client
102 jid = "%s@%s" % (self._user, self._host)
103 xmpp = OMFClient(jid, self._password)
104 # PROTOCOL_SSLv3 required for compatibility with OpenFire
105 xmpp.ssl_version = ssl.PROTOCOL_SSLv3
107 if xmpp.connect((self._host, self._port)):
108 xmpp.process(block=False)
109 while not xmpp.ready:
112 self._message = MessageHandler(self._slice, self._user)
114 msg = "Unable to connect to the XMPP server."
116 raise RuntimeError(msg)
118 def _enroll_experiment(self):
119 """ Create and Subscribe to the Session Topic
122 xmpp_node = self._exp_session_id
123 self._client.create(xmpp_node)
124 #print "Create experiment sesion id topics !!"
125 self._client.subscribe(xmpp_node)
126 #print "Subscribe to experiment sesion id topics !!"
129 def _enroll_newexperiment(self):
130 """ Publish New Experiment Message
133 address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice,
136 payload = self._message.newexp_function(self._user, address)
137 slice_sid = "/%s/%s" % (self._xmpp_root, self._slice)
138 self._client.publish(payload, slice_sid)
140 def _enroll_logger(self):
141 """ Create and Subscribe to the Logger Topic
144 xmpp_node = self._logger_session_id
145 self._client.create(xmpp_node)
146 self._client.subscribe(xmpp_node)
148 payload = self._message.log_function("2",
149 "nodeHandler::NodeHandler",
151 "OMF Experiment Controller 5.4 (git 529a626)")
152 self._client.publish(payload, xmpp_node)
154 def _host_session_id(self, hostname):
155 """ Return the Topic Name as /xmpp_root/slice/user/hostname
157 :param hostname: Full hrn of the node
161 return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user,
164 def _host_resource_id(self, hostname):
165 """ Return the Topic Name as /xmpp_root/slice/resources/hostname
167 :param hostname: Full hrn of the node
171 return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname)
174 def _exp_session_id(self):
175 """ Return the Topic Name as /xmpp_root/slice/user
178 return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user)
181 def _logger_session_id(self):
182 """ Return the Topic Name as /xmpp_root/slice/LOGGER
185 return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user)
187 def delete(self, hostname):
188 """ Delete the topic corresponding to the hostname for this session
190 :param hostname: Full hrn of the node
194 if not hostname in self._hostnames:
197 self._hostnames.remove(hostname)
199 xmpp_node = self._host_session_id(hostname)
200 self._client.delete(xmpp_node)
202 def enroll_host(self, hostname):
203 """ Create and Subscribe to the session topic and the resources
204 corresponding to the hostname
206 :param hostname: Full hrn of the node
210 if hostname in self._hostnames:
213 self._hostnames.append(hostname)
215 xmpp_node = self._host_session_id(hostname)
216 self._client.create(xmpp_node)
217 self._client.subscribe(xmpp_node)
219 xmpp_node = self._host_resource_id(hostname)
220 self._client.subscribe(xmpp_node)
222 payload = self._message.enroll_function("1", "*", "1", hostname)
223 self._client.publish(payload, xmpp_node)
225 def configure(self, hostname, attribute, value):
226 """ Configure attribute on the node
228 :param hostname: Full hrn of the node
230 :param attribute: Attribute that need to be configured (
231 often written as /net/wX/attribute, with X the interface number)
233 :param value: Value of the attribute
237 payload = self._message.configure_function(hostname, value, attribute)
238 xmpp_node = self._host_session_id(hostname)
239 self._client.publish(payload, xmpp_node)
242 def send_stdin(self, hostname, value, app_id):
243 """ Send to the stdin of the application the value
245 :param hostname: Full hrn of the node
247 :param appid: Application Id (Any id that represents in a unique
250 :param value: parameter to execute in the stdin of the application
254 payload = self._message.stdin_function(hostname, value, app_id)
255 xmpp_node = self._host_session_id(hostname)
256 self._client.publish(payload, xmpp_node)
259 def execute(self, hostname, app_id, arguments, path, env):
260 """ Execute command on the node
262 :param hostname: Full hrn of the node
264 :param app_id: Application Id (Any id that represents in a unique
267 :param arguments: Arguments of the application
269 :param path: Path of the application
271 :param env: Environnement values for the application
275 payload = self._message.execute_function(hostname, app_id, arguments,
277 xmpp_node = self._host_session_id(hostname)
278 self._client.publish(payload, xmpp_node)
280 def exit(self, hostname, app_id):
281 """ Kill an application started with OMF
283 :param hostname: Full hrn of the node
285 :param app_id: Application Id of the application you want to stop
289 payload = self._message.exit_function(hostname, app_id)
290 xmpp_node = self._host_session_id(hostname)
291 self._client.publish(payload, xmpp_node)
293 def release(self, hostname):
294 """ Delete the session and logger topics. Then disconnect
297 if hostname in self._hostnames:
298 self.delete(hostname)
300 def disconnect(self) :
301 """ Delete the session and logger topics. Then disconnect
304 self._client.delete(self._exp_session_id)
305 self._client.delete(self._logger_session_id)
309 # Wait the send queue to be empty before disconnect
310 self._client.disconnect(wait=True)
311 msg = " Disconnected from XMPP Server"