xmlbuilder: Simplify global XML vars

Just have classes specify a root XML path, and figure out root name,
indentation, and dumpxml path from there.
This commit is contained in:
Cole Robinson 2013-07-24 12:02:37 -04:00
parent 43d15d67ac
commit 7411776c9a
10 changed files with 36 additions and 61 deletions

View File

@ -27,9 +27,8 @@ class CPUFeature(XMLBuilder):
POLICIES = ["force", "require", "optional", "disable", "forbid"]
_XML_ROOT_XPATH = "/domain/cpu/feature"
_XML_PROP_ORDER = ["_xmlname", "policy"]
_XML_ROOT_NAME = "cpu"
_XML_INDENT = 4
def __init__(self, conn, name, parsexml=None, parsexmlnode=None):
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
@ -60,9 +59,7 @@ class CPU(XMLBuilder):
MATCHS = ["minimum", "exact", "strict"]
_dumpxml_xpath = "/domain/cpu"
_XML_ROOT_NAME = "cpu"
_XML_INDENT = 2
_XML_ROOT_XPATH = "/domain/cpu"
_XML_PROP_ORDER = ["mode", "match", "model", "vendor",
"sockets", "cores", "threads", "_features"]

View File

@ -21,8 +21,6 @@ from virtinst.xmlbuilder import XMLBuilder, XMLProperty
class Clock(XMLBuilder):
_dumpxml_xpath = "/domain/clock"
_XML_INDENT = 2
_XML_ROOT_NAME = "clock"
_XML_ROOT_XPATH = "/domain/clock"
offset = XMLProperty(xpath="./clock/@offset")

View File

@ -24,9 +24,7 @@ class DomainFeatures(XMLBuilder):
"""
Class for generating <features> XML
"""
_dumpxml_xpath = "/domain/features"
_XML_ROOT_NAME = "features"
_XML_INDENT = 2
_XML_ROOT_XPATH = "/domain/features"
_XML_PROP_ORDER = ["acpi", "apic", "pae"]
acpi = XMLProperty(xpath="./features/acpi", is_tri=True)

View File

@ -95,9 +95,7 @@ class DomainNumatune(XMLBuilder):
MEMORY_MODES = ["interleave", "strict", "preferred"]
_dumpxml_xpath = "/domain/numatune"
_XML_ROOT_NAME = "numatune"
_XML_INDENT = 2
_XML_ROOT_XPATH = "/domain/numatune"
_XML_PROP_ORDER = ["memory_mode", "memory_nodeset"]
memory_nodeset = XMLProperty(xpath="./numatune/memory/@nodeset")

View File

@ -161,8 +161,7 @@ class Guest(XMLBuilder):
return cpustr
_XML_ROOT_NAME = "domain"
_XML_INDENT = 0
_XML_ROOT_XPATH = "/domain"
_XML_PROP_ORDER = ["type", "name", "uuid", "description",
"maxmemory", "memory", "hugepage", "vcpus", "curvcpus",
"numatune", "bootloader", "os", "features", "cpu", "clock",

View File

@ -38,9 +38,7 @@ class Seclabel(XMLBuilder):
MODEL_NONE = "none"
MODELS = [MODEL_SELINUX, MODEL_DAC, MODEL_NONE]
_dumpxml_xpath = "/domain/seclabel"
_XML_ROOT_NAME = "seclabel"
_XML_INDENT = 2
_XML_ROOT_XPATH = "/domain/seclabel"
_XML_PROP_ORDER = ["type", "model", "relabel", "label", "imagelabel"]
def _guess_secmodel(self):

View File

@ -75,7 +75,6 @@ class VirtualDevice(XMLBuilder):
# General device type (disk, interface, etc.)
virtual_device_type = None
_XML_INDENT = 4
def __init__(self, conn, parsexml=None, parsexmlnode=None):
"""
@ -83,8 +82,9 @@ class VirtualDevice(XMLBuilder):
@param conn: libvirt connection to validate device against
"""
self._XML_ROOT_XPATH = "/domain/devices/%s" % self.virtual_device_type
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
self._XML_ROOT_NAME = self.virtual_device_type
self.alias = VirtualDeviceAlias(conn, parsexmlnode=parsexmlnode)
self.address = VirtualDeviceAddress(conn, parsexmlnode=parsexmlnode)
@ -111,9 +111,7 @@ class VirtualDevice(XMLBuilder):
class VirtualDeviceAlias(XMLBuilder):
_XML_ROOT_NAME = "alias"
_XML_INDENT = 0
_XML_ROOT_XPATH = "/domain/devices/device/alias"
name = XMLProperty(xpath="./alias/@name")
@ -136,8 +134,7 @@ class VirtualDeviceAddress(XMLBuilder):
ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID,
ADDRESS_TYPE_SPAPR_VIO]
_XML_ROOT_NAME = "address"
_XML_INDENT = 0
_XML_ROOT_XPATH = "/domain/devices/device/address"
_XML_PROP_ORDER = ["type", "domain", "bus", "slot", "function"]
def set_addrstr(self, addrstr):

View File

@ -53,6 +53,8 @@ def _random_mac(conn):
class VirtualPort(XMLBuilder):
_XML_ROOT_XPATH = "/domain/devices/interface/virtualport"
type = XMLProperty(xpath="./virtualport/@type")
managerid = XMLProperty(xpath="./virtualport/parameters/@managerid",
is_int=True)

View File

@ -39,15 +39,11 @@ class OSXML(XMLBuilder):
def is_container(self):
return self.os_type == "exe"
_dumpxml_xpath = "/domain/os"
_XML_ROOT_NAME = "os"
_XML_INDENT = 2
_XML_ROOT_XPATH = "/domain/os"
_XML_PROP_ORDER = ["arch", "os_type", "loader",
"kernel", "initrd", "kernel_args",
"bootorder"]
type = property(lambda s: s.snarf)
enable_bootmenu = XMLProperty(xpath="./os/bootmenu/@enable", is_yesno=True)
bootorder = XMLProperty(xpath="./os/boot/@dev", is_multi=True)

View File

@ -574,14 +574,8 @@ class XMLBuilder(object):
# consistent with what the test suite expects.
_XML_PROP_ORDER = []
# Root element name of this function, used to populate a default
# _get_xml_config
_XML_ROOT_NAME = None
# Integer indentation level for generated XML.
_XML_INDENT = None
_dumpxml_xpath = "."
# Absolute xpath this object is rooted at
_XML_ROOT_XPATH = None
def __init__(self, conn, parsexml=None, parsexmlnode=None):
"""
@ -595,7 +589,15 @@ class XMLBuilder(object):
"""
self.conn = conn
xpath = self._XML_ROOT_XPATH
if xpath is None or not xpath.startswith("/"):
raise RuntimeError("xpath=%s must start with /" % xpath)
self._xml_root_name = xpath.split("/")[-1]
self._xml_indent = (xpath.count("/") - 1) * 2
self._xml_dump_xpath = xpath
self._xml_root_xpath = ""
self._xml_node = None
self._xml_ctx = None
self._xml_root_doc = None
@ -640,7 +642,7 @@ class XMLBuilder(object):
def get_xml_config(self):
data = self._prepare_get_xml()
try:
return self._do_get_xml_config(self._dumpxml_xpath)
return self._do_get_xml_config()
finally:
self._finish_get_xml(data)
@ -648,7 +650,7 @@ class XMLBuilder(object):
for prop in self.all_xml_props().values():
prop._clear(self)
def _do_get_xml_config(self, dumpxml_xpath):
def _do_get_xml_config(self):
"""
Construct and return object xml
@ -656,22 +658,21 @@ class XMLBuilder(object):
@rtype: str
"""
if self._xml_ctx:
node = _get_xpath_node(self._xml_ctx, dumpxml_xpath)
node = _get_xpath_node(self._xml_ctx, self._xml_dump_xpath)
if not node:
ret = ""
else:
ret = _sanitize_libxml_xml(node.serialize())
else:
xmlstub = self._make_xml_stub(fail=False)
ret = self._make_xml_stub(fail=True)
if ret is None:
xmlstub = self._make_xml_stub()
if xmlstub is None:
return None
ret = self._add_parse_bits(ret)
ret = self._add_parse_bits(xmlstub)
if ret == xmlstub:
ret = ""
if self._XML_ROOT_NAME == "domain" and not ret.endswith("\n"):
if ret and self._xml_root_name == "domain" and not ret.endswith("\n"):
ret += "\n"
return ret
@ -704,18 +705,8 @@ class XMLBuilder(object):
# Internal XML parsers #
########################
def _make_xml_stub(self, fail=True):
if self._XML_ROOT_NAME is None:
if not fail:
return None
raise RuntimeError("Must specify _XML_ROOT_NAME.")
if self._XML_INDENT is None:
if not fail:
return None
raise RuntimeError("Must specify _XML_INDENT.")
if self._XML_ROOT_NAME == "":
return ""
return _indent("<%s/>" % (self._XML_ROOT_NAME), self._XML_INDENT)
def _make_xml_stub(self):
return _indent("<%s/>" % (self._xml_root_name), self._xml_indent)
def _add_child(self, parent_xpath, dev):
"""
@ -742,6 +733,7 @@ class XMLBuilder(object):
doc = libxml2.parseDoc(xml)
self._xml_root_doc = _DocCleanupWrapper(doc)
self._xml_node = doc.children
self._xml_dump_xpath = "."
# This just stores a reference to our root doc wrapper in
# the root node, so when the node goes away it triggers
@ -749,6 +741,7 @@ class XMLBuilder(object):
self._xml_node.virtinst_root_doc = self._xml_root_doc
else:
self._xml_node = node
self._xml_dump_xpath = self._XML_ROOT_XPATH
self._set_xml_context()
@ -804,8 +797,7 @@ class XMLBuilder(object):
obj._xml_root_xpath = self._xml_root_xpath
obj._add_parse_bits(xml=None, node=self._xml_node)
xml = self._do_get_xml_config(".").strip("\n")
return _indent(xml, indent)
return _indent(self._do_get_xml_config(), indent)
def _add_parse_bits(self, xml, node=None):
"""