xmlbuilder: Support clear()ing an object in place
This gives friendly XML output via virt-xml for clearxml=yes + extra options: the XML block is editted in place, rather than removed and with the newchanges appended
This commit is contained in:
parent
333103adbf
commit
55327c81b7
|
@ -1,20 +1,12 @@
|
|||
<feature policy="require" name="xtpr"/>
|
||||
<feature policy="require" name="acpi"/>
|
||||
</cpu>
|
||||
- <clock offset="utc">
|
||||
<clock offset="utc">
|
||||
- <timer name="rtc" tickpolicy="catchup"/>
|
||||
- <timer name="pit" tickpolicy="delay"/>
|
||||
- <timer name="hpet" present="no"/>
|
||||
- </clock>
|
||||
</clock>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>restart</on_crash>
|
||||
@@
|
||||
</panic>
|
||||
</devices>
|
||||
<seclabel type="dynamic" model="selinux" relabel="yes"/>
|
||||
+ <clock offset="utc"/>
|
||||
</domain>
|
||||
|
||||
Domain 'test-for-virtxml' defined successfully.
|
||||
Changes will take effect after the next domain shutdown.
|
|
@ -17,16 +17,10 @@
|
|||
- <feature policy="require" name="ds_cpl"/>
|
||||
- <feature policy="require" name="xtpr"/>
|
||||
- <feature policy="require" name="acpi"/>
|
||||
- </cpu>
|
||||
+ <cpu mode="host-passthrough">
|
||||
</cpu>
|
||||
<clock offset="utc">
|
||||
<timer name="rtc" tickpolicy="catchup"/>
|
||||
<timer name="pit" tickpolicy="delay"/>
|
||||
@@
|
||||
</panic>
|
||||
</devices>
|
||||
<seclabel type="dynamic" model="selinux" relabel="yes"/>
|
||||
+ <cpu mode="host-passthrough"/>
|
||||
</domain>
|
||||
|
||||
Domain 'test-for-virtxml' defined successfully.
|
||||
Changes will take effect after the next domain shutdown.
|
|
@ -1028,17 +1028,27 @@ class VirtCLIParser(object):
|
|||
|
||||
def __init_global_params(self):
|
||||
def set_clearxml_cb(opts, inst, cliname, val):
|
||||
ignore = opts = cliname
|
||||
ignore = opts
|
||||
ignore = cliname
|
||||
if not self.objclass and not self.clear_attr:
|
||||
raise RuntimeError("Don't know how to clearxml --%s" %
|
||||
self.cli_arg_name)
|
||||
if val is not True:
|
||||
return
|
||||
|
||||
clear_inst = inst
|
||||
if self.clear_attr:
|
||||
getattr(inst, self.clear_attr).clear()
|
||||
else:
|
||||
inst.clear()
|
||||
clear_inst = getattr(inst, self.clear_attr)
|
||||
|
||||
# If there's any opts remaining, leave the root stub element
|
||||
# in place, so virt-xml updates are done in place.
|
||||
#
|
||||
# So --edit --cpu clearxml=yes should remove the entire <cpu>
|
||||
# block. But --edit --cpu clearxml=yes,model=foo should leave
|
||||
# a <cpu> stub in place, so that it gets model=foo in place,
|
||||
# otherwise the newly created cpu block gets appened to the
|
||||
# end of the domain XML, which gives an ugly diff
|
||||
clear_inst.clear(leave_stub=bool(opts.opts))
|
||||
|
||||
self.set_param(None, "clearxml",
|
||||
setter_cb=set_clearxml_cb, is_onoff=True)
|
||||
|
|
|
@ -312,9 +312,9 @@ SUPPORT_CONN_MEM_STATS_PERIOD = _make(
|
|||
function="virDomain.setMemoryStatsPeriod",
|
||||
version="1.1.1", hv_version={"qemu": 0})
|
||||
SUPPORT_CONN_SPICE_GL = _make(version="1.3.3",
|
||||
hv_version={"qemu": "2.5.92", "test": 0})
|
||||
hv_version={"qemu": "2.7.92", "test": 0})
|
||||
SUPPORT_CONN_VIDEO_VIRTIO_ACCEL3D = _make(version="1.3.0",
|
||||
hv_version={"qemu": "2.5.0", "test": 0})
|
||||
hv_version={"qemu": "2.7.0", "test": 0})
|
||||
|
||||
|
||||
# This is for disk <driver name=qemu>. xen supports this, but it's
|
||||
|
|
|
@ -38,6 +38,10 @@ _trackprops = bool("VIRTINST_TEST_SUITE" in os.environ)
|
|||
_allprops = []
|
||||
_seenprops = []
|
||||
|
||||
# Convenience global to prevent _remove_xpath_node from unlinking the
|
||||
# top relavtive node in certain cases
|
||||
_top_node = None
|
||||
|
||||
|
||||
class _DocCleanupWrapper(object):
|
||||
def __init__(self, doc):
|
||||
|
@ -224,17 +228,17 @@ def _remove_xpath_node(ctx, xpath, dofree=True):
|
|||
if not is_orig:
|
||||
continue
|
||||
|
||||
if node == root_node or node == _top_node:
|
||||
# Don't unlink the root node, since it's spread out to all
|
||||
# child objects and it ends up wreaking havoc.
|
||||
break
|
||||
|
||||
# Look for preceding whitespace and remove it
|
||||
white = node.get_prev()
|
||||
if white and white.type == "text" and not white.content.count("<"):
|
||||
white.unlinkNode()
|
||||
white.freeNode()
|
||||
|
||||
if node == root_node:
|
||||
# Don't unlink the root node, since it's spread out to all
|
||||
# child objects and it ends up wreaking havoc.
|
||||
break
|
||||
|
||||
node.unlinkNode()
|
||||
if dofree:
|
||||
node.freeNode()
|
||||
|
@ -836,17 +840,28 @@ class XMLBuilder(object):
|
|||
finally:
|
||||
self._finish_get_xml(data)
|
||||
|
||||
def clear(self):
|
||||
def clear(self, leave_stub=False):
|
||||
"""
|
||||
Wipe out all properties of the object
|
||||
|
||||
:param leave_stub: if True, don't unlink the top stub node,
|
||||
see virtinst/cli usage for an explanation
|
||||
"""
|
||||
global _top_node
|
||||
old_top_node = _top_node
|
||||
try:
|
||||
if leave_stub:
|
||||
_top_node = _get_xpath_node(self._xmlstate.xml_ctx,
|
||||
self.get_root_xpath())
|
||||
props = self._all_xml_props().values()
|
||||
props += self._all_child_props().values()
|
||||
for prop in props:
|
||||
prop.clear(self)
|
||||
finally:
|
||||
_top_node = old_top_node
|
||||
|
||||
is_child = bool(re.match("^.*\[\d+\]$", self.get_root_xpath()))
|
||||
if is_child:
|
||||
if is_child or leave_stub:
|
||||
# User requested to clear an object that is the child of
|
||||
# another object (xpath ends in [1] etc). We can't fully remove
|
||||
# the node in that case, since then the xmlbuilder object is
|
||||
|
@ -855,6 +870,7 @@ class XMLBuilder(object):
|
|||
node = _get_xpath_node(self._xmlstate.xml_ctx,
|
||||
self.get_root_xpath())
|
||||
indent = 2 * self.get_root_xpath().count("/")
|
||||
if node:
|
||||
node.setContent("\n" + (indent * " "))
|
||||
else:
|
||||
_remove_xpath_node(self._xmlstate.xml_ctx,
|
||||
|
|
Loading…
Reference in New Issue