Drop a lot of usage of utility XML functions

This commit is contained in:
Cole Robinson 2013-09-22 17:34:53 -04:00
parent e9b8a289b5
commit a6d92c7001
8 changed files with 91 additions and 117 deletions

View File

@ -30,7 +30,6 @@ from gi.repository import Gtk
import libvirt
import virtinst
from virtinst import util
from virtManager import config
OPTICAL_DEV_PATH = 0
@ -84,7 +83,7 @@ def host_disk_space(conn):
# FIXME: make sure not inactive?
# FIXME: use a conn specific function after we send pool-added
pool.refresh()
avail = int(util.xpath(pool.get_xml(), "/pool/available"))
avail = int(pool.get_available())
elif not conn.is_remote() and os.path.exists(path):
vfs = os.statvfs(os.path.dirname(path))

View File

@ -76,7 +76,7 @@ DEVICE_GRAPHICS = "24"
def register_namespace(ctx):
def ovf_register_namespace(ctx):
ctx.xpathRegisterNs("ovf", "http://schemas.dmtf.org/ovf/envelope/1")
ctx.xpathRegisterNs("ovfenv", "http://schemas.dmtf.org/ovf/environment/1")
ctx.xpathRegisterNs("rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
@ -101,6 +101,34 @@ def get_child_content(parent_node, child_name):
return None
def _xpath(xml, path=None, func=None, return_list=False,
register_namespace=None):
"""
Return the content from the passed xml xpath, or return the result
of a passed function (receives xpathContext as its only arg)
"""
def _getter(doc, ctx, path):
ignore = doc
if func:
return func(ctx)
if not path:
raise ValueError("'path' or 'func' is required.")
ret = ctx.xpathEval(path)
if type(ret) is list:
if len(ret) >= 1:
if return_list:
return ret
else:
return ret[0].content
else:
ret = None
return ret
return util.xml_parse_wrapper(xml, _getter, path,
register_namespace=register_namespace)
def convert_alloc_val(ignore, val):
# XXX: This is a hack, but should we really have to decode
# allocation units = "bytes * 2^20"?
@ -238,9 +266,8 @@ class ovf_parser(formats.parser):
res = False
try:
if xml.count("</Envelope>"):
res = bool(util.xpath(xml, "/ovf:Envelope",
return_list=True,
register_namespace=register_namespace))
res = bool(_xpath(xml, "/ovf:Envelope", return_list=True,
register_namespace=ovf_register_namespace))
except Exception, e:
logging.debug("Error parsing OVF XML: %s", str(e))
@ -259,7 +286,7 @@ class ovf_parser(formats.parser):
logging.debug("Importing OVF XML:\n%s", xml)
return util.xml_parse_wrapper(xml, ovf_parser._import_file,
register_namespace=register_namespace)
register_namespace=ovf_register_namespace)
@staticmethod
def _import_file(doc, ctx):

View File

@ -88,8 +88,8 @@ class Cloner(object):
if type(val) is not str:
raise ValueError(_("Original xml must be a string."))
self._original_xml = val
self._original_guest = util.xpath(self.original_xml,
"/domain/name")
self._original_guest = Guest(self.conn,
parsexml=self._original_xml).name
def get_original_xml(self):
return self._original_xml
original_xml = property(get_original_xml, set_original_xml,

View File

@ -66,6 +66,7 @@ class _FetchObjWrapper(object):
def __init__(self, backend):
self._backend = backend
self._xml = None
self._xmlobj = None
def get_xml(self, refresh_if_nec=True):
if self._xml is None or refresh_if_nec:

View File

@ -24,7 +24,7 @@ import statvfs
import libvirt
from virtinst import StorageVolume
from virtinst import StoragePool, StorageVolume
from virtinst import util
@ -38,12 +38,9 @@ def _check_if_pool_source(conn, path):
def check_pool(poolname, path):
pool = conn.storagePoolLookupByName(poolname)
xml = pool.XMLDesc(0)
for element in ["dir", "device", "adapter"]:
xml_path = util.xpath(xml, "/pool/source/%s/@path" % element)
if xml_path == path:
return pool
xmlobj = StoragePool(conn, parsexml=pool.XMLDesc(0))
if xmlobj.source_path == path:
return pool
running_list = conn.listStoragePools()
inactive_list = conn.listDefinedStoragePools()
@ -87,7 +84,7 @@ def check_if_path_managed(conn, path):
vol = lookup_vol_by_path()[0]
if not vol:
pool = util.lookup_pool_by_path(conn, os.path.dirname(path))
pool = StoragePool.lookup_pool_by_path(conn, os.path.dirname(path))
# Is pool running?
if pool and pool.info()[0] != libvirt.VIR_STORAGE_POOL_RUNNING:
@ -225,9 +222,9 @@ class StorageCreator(_StorageBase):
def _get_path(self):
if self._vol_install and not self._path:
self._path = (util.xpath(self._vol_install.pool.XMLDesc(0),
"/pool/target/path") + "/" +
self._vol_install.name)
xmlobj = StoragePool(self._conn,
parsexml=self._vol_install.pool.XMLDesc(0))
self._path = (xmlobj.target_path + "/" + self._vol_install.name)
return self._path
path = property(_get_path)
@ -475,12 +472,14 @@ class StorageBackend(_StorageBase):
def _get_pool_xml(self):
if self._pool_xml is None:
self._pool_xml = self._pool_object.XMLDesc(0)
self._pool_xml = StoragePool(self._conn,
parsexml=self._pool_object.XMLDesc(0))
return self._pool_xml
def _get_vol_xml(self):
if self._vol_xml is None:
self._vol_xml = self._vol_object.XMLDesc(0)
self._vol_xml = StorageVolume(self._conn,
parsexml=self._vol_object.XMLDesc(0))
return self._vol_xml
@ -504,9 +503,9 @@ class StorageBackend(_StorageBase):
if self._size is None:
ret = 0
if self._vol_object:
ret = util.xpath(self._get_vol_xml(), "/volume/capacity")
ret = self._get_vol_xml().capacity
elif self._pool_object:
ret = util.xpath(self._get_pool_xml(), "/pool/capacity")
ret = self._get_pool_xml().capacity
elif self._path:
ignore, ret = util.stat_disk(self.path)
self._size = (float(ret) / 1024.0 / 1024.0 / 1024.0)
@ -539,14 +538,7 @@ class StorageBackend(_StorageBase):
self._dev_type = "file"
elif self._pool_object:
xml = self._get_pool_xml()
for source, source_type in [
("dir", "dir"),
("device", "block"),
("adapter", "block")]:
if util.xpath(xml, "/pool/source/%s/@dev" % source):
self._dev_type = source_type
break
self._dev_type = self._get_pool_xml().get_vm_disk_type()
elif self._path:
if os.path.isdir(self._path):
@ -562,9 +554,7 @@ class StorageBackend(_StorageBase):
def get_driver_type(self):
if self._vol_object:
fmt = util.xpath(self._get_vol_xml(),
"/volume/target/format/@type")
return fmt
return self._get_vol_xml().format
return None
def is_managed(self):

View File

@ -68,7 +68,7 @@ def _sanitize_url(url):
def _build_pool(conn, meter, path):
pool = util.lookup_pool_by_path(conn, path)
pool = StoragePool.lookup_pool_by_path(conn, path)
if pool:
logging.debug("Existing pool '%s' found for %s", pool.name(), path)
pool.refresh(0)
@ -106,7 +106,9 @@ def _upload_file(conn, meter, destpool, src):
# Build placeholder volume
size = os.path.getsize(src)
basename = os.path.basename(src)
poolpath = util.xpath(destpool.XMLDesc(0), "/pool/target/path")
xmlobj = StoragePool(conn, parsexml=destpool.XMLDesc(0))
poolpath = xmlobj.target_path
name = StorageVolume.find_free_name(basename, pool_object=destpool)
if name != basename:
logging.debug("Generated non-colliding volume name %s", name)

View File

@ -204,6 +204,31 @@ class StoragePool(_StorageObject):
_("Couldn't create default storage pool '%s': %s") %
(path, str(e)))
@staticmethod
def lookup_pool_by_path(conn, path):
"""
Return the first pool with matching matching target path.
return the first we find, active or inactive. This iterates over
all pools and dumps their xml, so it is NOT quick.
Favor running pools over inactive pools.
@returns: virStoragePool object if found, None otherwise
"""
if not conn.check_conn_support(conn.SUPPORT_CONN_STORAGE):
return None
def check_pool(pool, path):
xml = pool.get_xml(refresh_if_nec=False)
xml_path = StoragePool(conn, parsexml=xml).target_path
if xml_path is not None and os.path.abspath(xml_path) == path:
return pool
for pool in conn.fetch_all_pools():
p = check_pool(pool, path)
if p:
return p.get_backend()
return None
def __init__(self, *args, **kwargs):
_StorageObject.__init__(self, *args, **kwargs)
@ -349,6 +374,16 @@ class StoragePool(_StorageObject):
StoragePool.TYPE_NETFS, StoragePool.TYPE_LOGICAL,
StoragePool.TYPE_DISK]
def get_vm_disk_type(self):
"""
Return the /disk/@type value if the pool source is used as
VirtualDisk path
"""
xpath = self._source_path_xpath()
if "/dir/" in xpath:
return "dir"
return "block"
##################
# Build routines #

View File

@ -299,34 +299,6 @@ def xml_parse_wrapper(xml, parse_func, *args, **kwargs):
return ret
def set_xml_path(xml, path, newval):
"""
Set the passed xml xpath to the new value
"""
def cb(doc, ctx):
ret = ctx.xpathEval(path)
if ret is not None:
if type(ret) == list:
if len(ret) == 1:
ret[0].setContent(newval)
else:
ret.setContent(newval)
return doc.serialize()
return xml_parse_wrapper(xml, cb)
def xml_append(orig, new):
"""
Little function that helps generate consistent xml
"""
if not new:
return orig
if orig:
orig += "\n"
return orig + new
def generate_uuid(conn):
for ignore in range(256):
uuid = randomUUID(conn=conn)
@ -408,58 +380,6 @@ def xml_escape(xml):
return xml
def xpath(xml, path=None, func=None, return_list=False,
register_namespace=None):
"""
Return the content from the passed xml xpath, or return the result
of a passed function (receives xpathContext as its only arg)
"""
def _getter(doc, ctx, path):
ignore = doc
if func:
return func(ctx)
if not path:
raise ValueError("'path' or 'func' is required.")
ret = ctx.xpathEval(path)
if type(ret) is list:
if len(ret) >= 1:
if return_list:
return ret
else:
return ret[0].content
else:
ret = None
return ret
return xml_parse_wrapper(xml, _getter, path,
register_namespace=register_namespace)
def lookup_pool_by_path(conn, path):
"""
Return the first pool with matching matching target path.
return the first we find, active or inactive. This iterates over
all pools and dumps their xml, so it is NOT quick.
Favor running pools over inactive pools.
@returns: virStoragePool object if found, None otherwise
"""
if not conn.check_conn_support(conn.SUPPORT_CONN_STORAGE):
return None
def check_pool(pool, path):
xml_path = xpath(pool.get_xml(refresh_if_nec=False),
"/pool/target/path")
if xml_path is not None and os.path.abspath(xml_path) == path:
return pool
for pool in conn.fetch_all_pools():
p = check_pool(pool, path)
if p:
return p.get_backend()
return None
def uri_split(uri):
"""
Parse a libvirt hypervisor uri into it's individual parts