cli: Add --boot refresh-machine-type=yes

This is a virt-xml option to refresh a VM to use the latest machine
type version for the machine type it's currently using. Ex:

pseries-2.11 -> pseries
pc-q35-5.0 -> q35

This is useful for when qemu deprecates and removes the machine type
out from under you, or to pick up bug fixes.

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2022-02-24 19:08:18 -05:00
parent 310136337c
commit b275e3c266
9 changed files with 120 additions and 16 deletions

View File

@ -257,6 +257,17 @@ For any option, use --option=? to see a list of all available sub options, examp
--help output also lists a few general examples. See the EXAMPLES section below for some common examples. --help output also lists a few general examples. See the EXAMPLES section below for some common examples.
virt-xml specifically has some operations that don't really apply to virt-install
Examples:
``--boot refresh-machine-type=yes``
Refresh the XML ``<os><type machine=X></os>`` value to the latest one
that qemu provides. For example, if your VM has a machine type value
``pc-q35-4.0``, this will reset the value to ``q35``, and works
similarly with other versioned machine types. Occasionally this is
necessary to get enable qemu bug fixes, or when qemu deprecates and
removes old machine type values.
MISCELLANEOUS OPTIONS MISCELLANEOUS OPTIONS
===================== =====================

View File

@ -49,24 +49,36 @@
<guest> <guest>
<os_type>hvm</os_type> <os_type>hvm</os_type>
<arch name="s390x"> <arch name='s390x'>
<wordsize>64</wordsize> <wordsize>64</wordsize>
<emulator>/usr/bin/qemu-system-s390x</emulator> <emulator>/usr/bin/qemu-system-s390x</emulator>
<machine canonical="s390-virtio" maxCpus="255">s390</machine> <machine maxCpus='248'>s390-ccw-virtio-6.1</machine>
<machine canonical="s390-ccw-virtio" maxCpus="255">s390-ccw</machine> <machine canonical='s390-ccw-virtio-6.1' maxCpus='248'>s390-ccw-virtio</machine>
<domain type="qemu"> <machine maxCpus='248'>s390-ccw-virtio-4.0</machine>
<emulator>/usr/bin/qemu-system-s390x</emulator> <machine maxCpus='248'>s390-ccw-virtio-5.2</machine>
</domain> <machine maxCpus='248'>s390-ccw-virtio-3.1</machine>
<domain type="kvm"> <machine maxCpus='248'>s390-ccw-virtio-2.6</machine>
<emulator>/usr/bin/qemu-system-s390x</emulator> <machine maxCpus='248'>s390-ccw-virtio-2.12</machine>
<machine canonical="s390-virtio" maxCpus="255">s390</machine> <machine maxCpus='248'>s390-ccw-virtio-2.9</machine>
<machine canonical="s390-ccw-virtio" maxCpus="255">s390-ccw</machine> <machine maxCpus='248'>s390-ccw-virtio-6.0</machine>
</domain> <machine maxCpus='248'>s390-ccw-virtio-5.1</machine>
<machine maxCpus='248'>s390-ccw-virtio-3.0</machine>
<machine maxCpus='248'>s390-ccw-virtio-4.2</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.5</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.11</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.8</machine>
<machine maxCpus='248'>s390-ccw-virtio-5.0</machine>
<machine maxCpus='248'>s390-ccw-virtio-4.1</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.4</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.10</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.7</machine>
<domain type='qemu'/>
<domain type='kvm'/>
</arch> </arch>
<features> <features>
<cpuselection/> <cpuselection/>
<deviceboot/> <deviceboot/>
<disksnapshot default="on" toggle="no"/> <disksnapshot default='on' toggle='no'/>
</features> </features>
</guest> </guest>

View File

@ -0,0 +1,17 @@
<domain type="kvm">
<name>test</name>
<uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>
<memory unit="KiB">8388608</memory>
<currentMemory unit="KiB">2097152</currentMemory>
<vcpu placement="static">2</vcpu>
<os>
<type arch="x86_64" machine="q35">hvm</type>
<boot dev="hd"/>
</os>
<clock offset="utc"/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
</devices>
</domain>

View File

@ -1,11 +1,11 @@
<domain type="test" id="1"> <domain type="kvm">
<name>test</name> <name>test</name>
<uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid> <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>
<memory unit="KiB">8388608</memory> <memory unit="KiB">8388608</memory>
<currentMemory unit="KiB">2097152</currentMemory> <currentMemory unit="KiB">2097152</currentMemory>
<vcpu placement="static">2</vcpu> <vcpu placement="static">2</vcpu>
<os> <os>
<type arch="i686">hvm</type> <type arch="x86_64" machine="pc-q35-foobar">hvm</type>
<boot dev="hd"/> <boot dev="hd"/>
</os> </os>
<clock offset="utc"/> <clock offset="utc"/>

View File

@ -1,11 +1,11 @@
<domain type='test' id='1'> <domain type='kvm'>
<name>test</name> <name>test</name>
<uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid> <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>
<memory unit='KiB'>8388608</memory> <memory unit='KiB'>8388608</memory>
<currentMemory unit='KiB'>2097152</currentMemory> <currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>2</vcpu> <vcpu placement='static'>2</vcpu>
<os> <os>
<type arch='i686'>hvm</type> <type arch='x86_64' machine="pc-q35-foobar">hvm</type>
<boot dev='hd'/> <boot dev='hd'/>
</os> </os>
<clock offset='utc'/> <clock offset='utc'/>

View File

@ -1316,8 +1316,10 @@ c.add_invalid("test-for-virtxml --edit --graphics password=foo,keymap= --update
c.add_invalid("--build-xml --memory 10,maxmemory=20", grep="--build-xml not supported for --memory") c.add_invalid("--build-xml --memory 10,maxmemory=20", grep="--build-xml not supported for --memory")
c.add_invalid("test-state-shutoff --edit sparse=no --disk path=blah", grep="Don't know how to match device type 'disk' property 'sparse'") c.add_invalid("test-state-shutoff --edit sparse=no --disk path=blah", grep="Don't know how to match device type 'disk' property 'sparse'")
c.add_invalid("test --add-device --xml ./@foo=bar", grep="--xml can only be used with --edit") c.add_invalid("test --add-device --xml ./@foo=bar", grep="--xml can only be used with --edit")
c.add_invalid("test-for-virtxml --edit --boot refresh-machine-type=yes", grep="Don't know how to refresh")
c.add_compare("test --print-xml --edit --vcpus 7", "print-xml") # test --print-xml c.add_compare("test --print-xml --edit --vcpus 7", "print-xml") # test --print-xml
c.add_compare("--edit --cpu host-passthrough", "stdin-edit", input_file=(_VIRTXMLDIR + "virtxml-stdin-edit.xml")) # stdin test c.add_compare("--edit --cpu host-passthrough", "stdin-edit", input_file=(_VIRTXMLDIR + "virtxml-stdin-edit.xml")) # stdin test
c.add_compare("--connect %(URI-KVM-X86)s --edit --boot refresh-machine-type=yes", "refresh-machine-type", input_file=(_VIRTXMLDIR + "virtxml-stdin-edit.xml")) # refresh-machine-type test. we need to use stdin XML since we can't get the libvirt testdriver to start with the machine XML we need
c.add_compare("--build-xml --cpu pentium3,+x2apic", "build-cpu") c.add_compare("--build-xml --cpu pentium3,+x2apic", "build-cpu")
c.add_compare("--build-xml --tpm path=/dev/tpm", "build-tpm") c.add_compare("--build-xml --tpm path=/dev/tpm", "build-tpm")
c.add_compare("--build-xml --blkiotune weight=100,device0.path=/dev/sdf,device.weight=200,device0.read_bytes_sec=10000,device0.write_bytes_sec=10000,device0.read_iops_sec=20000,device0.write_iops_sec=20000", "build-blkiotune") c.add_compare("--build-xml --blkiotune weight=100,device0.path=/dev/sdf,device.weight=200,device0.read_bytes_sec=10000,device0.write_bytes_sec=10000,device0.read_iops_sec=20000,device0.write_iops_sec=20000", "build-blkiotune")

View File

@ -1137,3 +1137,20 @@ def testControllerAttachedDevices():
# Little test for DeviceAddress.pretty_desc # Little test for DeviceAddress.pretty_desc
assert devs[-1].address.pretty_desc() == "0:0:0:3" assert devs[-1].address.pretty_desc() == "0:0:0:3"
def testRefreshMachineType():
guest = virtinst.Guest(utils.URIs.openconn(utils.URIs.kvm_x86))
guest.os.machine = "pc-i440fx-5.2"
guest.refresh_machine_type()
assert guest.os.machine == "pc"
guest = virtinst.Guest(utils.URIs.openconn(utils.URIs.kvm_x86))
guest.os.machine = "pc-q35-XYZ"
guest.refresh_machine_type()
assert guest.os.machine == "q35"
guest = virtinst.Guest(utils.URIs.openconn(utils.URIs.kvm_s390x))
guest.os.machine = "s390-ccw-virtio-12345"
guest.refresh_machine_type()
assert guest.os.machine == "s390-ccw-virtio"

View File

@ -2738,6 +2738,10 @@ class ParserBoot(VirtCLIParser):
# Option handling # # Option handling #
################### ###################
def refresh_machine_type_cb(self, inst, val, virtarg):
if val is True:
self.guest.refresh_machine_type()
def set_uefi_cb(self, inst, val, virtarg): def set_uefi_cb(self, inst, val, virtarg):
if not self.editing: if not self.editing:
# From virt-install, we just set this flag, and set_defaults() # From virt-install, we just set this flag, and set_defaults()
@ -2797,6 +2801,10 @@ class ParserBoot(VirtCLIParser):
cls.add_arg("fd", None, lookup_cb=None, cb=cls.noset_cb) cls.add_arg("fd", None, lookup_cb=None, cb=cls.noset_cb)
cls.add_arg("network", None, lookup_cb=None, cb=cls.noset_cb) cls.add_arg("network", None, lookup_cb=None, cb=cls.noset_cb)
cls.add_arg("refresh-machine-type", None,
cb=cls.refresh_machine_type_cb,
lookup_cb=None, is_onoff=True)
# UEFI depends on these bits, so set them first # UEFI depends on these bits, so set them first
cls.add_arg("os_type", "os_type") cls.add_arg("os_type", "os_type")
cls.add_arg("arch", "arch") cls.add_arg("arch", "arch")

View File

@ -674,6 +674,43 @@ class Guest(XMLBuilder):
log.warning( # pragma: no cover log.warning( # pragma: no cover
"KVM acceleration not available, using '%s'", self.type) "KVM acceleration not available, using '%s'", self.type)
def refresh_machine_type(self):
"""
Reset the guests's machine type to the latest 'canonical' machine
name that qemu reports. So if my VM is using ancient pc-0.11, we
try to turn that into just `pc`
The algorithm here is to fetch all machine types that are aliases
for a stable name (like pc -> pc-i440fx-6.2), and see if our current
machine type uses alias as a prefix. This is the format that qemu
uses for its stable machine type names.
"""
# We need to unset the machine type first, so we can perform
# a successful capsinfo lookup, otherwise we will error when qemu
# has deprecated and removed the old machine type
original_machine_type = self.os.machine or ""
self.os.machine = None
capsinfo = self.lookup_capsinfo()
mobjs = (capsinfo.domain and
capsinfo.domain.machines) or capsinfo.guest.machines
canonical_names = [m.name for m in mobjs if m.canonical]
for machine_alias in canonical_names:
if machine_alias == "pc":
prefix = "pc-i440fx-"
elif machine_alias == "q35":
prefix = "pc-q35-"
else:
# Example: pseries-X, virt-X, s390-ccw-virtio-X
prefix = machine_alias + "-"
if original_machine_type.startswith(prefix):
self.os.machine = machine_alias
return
raise Exception("Don't know how to refresh machine type '%s'" %
original_machine_type)
def sync_vcpus_topology(self, defCPUs): def sync_vcpus_topology(self, defCPUs):
""" """
<cpu> topology count and <vcpus> always need to match. Handle <cpu> topology count and <vcpus> always need to match. Handle