diff --git a/virtinst/CPU.py b/virtinst/CPU.py index 7ad6c40a..0c9456a4 100644 --- a/virtinst/CPU.py +++ b/virtinst/CPU.py @@ -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"] diff --git a/virtinst/Clock.py b/virtinst/Clock.py index 1604681b..62f6c0be 100644 --- a/virtinst/Clock.py +++ b/virtinst/Clock.py @@ -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") diff --git a/virtinst/DomainFeatures.py b/virtinst/DomainFeatures.py index 0b896546..38a036f6 100644 --- a/virtinst/DomainFeatures.py +++ b/virtinst/DomainFeatures.py @@ -24,9 +24,7 @@ class DomainFeatures(XMLBuilder): """ Class for generating 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) diff --git a/virtinst/DomainNumatune.py b/virtinst/DomainNumatune.py index e660bb67..356d82bf 100644 --- a/virtinst/DomainNumatune.py +++ b/virtinst/DomainNumatune.py @@ -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") diff --git a/virtinst/Guest.py b/virtinst/Guest.py index ede0627d..50b27851 100644 --- a/virtinst/Guest.py +++ b/virtinst/Guest.py @@ -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", diff --git a/virtinst/Seclabel.py b/virtinst/Seclabel.py index 4dc46cb6..43e5c117 100644 --- a/virtinst/Seclabel.py +++ b/virtinst/Seclabel.py @@ -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): diff --git a/virtinst/VirtualDevice.py b/virtinst/VirtualDevice.py index 5df00e80..af78bf0f 100644 --- a/virtinst/VirtualDevice.py +++ b/virtinst/VirtualDevice.py @@ -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): diff --git a/virtinst/VirtualNetworkInterface.py b/virtinst/VirtualNetworkInterface.py index b8465dc0..3249366a 100644 --- a/virtinst/VirtualNetworkInterface.py +++ b/virtinst/VirtualNetworkInterface.py @@ -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) diff --git a/virtinst/osxml.py b/virtinst/osxml.py index 633da14b..51b6c766 100644 --- a/virtinst/osxml.py +++ b/virtinst/osxml.py @@ -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) diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py index 9a823750..248e0649 100644 --- a/virtinst/xmlbuilder.py +++ b/virtinst/xmlbuilder.py @@ -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): """