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