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

View File

@ -49,24 +49,36 @@
<guest>
<os_type>hvm</os_type>
<arch name="s390x">
<arch name='s390x'>
<wordsize>64</wordsize>
<emulator>/usr/bin/qemu-system-s390x</emulator>
<machine canonical="s390-virtio" maxCpus="255">s390</machine>
<machine canonical="s390-ccw-virtio" maxCpus="255">s390-ccw</machine>
<domain type="qemu">
<emulator>/usr/bin/qemu-system-s390x</emulator>
</domain>
<domain type="kvm">
<emulator>/usr/bin/qemu-system-s390x</emulator>
<machine canonical="s390-virtio" maxCpus="255">s390</machine>
<machine canonical="s390-ccw-virtio" maxCpus="255">s390-ccw</machine>
</domain>
<machine maxCpus='248'>s390-ccw-virtio-6.1</machine>
<machine canonical='s390-ccw-virtio-6.1' maxCpus='248'>s390-ccw-virtio</machine>
<machine maxCpus='248'>s390-ccw-virtio-4.0</machine>
<machine maxCpus='248'>s390-ccw-virtio-5.2</machine>
<machine maxCpus='248'>s390-ccw-virtio-3.1</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.6</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.12</machine>
<machine maxCpus='248'>s390-ccw-virtio-2.9</machine>
<machine maxCpus='248'>s390-ccw-virtio-6.0</machine>
<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>
<features>
<cpuselection/>
<deviceboot/>
<disksnapshot default="on" toggle="no"/>
<disksnapshot default='on' toggle='no'/>
</features>
</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>
<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="i686">hvm</type>
<type arch="x86_64" machine="pc-q35-foobar">hvm</type>
<boot dev="hd"/>
</os>
<clock offset="utc"/>

View File

@ -1,11 +1,11 @@
<domain type='test' id='1'>
<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='i686'>hvm</type>
<type arch='x86_64' machine="pc-q35-foobar">hvm</type>
<boot dev='hd'/>
</os>
<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("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-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("--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 --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")

View File

@ -1137,3 +1137,20 @@ def testControllerAttachedDevices():
# Little test for DeviceAddress.pretty_desc
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 #
###################
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):
if not self.editing:
# 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("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
cls.add_arg("os_type", "os_type")
cls.add_arg("arch", "arch")

View File

@ -674,6 +674,43 @@ class Guest(XMLBuilder):
log.warning( # pragma: no cover
"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):
"""
<cpu> topology count and <vcpus> always need to match. Handle