Also move former xmlutils.py to xmlutils/utils.py and adjust the imports
accordingly to it.
Signed-off-by: Aline Manera <alinefm(a)linux.vnet.ibm.com>
---
src/kimchi/config.py.in | 2 +-
src/kimchi/model/host.py | 4 +--
src/kimchi/model/hostdev.py | 2 +-
src/kimchi/model/networks.py | 22 ++++++-------
src/kimchi/model/storagepools.py | 16 +++++-----
src/kimchi/model/storagevolumes.py | 5 ++-
src/kimchi/model/templates.py | 8 ++---
src/kimchi/model/vms.py | 21 ++++++-------
src/kimchi/xmlutils.py | 63 --------------------------------------
src/kimchi/xmlutils/__init__.py | 18 +++++++++++
src/kimchi/xmlutils/utils.py | 63 ++++++++++++++++++++++++++++++++++++++
tests/test_networkxml.py | 2 +-
tests/test_vmtemplate.py | 2 +-
13 files changed, 121 insertions(+), 107 deletions(-)
delete mode 100644 src/kimchi/xmlutils.py
create mode 100644 src/kimchi/xmlutils/__init__.py
create mode 100644 src/kimchi/xmlutils/utils.py
diff --git a/src/kimchi/config.py.in b/src/kimchi/config.py.in
index 097c017..4792421 100644
--- a/src/kimchi/config.py.in
+++ b/src/kimchi/config.py.in
@@ -27,7 +27,7 @@ import threading
from ConfigParser import SafeConfigParser
-from kimchi.xmlutils import xpath_get_text
+from kimchi.xmlutils.utils import xpath_get_text
__version__ = "@kimchiversion@"
__release__ = "@kimchirelease@"
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py
index 5d31809..1bc3ca2 100644
--- a/src/kimchi/model/host.py
+++ b/src/kimchi/model/host.py
@@ -30,7 +30,6 @@ from cherrypy.process.plugins import BackgroundTask
from kimchi import disks
from kimchi import netinfo
-from kimchi import xmlutils
from kimchi.basemodel import Singleton
from kimchi.model import hostdev
from kimchi.exception import InvalidOperation, InvalidParameter
@@ -41,6 +40,7 @@ from kimchi.model.vms import DOM_STATE_MAP
from kimchi.repositories import Repositories
from kimchi.swupdate import SoftwareUpdate
from kimchi.utils import add_task, kimchi_log
+from kimchi.xmlutils.utils import xpath_get_text
HOST_STATS_INTERVAL = 1
@@ -348,7 +348,7 @@ class DevicesModel(object):
for host in scsi_hosts:
xml = conn.nodeDeviceLookupByName(host).XMLDesc(0)
path = '/device/capability/capability/@type'
- if 'fc_host' in xmlutils.xpath_get_text(xml, path):
+ if 'fc_host' in xpath_get_text(xml, path):
ret.append(host)
return ret
# Double verification to catch the case where the libvirt
diff --git a/src/kimchi/model/hostdev.py b/src/kimchi/model/hostdev.py
index 58ca92e..2a4a311 100644
--- a/src/kimchi/model/hostdev.py
+++ b/src/kimchi/model/hostdev.py
@@ -23,7 +23,7 @@ from pprint import pprint
from kimchi.model.libvirtconnection import LibvirtConnection
from kimchi.utils import kimchi_log
-from kimchi.xmlutils import dictize
+from kimchi.xmlutils.utils import dictize
def _get_all_host_dev_infos(libvirt_conn):
diff --git a/src/kimchi/model/networks.py b/src/kimchi/model/networks.py
index 43f9d50..92fae4d 100644
--- a/src/kimchi/model/networks.py
+++ b/src/kimchi/model/networks.py
@@ -28,11 +28,11 @@ from xml.sax.saxutils import escape
from kimchi import netinfo
from kimchi import network as knetwork
from kimchi import networkxml
-from kimchi import xmlutils
from kimchi.exception import InvalidOperation, InvalidParameter
from kimchi.exception import MissingParameter, NotFoundError, OperationFailed
from kimchi.rollbackcontext import RollbackContext
from kimchi.utils import kimchi_log, run_command
+from kimchi.xmlutils.utils import xpath_get_text
KIMCHI_BRIDGE_PREFIX = 'kb'
@@ -301,7 +301,7 @@ class NetworkModel(object):
def _vm_get_networks(self, dom):
xml = dom.XMLDesc(0)
xpath =
"/domain/devices/interface[@type='network']/source/@network"
- return xmlutils.xpath_get_text(xml, xpath)
+ return xpath_get_text(xml, xpath)
def activate(self, name):
network = self.get_network(self.conn.get(), name)
@@ -335,25 +335,23 @@ class NetworkModel(object):
@staticmethod
def get_network_from_xml(xml):
- address = xmlutils.xpath_get_text(xml, "/network/ip/@address")
+ address = xpath_get_text(xml, "/network/ip/@address")
address = address and address[0] or ''
- netmask = xmlutils.xpath_get_text(xml, "/network/ip/@netmask")
+ netmask = xpath_get_text(xml, "/network/ip/@netmask")
netmask = netmask and netmask[0] or ''
net = address and netmask and "/".join([address, netmask]) or
''
- dhcp_start = xmlutils.xpath_get_text(xml,
- "/network/ip/dhcp/range/@start")
+ dhcp_start = xpath_get_text(xml, "/network/ip/dhcp/range/@start")
dhcp_start = dhcp_start and dhcp_start[0] or ''
- dhcp_end = xmlutils.xpath_get_text(xml, "/network/ip/dhcp/range/@end")
+ dhcp_end = xpath_get_text(xml, "/network/ip/dhcp/range/@end")
dhcp_end = dhcp_end and dhcp_end[0] or ''
dhcp = {'start': dhcp_start, 'end': dhcp_end}
- forward_mode = xmlutils.xpath_get_text(xml, "/network/forward/@mode")
+ forward_mode = xpath_get_text(xml, "/network/forward/@mode")
forward_mode = forward_mode and forward_mode[0] or ''
- forward_if = xmlutils.xpath_get_text(xml,
-
"/network/forward/interface/@dev")
- forward_pf = xmlutils.xpath_get_text(xml, "/network/forward/pf/@dev")
- bridge = xmlutils.xpath_get_text(xml, "/network/bridge/@name")
+ forward_if = xpath_get_text(xml, "/network/forward/interface/@dev")
+ forward_pf = xpath_get_text(xml, "/network/forward/pf/@dev")
+ bridge = xpath_get_text(xml, "/network/bridge/@name")
bridge = bridge and bridge[0] or ''
return {'subnet': net, 'dhcp': dhcp, 'bridge': bridge,
'forward': {'mode': forward_mode,
diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py
index 49b2f6a..d44e079 100644
--- a/src/kimchi/model/storagepools.py
+++ b/src/kimchi/model/storagepools.py
@@ -19,7 +19,6 @@
import libvirt
-from kimchi import xmlutils
from kimchi.scan import Scanner
from kimchi.exception import InvalidOperation, MissingParameter
from kimchi.exception import NotFoundError, OperationFailed
@@ -27,6 +26,7 @@ from kimchi.model.config import CapabilitiesModel
from kimchi.model.host import DeviceModel
from kimchi.model.libvirtstoragepool import StoragePoolDef
from kimchi.utils import add_task, kimchi_log, pool_name_from_uri, run_command
+from kimchi.xmlutils.utils import xpath_get_text
ISO_POOL_NAME = u'kimchi_isos'
@@ -212,7 +212,7 @@ class StoragePoolModel(object):
return source
for key, val in STORAGE_SOURCES[pool_type].items():
- res = xmlutils.xpath_get_text(pool_xml, val)
+ res = xpath_get_text(pool_xml, val)
if len(res) == 1:
source[key] = res[0]
elif len(res) == 0:
@@ -224,7 +224,7 @@ class StoragePoolModel(object):
def _nfs_status_online(self, pool, poolArgs=None):
if not poolArgs:
xml = pool.XMLDesc(0)
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
source = self._get_storage_source(pool_type, xml)
poolArgs = {}
poolArgs['name'] = pool.name()
@@ -245,8 +245,8 @@ class StoragePoolModel(object):
autostart = True if pool.autostart() else False
persistent = True if pool.isPersistent() else False
xml = pool.XMLDesc(0)
- path = xmlutils.xpath_get_text(xml, "/pool/target/path")[0]
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ path = xpath_get_text(xml, "/pool/target/path")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
source = self._get_storage_source(pool_type, xml)
# FIXME: nfs workaround - prevent any libvirt operation
# for a nfs if the corresponding NFS server is down.
@@ -319,7 +319,7 @@ class StoragePoolModel(object):
if 'disks' in params:
# check if pool is type 'logical'
xml = pool.XMLDesc(0)
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
if pool_type != 'logical':
raise InvalidOperation('KCHPOOL0029E')
self._update_lvm_disks(name, params['disks'])
@@ -331,7 +331,7 @@ class StoragePoolModel(object):
# FIXME: nfs workaround - do not activate a NFS pool
# if the NFS server is not reachable.
xml = pool.XMLDesc(0)
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
if pool_type == 'netfs' and not self._nfs_status_online(pool):
# block the user from activating the pool.
source = self._get_storage_source(pool_type, xml)
@@ -362,7 +362,7 @@ class StoragePoolModel(object):
# FIXME: nfs workaround - do not try to deactivate a NFS pool
# if the NFS server is not reachable.
xml = pool.XMLDesc(0)
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
if pool_type == 'netfs' and not self._nfs_status_online(pool):
# block the user from dactivating the pool.
source = self._get_storage_source(pool_type, xml)
diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py
index 23927e3..1ee8d0a 100644
--- a/src/kimchi/model/storagevolumes.py
+++ b/src/kimchi/model/storagevolumes.py
@@ -24,7 +24,6 @@ import urllib2
import libvirt
-from kimchi import xmlutils
from kimchi.config import READONLY_POOL_TYPE
from kimchi.exception import InvalidOperation, InvalidParameter, IsoFormatError
from kimchi.exception import MissingParameter, NotFoundError, OperationFailed
@@ -34,6 +33,7 @@ from kimchi.model.tasks import TaskModel
from kimchi.model.vms import VMsModel, VMModel
from kimchi.utils import add_task, kimchi_log
from kimchi.vmdisks import get_vm_disk, get_vm_disk_list
+from kimchi.xmlutils.utils import xpath_get_text
VOLUME_TYPE_MAP = {0: 'file',
@@ -286,8 +286,7 @@ class StorageVolumeModel(object):
info = vol.info()
xml = vol.XMLDesc(0)
try:
- fmt = xmlutils.xpath_get_text(
- xml, "/volume/target/format/@type")[0]
+ fmt = xpath_get_text(xml, "/volume/target/format/@type")[0]
except IndexError:
# Not all types of libvirt storage can provide volume format
# infomation. When there is no format information, we assume
diff --git a/src/kimchi/model/templates.py b/src/kimchi/model/templates.py
index 9278cdc..bb5bd3a 100644
--- a/src/kimchi/model/templates.py
+++ b/src/kimchi/model/templates.py
@@ -22,13 +22,13 @@ import os
import libvirt
-from kimchi import xmlutils
from kimchi.exception import InvalidOperation, InvalidParameter
from kimchi.exception import NotFoundError, OperationFailed
from kimchi.kvmusertests import UserTests
from kimchi.utils import pool_name_from_uri
from kimchi.utils import probe_file_permission_as_user
from kimchi.vmtemplate import VMTemplate
+from kimchi.xmlutils.utils import xpath_get_text
class TemplatesModel(object):
@@ -88,7 +88,7 @@ class TemplatesModel(object):
def template_volume_validate(self, tmp_volumes, pool):
kwargs = {'conn': self.conn, 'objstore': self.objstore}
- pool_type = xmlutils.xpath_get_text(pool.XMLDesc(0), "/pool/@type")[0]
+ pool_type = xpath_get_text(pool.XMLDesc(0), "/pool/@type")[0]
pool_name = pool.name()
# as we discussion, we do not mix disks from 2 different types of
@@ -235,12 +235,12 @@ class LibvirtVMTemplate(VMTemplate):
def _get_storage_path(self):
pool = self._storage_validate()
xml = pool.XMLDesc(0)
- return xmlutils.xpath_get_text(xml, "/pool/target/path")[0]
+ return xpath_get_text(xml, "/pool/target/path")[0]
def _get_storage_type(self):
pool = self._storage_validate()
xml = pool.XMLDesc(0)
- return xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ return xpath_get_text(xml, "/pool/@type")[0]
def _get_volume_path(self, pool, vol):
pool = self._storage_validate()
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index 58686cd..1089464 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -31,7 +31,6 @@ import libvirt
from cherrypy.process.plugins import BackgroundTask
from kimchi import vnc
-from kimchi import xmlutils
from kimchi.config import READONLY_POOL_TYPE
from kimchi.exception import InvalidOperation, InvalidParameter
from kimchi.exception import NotFoundError, OperationFailed
@@ -43,7 +42,7 @@ from kimchi.model.utils import set_metadata_node
from kimchi.screenshot import VMScreenshot
from kimchi.utils import import_class, kimchi_log, run_setfacl_set_attr
from kimchi.utils import template_name_from_uri
-from kimchi.xmlutils import xpath_get_text
+from kimchi.xmlutils.utils import xpath_get_text, xml_item_update
DOM_STATE_MAP = {0: 'nostate',
@@ -352,7 +351,7 @@ class VMModel(object):
if type(val) == int:
val = str(val)
xpath = VM_STATIC_UPDATE_PARAMS[key]
- new_xml = xmlutils.xml_item_update(new_xml, xpath, val)
+ new_xml = xml_item_update(new_xml, xpath, val)
if 'graphics' in params:
new_xml = self._update_graphics(dom, new_xml, params)
@@ -445,7 +444,7 @@ class VMModel(object):
def _vm_get_disk_paths(self, dom):
xml = dom.XMLDesc(0)
xpath = "/domain/devices/disk[@device='disk']/source/@file"
- return xmlutils.xpath_get_text(xml, xpath)
+ return xpath_get_text(xml, xpath)
@staticmethod
def get_vm(name, conn):
@@ -480,7 +479,7 @@ class VMModel(object):
vol = conn.storageVolLookupByPath(path)
pool = vol.storagePoolLookupByVolume()
xml = pool.XMLDesc(0)
- pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
+ pool_type = xpath_get_text(xml, "/pool/@type")[0]
if pool_type not in READONLY_POOL_TYPE:
vol.delete(0)
try:
@@ -498,7 +497,7 @@ class VMModel(object):
dom = self.get_vm(name, self.conn)
xml = dom.XMLDesc(0)
xpath = "/domain/devices/disk[@device='cdrom']/source/@file"
- isofiles = xmlutils.xpath_get_text(xml, xpath)
+ isofiles = xpath_get_text(xml, xpath)
for iso in isofiles:
run_setfacl_set_attr(iso)
@@ -538,25 +537,25 @@ class VMModel(object):
xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
expr = "/domain/devices/graphics/@type"
- res = xmlutils.xpath_get_text(xml, expr)
+ res = xpath_get_text(xml, expr)
graphics_type = res[0] if res else None
expr = "/domain/devices/graphics/@listen"
- res = xmlutils.xpath_get_text(xml, expr)
+ res = xpath_get_text(xml, expr)
graphics_listen = res[0] if res else None
graphics_port = graphics_passwd = graphics_passwdValidTo = None
if graphics_type:
expr = "/domain/devices/graphics[@type='%s']/@port"
- res = xmlutils.xpath_get_text(xml, expr % graphics_type)
+ res = xpath_get_text(xml, expr % graphics_type)
graphics_port = int(res[0]) if res else None
expr = "/domain/devices/graphics[@type='%s']/@passwd"
- res = xmlutils.xpath_get_text(xml, expr % graphics_type)
+ res = xpath_get_text(xml, expr % graphics_type)
graphics_passwd = res[0] if res else None
expr =
"/domain/devices/graphics[@type='%s']/@passwdValidTo"
- res = xmlutils.xpath_get_text(xml, expr % graphics_type)
+ res = xpath_get_text(xml, expr % graphics_type)
if res:
to = time.mktime(time.strptime(res[0], '%Y-%m-%dT%H:%M:%S'))
graphics_passwdValidTo = to - time.mktime(time.gmtime())
diff --git a/src/kimchi/xmlutils.py b/src/kimchi/xmlutils.py
deleted file mode 100644
index 00a9d55..0000000
--- a/src/kimchi/xmlutils.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Project Kimchi
-#
-# Copyright IBM, Corp. 2013-2014
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-import libxml2
-from lxml import objectify
-
-
-from xml.etree import ElementTree
-
-
-def xpath_get_text(xml, expr):
- doc = libxml2.parseDoc(xml)
- res = doc.xpathEval(expr)
- ret = [None if x.children is None else x.children.content for x in res]
-
- doc.freeDoc()
- return ret
-
-
-def xml_item_update(xml, xpath, value):
- root = ElementTree.fromstring(xml)
- item = root.find(xpath)
- item.text = value
- return ElementTree.tostring(root, encoding="utf-8")
-
-
-def dictize(xmlstr):
- root = objectify.fromstring(xmlstr)
- return {root.tag: _dictize(root)}
-
-
-def _dictize(e):
- d = {}
- if e.text is not None:
- if not e.attrib and e.countchildren() == 0:
- return e.pyval
- d['pyval'] = e.pyval
- d.update(e.attrib)
- for child in e.iterchildren():
- if child.tag in d:
- continue
- if len(child) > 1:
- d[child.tag] = [
- _dictize(same_tag_child) for same_tag_child in child]
- else:
- d[child.tag] = _dictize(child)
- return d
diff --git a/src/kimchi/xmlutils/__init__.py b/src/kimchi/xmlutils/__init__.py
new file mode 100644
index 0000000..ca7ede4
--- /dev/null
+++ b/src/kimchi/xmlutils/__init__.py
@@ -0,0 +1,18 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2014
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
diff --git a/src/kimchi/xmlutils/utils.py b/src/kimchi/xmlutils/utils.py
new file mode 100644
index 0000000..2af1c2c
--- /dev/null
+++ b/src/kimchi/xmlutils/utils.py
@@ -0,0 +1,63 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2014
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import libxml2
+from lxml import objectify
+
+
+from xml.etree import ElementTree
+
+
+def xpath_get_text(xml, expr):
+ doc = libxml2.parseDoc(xml)
+ res = doc.xpathEval(expr)
+ ret = [None if x.children is None else x.children.content for x in res]
+
+ doc.freeDoc()
+ return ret
+
+
+def xml_item_update(xml, xpath, value):
+ root = ElementTree.fromstring(xml)
+ item = root.find(xpath)
+ item.text = value
+ return ElementTree.tostring(root, encoding="utf-8")
+
+
+def dictize(xmlstr):
+ root = objectify.fromstring(xmlstr)
+ return {root.tag: _dictize(root)}
+
+
+def _dictize(e):
+ d = {}
+ if e.text is not None:
+ if not e.attrib and e.countchildren() == 0:
+ return e.pyval
+ d['pyval'] = e.pyval
+ d.update(e.attrib)
+ for child in e.iterchildren():
+ if child.tag in d:
+ continue
+ if len(child) > 1:
+ d[child.tag] = [
+ _dictize(same_tag_child) for same_tag_child in child]
+ else:
+ d[child.tag] = _dictize(child)
+ return d
diff --git a/tests/test_networkxml.py b/tests/test_networkxml.py
index d714413..674008d 100644
--- a/tests/test_networkxml.py
+++ b/tests/test_networkxml.py
@@ -25,7 +25,7 @@ import kimchi.networkxml as nxml
import utils
-from kimchi.xmlutils import xpath_get_text
+from kimchi.xmlutils.utils import xpath_get_text
class NetworkXmlTests(unittest.TestCase):
diff --git a/tests/test_vmtemplate.py b/tests/test_vmtemplate.py
index 2a6fb8e..550bb2a 100644
--- a/tests/test_vmtemplate.py
+++ b/tests/test_vmtemplate.py
@@ -23,7 +23,7 @@ import uuid
from kimchi.vmtemplate import VMTemplate
-from kimchi.xmlutils import xpath_get_text
+from kimchi.xmlutils.utils import xpath_get_text
class VMTemplateTests(unittest.TestCase):
--
1.9.3