mirror of
				https://git.proxmox.com/git/qemu-server
				synced 2025-11-04 12:52:06 +00:00 
			
		
		
		
	Pinned machine versions like "pc-i440fx-4.2+pve2.pxe" would otherwise get a second "+pve0" suffix, which is incorrect. Also deal with non-pve pinned versions correctly, i.e. "pc-i440fx-5.2.pxe" becomes "pc-i440fx-5.2+pve0.pxe". Handle .pxe suffixes in Machine.pm as well, and add two test cases. Co-developed-by: Luca Berneking <luca@berneking.net> Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
		
			
				
	
	
		
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
package PVE::QemuServer::Machine;
 | 
						|
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
 | 
						|
use PVE::QemuServer::Helpers;
 | 
						|
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 = {
 | 
						|
    '4.1' => 2,
 | 
						|
};
 | 
						|
 | 
						|
sub machine_type_is_q35 {
 | 
						|
    my ($conf) = @_;
 | 
						|
 | 
						|
    return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
sub current_from_query_machines {
 | 
						|
    my ($res) = @_;
 | 
						|
 | 
						|
    my ($current, $pve_version, $default);
 | 
						|
    foreach my $e (@$res) {
 | 
						|
	$default = $e->{name} if $e->{'is-default'};
 | 
						|
	$current = $e->{name} if $e->{'is-current'};
 | 
						|
	$pve_version = $e->{'pve-version'} if $e->{'pve-version'};
 | 
						|
    }
 | 
						|
 | 
						|
    $current .= "+$pve_version" if $current && $pve_version;
 | 
						|
 | 
						|
    # fallback to the default machine if current is not supported by qemu
 | 
						|
    return $current || $default || 'pc';
 | 
						|
}
 | 
						|
 | 
						|
# this only works if VM is running
 | 
						|
sub get_current_qemu_machine {
 | 
						|
    my ($vmid) = @_;
 | 
						|
 | 
						|
    my $res = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-machines');
 | 
						|
 | 
						|
    return current_from_query_machines($res);
 | 
						|
}
 | 
						|
 | 
						|
# returns a string with major.minor+pve<VERSION>, patch version-part is ignored
 | 
						|
# as it's seldom ressembling a real QEMU machine type, so it would be '0' 99% of
 | 
						|
# the time anyway.. This explicitly separates pveversion from the machine.
 | 
						|
sub extract_version {
 | 
						|
    my ($machine_type, $kvmversion) = @_;
 | 
						|
 | 
						|
    if (defined($machine_type) && $machine_type =~
 | 
						|
	m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/)
 | 
						|
    {
 | 
						|
	my $versionstr = "$1.$2";
 | 
						|
	$versionstr .= $4 if $4;
 | 
						|
	return $versionstr;
 | 
						|
    } elsif (defined($kvmversion)) {
 | 
						|
	if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
 | 
						|
	    my $pvever = get_pve_version($kvmversion);
 | 
						|
	    return "$1.$2+pve$pvever";
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
sub machine_version {
 | 
						|
    my ($machine_type, $major, $minor, $pve) = @_;
 | 
						|
 | 
						|
    return PVE::QemuServer::Helpers::min_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+))?(?:\.pxe)?$/;
 | 
						|
    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 {
 | 
						|
    my ($vmid, $major, $minor, $extra) = @_;
 | 
						|
 | 
						|
    my $v = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-version');
 | 
						|
    die "could not query currently running version for VM $vmid\n" if !defined($v);
 | 
						|
    $v = $v->{qemu};
 | 
						|
 | 
						|
    return PVE::QemuServer::Helpers::version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
 | 
						|
}
 | 
						|
 | 
						|
sub qemu_machine_pxe {
 | 
						|
    my ($vmid, $conf) = @_;
 | 
						|
 | 
						|
    my $machine =  get_current_qemu_machine($vmid);
 | 
						|
 | 
						|
    if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
 | 
						|
	$machine .= '.pxe';
 | 
						|
    }
 | 
						|
 | 
						|
    return $machine;
 | 
						|
}
 | 
						|
 | 
						|
1;
 |