xmlbuilder: Add replace_child

This will be used for UI XML editing of devices
This commit is contained in:
Cole Robinson
2019-05-08 18:59:12 -04:00
parent 5e7322edca
commit f22a0ec2e4
5 changed files with 186 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
<domain type="test">
<uuid>00000000-1111-2222-3333-444444444444</uuid>
<vcpu>1</vcpu>
<os>
<type arch="i686">hvm</type>
</os>
<features>
<pae/>
<vmport state="off"/>
</features>
<clock offset="utc"/>
<pm>
<suspend-to-mem enabled="no"/>
<suspend-to-disk enabled="no"/>
</pm>
<devices>
<emulator>/usr/bin/test-hv</emulator>
<disk type="file" device="cdrom">
<target dev="sda" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdb" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdz" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdd" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sde" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdf" bus="scsi"/>
<readonly/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<console type="pty"/>
<input type="tablet" bus="usb"/>
<graphics type="spice" port="-1" tlsPort="-1" autoport="yes">
<image compression="off"/>
</graphics>
<sound model="ich6"/>
<video>
<model type="qxl"/>
</video>
<redirdev bus="usb" type="spicevmc"/>
<redirdev bus="usb" type="spicevmc"/>
</devices>
</domain>

View File

@@ -0,0 +1,63 @@
<domain type="test">
<uuid>00000000-1111-2222-3333-444444444444</uuid>
<vcpu>1</vcpu>
<os>
<type arch="i686">hvm</type>
</os>
<features>
<pae/>
<vmport state="off"/>
</features>
<clock offset="utc"/>
<pm>
<suspend-to-mem enabled="no"/>
<suspend-to-disk enabled="no"/>
</pm>
<devices>
<emulator>/usr/bin/test-hv</emulator>
<disk type="file" device="cdrom">
<target dev="sda" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdb" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdz" bus="scsi"/>
<readonly/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdd" bus="scsi"/>
<readonly/>
</disk>
<disk device="cdrom">
<target dev="sdw" bus="scsi"/>
</disk>
<disk type="file" device="cdrom">
<target dev="sdf" bus="scsi"/>
<readonly/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<console type="pty"/>
<input type="tablet" bus="usb"/>
<graphics type="spice" port="-1" tlsPort="-1" autoport="yes">
<image compression="off"/>
</graphics>
<sound model="ich6"/>
<video>
<model type="qxl"/>
</video>
<redirdev bus="usb" type="spicevmc"/>
<redirdev bus="usb" type="spicevmc"/>
</devices>
</domain>

View File

@@ -1451,3 +1451,31 @@ class XMLParseTest(unittest.TestCase):
raise AssertionError("Expected parse failure")
except RuntimeError as e:
self.assertTrue("'foo'" in str(e))
def testReplaceChildParse(self):
buildfile = "tests/xmlparse-xml/replace-child-build.xml"
parsefile = "tests/xmlparse-xml/replace-child-parse.xml"
def mkdisk(target):
disk = virtinst.DeviceDisk(self.conn)
disk.device = "cdrom"
disk.bus = "scsi"
disk.target = target
return disk
guest = virtinst.Guest(self.conn)
guest.add_device(mkdisk("sda"))
guest.add_device(mkdisk("sdb"))
guest.add_device(mkdisk("sdc"))
guest.add_device(mkdisk("sdd"))
guest.add_device(mkdisk("sde"))
guest.add_device(mkdisk("sdf"))
guest.devices.replace_child(guest.devices.disk[2], mkdisk("sdz"))
guest.set_defaults(guest)
utils.diff_compare(guest.get_xml(), buildfile)
guest = virtinst.Guest(self.conn, parsexml=guest.get_xml())
newdisk = virtinst.DeviceDisk(self.conn,
parsexml=mkdisk("sdw").get_xml())
guest.devices.replace_child(guest.devices.disk[4], newdisk)
utils.diff_compare(guest.get_xml(), parsefile)

View File

@@ -109,6 +109,8 @@ class _XMLBase(object):
raise NotImplementedError()
def _node_remove_child(self, parentnode, childnode):
raise NotImplementedError()
def _node_replace_child(self, xpath, newnode):
raise NotImplementedError()
def _node_from_xml(self, xml):
raise NotImplementedError()
def _node_has_content(self, node):
@@ -160,6 +162,13 @@ class _XMLBase(object):
parentnode = self._node_make_stub(xpath)
self._node_add_child(xpath, parentnode, newnode)
def node_replace_xml(self, xpath, xml):
"""
Replace the node at xpath with the passed in xml
"""
newnode = self._node_from_xml(xml)
self._node_replace_child(xpath, newnode)
def node_force_remove(self, fullxpath):
"""
Remove the element referenced at the passed xpath, regardless
@@ -390,5 +399,9 @@ class _Libxml2API(_XMLBase):
parentnode.addChild(newnode)
parentnode.addChild(libxml2.newText(endtext))
def _node_replace_child(self, xpath, newnode):
oldnode = self._find(xpath)
oldnode.replaceNode(newnode)
XMLAPI = _Libxml2API

View File

@@ -709,6 +709,24 @@ class XMLBuilder(object):
self._xmlstate.xmlapi.node_force_remove(xpath)
self._set_child_xpaths()
def replace_child(self, origobj, newobj):
"""
Replace the origobj child with the newobj. For is_build, this
replaces the objects, but for !is_build this only replaces the
XML and keeps the object references in place. This is hacky and
it's fixable but at time or writing it doesn't matter for
our usecases.
"""
if not self._xmlstate.is_build:
xpath = origobj.get_xml_id()
indent = 2 * xpath.count("/")
xml = util.xml_indent(newobj.get_xml(), indent).strip()
self._xmlstate.xmlapi.node_replace_xml(xpath, xml)
else:
origidx = origobj.get_xml_idx()
self.remove_child(origobj)
self.add_child(newobj, idx=origidx)
def _prop_is_unset(self, propname):
"""
Return True if the property name has never had a value set