[Libvirt-cim] [PATCH] [TEST] Use python-lxml instead of PyXML

Eduardo Lima (Etrunko) eblima at linux.vnet.ibm.com
Mon Dec 5 16:24:05 UTC 2011


From: Eduardo Lima (Etrunko) <eblima at br.ibm.com>

PyXML is a legacy python XML library which won't work with recent versions of
python unless you patch the code. The following link describes the problem:

http://stackoverflow.com/questions/4953600/pyxml-on-ubuntu

In summary, when trying to install PyXML with easy_install, you get an error
because it tries to use 'as' which is a reserved keyword introduced in python
2.5.

This patch removes dependency of PyXML in favor of python-lxml, which provides
bindings to the very complete and fast libxml2:

http://lxml.de/intro.html

Signed-off-by: Eduardo Lima (Etrunko) <eblima at br.ibm.com>
---
 suites/libvirt-cim/cimtest/FilterList/helper.py    |    8 +--
 .../12_referenced_config.py                        |   14 +---
 .../24_define_sys_features.py                      |    6 +-
 suites/libvirt-cim/lib/XenKvmLib/test_xml.py       |   27 +++---
 suites/libvirt-cim/lib/XenKvmLib/vxml.py           |   95 ++++++++++----------
 5 files changed, 69 insertions(+), 81 deletions(-)

diff --git a/suites/libvirt-cim/cimtest/FilterList/helper.py b/suites/libvirt-cim/cimtest/FilterList/helper.py
index 138f941..9ae2f62 100644
--- a/suites/libvirt-cim/cimtest/FilterList/helper.py
+++ b/suites/libvirt-cim/cimtest/FilterList/helper.py
@@ -35,11 +35,7 @@ from XenKvmLib.vxml import get_class
 import VirtLib
 from VirtLib.utils import run_remote
 
-try:
-    from xml.etree import cElementTree as ElementTree
-except:
-    from xml.etree import ElementTree
-
+from lxml import etree
 
 class BaseTestObject(object):
 
@@ -247,7 +243,7 @@ class FilterListTest(BaseTestObject):
 
         # Remove all unecessary spaces and new lines
         _xml = "".join([a.strip() for a in out.split("\n") if a])
-        return ElementTree.fromstring(_xml)
+        return etree.fromstring(_xml)
     # libvirt_filter_dumpxml
 
     def libvirt_entries_in_filter_lists(self):
diff --git a/suites/libvirt-cim/cimtest/VirtualSystemManagementService/12_referenced_config.py b/suites/libvirt-cim/cimtest/VirtualSystemManagementService/12_referenced_config.py
index 7af65fd..24b47e9 100644
--- a/suites/libvirt-cim/cimtest/VirtualSystemManagementService/12_referenced_config.py
+++ b/suites/libvirt-cim/cimtest/VirtualSystemManagementService/12_referenced_config.py
@@ -102,20 +102,8 @@ def setup_second_guest(ip, virt, cxml2, ref):
     return PASS, "define"
 
 def get_dom_disk_src(xml, ip):
-    disk_list = []
-
     xml.dumpxml(ip)
-    myxml = xml.get_formatted_xml()
-
-    lines = myxml.splitlines()
-    for l in lines:
-        if l.find("source file=") != -1:
-            disk = l.split('=')[1]
-            disk = disk.lstrip('\'')
-            disk = disk.rstrip('\'/>')
-            disk_list.append(disk)
-   
-    return disk_list 
+    return xml.xdoc.xpath("/domain/devices/disk/source/@file")
 
 @do_main(sup_types)
 def main():
diff --git a/suites/libvirt-cim/cimtest/VirtualSystemManagementService/24_define_sys_features.py b/suites/libvirt-cim/cimtest/VirtualSystemManagementService/24_define_sys_features.py
index 9716cd1..42c59ec 100644
--- a/suites/libvirt-cim/cimtest/VirtualSystemManagementService/24_define_sys_features.py
+++ b/suites/libvirt-cim/cimtest/VirtualSystemManagementService/24_define_sys_features.py
@@ -48,13 +48,13 @@ def main():
 
         cxml.dumpxml(options.ip)
 
-        if cxml.xml_get_pae() == None:
+        if cxml.xml_get_pae() is None:
             raise Exception("Failed to set pae for dom: %s" % default_dom)
 
-        if cxml.xml_get_acpi() == None:
+        if cxml.xml_get_acpi() is None:
             raise Exception("Failed to set acpi for dom: %s" % default_dom)
 
-        if cxml.xml_get_apic() == None:
+        if cxml.xml_get_apic() is None:
             raise Exception("Failed to set apic for dom: %s" % default_dom)
 
         status = PASS
diff --git a/suites/libvirt-cim/lib/XenKvmLib/test_xml.py b/suites/libvirt-cim/lib/XenKvmLib/test_xml.py
index 033275b..b32ae4c 100755
--- a/suites/libvirt-cim/lib/XenKvmLib/test_xml.py
+++ b/suites/libvirt-cim/lib/XenKvmLib/test_xml.py
@@ -29,8 +29,7 @@ import os
 import sys 
 import random
 from VirtLib import utils
-from xml import xpath
-from xml.dom import minidom, Node
+from lxml import etree
 from CimTest.Globals import logger
 from XenKvmLib.test_doms import set_uuid, create_vnet
 from VirtLib.live import available_bridges
@@ -212,22 +211,26 @@ def dumpxml(name, server, virt="Xen"):
         return o
 
 def get_value_xpath(xmlStr, xpathStr):
-    xmldoc = minidom.parseString(xmlStr)
-    nodes = xpath.Evaluate(xpathStr, xmldoc.documentElement)
+    xmldoc = etree.fromstring(xmlStr)
+    nodes = xmldoc.xpath(xpathStr)
 
     if len(nodes) != 1:
         raise LookupError('Zero or multiple xpath results found!')
 
     node = nodes[0]
-    if node.nodeType == Node.ATTRIBUTE_NODE:
-        return node.value
-    if node.nodeType == Node.TEXT_NODE:
-        return node.toxml()
-    if node.nodeType == Node.ELEMENT_NODE:
+    ret = ''
+
+    if etree.iselement(node):
+        ret = node.text
+        for child in node:
+            ret = ret + child.text
+    elif isinstance(node, str):
+        ret = node
+
+    if ret is None:
         ret = ''
-        for child in node.childNodes:
-            ret = ret + child.toxml()
-        return ret
+
+    return ret
 
 def xml_get_dom_name(xmlStr):
     return get_value_xpath(xmlStr,
diff --git a/suites/libvirt-cim/lib/XenKvmLib/vxml.py b/suites/libvirt-cim/lib/XenKvmLib/vxml.py
index 15859c1..51a4166 100644
--- a/suites/libvirt-cim/lib/XenKvmLib/vxml.py
+++ b/suites/libvirt-cim/lib/XenKvmLib/vxml.py
@@ -34,15 +34,10 @@ import sys
 import random
 import platform
 import tempfile
-from time import sleep
 import pywbem
-from xml.dom import minidom, Node
-from xml import xpath
 
-try:
-    from xml.etree import cElementTree as ElementTree
-except:
-    from xml.etree import ElementTree
+from lxml import etree
+from time import sleep
 
 from VirtLib import utils, live
 from XenKvmLib.xm_virt_util import get_bridge_from_network_xml, bootloader, \
@@ -64,35 +59,37 @@ class XMLClass:
     xdoc = None
 
     def __init__(self):
-        self.xdoc = minidom.Document()
         self.refresh()
 
     def __str__(self):
         return self.xml_string
 
     def refresh(self):
-        self.xml_string = self.xdoc.toxml()
+        if self.xdoc is not None:
+            self.xml_string = etree.tostring(self.xdoc)
 
     def get_node(self, ixpath):
-        node_list = xpath.Evaluate(ixpath, self.xdoc.documentElement)
+        if self.xdoc is None:
+            return None
+
+        node_list = self.xdoc.xpath(ixpath)
         if len(node_list) != 1:
             raise LookupError('Zero or multiple nodes found for XPath' + ixpath)
         return node_list[0]
+
     def add_sub_node(self, parent, node_name, text_cdata=None, **attrs):
         if isinstance(parent, basestring):
             pnode = self.get_node(parent)
         else:
             pnode = parent
 
-        node = self.xdoc.createElement(node_name)
-
-        for key in attrs.keys():
-            node.setAttribute(key, str(attrs[key]))
-
-        if text_cdata is not None:
-            node.appendChild(self.xdoc.createTextNode(str(text_cdata)))
+        if pnode is None:
+            self.xdoc = etree.Element(node_name, **attrs)
+            node = self.xdoc
+        else:
+            node = etree.SubElement(pnode, node_name, **attrs)
 
-        pnode.appendChild(node)
+        node.text = str(text_cdata)
         self.refresh()
 
         return node
@@ -103,13 +100,7 @@ class XMLClass:
         else:
             pnode = parent
         
-        for cnode in pnode.childNodes:
-            pnode.removeChild(cnode)
-            cnode.unlink()
-
-        if text_cdata is not None:
-            pnode.appendChild(self.xdoc.createTextNode(str(text_cdata)))
-
+        pnode.text = str(text_cdata)
         self.refresh()
 
     def set_attributes(self, node, **attrs):
@@ -118,8 +109,8 @@ class XMLClass:
         else:
             pnode = node
 
-        for key in attrs.keys():
-            pnode.setAttribute(key, str(attrs[key]))
+        for key, val in attrs.items():
+            pnode.set(key, val)
 
         self.refresh()
 
@@ -127,7 +118,7 @@ class XMLClass:
         '''Don't use this to define domain.
            Extra newline in the text node fails libvirt
         '''
-        return self.xdoc.toprettyxml()
+        return etree.tostring(self.xdoc, pretty_print=True)
 
     def get_value_xpath(self, xpathStr):
         try:
@@ -136,15 +127,19 @@ class XMLClass:
             logger.info('Zero or multiple node found')
             return None
 
-        if node.nodeType == Node.ATTRIBUTE_NODE:
-            return node.value
-        if node.nodeType == Node.TEXT_NODE:
-            return node.toxml()
-        if node.nodeType == Node.ELEMENT_NODE:
+        ret = ''
+
+        if etree.iselement(node):
+            ret = node.text
+            for child in node:
+                ret = ret + child.text
+        elif isinstance(node, basestring):
+            ret = node
+
+        if ret is None:
             ret = ''
-            for child in node.childNodes:
-                ret = ret + child.toxml()
-            return ret
+
+        return ret
     
 
 class Virsh:
@@ -220,7 +215,7 @@ class NetXML(Virsh, XMLClass):
 
         def _parse_net_dumpxml(_xml):
             try:
-                root = ElementTree.fromstring(_xml)
+                root = etree.fromstring(_xml)
                 ip_element = root.find("ip")
                 return ip_element.get("address")
             except:
@@ -247,7 +242,7 @@ class NetXML(Virsh, XMLClass):
                 return None
             else:
                 self.xml_string = net_xml
-                self.xdoc = minidom.parseString(self.xml_string)
+                self.xdoc = etree.fromstring(self.xml_string)
                 return 
     
         network = self.add_sub_node(self.xdoc, 'network')
@@ -337,7 +332,7 @@ class PoolXML(Virsh, XMLClass):
                 return None
             else:
                 self.xml_string = disk_xml
-                self.xdoc = minidom.parseString(self.xml_string)
+                self.xdoc = etree.fromstring(self.xml_string)
                 return
 
         pool = self.add_sub_node(self.xdoc, 'pool', type='dir')
@@ -547,8 +542,9 @@ class VirtXML(Virsh, XMLClass):
         cmd = 'virsh -c %s dumpxml %s 2>/dev/null' % (self.vuri, self.dname)
         s, o = utils.run_remote(ip, cmd)
         if s == 0:
-            self.xml_string = o
-            self.xdoc = minidom.parseString(self.xml_string)
+            o = "".join([i.strip() for i in o.split("\n") if i])
+            self.xdoc = etree.fromstring(o)
+            self.refresh()
 
     def _set_emulator(self, emu):
         self.add_sub_node('/domain/devices', 'emulator', emu)
@@ -562,7 +558,7 @@ class VirtXML(Virsh, XMLClass):
         # pick the 1st virtual bridge
         br = br_list[0]
         interface = self.get_node('/domain/devices/interface')
-        interface.setAttribute('type', 'bridge')
+        interface.set('type', 'bridge')
         self.add_sub_node(interface, 'source', bridge=br)
             
         return br
@@ -570,20 +566,25 @@ class VirtXML(Virsh, XMLClass):
     def _set_vbridge(self, ip, virt_type, net_name):
         vbr = get_bridge_from_network_xml(net_name, ip, virt=virt_type)
 
-        interface = self.get_node('/domain/devices/interface')
-        interface.setAttribute('type', 'bridge')
-        self.add_sub_node(interface, 'source', bridge=vbr)
+        if vbr is not None:
+            interface = self.get_node('/domain/devices/interface')
+            interface.set('type', 'bridge')
+            self.add_sub_node(interface, 'source', bridge=vbr)
 
         return vbr
 
     def set_interface_details(self, devices, net_mac, net_type, net_name, 
                               virt_type):
         interface = self.add_sub_node(devices, 'interface', type=net_type)
-        self.add_sub_node(interface, 'mac', address=net_mac)
+
+        if net_mac:
+            self.add_sub_node(interface, 'mac', address=net_mac)
+
         if net_type == 'bridge':
             self._set_vbridge(CIM_IP, virt_type, net_name)
         elif net_type == 'network':
-            self.add_sub_node(interface, 'source', network=net_name)
+            if net_name:
+                self.add_sub_node(interface, 'source', network=net_name)
         elif net_type == 'ethernet':
             pass
         elif net_type == 'user':
-- 
1.7.4.4




More information about the Libvirt-cim mailing list