diff --git a/man/virt-xml.rst b/man/virt-xml.rst
index cf5db45c..ddd586bb 100644
--- a/man/virt-xml.rst
+++ b/man/virt-xml.rst
@@ -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 ```` 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
=====================
diff --git a/tests/data/capabilities/kvm-s390x.xml b/tests/data/capabilities/kvm-s390x.xml
index b79c0924..48365593 100644
--- a/tests/data/capabilities/kvm-s390x.xml
+++ b/tests/data/capabilities/kvm-s390x.xml
@@ -49,24 +49,36 @@
hvm
-
+
64
/usr/bin/qemu-system-s390x
- s390
- s390-ccw
-
- /usr/bin/qemu-system-s390x
-
-
- /usr/bin/qemu-system-s390x
- s390
- s390-ccw
-
+ s390-ccw-virtio-6.1
+ s390-ccw-virtio
+ s390-ccw-virtio-4.0
+ s390-ccw-virtio-5.2
+ s390-ccw-virtio-3.1
+ s390-ccw-virtio-2.6
+ s390-ccw-virtio-2.12
+ s390-ccw-virtio-2.9
+ s390-ccw-virtio-6.0
+ s390-ccw-virtio-5.1
+ s390-ccw-virtio-3.0
+ s390-ccw-virtio-4.2
+ s390-ccw-virtio-2.5
+ s390-ccw-virtio-2.11
+ s390-ccw-virtio-2.8
+ s390-ccw-virtio-5.0
+ s390-ccw-virtio-4.1
+ s390-ccw-virtio-2.4
+ s390-ccw-virtio-2.10
+ s390-ccw-virtio-2.7
+
+
-
+
diff --git a/tests/data/cli/compare/virt-xml-refresh-machine-type.xml b/tests/data/cli/compare/virt-xml-refresh-machine-type.xml
new file mode 100644
index 00000000..9beb406b
--- /dev/null
+++ b/tests/data/cli/compare/virt-xml-refresh-machine-type.xml
@@ -0,0 +1,17 @@
+
+ test
+ 6695eb01-f6a4-8304-79aa-97f2502e193f
+ 8388608
+ 2097152
+ 2
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+
+
diff --git a/tests/data/cli/compare/virt-xml-stdin-edit.xml b/tests/data/cli/compare/virt-xml-stdin-edit.xml
index 834755f1..5aa54146 100644
--- a/tests/data/cli/compare/virt-xml-stdin-edit.xml
+++ b/tests/data/cli/compare/virt-xml-stdin-edit.xml
@@ -1,11 +1,11 @@
-
+
test
6695eb01-f6a4-8304-79aa-97f2502e193f
8388608
2097152
2
- hvm
+ hvm
diff --git a/tests/data/cli/virtxml/virtxml-stdin-edit.xml b/tests/data/cli/virtxml/virtxml-stdin-edit.xml
index 4a7b3e32..55882a91 100644
--- a/tests/data/cli/virtxml/virtxml-stdin-edit.xml
+++ b/tests/data/cli/virtxml/virtxml-stdin-edit.xml
@@ -1,11 +1,11 @@
-
+
test
6695eb01-f6a4-8304-79aa-97f2502e193f
8388608
2097152
2
- hvm
+ hvm
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 01ab59a8..d3629350 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -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")
diff --git a/tests/test_xmlparse.py b/tests/test_xmlparse.py
index ea02eea9..49c924c7 100644
--- a/tests/test_xmlparse.py
+++ b/tests/test_xmlparse.py
@@ -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"
diff --git a/virtinst/cli.py b/virtinst/cli.py
index 81dd7e3c..c99ad039 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -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")
diff --git a/virtinst/guest.py b/virtinst/guest.py
index 5d693e3b..8e95e61d 100644
--- a/virtinst/guest.py
+++ b/virtinst/guest.py
@@ -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):
"""
topology count and always need to match. Handle