mirror of
git://git.proxmox.com/git/qemu-server.git
synced 2025-01-11 05:17:57 +03:00
Use 'QEMU version' -> '+pve-version' mapping for machine types
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@proxmox.com>
This commit is contained in:
parent
8541f8cddb
commit
ac0077cc33
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user