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:
Cole Robinson 2016-05-20 14:23:39 -04:00
parent 333103adbf
commit 55327c81b7
5 changed files with 48 additions and 36 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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
"""
props = self._all_xml_props().values()
props += self._all_child_props().values()
for prop in props:
prop.clear(self)
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,7 +870,8 @@ class XMLBuilder(object):
node = _get_xpath_node(self._xmlstate.xml_ctx,
self.get_root_xpath())
indent = 2 * self.get_root_xpath().count("/")
node.setContent("\n" + (indent * " "))
if node:
node.setContent("\n" + (indent * " "))
else:
_remove_xpath_node(self._xmlstate.xml_ctx,
self.get_root_xpath())