1 package PVE
::QemuServer
::Machine
;
6 use PVE
::QemuServer
::Helpers
;
7 use PVE
::QemuServer
::Monitor
;
8 use PVE
::JSONSchema
qw(get_standard_option parse_property_string);
10 # Bump this for VM HW layout changes during a release (where the QEMU machine
11 # version stays the same)
12 our $PVE_MACHINE_VERSION = {
19 description
=> "Specifies the QEMU machine type.",
21 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
23 format_description
=> 'machine type',
28 PVE
::JSONSchema
::register_format
('pve-qemu-machine-fmt', $machine_fmt);
30 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
31 description
=> "Specify the QEMU machine type.",
34 format
=> PVE
::JSONSchema
::get_format
('pve-qemu-machine-fmt'),
42 my $res = parse_property_string
($machine_fmt, $value);
47 my ($machine_conf) = @_;
48 return print_property_string
($machine_conf, $machine_fmt);
51 sub machine_type_is_q35
{
54 my $machine_conf = parse_machine
($conf->{machine
});
55 return $machine_conf->{type
} && ($machine_conf->{type
} =~ m/q35/) ?
1 : 0;
58 # In list context, also returns whether the current machine is deprecated or not.
59 sub current_from_query_machines
{
62 my ($current, $default);
63 for my $machine ($machines->@*) {
64 $default = $machine->{name
} if $machine->{'is-default'};
66 if ($machine->{'is-current'}) {
67 $current = $machine->{name
};
68 # pve-version only exists for the current machine
69 $current .= "+$machine->{'pve-version'}" if $machine->{'pve-version'};
70 return wantarray ?
($current, $machine->{deprecated
} ?
1 : 0) : $current;
74 # fallback to the default machine if current is not supported by qemu - assume never deprecated
75 my $fallback = $default || 'pc';
76 return wantarray ?
($fallback, 0) : $fallback;
79 # This only works if VM is running.
80 # In list context, also returns whether the current machine is deprecated or not.
81 sub get_current_qemu_machine
{
84 my $res = PVE
::QemuServer
::Monitor
::mon_cmd
($vmid, 'query-machines');
86 return current_from_query_machines
($res);
89 # returns a string with major.minor+pve<VERSION>, patch version-part is ignored
90 # as it's seldom ressembling a real QEMU machine type, so it would be '0' 99% of
91 # the time anyway.. This explicitly separates pveversion from the machine.
93 my ($machine_type, $kvmversion) = @_;
95 if (defined($machine_type) && $machine_type =~
96 m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/)
98 my $versionstr = "$1.$2";
99 $versionstr .= $4 if $4;
101 } elsif (defined($kvmversion)) {
102 if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
103 my $pvever = get_pve_version
($kvmversion);
104 return "$1.$2+pve$pvever";
111 sub machine_version
{
112 my ($machine_type, $major, $minor, $pve) = @_;
114 return PVE
::QemuServer
::Helpers
::min_version
(
115 extract_version
($machine_type), $major, $minor, $pve);
118 sub get_pve_version
{
121 if ($verstr =~ m/^(\d+\.\d+)/) {
122 return $PVE_MACHINE_VERSION->{$1} // 0;
125 die "internal error: cannot get pve version for invalid string '$verstr'";
128 sub can_run_pve_machine_version
{
129 my ($machine_version, $kvmversion) = @_;
131 $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))?(?:\.pxe)?$/;
136 $kvmversion =~ m/(\d+)\.(\d+)/;
137 return 0 if PVE
::QemuServer
::Helpers
::version_cmp
($1, $major, $2, $minor) < 0;
139 # if $pvever is missing or 0, we definitely support it as long as we didn't
140 # fail the QEMU version check above
141 return 1 if !$pvever;
143 my $max_supported = get_pve_version
("$major.$minor");
144 return 1 if $max_supported >= $pvever;
149 # dies if a) VM not running or not exisiting b) Version query failed
150 # So, any defined return value is valid, any invalid state can be caught by eval
151 sub runs_at_least_qemu_version
{
152 my ($vmid, $major, $minor, $extra) = @_;
154 my $v = PVE
::QemuServer
::Monitor
::mon_cmd
($vmid, 'query-version');
155 die "could not query currently running version for VM $vmid\n" if !defined($v);
158 return PVE
::QemuServer
::Helpers
::version_cmp
($v->{major
}, $major, $v->{minor
}, $minor, $v->{micro
}, $extra) >= 0;
161 sub qemu_machine_pxe
{
162 my ($vmid, $conf) = @_;
164 my $machine = get_current_qemu_machine
($vmid);
166 my $machine_conf = parse_machine
($conf->{machine
});
167 if ($machine_conf->{type
} && $machine_conf->{type
} =~ m/\.pxe$/) {