OMF examples
[nepi.git] / src / nepi / resources / omf / omf6_parser.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
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.
9 #
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.
14 #
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/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 #         Julien Tribino <julien.tribino@inria.fr>
20
21 from nepi.util.logger import Logger
22
23 import os
24 import traceback
25 import xml.etree.ElementTree as ET
26
27 # inherit from BaseXmpp and XMLstream classes
28 class OMF6Parser(Logger): 
29     """
30     .. class:: Class Args :
31       
32         :param jid: Jabber Id (= Xmpp Slice + Date)
33         :type jid: str
34         :param password: Jabber Password (= Xmpp Password)
35         :type password: str
36
37     .. note::
38
39        This class is an XMPP Client with customized method
40
41     """
42
43     def __init__(self):
44         """
45
46         :param jid: Jabber Id (= Xmpp Slice + Date)
47         :type jid: str
48         :param password: Jabber Password (= Xmpp Password)
49         :type password: str
50
51
52         """
53         super(OMF6Parser, self).__init__("OMF6API")
54         self.mailbox={}
55         self.traces={}
56         self.trace='NULL'
57
58         self.init_mailbox()
59
60
61     def init_mailbox(self):
62         self.mailbox['create'] = []
63         self.mailbox['started'] = []
64         self.mailbox['release'] = []
65   
66     def _check_for_tag(self, root, namespaces, tag):
67         """  Check if an element markup is in the ElementTree
68
69         :param root: Root of the tree
70         :type root: ElementTree Element
71         :param namespaces: Namespaces of the element
72         :type namespaces: str
73         :param tag: Tag that will search in the tree
74         :type tag: str
75
76         """
77         for element in root.iter(namespaces+tag):
78             if element.text:
79                 return element.text
80             else : 
81                 return None
82
83     def _check_for_props(self, root, namespaces):
84         """  Check if an element markup is in the ElementTree
85
86         :param root: Root of the tree
87         :type root: ElementTree Element
88         :param namespaces: Namespaces of the element
89         :type namespaces: str
90
91         """
92         props = {}
93         for properties in root.iter(namespaces+'props'):
94             for element in properties.iter():
95                 if element.tag and element.text:
96                     props[element.tag] = element.text
97         return props
98
99     def _check_for_membership(self, root, namespaces):
100         """  Check if an element markup is in the ElementTree
101
102         :param root: Root of the tree
103         :type root: ElementTree Element
104         :param namespaces: Namespaces of the element
105         :type namespaces: str
106
107         """
108         for element in root.iter(namespaces+'membership'):
109             for elt in element.iter(namespaces+'it'):
110                 ##XXX : change
111                 return elt.text
112
113
114     def _check_output(self, root, namespaces):
115         """ Check the significative element in the answer and display it
116
117         :param root: Root of the tree
118         :type root: ElementTree Element
119         :param namespaces: Namespaces of the tree
120         :type namespaces: str
121
122         """
123         fields = ["TARGET", "REASON", "PATH", "APPID", "VALUE"]
124         response = ""
125         for elt in fields:
126             msg = self._check_for_tag(root, namespaces, elt)
127             if msg is not None:
128                 response = response + " " + msg.text + " :"
129         deb = self._check_for_tag(root, namespaces, "MESSAGE")
130         if deb is not None:
131             msg = response + " " + deb.text
132             self.debug(msg)
133         else :
134             self.info(response)
135
136
137     def _inform_creation_ok(self, root, namespaces):
138         """ Parse and Display CREATION OK message
139
140         """
141         #ET.dump(root)
142         uid = self._check_for_tag(root, namespaces, "uid")
143         cid = self._check_for_tag(root, namespaces, "cid")
144         member = self._check_for_membership(root, namespaces)
145         binary_path = self._check_for_tag(root, namespaces, "binary_path")
146         msg = "CREATION OK -- "
147         if binary_path :
148             msg = msg + "The resource : '"+binary_path
149         else :
150             msg = msg + "The interface"
151         if uid :
152             msg = msg + "' is listening to the topics : '"+ uid
153         if member :
154             msg = msg + "' and '"+ member +"'"
155         if cid:
156             self.info(msg)
157             self.mailbox['create'].append([cid, uid ])
158
159     def _inform_creation_failed(self, root, namespaces):
160         """ Parse and Display CREATION FAILED message
161
162         """
163         reason = self._check_for_tag(root, namespaces, "reason")
164         cid = self._check_for_tag(root, namespaces, "cid")
165         msg = "CREATION FAILED - The reason : "+reason
166         if cid:
167             self.error(msg)
168             self.mailbox['create'].append([cid, uid ])
169
170     def _inform_status(self, root, namespaces):
171         """ Parse and Display STATUS message
172
173         """
174         props = self._check_for_props(root, namespaces)
175         uid = self._check_for_tag(root, namespaces, "uid")
176         event = self._check_for_tag(root, namespaces, "event")
177
178         log = "STATUS -- "
179         for elt in props.keys():
180             ns, tag = elt.split('}')
181             if tag == "it":
182                 log = log + "membership : " + props[elt]+" -- "
183             elif tag == "event":
184                 self.mailbox['started'].append(uid)
185                 log = log + "event : " + props[elt]+" -- "
186             elif tag == "msg":
187                 if event == "STDOUT" : 
188                     filename = os.path.join("/tmp", "%s.out" % uid)
189                     f = open(filename,'a+')
190                     # XXX: Adding fake \n for visual formatting 
191                     msg = props[elt] + "\n"
192                     f.write(msg)
193                     f.close()
194                 elif event == "STDERR" :
195                     filename = os.path.join("/tmp", "%s.err" % uid)
196                     f = open(filename,'a+')
197                     # XXX: Adding fake \n for visual formatting 
198                     msg = props[elt] + "\n"
199                     f.write(msg)
200                     f.close()
201                 log = log + tag +" : " + props[elt]+" -- "
202             else:
203                 log = log + tag +" : " + props[elt]+" -- "
204         log = log + " STATUS "
205         self.info(log)
206
207     def _inform_released(self, root, namespaces):
208         """ Parse and Display RELEASED message
209
210         """
211         #ET.dump(root)
212         parent_id = self._check_for_tag(root, namespaces, "src")
213         child_id = self._check_for_tag(root, namespaces, "res_id")
214         cid = self._check_for_tag(root, namespaces, "cid")
215         if cid :
216             msg = "RELEASED - The resource : '"+child_id+ \
217               "' has been released by : '"+ parent_id
218             self.info(msg)
219             self.mailbox['release'].append(cid)
220
221     def _inform_error(self, root, namespaces):
222         """ Parse and Display ERROR message
223
224         """
225         reason = self._check_for_tag(root, namespaces, "reason")
226         msg = "The reason : "+reason
227         self.error(msg)
228
229     def _inform_warn(self, root, namespaces):
230         """ Parse and Display WARN message
231
232         """
233         reason = self._check_for_tag(root, namespaces, "reason")
234         msg = "The reason : "+reason
235         self.warn(msg)
236
237     def _parse_inform(self, root, namespaces):
238         """ Check the significative element in the answer
239             Then Parse it and display using specific method
240
241         :param root: Root of the tree
242         :type root: ElementTree Element
243         :param namespaces: Namespaces of the tree
244         :type namespaces: str
245
246         """
247         itype = self._check_for_tag(root, namespaces, "itype")
248         if itype :
249             method_name = '_inform_'+ itype.replace('.', '_').lower()
250             method = getattr(self, method_name)
251             if method :
252                 method(root, namespaces)
253             else :
254                 msg = "There is no method to parse the response of the type " + itype
255                 self.info(msg)
256                 return
257         
258
259     def check_mailbox(self, itype, attr):
260         """ Check the mail box
261
262         :param itype: type of mail
263         :type itype: str
264         :param attr: value wanted
265         :type attr: str
266
267         """
268         if itype == "create":
269             for res in self.mailbox[itype]:
270                 binary, uid = res
271                 if binary == attr:
272                     self.mailbox[itype].remove(res)
273                     return uid
274         else :
275             for res in self.mailbox[itype]:
276                 if attr == res:
277                     self.mailbox[itype].remove(res)
278                     return res
279                
280
281     def handle(self, iq):
282         """ Check the mail box
283
284         :param iq: message received
285         :type itype: iq
286         """
287         namespaces = "{http://schema.mytestbed.net/omf/6.0/protocol}"
288         for i in iq['pubsub_event']['items']:
289             root = ET.fromstring(str(i))
290             #ET.dump(root)
291             self._parse_inform(root, namespaces)
292