125360e30d1f6d3d8eca784357696266b2e03e19
[nepi.git] / src / nepi / util / parsers / xml_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
20 from nepi.util.timefuncs import stformat, tsformat
21
22 from xml.dom import minidom
23
24 import datetime
25 import sys
26 import os
27
28 STRING = "string"
29 BOOL = "bool"
30 INTEGER = "integer"
31 DOUBLE = "float"
32
33 def xmlencode(s):
34     if isinstance(s, str):
35         rv = s.decode("latin1")
36     if isinstance(s, datetime.datetime):
37         rv = tsformat(s)
38     elif not isinstance(s, unicode):
39         rv = unicode(s)
40     else:
41         rv = s
42     return rv.replace(u'\x00',u'&#0000;')
43
44 def xmldecode(s, cast = str):
45     ret = s.replace(u'&#0000',u'\x00').encode("ascii")
46     ret = cast(ret)
47     if s == "None":
48         return None
49     return ret
50
51 def from_type(value):
52     if isinstance(value, bool):
53         return BOOL
54     if isinstance(value, int):
55         return INTEGER
56     if isinstance(value, float):
57         return DOUBLE
58
59     return STRING
60
61 def to_type(type, value):
62     if not value:
63         return value
64
65     if type == STRING:
66         return str(value)
67     if type == BOOL:
68         return value == "True"
69     if type == INTEGER:
70         return int(value)
71     if type == DOUBLE:
72         return float(value)
73
74 class ECXMLParser(object):
75     def to_xml(self, ec):
76         
77         doc = minidom.Document()
78         
79         self._ec_to_xml(doc, ec)
80        
81         try:
82             xml = doc.toprettyxml(indent="    ", encoding="UTF-8")
83         except:
84             print >>sys.stderr, "Oops: generating XML from %s" % (data,)
85             raise
86         
87         return xml
88
89     def _ec_to_xml(self, doc, ec):
90         ecnode = doc.createElement("experiment")
91         ecnode.setAttribute("exp_id", xmlencode(ec.exp_id))
92         ecnode.setAttribute("run_id", xmlencode(ec.run_id))
93         ecnode.setAttribute("nthreads", xmlencode(ec.nthreads))
94         ecnode.setAttribute("local_dir", xmlencode(ec.local_dir))
95         ecnode.setAttribute("exp_dir", xmlencode(ec.exp_dir))
96         doc.appendChild(ecnode)
97
98         for guid, rm in ec._resources.iteritems():
99             self._rm_to_xml(doc, ecnode, ec, guid, rm)
100
101         return doc
102
103     def _rm_to_xml(self, doc, ecnode, ec, guid, rm):
104         rmnode = doc.createElement("rm")
105         rmnode.setAttribute("guid", xmlencode(guid))
106         rmnode.setAttribute("rtype", xmlencode(rm._rtype))
107         rmnode.setAttribute("state", xmlencode(rm._state))
108         if rm._start_time:
109             rmnode.setAttribute("start_time", xmlencode(rm._start_time))
110         if rm._stop_time:
111             rmnode.setAttribute("stop_time", xmlencode(rm._stop_time))
112         if rm._discover_time:
113             rmnode.setAttribute("discover_time", xmlencode(rm._discover_time))
114         if rm._provision_time:    
115             rmnode.setAttribute("provision_time", xmlencode(rm._provision_time))
116         if rm._ready_time:
117             rmnode.setAttribute("ready_time", xmlencode(rm._ready_time))
118         if rm._release_time:
119             rmnode.setAttribute("release_time", xmlencode(rm._release_time))
120         if rm._failed_time:
121             rmnode.setAttribute("failed_time", xmlencode(rm._failed_time))
122         ecnode.appendChild(rmnode)
123
124         anode = doc.createElement("attributes")
125         attributes = False
126
127         for attr in rm._attrs.values():
128             if attr.has_changed:
129                 attributes = True
130                 aanode = doc.createElement("attribute")
131                 aanode.setAttribute("name", xmlencode(attr.name))
132                 aanode.setAttribute("value", xmlencode(attr.value))
133                 aanode.setAttribute("type", from_type(attr.value))
134                 anode.appendChild(aanode)
135     
136         if attributes: 
137             rmnode.appendChild(anode)
138
139         cnode = doc.createElement("connections")
140         connections = False
141         
142         for guid in rm._connections:
143             connections = True
144             ccnode = doc.createElement("connection")
145             ccnode.setAttribute("guid", xmlencode(guid))
146             cnode.appendChild(ccnode)
147         
148         if connections:
149            rmnode.appendChild(cnode)
150
151         cnnode = doc.createElement("conditions")
152         conditions = False
153
154         for action, conds in rm._conditions.iteritems():
155             conditions = True
156             for (group, state, time) in conds:
157                 ccnnode = doc.createElement("condition")
158                 ccnnode.setAttribute("action", xmlencode(action))
159                 ccnnode.setAttribute("group", xmlencode(group))
160                 ccnnode.setAttribute("state", xmlencode(state))
161                 ccnnode.setAttribute("time", xmlencode(time))
162                 cnnode.appendChild(ccnnode)
163         
164         if conditions:
165            rmnode.appendChild(cnnode)
166
167         tnode = doc.createElement("traces")
168         traces = False
169
170         for trace in rm._trcs.values():
171             if trace.enabled:
172                 traces = True
173                 ttnode = doc.createElement("trace")
174                 ttnode.setAttribute("name", xmlencode(trace.name))
175                 tnode.appendChild(ttnode)
176     
177         if traces: 
178             rmnode.appendChild(tnode)
179
180     def from_xml(self, xml):
181         doc = minidom.parseString(xml)
182         return self._ec_from_xml(doc)
183
184     def _ec_from_xml(self, doc):
185         from nepi.execution.ec import ExperimentController
186         ec = None
187         
188         ecnode_list = doc.getElementsByTagName("experiment")
189         for ecnode in ecnode_list:
190             if ecnode.nodeType == doc.ELEMENT_NODE:
191                 exp_id = xmldecode(ecnode.getAttribute("exp_id"))
192                 run_id = xmldecode(ecnode.getAttribute("run_id"))
193                 local_dir = xmldecode(ecnode.getAttribute("local_dir"))
194                 nthreads = xmldecode(ecnode.getAttribute("nthreads"))
195             
196                 os.environ["NEPI_NTHREADS"] = nthreads
197                 ec = ExperimentController(exp_id = exp_id, local_dir = local_dir)
198
199                 connections = set()
200
201                 rmnode_list = ecnode.getElementsByTagName("rm")
202                 for rmnode in rmnode_list:
203                     if rmnode.nodeType == doc.ELEMENT_NODE:
204                         self._rm_from_xml(doc, rmnode, ec, connections)
205
206                 for (guid1, guid2) in connections:
207                     ec.register_connection(guid1, guid2)
208
209                 break
210
211         return ec
212
213     def _rm_from_xml(self, doc, rmnode, ec, connections):
214         start_time = None
215         stop_time = None
216         discover_time = None
217         provision_time = None
218         ready_time = None
219         release_time = None
220         failed_time = None
221
222         guid = xmldecode(rmnode.getAttribute("guid"), int)
223         rtype = xmldecode(rmnode.getAttribute("rtype"))
224
225         # FOR NOW ONLY STATE NEW IS ALLOWED
226         state = 0
227         """
228         state = xmldecode(rmnode.getAttribute("state"), int)
229
230         if rmnode.hasAttribute("start_time"):
231             start_time = xmldecode(rmnode.getAttribute("start_time"), 
232                     datetime.datetime)
233         if rmnode.hasAttribute("stop_time"):
234             stop_time = xmldecode(rmnode.getAttribute("stop_time"), 
235                     datetime.datetime)
236         if rmnode.hasAttribute("discover_time"):
237             dicover_time = xmldecode(rmnode.getAttribute("discover_time"), 
238                     datetime.datetime)
239         if rmnode.hasAttribute("provision_time"):
240             provision_time = xmldecode(rmnode.getAttribute("provision_time"),
241                     datetime.datetime)
242         if rmnode.hasAttribute("ready_time"):
243             ready_time = xmldecode(rmnode.getAttribute("ready_time"),
244                     datetime.datetime)
245         if rmnode.hasAttribute("release_time"):
246             release_time = xmldecode(rmnode.getAttribute("release_time"),
247                     datetime.datetime)
248         if rmnode.hasAttribute("failed_time"):
249             failed_time = xmldecode(rmnode.getAttribute("failed_time"),
250                     datetime.datetime)
251         """
252
253         ec.register_resource(rtype, guid = guid)
254         rm = ec.get_resource(guid)
255         rm.set_state_time(state, "_start_time", start_time)
256         rm.set_state_time(state, "_stop_time", stop_time)
257         rm.set_state_time(state, "_discover_time", discover_time)
258         rm.set_state_time(state, "_provision_time", provision_time)
259         rm.set_state_time(state, "_ready_time", ready_time)
260         rm.set_state_time(state, "_release_time", release_time)
261         rm.set_state_time(state, "_failed_time", failed_time)
262         
263         anode_list = rmnode.getElementsByTagName("attributes")
264         if anode_list:
265             aanode_list = anode_list[0].getElementsByTagName("attribute") 
266             for aanode in aanode_list:
267                 name = xmldecode(aanode.getAttribute("name"))
268                 value = xmldecode(aanode.getAttribute("value"))
269                 tipe = xmldecode(aanode.getAttribute("type"))
270                 value = to_type(tipe, value)
271                 rm.set(name, value)
272
273         cnode_list = rmnode.getElementsByTagName("connections")
274         if cnode_list:
275             ccnode_list = cnode_list[0].getElementsByTagName("connection") 
276             for ccnode in ccnode_list:
277                 guid2 = xmldecode(ccnode.getAttribute("guid"), int)
278                 connections.add((guid, guid2))
279
280         tnode_list = rmnode.getElementsByTagName("traces")
281         if tnode_list:
282             ttnode_list = tnode_list[0].getElementsByTagName("trace") 
283             for ttnode in ttnode_list:
284                 name = xmldecode(ttnode.getAttribute("name"))
285                 ec.enable_trace(guid, name)
286
287         cnnode_list = rmnode.getElementsByTagName("conditions")
288         if cnnode_list:
289             ccnnode_list = cnnode_list[0].getElementsByTagName("condition") 
290             for ccnnode in ccnnode_list:
291                 action = xmldecode(ccnnode.getAttribute("action"), int)
292                 group = xmldecode(ccnnode.getAttribute("group"), eval)
293                 state = xmldecode(ccnnode.getAttribute("state"), int)
294                 time = xmldecode(ccnnode.getAttribute("time"))
295                 time = to_type('STRING', time)
296                 ec.register_condition(guid, action, group, state, time = time)
297