[pve-devel] [PATCH qemu-server 1/2] Use 'QEMU version' -> '+pve-version' mapping for machine types
Stefan Reiter
s.reiter at proxmox.com
Mon Feb 10 16:05:35 CET 2020
The previously introduced approach can fail for pinned versions when a
new QEMU release is introduced. The saner approach is to use a mapping
that gives one pve-version for each QEMU release.
Fortunately, the old system has not been bumped yet, so we can still
change it without too much effort.
QEMU versions without a mapping are assumed to be pve0, 4.1 is mapped to
pve1 since thats what we had as our default previously.
Pinned machine versions (i.e. pc-i440fx-4.1) are always assumed to be
pve0, for specific pve-versions they'd have to be pinned as well (i.e.
pc-i440fx-4.1+pve1).
The new logic also makes the pve-version dynamic, and starts VMs with
the lowest possible 'feature-level', i.e. if a feature is only available
with 4.1+pve2, but the VM isn't using it, we still start it with
4.1+pve0.
We die if we don't support a version that is requested from us. This
allows us to use the pve-version as live-migration blocks (i.e. bumping
the version and then live-migrating a VM which uses the new feature (so
is running with the bumped version) to an outdated node will present the
user with a helpful error message and fail instead of silently modifying
the config and only failing *after* the migration).
$version_guard is introduced in config_to_command to use for features
that need to check pve-version, it automatically handles selecting the
newest necessary pve-version for the VM.
Tests have to be adjusted, since all of them now resolve to pve0 instead
of pve1. EXPECT_ERROR matching is changed to use 'eq' instead of regex
to allow special characters in error messages.
Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
For some reason, thinking this through is astonishingly confusing. My head is
spinning with QEMU versions, and I'll probably have nightmares of '+pve0'
tonight, but I *think* this should now cover all of our bases?
Based on several off-list email and in-person discussions with Thomas and
Dominik.
Speaking of @Dominik: You'd have to rebase your recent patch [0] to use the new
format.
Anyway, thourough review appreciated, let's avoid having to change this again.
[0] https://pve.proxmox.com/pipermail/pve-devel/2020-February/041588.html
PVE/QemuServer.pm | 53 +++++++++++++++----
PVE/QemuServer/Machine.pm | 38 ++++++++++++-
test/cfg2cmd/i440fx-win10-hostpci.conf.cmd | 2 +-
.../minimal-defaults-to-new-machine.conf | 2 +-
...imal-defaults-unsupported-pve-version.conf | 5 ++
test/cfg2cmd/minimal-defaults.conf.cmd | 2 +-
test/cfg2cmd/pinned-version.conf.cmd | 2 +-
.../q35-linux-hostpci-multifunction.conf.cmd | 2 +-
test/cfg2cmd/q35-linux-hostpci.conf.cmd | 2 +-
test/cfg2cmd/q35-win10-hostpci.conf.cmd | 2 +-
test/cfg2cmd/spice-linux-4.1.conf.cmd | 2 +-
test/run_config2command_tests.pl | 2 +-
12 files changed, 92 insertions(+), 22 deletions(-)
create mode 100644 test/cfg2cmd/minimal-defaults-unsupported-pve-version.conf
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 318ee54..37ffc86 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -3241,14 +3241,24 @@ my $default_machines = {
};
sub get_vm_machine {
- my ($conf, $forcemachine, $arch, $add_pve_version) = @_;
+ my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
my $machine = $forcemachine || $conf->{machine};
if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
$arch //= 'x86_64';
$machine ||= $default_machines->{$arch};
- $machine .= "+pve$PVE::QemuServer::Machine::PVE_MACHINE_VERSION" if $add_pve_version;
+ if ($add_pve_version) {
+ $kvmversion //= kvm_user_version();
+ my $pvever = PVE::QemuServer::Machine::get_pve_version($kvmversion);
+ $machine .= "+pve$pvever";
+ }
+ }
+
+ if ($add_pve_version && $machine !~ m/\+pve\d+$/) {
+ # for version-pinned machines that do not include a pve-version (e.g.
+ # pc-q35-4.1), we assume 0 to keep them stable in case we bump
+ $machine .= '+pve0';
}
return $machine;
@@ -3422,8 +3432,26 @@ sub config_to_command {
$kvm //= 1 if is_native($arch);
$machine_version =~ m/(\d+)\.(\d+)/;
+ my ($machine_major, $machine_minor) = ($1, $2);
die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
- if !PVE::QemuServer::min_version($kvmver, $1, $2);
+ if !PVE::QemuServer::min_version($kvmver, $machine_major, $machine_minor);
+
+ if (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
+ my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
+ die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
+ . " is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
+ }
+
+ # if a specific +pve version is required for a feature, use $version_guard
+ # instead of min_version to allow machines to be run with the minimum
+ # required version
+ my $required_pve_version = 0;
+ my $version_guard = sub {
+ my ($major, $minor, $pve) = @_;
+ return 0 if !min_version($machine_version, $major, $minor, $pve);
+ $required_pve_version = $pve if $pve && $pve > $required_pve_version;
+ return 1;
+ };
if ($kvm) {
die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
@@ -3774,14 +3802,6 @@ sub config_to_command {
push @$rtcFlags, 'driftfix=slew' if $tdf;
- if (!$kvm) {
- push @$machineFlags, 'accel=tcg';
- }
-
- if ($machine_type) {
- push @$machineFlags, "type=${machine_type}";
- }
-
if (($conf->{startdate}) && ($conf->{startdate} ne 'now')) {
push @$rtcFlags, "base=$conf->{startdate}";
} elsif ($useLocaltime) {
@@ -4005,6 +4025,17 @@ sub config_to_command {
}
}
+ if (!$kvm) {
+ push @$machineFlags, 'accel=tcg';
+ }
+
+ my $machine_type_min = $machine_type;
+ if ($add_pve_version) {
+ $machine_type_min =~ s/\+pve\d+$//;
+ $machine_type_min .= "+pve$required_pve_version";
+ }
+ push @$machineFlags, "type=${machine_type_min}";
+
push @$cmd, @$devices;
push @$cmd, '-rtc', join(',', @$rtcFlags)
if scalar(@$rtcFlags);
diff --git a/PVE/QemuServer/Machine.pm b/PVE/QemuServer/Machine.pm
index 8c13402..9fbe9a8 100644
--- a/PVE/QemuServer/Machine.pm
+++ b/PVE/QemuServer/Machine.pm
@@ -8,7 +8,9 @@ use PVE::QemuServer::Monitor;
# Bump this for VM HW layout changes during a release (where the QEMU machine
# version stays the same)
-our $PVE_MACHINE_VERSION = 1;
+our $PVE_MACHINE_VERSION = {
+ '4.1' => 1,
+};
sub machine_type_is_q35 {
my ($conf) = @_;
@@ -47,7 +49,8 @@ sub extract_version {
return $versionstr;
} elsif (defined($kvmversion)) {
if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
- return "$1.$2+pve$PVE_MACHINE_VERSION";
+ my $pvever = get_pve_version($kvmversion);
+ return "$1.$2+pve$pvever";
}
}
@@ -61,6 +64,37 @@ sub machine_version {
extract_version($machine_type), $major, $minor, $pve);
}
+sub get_pve_version {
+ my ($verstr) = @_;
+
+ if ($verstr =~ m/^(\d+\.\d+)/) {
+ return $PVE_MACHINE_VERSION->{$1} // 0;
+ }
+
+ die "internal error: cannot get pve version for invalid string '$verstr'";
+}
+
+sub can_run_pve_machine_version {
+ my ($machine_version, $kvmversion) = @_;
+
+ $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))$/;
+ my $major = $1;
+ my $minor = $2;
+ my $pvever = $3;
+
+ $kvmversion =~ m/(\d+)\.(\d+)/;
+ return 0 if PVE::QemuServer::Helpers::version_cmp($1, $major, $2, $minor) < 0;
+
+ # if $pvever is missing or 0, we definitely support it as long as we didn't
+ # fail the QEMU version check above
+ return 1 if !$pvever;
+
+ my $max_supported = get_pve_version("$major.$minor");
+ return 1 if $max_supported >= $pvever;
+
+ return 0;
+}
+
# dies if a) VM not running or not exisiting b) Version query failed
# So, any defined return value is valid, any invalid state can be caught by eval
sub runs_at_least_qemu_version {
diff --git a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
index bda7f63..43741ae 100644
--- a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
+++ b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd
@@ -33,5 +33,5 @@
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
-rtc 'driftfix=slew,base=localtime' \
- -machine 'type=pc+pve1' \
+ -machine 'type=pc+pve0' \
-global 'kvm-pit.lost_tick_policy=discard'
diff --git a/test/cfg2cmd/minimal-defaults-to-new-machine.conf b/test/cfg2cmd/minimal-defaults-to-new-machine.conf
index 5c0486b..35967cf 100644
--- a/test/cfg2cmd/minimal-defaults-to-new-machine.conf
+++ b/test/cfg2cmd/minimal-defaults-to-new-machine.conf
@@ -1,5 +1,5 @@
# TEST: newer machine verison than QEMU version installed on node
# QEMU_VERSION: 4.1.1
-# EXPECT_ERROR: Installed QEMU version '4.1.1' is too old to run machine type 'pc-q35-42.9', please upgrade node 'localhost'
+# EXPECT_ERROR: Installed QEMU version '4.1.1' is too old to run machine type 'pc-q35-42.9+pve0', please upgrade node 'localhost'
smbios1: uuid=6cf17dc3-8341-4ecc-aebd-7503f2583fb3
machine: pc-q35-42.9
diff --git a/test/cfg2cmd/minimal-defaults-unsupported-pve-version.conf b/test/cfg2cmd/minimal-defaults-unsupported-pve-version.conf
new file mode 100644
index 0000000..87e7a07
--- /dev/null
+++ b/test/cfg2cmd/minimal-defaults-unsupported-pve-version.conf
@@ -0,0 +1,5 @@
+# TEST: newer machine verison than QEMU version installed on node
+# QEMU_VERSION: 4.1.1
+# EXPECT_ERROR: Installed qemu-server (max feature level for 4.0 is pve0) is too old to run machine type 'pc-q35-4.0+pve77', please upgrade node 'localhost'
+smbios1: uuid=6cf17dc3-8341-4ecc-aebd-7503f2583fb3
+machine: pc-q35-4.0+pve77
diff --git a/test/cfg2cmd/minimal-defaults.conf.cmd b/test/cfg2cmd/minimal-defaults.conf.cmd
index 83ae328..c499a85 100644
--- a/test/cfg2cmd/minimal-defaults.conf.cmd
+++ b/test/cfg2cmd/minimal-defaults.conf.cmd
@@ -21,4 +21,4 @@
-device 'VGA,id=vga,bus=pci.0,addr=0x2' \
-device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3' \
-iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
- -machine 'type=pc+pve1'
+ -machine 'type=pc+pve0'
diff --git a/test/cfg2cmd/pinned-version.conf.cmd b/test/cfg2cmd/pinned-version.conf.cmd
index abfbea0..2fc31fc 100644
--- a/test/cfg2cmd/pinned-version.conf.cmd
+++ b/test/cfg2cmd/pinned-version.conf.cmd
@@ -27,4 +27,4 @@
-device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,bootindex=100' \
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=A2:C0:43:77:08:A1,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
- -machine 'type=pc-q35-3.1'
+ -machine 'type=pc-q35-3.1+pve0'
diff --git a/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd b/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
index e20be7d..c766d33 100644
--- a/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
+++ b/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd
@@ -31,4 +31,4 @@
-iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
- -machine 'type=q35+pve1'
+ -machine 'type=q35+pve0'
diff --git a/test/cfg2cmd/q35-linux-hostpci.conf.cmd b/test/cfg2cmd/q35-linux-hostpci.conf.cmd
index 152624c..7059b29 100644
--- a/test/cfg2cmd/q35-linux-hostpci.conf.cmd
+++ b/test/cfg2cmd/q35-linux-hostpci.conf.cmd
@@ -36,4 +36,4 @@
-iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
- -machine 'type=q35+pve1'
+ -machine 'type=q35+pve0'
diff --git a/test/cfg2cmd/q35-win10-hostpci.conf.cmd b/test/cfg2cmd/q35-win10-hostpci.conf.cmd
index ff799ea..3397324 100644
--- a/test/cfg2cmd/q35-win10-hostpci.conf.cmd
+++ b/test/cfg2cmd/q35-win10-hostpci.conf.cmd
@@ -34,5 +34,5 @@
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
-rtc 'driftfix=slew,base=localtime' \
- -machine 'type=q35+pve1' \
+ -machine 'type=q35+pve0' \
-global 'kvm-pit.lost_tick_policy=discard'
diff --git a/test/cfg2cmd/spice-linux-4.1.conf.cmd b/test/cfg2cmd/spice-linux-4.1.conf.cmd
index 4ed6fd2..6aa781b 100644
--- a/test/cfg2cmd/spice-linux-4.1.conf.cmd
+++ b/test/cfg2cmd/spice-linux-4.1.conf.cmd
@@ -27,4 +27,4 @@
-iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
-netdev 'type=tap,id=net0,ifname=tap8006i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown,vhost=on' \
-device 'virtio-net-pci,mac=A2:C0:43:67:08:A1,netdev=net0,bus=pci.0,addr=0x12,id=net0,bootindex=300' \
- -machine 'type=pc+pve1'
+ -machine 'type=pc+pve0'
diff --git a/test/run_config2command_tests.pl b/test/run_config2command_tests.pl
index bad6501..c3e5092 100755
--- a/test/run_config2command_tests.pl
+++ b/test/run_config2command_tests.pl
@@ -292,7 +292,7 @@ sub do_test($) {
return;
}
chomp $err;
- if ($err !~ /^\s*$err_expect\s*$/) {
+ if ($err ne $err_expect) {
fail("$testname");
note("error does not match expected error: '$err' !~ '$err_expect'");
} else {
--
2.20.1
More information about the pve-devel
mailing list