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>
20 from nepi.util.netgraph import NetGraph, TopologyType
21 from nepi.util.timefuncs import stformat, tsformat
23 from xml.dom import minidom
35 if isinstance(s, str):
36 rv = s.decode("latin1")
37 if isinstance(s, datetime.datetime):
39 elif not isinstance(s, unicode):
43 return rv.replace(u'\x00',u'�')
45 def xmldecode(s, cast = str):
46 ret = s.replace(u'�',u'\x00').encode("ascii")
53 if isinstance(value, bool):
55 if isinstance(value, int):
57 if isinstance(value, float):
62 def to_type(type, value):
69 return value == "True"
75 class ECXMLParser(object):
78 doc = minidom.Document()
80 self._ec_to_xml(doc, ec)
83 xml = doc.toprettyxml(indent=" ", encoding="UTF-8")
85 print >>sys.stderr, "Oops: generating XML from %s" % (data,)
90 def _ec_to_xml(self, doc, ec):
91 ecnode = doc.createElement("experiment")
92 ecnode.setAttribute("exp_id", xmlencode(ec.exp_id))
93 ecnode.setAttribute("run_id", xmlencode(ec.run_id))
94 ecnode.setAttribute("nthreads", xmlencode(ec.nthreads))
95 ecnode.setAttribute("local_dir", xmlencode(ec.local_dir))
96 doc.appendChild(ecnode)
98 if ec.netgraph != None:
99 self._netgraph_to_xml(doc, ecnode, ec)
101 rmsnode = doc.createElement("rms")
102 ecnode.appendChild(rmsnode)
104 for guid, rm in ec._resources.iteritems():
105 self._rm_to_xml(doc, rmsnode, ec, guid, rm)
109 def _netgraph_to_xml(self, doc, ecnode, ec):
110 ngnode = doc.createElement("topology")
111 ngnode.setAttribute("topo-type", xmlencode(ec.netgraph.topo_type))
112 ecnode.appendChild(ngnode)
114 self. _netgraph_nodes_to_xml(doc, ngnode, ec)
115 self. _netgraph_edges_to_xml(doc, ngnode, ec)
117 def _netgraph_nodes_to_xml(self, doc, ngnode, ec):
118 ngnsnode = doc.createElement("nodes")
119 ngnode.appendChild(ngnsnode)
121 for nid in ec.netgraph.nodes():
122 ngnnode = doc.createElement("node")
123 ngnnode.setAttribute("nid", xmlencode(nid))
124 ngnsnode.appendChild(ngnnode)
126 # Mark ources and targets
127 if ec.netgraph.is_source(nid):
128 ngnnode.setAttribute("source", xmlencode(True))
130 if ec.netgraph.is_target(nid):
131 ngnnode.setAttribute("target", xmlencode(True))
134 annosnode = doc.createElement("node-annotations")
135 add_annotations = False
136 for name in ec.netgraph.node_annotations(nid):
137 add_annotations = True
138 value = ec.netgraph.node_annotation(nid, name)
139 annonode = doc.createElement("node-annotation")
140 annonode.setAttribute("name", xmlencode(name))
141 annonode.setAttribute("value", xmlencode(value))
142 annonode.setAttribute("type", from_type(value))
143 annosnode.appendChild(annonode)
146 ngnnode.appendChild(annosnode)
148 def _netgraph_edges_to_xml(self, doc, ngnode, ec):
149 ngesnode = doc.createElement("edges")
150 ngnode.appendChild(ngesnode)
152 for nid1, nid2 in ec.netgraph.edges():
153 ngenode = doc.createElement("edge")
154 ngenode.setAttribute("nid1", xmlencode(nid1))
155 ngenode.setAttribute("nid2", xmlencode(nid2))
156 ngesnode.appendChild(ngenode)
159 annosnode = doc.createElement("edge-annotations")
160 add_annotations = False
161 for name in ec.netgraph.edge_annotations(nid1, nid2):
162 add_annotations = True
163 value = ec.netgraph.edge_annotation(nid1, nid2, name)
164 annonode = doc.createElement("edge-annotation")
165 annonode.setAttribute("name", xmlencode(name))
166 annonode.setAttribute("value", xmlencode(value))
167 annonode.setAttribute("type", from_type(value))
168 annosnode.appendChild(annonode)
171 ngenode.appendChild(annosnode)
173 def _rm_to_xml(self, doc, rmsnode, ec, guid, rm):
174 rmnode = doc.createElement("rm")
175 rmnode.setAttribute("guid", xmlencode(guid))
176 rmnode.setAttribute("rtype", xmlencode(rm._rtype))
177 rmnode.setAttribute("state", xmlencode(rm._state))
179 rmnode.setAttribute("start_time", xmlencode(rm._start_time))
181 rmnode.setAttribute("stop_time", xmlencode(rm._stop_time))
182 if rm._discover_time:
183 rmnode.setAttribute("discover_time", xmlencode(rm._discover_time))
184 if rm._provision_time:
185 rmnode.setAttribute("provision_time", xmlencode(rm._provision_time))
187 rmnode.setAttribute("ready_time", xmlencode(rm._ready_time))
189 rmnode.setAttribute("release_time", xmlencode(rm._release_time))
191 rmnode.setAttribute("failed_time", xmlencode(rm._failed_time))
192 rmsnode.appendChild(rmnode)
194 anode = doc.createElement("attributes")
197 for attr in rm._attrs.values():
200 aanode = doc.createElement("attribute")
201 aanode.setAttribute("name", xmlencode(attr.name))
202 aanode.setAttribute("value", xmlencode(attr.value))
203 aanode.setAttribute("type", from_type(attr.value))
204 anode.appendChild(aanode)
207 rmnode.appendChild(anode)
209 cnode = doc.createElement("connections")
212 for guid in rm._connections:
214 ccnode = doc.createElement("connection")
215 ccnode.setAttribute("guid", xmlencode(guid))
216 cnode.appendChild(ccnode)
219 rmnode.appendChild(cnode)
221 cnnode = doc.createElement("conditions")
224 for action, conds in rm._conditions.iteritems():
226 for (group, state, time) in conds:
227 ccnnode = doc.createElement("condition")
228 ccnnode.setAttribute("action", xmlencode(action))
229 ccnnode.setAttribute("group", xmlencode(group))
230 ccnnode.setAttribute("state", xmlencode(state))
231 ccnnode.setAttribute("time", xmlencode(time))
232 cnnode.appendChild(ccnnode)
235 rmnode.appendChild(cnnode)
237 tnode = doc.createElement("traces")
240 for trace in rm._trcs.values():
243 ttnode = doc.createElement("trace")
244 ttnode.setAttribute("name", xmlencode(trace.name))
245 tnode.appendChild(ttnode)
248 rmnode.appendChild(tnode)
250 def from_xml(self, xml):
251 doc = minidom.parseString(xml)
252 return self._ec_from_xml(doc)
254 def _ec_from_xml(self, doc):
255 from nepi.execution.ec import ExperimentController
258 ecnode_list = doc.getElementsByTagName("experiment")
259 for ecnode in ecnode_list:
260 if ecnode.nodeType == doc.ELEMENT_NODE:
261 exp_id = xmldecode(ecnode.getAttribute("exp_id"))
262 run_id = xmldecode(ecnode.getAttribute("run_id"))
263 local_dir = xmldecode(ecnode.getAttribute("local_dir"))
265 # Configure number of preocessing threads
266 nthreads = xmldecode(ecnode.getAttribute("nthreads"))
267 os.environ["NEPI_NTHREADS"] = nthreads
269 # Deserialize netgraph
270 netgraph = self._netgraph_from_xml(doc, ecnode)
271 topo_type = netgraph.topo_type if netgraph else None
274 ec = ExperimentController(exp_id = exp_id, local_dir = local_dir,
275 topology = netgraph.topology, topo_type = topo_type)
279 rmsnode_list = ecnode.getElementsByTagName("rms")
281 rmnode_list = rmsnode_list[0].getElementsByTagName("rm")
282 for rmnode in rmnode_list:
283 if rmnode.nodeType == doc.ELEMENT_NODE:
284 self._rm_from_xml(doc, rmnode, ec, connections)
286 for (guid1, guid2) in connections:
287 ec.register_connection(guid1, guid2)
293 def _netgraph_from_xml(self, doc, ecnode):
296 topology = ecnode.getElementsByTagName("topology")
298 topology = topology[0]
299 topo_type = xmldecode(topology.getAttribute("topo-type"))
301 netgraph = NetGraph(topo_type = topo_type)
303 ngnsnode_list = topology.getElementsByTagName("nodes")
305 ngnsnode = ngnsnode_list[0].getElementsByTagName("node")
306 for ngnnode in ngnsnode:
307 nid = xmldecode(ngnnode.getAttribute("nid"))
308 netgraph.add_node(nid)
310 if ngnnode.hasAttribute("source"):
311 netgraph.set_source(nid)
312 if ngnnode.hasAttribute("target"):
313 netgraph.set_target(nid)
315 annosnode_list = ngnnode.getElementsByTagName("node-annotations")
318 annosnode = annosnode_list[0].getElementsByTagName("node-annotation")
319 for annonode in annosnode:
320 name = xmldecode(annonode.getAttribute("name"))
323 ips = xmldecode(annonode.getAttribute("value"), eval) # list
325 netgraph.annotate_node_ip(nid, ip)
327 value = xmldecode(annonode.getAttribute("value"))
328 tipe = xmldecode(annonode.getAttribute("type"))
329 value = to_type(tipe, value)
330 netgraph.annotate_node(nid, name, value)
332 ngesnode_list = topology.getElementsByTagName("edges")
334 ngesnode = ngesnode_list[0].getElementsByTagName("edge")
335 for ngenode in ngesnode:
336 nid1 = xmldecode(ngenode.getAttribute("nid1"))
337 nid2 = xmldecode(ngenode.getAttribute("nid2"))
338 netgraph.add_edge(nid1, nid2)
340 annosnode_list = ngenode.getElementsByTagName("edge-annotations")
342 annosnode = annosnode_list[0].getElementsByTagName("edge-annotation")
343 for annonode in annosnode:
344 name = xmldecode(annonode.getAttribute("name"))
347 net = xmldecode(annonode.getAttribute("value"), eval) # dict
348 netgraph.annotate_edge_net(nid1, nid2, net[nid1], net[nid2],
349 net["mask"], net["network"], net["prefix"])
351 value = xmldecode(annonode.getAttribute("value"))
352 tipe = xmldecode(annonode.getAttribute("type"))
353 value = to_type(tipe, value)
354 netgraph.annotate_edge(nid1, nid2, name, value)
357 def _rm_from_xml(self, doc, rmnode, ec, connections):
361 provision_time = None
366 guid = xmldecode(rmnode.getAttribute("guid"), int)
367 rtype = xmldecode(rmnode.getAttribute("rtype"))
369 # FOR NOW ONLY STATE NEW IS ALLOWED
372 state = xmldecode(rmnode.getAttribute("state"), int)
374 if rmnode.hasAttribute("start_time"):
375 start_time = xmldecode(rmnode.getAttribute("start_time"),
377 if rmnode.hasAttribute("stop_time"):
378 stop_time = xmldecode(rmnode.getAttribute("stop_time"),
380 if rmnode.hasAttribute("discover_time"):
381 dicover_time = xmldecode(rmnode.getAttribute("discover_time"),
383 if rmnode.hasAttribute("provision_time"):
384 provision_time = xmldecode(rmnode.getAttribute("provision_time"),
386 if rmnode.hasAttribute("ready_time"):
387 ready_time = xmldecode(rmnode.getAttribute("ready_time"),
389 if rmnode.hasAttribute("release_time"):
390 release_time = xmldecode(rmnode.getAttribute("release_time"),
392 if rmnode.hasAttribute("failed_time"):
393 failed_time = xmldecode(rmnode.getAttribute("failed_time"),
397 ec.register_resource(rtype, guid = guid)
398 rm = ec.get_resource(guid)
399 rm.set_state_time(state, "_start_time", start_time)
400 rm.set_state_time(state, "_stop_time", stop_time)
401 rm.set_state_time(state, "_discover_time", discover_time)
402 rm.set_state_time(state, "_provision_time", provision_time)
403 rm.set_state_time(state, "_ready_time", ready_time)
404 rm.set_state_time(state, "_release_time", release_time)
405 rm.set_state_time(state, "_failed_time", failed_time)
407 anode_list = rmnode.getElementsByTagName("attributes")
409 aanode_list = anode_list[0].getElementsByTagName("attribute")
410 for aanode in aanode_list:
411 name = xmldecode(aanode.getAttribute("name"))
412 value = xmldecode(aanode.getAttribute("value"))
413 tipe = xmldecode(aanode.getAttribute("type"))
414 value = to_type(tipe, value)
417 cnode_list = rmnode.getElementsByTagName("connections")
419 ccnode_list = cnode_list[0].getElementsByTagName("connection")
420 for ccnode in ccnode_list:
421 guid2 = xmldecode(ccnode.getAttribute("guid"), int)
422 connections.add((guid, guid2))
424 tnode_list = rmnode.getElementsByTagName("traces")
426 ttnode_list = tnode_list[0].getElementsByTagName("trace")
427 for ttnode in ttnode_list:
428 name = xmldecode(ttnode.getAttribute("name"))
429 ec.enable_trace(guid, name)
431 cnnode_list = rmnode.getElementsByTagName("conditions")
433 ccnnode_list = cnnode_list[0].getElementsByTagName("condition")
434 for ccnnode in ccnnode_list:
435 action = xmldecode(ccnnode.getAttribute("action"), int)
436 group = xmldecode(ccnnode.getAttribute("group"), eval) # list
437 state = xmldecode(ccnnode.getAttribute("state"), int)
438 time = xmldecode(ccnnode.getAttribute("time"))
439 time = to_type('STRING', time)
440 ec.register_condition(guid, action, group, state, time = time)