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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -39,15 +39,11 @@ class OSXML(XMLBuilder):
def is_container(self): def is_container(self):
return self.os_type == "exe" return self.os_type == "exe"
_dumpxml_xpath = "/domain/os" _XML_ROOT_XPATH = "/domain/os"
_XML_ROOT_NAME = "os"
_XML_INDENT = 2
_XML_PROP_ORDER = ["arch", "os_type", "loader", _XML_PROP_ORDER = ["arch", "os_type", "loader",
"kernel", "initrd", "kernel_args", "kernel", "initrd", "kernel_args",
"bootorder"] "bootorder"]
type = property(lambda s: s.snarf)
enable_bootmenu = XMLProperty(xpath="./os/bootmenu/@enable", is_yesno=True) enable_bootmenu = XMLProperty(xpath="./os/bootmenu/@enable", is_yesno=True)
bootorder = XMLProperty(xpath="./os/boot/@dev", is_multi=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. # consistent with what the test suite expects.
_XML_PROP_ORDER = [] _XML_PROP_ORDER = []
# Root element name of this function, used to populate a default # Absolute xpath this object is rooted at
# _get_xml_config _XML_ROOT_XPATH = None
_XML_ROOT_NAME = None
# Integer indentation level for generated XML.
_XML_INDENT = None
_dumpxml_xpath = "."
def __init__(self, conn, parsexml=None, parsexmlnode=None): def __init__(self, conn, parsexml=None, parsexmlnode=None):
""" """
@ -595,7 +589,15 @@ class XMLBuilder(object):
""" """
self.conn = conn 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_root_xpath = ""
self._xml_node = None self._xml_node = None
self._xml_ctx = None self._xml_ctx = None
self._xml_root_doc = None self._xml_root_doc = None
@ -640,7 +642,7 @@ class XMLBuilder(object):
def get_xml_config(self): def get_xml_config(self):
data = self._prepare_get_xml() data = self._prepare_get_xml()
try: try:
return self._do_get_xml_config(self._dumpxml_xpath) return self._do_get_xml_config()
finally: finally:
self._finish_get_xml(data) self._finish_get_xml(data)
@ -648,7 +650,7 @@ class XMLBuilder(object):
for prop in self.all_xml_props().values(): for prop in self.all_xml_props().values():
prop._clear(self) prop._clear(self)
def _do_get_xml_config(self, dumpxml_xpath): def _do_get_xml_config(self):
""" """
Construct and return object xml Construct and return object xml
@ -656,22 +658,21 @@ class XMLBuilder(object):
@rtype: str @rtype: str
""" """
if self._xml_ctx: 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: if not node:
ret = "" ret = ""
else: else:
ret = _sanitize_libxml_xml(node.serialize()) ret = _sanitize_libxml_xml(node.serialize())
else: else:
xmlstub = self._make_xml_stub(fail=False) xmlstub = self._make_xml_stub()
ret = self._make_xml_stub(fail=True) if xmlstub is None:
if ret is None:
return None return None
ret = self._add_parse_bits(ret) ret = self._add_parse_bits(xmlstub)
if ret == xmlstub: if ret == xmlstub:
ret = "" 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" ret += "\n"
return ret return ret
@ -704,18 +705,8 @@ class XMLBuilder(object):
# Internal XML parsers # # Internal XML parsers #
######################## ########################
def _make_xml_stub(self, fail=True): def _make_xml_stub(self):
if self._XML_ROOT_NAME is None: return _indent("<%s/>" % (self._xml_root_name), self._xml_indent)
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 _add_child(self, parent_xpath, dev): def _add_child(self, parent_xpath, dev):
""" """
@ -742,6 +733,7 @@ class XMLBuilder(object):
doc = libxml2.parseDoc(xml) doc = libxml2.parseDoc(xml)
self._xml_root_doc = _DocCleanupWrapper(doc) self._xml_root_doc = _DocCleanupWrapper(doc)
self._xml_node = doc.children self._xml_node = doc.children
self._xml_dump_xpath = "."
# This just stores a reference to our root doc wrapper in # This just stores a reference to our root doc wrapper in
# the root node, so when the node goes away it triggers # 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 self._xml_node.virtinst_root_doc = self._xml_root_doc
else: else:
self._xml_node = node self._xml_node = node
self._xml_dump_xpath = self._XML_ROOT_XPATH
self._set_xml_context() self._set_xml_context()
@ -804,8 +797,7 @@ class XMLBuilder(object):
obj._xml_root_xpath = self._xml_root_xpath obj._xml_root_xpath = self._xml_root_xpath
obj._add_parse_bits(xml=None, node=self._xml_node) obj._add_parse_bits(xml=None, node=self._xml_node)
xml = self._do_get_xml_config(".").strip("\n") return _indent(self._do_get_xml_config(), indent)
return _indent(xml, indent)
def _add_parse_bits(self, xml, node=None): def _add_parse_bits(self, xml, node=None):
""" """