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 host: Xmpp Server
36 :param slice: Xmpp Slice
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, host, slice, port, password, xmpp_root = None,
55 :param host: Xmpp Server
57 :param slice: Xmpp Slice
59 :param port: Xmpp Port
61 :param password: Xmpp password
63 :param xmpp_root: Root of the Xmpp Topic Architecture
67 super(OMF5API, self).__init__("OMF5API")
69 self._user = "%s-%s" % (slice, self._exp_id)
73 self._password = password
75 self._xmpp_root = xmpp_root or "OMF_5.4"
83 if sys.version_info < (3, 0):
85 sys.setdefaultencoding('utf8')
87 # instantiate the xmpp client
90 # register xmpp nodes for the experiment
91 self._enroll_experiment()
92 self._enroll_newexperiment()
94 # register xmpp logger for the experiment
97 def _init_client(self):
98 """ Initialize XMPP Client
101 jid = "%s@%s" % (self._user, self._host)
102 xmpp = OMFClient(jid, self._password)
103 # PROTOCOL_SSLv3 required for compatibility with OpenFire
104 xmpp.ssl_version = ssl.PROTOCOL_SSLv3
106 if xmpp.connect((self._host, self._port)):
107 xmpp.process(block=False)
108 while not xmpp.ready:
111 self._message = MessageHandler(self._slice, self._user)
113 msg = "Unable to connect to the XMPP server."
115 raise RuntimeError(msg)
117 def _enroll_experiment(self):
118 """ Create and Subscribe to the Session Topic
121 xmpp_node = self._exp_session_id
122 self._client.create(xmpp_node)
123 #print "Create experiment sesion id topics !!"
124 self._client.subscribe(xmpp_node)
125 #print "Subscribe to experiment sesion id topics !!"
128 def _enroll_newexperiment(self):
129 """ Publish New Experiment Message
132 address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice,
135 payload = self._message.newexp_function(self._user, address)
136 slice_sid = "/%s/%s" % (self._xmpp_root, self._slice)
137 self._client.publish(payload, slice_sid)
139 def _enroll_logger(self):
140 """ Create and Subscribe to the Logger Topic
143 xmpp_node = self._logger_session_id
144 self._client.create(xmpp_node)
145 self._client.subscribe(xmpp_node)
147 payload = self._message.log_function("2",
148 "nodeHandler::NodeHandler",
150 "OMF Experiment Controller 5.4 (git 529a626)")
151 self._client.publish(payload, xmpp_node)
153 def _host_session_id(self, hostname):
154 """ Return the Topic Name as /xmpp_root/slice/user/hostname
156 :param hostname: Full hrn of the node
160 return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user,
163 def _host_resource_id(self, hostname):
164 """ Return the Topic Name as /xmpp_root/slice/resources/hostname
166 :param hostname: Full hrn of the node
170 return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname)
173 def _exp_session_id(self):
174 """ Return the Topic Name as /xmpp_root/slice/user
177 return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user)
180 def _logger_session_id(self):
181 """ Return the Topic Name as /xmpp_root/slice/LOGGER
184 return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user)
186 def delete(self, hostname):
187 """ Delete the topic corresponding to the hostname for this session
189 :param hostname: Full hrn of the node
193 if not hostname in self._hostnames:
196 self._hostnames.remove(hostname)
198 xmpp_node = self._host_session_id(hostname)
199 self._client.delete(xmpp_node)
201 def enroll_host(self, hostname):
202 """ Create and Subscribe to the session topic and the resources
203 corresponding to the hostname
205 :param hostname: Full hrn of the node
209 if hostname in self._hostnames:
212 self._hostnames.append(hostname)
214 xmpp_node = self._host_session_id(hostname)
215 self._client.create(xmpp_node)
216 self._client.subscribe(xmpp_node)
218 xmpp_node = self._host_resource_id(hostname)
219 self._client.subscribe(xmpp_node)
221 payload = self._message.enroll_function("1", "*", "1", hostname)
222 self._client.publish(payload, xmpp_node)
224 def configure(self, hostname, attribute, value):
225 """ Configure attribute on the node
227 :param hostname: Full hrn of the node
229 :param attribute: Attribute that need to be configured (
230 often written as /net/wX/attribute, with X the interface number)
232 :param value: Value of the attribute
236 payload = self._message.configure_function(hostname, value, attribute)
237 xmpp_node = self._host_session_id(hostname)
238 self._client.publish(payload, xmpp_node)
241 def send_stdin(self, hostname, value, app_id):
242 """ Send to the stdin of the application the value
244 :param hostname: Full hrn of the node
246 :param appid: Application Id (Any id that represents in a unique
249 :param value: parameter to execute in the stdin of the application
253 payload = self._message.stdin_function(hostname, value, app_id)
254 xmpp_node = self._host_session_id(hostname)
255 self._client.publish(payload, xmpp_node)
258 def execute(self, hostname, app_id, arguments, path, env):
259 """ Execute command on the node
261 :param hostname: Full hrn of the node
263 :param app_id: Application Id (Any id that represents in a unique
266 :param arguments: Arguments of the application
268 :param path: Path of the application
270 :param env: Environnement values for the application
274 payload = self._message.execute_function(hostname, app_id, arguments,
276 xmpp_node = self._host_session_id(hostname)
277 self._client.publish(payload, xmpp_node)
279 def exit(self, hostname, app_id):
280 """ Kill an application started with OMF
282 :param hostname: Full hrn of the node
284 :param app_id: Application Id of the application you want to stop
288 payload = self._message.exit_function(hostname, app_id)
289 xmpp_node = self._host_session_id(hostname)
290 self._client.publish(payload, xmpp_node)
292 def release(self, hostname):
293 """ Delete the session and logger topics. Then disconnect
296 if hostname in self._hostnames:
297 self.delete(hostname)
299 def disconnect(self) :
300 """ Delete the session and logger topics. Then disconnect
303 self._client.delete(self._exp_session_id)
304 self._client.delete(self._logger_session_id)
308 # Wait the send queue to be empty before disconnect
309 self._client.disconnect(wait=True)
310 msg = " Disconnected from XMPP Server"