X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Futil%2Fparsers%2Fxml_parser.py;h=d82ea691afad1af337e74b8bd6e02f7c0d9e573a;hb=3fe2e6f7812888dc1366915545dd2243ff6fb1bb;hp=d5bc8a3fe36fbd8063e60bc042a808c3721c8fb4;hpb=d83307efc3a24a5d5b307bfb6d575368d1a10f64;p=nepi.git diff --git a/src/nepi/util/parsers/xml_parser.py b/src/nepi/util/parsers/xml_parser.py index d5bc8a3f..d82ea691 100644 --- a/src/nepi/util/parsers/xml_parser.py +++ b/src/nepi/util/parsers/xml_parser.py @@ -3,9 +3,8 @@ # Copyright (C) 2013 INRIA # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,6 +16,9 @@ # # Author: Alina Quereilhac +from __future__ import print_function + +from nepi.util.netgraph import NetGraph, TopologyType from nepi.util.timefuncs import stformat, tsformat from xml.dom import minidom @@ -30,22 +32,44 @@ BOOL = "bool" INTEGER = "integer" DOUBLE = "float" -def xmlencode(s): - if isinstance(s, str): - rv = s.decode("latin1") - if isinstance(s, datetime.datetime): - rv = tsformat(s) - elif not isinstance(s, unicode): - rv = unicode(s) - else: - rv = s - return rv.replace(u'\x00',u'�') - +from six import PY2 + +if PY2: + # xxx old py2 code had a hack, that had 'latin1' hardcoded + # as the encoding for 8-byte strings + # this is very wrong; I keep it for now + # but will probably remove it altogether some day + def xmlencode(s): + """xml encoder for python2""" + if isinstance(s, str): + rv = s.decode("latin1") + if isinstance(s, datetime.datetime): + rv = tsformat(s) + elif not isinstance(s, unicode): + rv = unicode(s) + else: + rv = s + return rv.replace(u'\x00',u'�') +else: + # use sys.getdefaultencoding() to decode bytes into string + def xmlencode(s): + """xml encoder for python3""" + if isinstance(s, datetime.datetime): + rv = tsformat(s) + elif isinstance(s, bytes): + rv = s.decode(sys.getdefaultencoding()) + else: + rv = s + return rv.replace('\x00', '�') + def xmldecode(s, cast = str): - ret = s.replace(u'�',u'\x00').encode("ascii") - ret = cast(ret) - if s == "None": + if s is None: return None + if PY2: + ret = s.replace(u'�', u'\x00').encode("ascii") + else: + ret = s.replace('�', '\x00') + ret = cast(ret) return ret def from_type(value): @@ -81,7 +105,7 @@ class ECXMLParser(object): try: xml = doc.toprettyxml(indent=" ", encoding="UTF-8") except: - print >>sys.stderr, "Oops: generating XML from %s" % (data,) + print("Oops: generating XML from %s" % (data,), file=sys.stderr) raise return xml @@ -91,14 +115,88 @@ class ECXMLParser(object): ecnode.setAttribute("exp_id", xmlencode(ec.exp_id)) ecnode.setAttribute("run_id", xmlencode(ec.run_id)) ecnode.setAttribute("nthreads", xmlencode(ec.nthreads)) + ecnode.setAttribute("local_dir", xmlencode(ec.local_dir)) doc.appendChild(ecnode) - for guid, rm in ec._resources.iteritems(): - self._rm_to_xml(doc, ecnode, ec, guid, rm) + if ec.netgraph != None: + self._netgraph_to_xml(doc, ecnode, ec) - return doc + rmsnode = doc.createElement("rms") + ecnode.appendChild(rmsnode) + + for guid, rm in ec._resources.items(): + self._rm_to_xml(doc, rmsnode, ec, guid, rm) - def _rm_to_xml(self, doc, ecnode, ec, guid, rm): + return doc + + def _netgraph_to_xml(self, doc, ecnode, ec): + ngnode = doc.createElement("topology") + ngnode.setAttribute("topo-type", xmlencode(ec.netgraph.topo_type)) + ecnode.appendChild(ngnode) + + self. _netgraph_nodes_to_xml(doc, ngnode, ec) + self. _netgraph_edges_to_xml(doc, ngnode, ec) + + def _netgraph_nodes_to_xml(self, doc, ngnode, ec): + ngnsnode = doc.createElement("nodes") + ngnode.appendChild(ngnsnode) + + for nid in ec.netgraph.nodes(): + ngnnode = doc.createElement("node") + ngnnode.setAttribute("nid", xmlencode(nid)) + ngnnode.setAttribute("nid-type", from_type(nid)) + ngnsnode.appendChild(ngnnode) + + # Mark ources and targets + if ec.netgraph.is_source(nid): + ngnnode.setAttribute("source", xmlencode(True)) + + if ec.netgraph.is_target(nid): + ngnnode.setAttribute("target", xmlencode(True)) + + # Node annotations + annosnode = doc.createElement("node-annotations") + add_annotations = False + for name in ec.netgraph.node_annotations(nid): + add_annotations = True + value = ec.netgraph.node_annotation(nid, name) + annonode = doc.createElement("node-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngnnode.appendChild(annosnode) + + def _netgraph_edges_to_xml(self, doc, ngnode, ec): + ngesnode = doc.createElement("edges") + ngnode.appendChild(ngesnode) + + for nid1, nid2 in ec.netgraph.edges(): + ngenode = doc.createElement("edge") + ngenode.setAttribute("nid1", xmlencode(nid1)) + ngenode.setAttribute("nid1-type", from_type(nid1)) + ngenode.setAttribute("nid2", xmlencode(nid2)) + ngenode.setAttribute("nid2-type", from_type(nid2)) + ngesnode.appendChild(ngenode) + + # Edge annotations + annosnode = doc.createElement("edge-annotations") + add_annotations = False + for name in ec.netgraph.edge_annotations(nid1, nid2): + add_annotations = True + value = ec.netgraph.edge_annotation(nid1, nid2, name) + annonode = doc.createElement("edge-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngenode.appendChild(annosnode) + + def _rm_to_xml(self, doc, rmsnode, ec, guid, rm): rmnode = doc.createElement("rm") rmnode.setAttribute("guid", xmlencode(guid)) rmnode.setAttribute("rtype", xmlencode(rm._rtype)) @@ -117,7 +215,7 @@ class ECXMLParser(object): rmnode.setAttribute("release_time", xmlencode(rm._release_time)) if rm._failed_time: rmnode.setAttribute("failed_time", xmlencode(rm._failed_time)) - ecnode.appendChild(rmnode) + rmsnode.appendChild(rmnode) anode = doc.createElement("attributes") attributes = False @@ -149,7 +247,7 @@ class ECXMLParser(object): cnnode = doc.createElement("conditions") conditions = False - for action, conds in rm._conditions.iteritems(): + for action, conds in rm._conditions.items(): conditions = True for (group, state, time) in conds: ccnnode = doc.createElement("condition") @@ -188,17 +286,34 @@ class ECXMLParser(object): if ecnode.nodeType == doc.ELEMENT_NODE: exp_id = xmldecode(ecnode.getAttribute("exp_id")) run_id = xmldecode(ecnode.getAttribute("run_id")) + local_dir = xmldecode(ecnode.getAttribute("local_dir")) + + # Configure number of preocessing threads nthreads = xmldecode(ecnode.getAttribute("nthreads")) - os.environ["NEPI_NTHREADS"] = nthreads - ec = ExperimentController(exp_id = exp_id) + + # Deserialize netgraph + topology = None + topo_type = None + + netgraph = self._netgraph_from_xml(doc, ecnode) + + if netgraph: + topo_type = netgraph.topo_type + topology = netgraph.topology + + # Instantiate EC + ec = ExperimentController(exp_id = exp_id, local_dir = local_dir, + topology = topology, topo_type = topo_type) connections = set() - rmnode_list = ecnode.getElementsByTagName("rm") - for rmnode in rmnode_list: - if rmnode.nodeType == doc.ELEMENT_NODE: - self._rm_from_xml(doc, rmnode, ec, connections) + rmsnode_list = ecnode.getElementsByTagName("rms") + if rmsnode_list: + rmnode_list = rmsnode_list[0].getElementsByTagName("rm") + for rmnode in rmnode_list: + if rmnode.nodeType == doc.ELEMENT_NODE: + self._rm_from_xml(doc, rmnode, ec, connections) for (guid1, guid2) in connections: ec.register_connection(guid1, guid2) @@ -207,6 +322,78 @@ class ECXMLParser(object): return ec + def _netgraph_from_xml(self, doc, ecnode): + netgraph = None + + topology = ecnode.getElementsByTagName("topology") + if topology: + topology = topology[0] + topo_type = xmldecode(topology.getAttribute("topo-type")) + + netgraph = NetGraph(topo_type = topo_type) + + ngnsnode_list = topology.getElementsByTagName("nodes") + if ngnsnode_list: + ngnsnode = ngnsnode_list[0].getElementsByTagName("node") + for ngnnode in ngnsnode: + nid = xmldecode(ngnnode.getAttribute("nid")) + tipe = xmldecode(ngnnode.getAttribute("nid-type")) + nid = to_type(tipe, nid) + netgraph.add_node(nid) + + if ngnnode.hasAttribute("source"): + netgraph.set_source(nid) + if ngnnode.hasAttribute("target"): + netgraph.set_target(nid) + + annosnode_list = ngnnode.getElementsByTagName("node-annotations") + + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("node-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "ips": + ips = xmldecode(annonode.getAttribute("value"), eval) # list + for ip in ips: + netgraph.annotate_node_ip(nid, ip) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_node(nid, name, value) + + ngesnode_list = topology.getElementsByTagName("edges") + if ngesnode_list: + ngesnode = ngesnode_list[0].getElementsByTagName("edge") + for ngenode in ngesnode: + nid1 = xmldecode(ngenode.getAttribute("nid1")) + tipe1 = xmldecode(ngenode.getAttribute("nid1-type")) + nid1 = to_type(tipe1, nid1) + + nid2 = xmldecode(ngenode.getAttribute("nid2")) + tipe2 = xmldecode(ngenode.getAttribute("nid2-type")) + nid2 = to_type(tipe2, nid2) + + netgraph.add_edge(nid1, nid2) + + annosnode_list = ngenode.getElementsByTagName("edge-annotations") + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("edge-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "net": + net = xmldecode(annonode.getAttribute("value"), eval) # dict + netgraph.annotate_edge_net(nid1, nid2, net[nid1], net[nid2], + net["mask"], net["network"], net["prefix"]) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_edge(nid1, nid2, name, value) + return netgraph + def _rm_from_xml(self, doc, rmnode, ec, connections): start_time = None stop_time = None @@ -286,7 +473,7 @@ class ECXMLParser(object): ccnnode_list = cnnode_list[0].getElementsByTagName("condition") for ccnnode in ccnnode_list: action = xmldecode(ccnnode.getAttribute("action"), int) - group = xmldecode(ccnnode.getAttribute("group"), eval) + group = xmldecode(ccnnode.getAttribute("group"), eval) # list state = xmldecode(ccnnode.getAttribute("state"), int) time = xmldecode(ccnnode.getAttribute("time")) time = to_type('STRING', time)