X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FQemuServer.pm;h=0b4c597368ff0c0fc5554b9c5ba888ef1a9b507f;hb=38277afcd450a53e987f9b983c4d531bb404f46c;hp=6d8e942eba1cef182d19aca4327d4563fe7a8300;hpb=70740c1a4d60b002249a648cc6588ecddb44ec70;p=qemu-server.git diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 6d8e942..0b4c597 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -93,7 +93,7 @@ PVE::JSONSchema::register_standard_option('pve-qm-image-format', { PVE::JSONSchema::register_standard_option('pve-qemu-machine', { description => "Specifies the Qemu machine type.", type => 'string', - pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\.pxe)?|virt(?:-\d+(\.\d+)+)?)', + pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)', maxLength => 40, optional => 1, }); @@ -108,7 +108,11 @@ sub cgroups_write { } -my $nodename = PVE::INotify::nodename(); +my $nodename_cache; +sub nodename { + $nodename_cache //= PVE::INotify::nodename(); + return $nodename_cache; +} my $cpu_vendor_list = { # Intel CPUs @@ -699,6 +703,11 @@ EODESCR description => "Configure additional enhancements for SPICE.", optional => 1 }, + tags => { + type => 'string', format => 'pve-tag-list', + description => 'Tags of the VM. This is only meta information.', + optional => 1, + }, }; my $cicustom_fmt = { @@ -1746,7 +1755,7 @@ sub parse_drive { } sub print_drive { - my ($vmid, $drive) = @_; + my ($drive) = @_; my $data = { %$drive }; delete $data->{$_} for qw(index interface); return PVE::JSONSchema::print_property_string($data, $alldrive_fmt); @@ -1870,7 +1879,7 @@ sub print_drivedevice_full { } # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380) - my $version = PVE::QemuServer::Machine::extract_version($machine_type) // kvm_user_version(); + my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version()); if ($path =~ m/^iscsi\:\/\// && !min_version($version, 4, 1)) { $devicetype = 'generic'; @@ -2241,13 +2250,9 @@ sub parse_hostpci { my @idlist = split(/;/, $res->{host}); delete $res->{host}; foreach my $id (@idlist) { - if ($id =~ m/\./) { # full id 00:00.1 - push @{$res->{pciid}}, { - id => $id, - }; - } else { # partial id 00:00 - $res->{pciid} = PVE::SysFSTools::lspci($id); - } + my $devs = PVE::SysFSTools::lspci($id); + die "no PCI device found for '$id'\n" if !scalar(@$devs); + push @{$res->{pciid}}, @$devs; } return $res; } @@ -2662,7 +2667,7 @@ sub parse_vm_config { my $v = parse_drive($key, $value); if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) { $v->{file} = $volid; - $value = print_drive($vmid, $v); + $value = print_drive($v); } else { warn "vm $vmid - unable to parse value of '$key'\n"; next; @@ -2735,7 +2740,7 @@ sub write_vm_config { &$cleanup_config($conf->{pending}, 1); foreach my $snapname (keys %{$conf->{snapshots}}) { - die "internal error" if $snapname eq 'pending'; + die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending'; &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname); } @@ -2804,6 +2809,7 @@ sub config_list { my $res = {}; return $res if !$vmlist || !$vmlist->{ids}; my $ids = $vmlist->{ids}; + my $nodename = nodename(); foreach my $vmid (keys %$ids) { my $d = $ids->{$vmid}; @@ -2862,7 +2868,7 @@ sub shared_nodes { my $nodelist = PVE::Cluster::get_nodelist(); my $nodehash = { map { $_ => 1 } @$nodelist }; - my $nodename = PVE::INotify::nodename(); + my $nodename = nodename(); foreach_drive($conf, sub { my ($ds, $drive) = @_; @@ -3024,7 +3030,12 @@ our $vmstatus_return_properties = { description => "The current config lock, if any.", type => 'string', optional => 1, - } + }, + tags => { + description => "The current configured tags, if any", + type => 'string', + optional => 1, + }, }; my $last_proc_pid_stat; @@ -3095,6 +3106,7 @@ sub vmstatus { $d->{serial} = 1 if conf_has_serial($conf); $d->{lock} = $conf->{lock} if $conf->{lock}; + $d->{tags} = $conf->{tags} if defined($conf->{tags}); $res->{$vmid} = $d; } @@ -3339,17 +3351,28 @@ sub is_native($) { return get_host_arch() eq $arch; } +sub get_vm_arch { + my ($conf) = @_; + return $conf->{arch} // get_host_arch(); +} + my $default_machines = { x86_64 => 'pc', aarch64 => 'virt', }; -sub get_basic_machine_info { - my ($conf, $forcemachine) = @_; +sub get_vm_machine { + my ($conf, $forcemachine, $arch, $add_pve_version) = @_; + + my $machine = $forcemachine || $conf->{machine}; - my $arch = $conf->{arch} // get_host_arch(); - my $machine = $forcemachine || $conf->{machine} || $default_machines->{$arch}; - return ($arch, $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; + } + + return $machine; } sub get_ovmf_files($) { @@ -3443,13 +3466,22 @@ sub config_to_command { my $ostype = $conf->{ostype}; my $winversion = windows_version($ostype); my $kvm = $conf->{kvm}; + my $nodename = nodename(); - my ($arch, $machine_type) = get_basic_machine_info($conf, $forcemachine); + my $arch = get_vm_arch($conf); my $kvm_binary = get_command_for_arch($arch); my $kvmver = kvm_user_version($kvm_binary); - my $machine_version = PVE::QemuServer::Machine::extract_version($machine_type) // $kvmver; + + my $add_pve_version = min_version($kvmver, 4, 1); + + my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version); + my $machine_version = PVE::QemuServer::Machine::extract_version($machine_type, $kvmver); $kvm //= 1 if is_native($arch); + $machine_version =~ m/(\d+)\.(\d+)/; + 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 ($kvm) { die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if !defined kvm_version(); @@ -3858,7 +3890,6 @@ sub config_to_command { my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type); - my $nodename = PVE::INotify::nodename(); my $pfamily = PVE::Tools::get_host_address_family($nodename); my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily); die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs; @@ -4032,6 +4063,7 @@ sub config_to_command { my $statepath = PVE::Storage::path($storecfg, $vmstate); push @$vollist, $vmstate; push @$cmd, '-loadstate', $statepath; + print "activating and using '$vmstate' as vmstate\n"; } # add custom args @@ -4713,6 +4745,7 @@ my $fast_plug_option = { 'protection' => 1, 'vmstatestorage' => 1, 'hookscript' => 1, + 'tags' => 1, }; # hotplug changes in [PENDING] @@ -4723,7 +4756,8 @@ sub vmconfig_hotplug_pending { my ($vmid, $conf, $storecfg, $selection, $errors) = @_; my $defaults = load_defaults(); - my ($arch, $machine_type) = get_basic_machine_info($conf, undef); + my $arch = get_vm_arch($conf); + my $machine_type = get_vm_machine($conf, undef, $arch); # commit values which do not have any impact on running VM first # Note: those option cannot raise errors, we we do not care about @@ -4874,6 +4908,7 @@ sub vmconfig_hotplug_pending { vmconfig_update_net($storecfg, $conf, $hotplug_features->{network}, $vmid, $opt, $value, $arch, $machine_type); } elsif (is_valid_drivename($opt)) { + die "skip\n" if $opt eq 'efidisk0'; # some changes can be done without hotplug my $drive = parse_drive($opt, $value); if (drive_is_cloudinit($drive)) { @@ -5237,7 +5272,7 @@ sub vm_start { my $newdrive = $drive; $newdrive->{format} = $format; $newdrive->{file} = $newvolid; - my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive); + my $drivestr = print_drive($newdrive); $local_volumes->{$opt} = $drivestr; #pass drive to conf for command line $conf->{$opt} = $drivestr; @@ -5288,7 +5323,7 @@ sub vm_start { if ($statefile eq 'tcp') { my $localip = "localhost"; my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg'); - my $nodename = PVE::INotify::nodename(); + my $nodename = nodename(); if (!defined($migration_type)) { if (defined($datacenterconf->{migration}->{type})) { @@ -5428,7 +5463,7 @@ sub vm_start { #start nbd server for storage migration if ($targetstorage) { - my $nodename = PVE::INotify::nodename(); + my $nodename = nodename(); my $localip = $get_migration_ip->($migration_network, $nodename); my $pfamily = PVE::Tools::get_host_address_family($nodename); my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily); @@ -5475,11 +5510,13 @@ sub vm_start { property => "guest-stats-polling-interval", value => 2) if (!defined($conf->{balloon}) || $conf->{balloon}); - if ($is_suspended && (my $vmstate = $conf->{vmstate})) { + if ($is_suspended) { print "Resumed VM, removing state\n"; + if (my $vmstate = $conf->{vmstate}) { + PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); + PVE::Storage::vdisk_free($storecfg, $vmstate); + } delete $conf->@{qw(lock vmstate runningmachine)}; - PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); - PVE::Storage::vdisk_free($storecfg, $vmstate); PVE::QemuConfig->write_config($vmid, $conf); } @@ -5943,7 +5980,7 @@ sub restore_update_config_line { } elsif ($map->{$virtdev}) { delete $di->{format}; # format can change on restore $di->{file} = $map->{$virtdev}; - $value = print_drive($vmid, $di); + $value = print_drive($di); print $outfd "$virtdev: $value\n"; } else { print $outfd $line; @@ -6057,7 +6094,7 @@ sub update_disksize { next if !$volid_hash->{$volid}; $drive->{size} = $volid_hash->{$volid}->{size}; - my $new = print_drive($vmid, $drive); + my $new = print_drive($drive); if ($new ne $conf->{$opt}) { $changes = 1; $conf->{$opt} = $new; @@ -6655,7 +6692,7 @@ sub template_create { my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid); $drive->{file} = $voliddst; - $conf->{$ds} = print_drive($vmid, $drive); + $conf->{$ds} = print_drive($drive); PVE::QemuConfig->write_config($vmid, $conf); }); } @@ -6689,7 +6726,7 @@ sub qemu_img_convert { my $cachemode; my $src_path; my $src_is_iscsi = 0; - my $src_format = 'raw'; + my $src_format; if ($src_storeid) { PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname); @@ -6714,14 +6751,15 @@ sub qemu_img_convert { my $cmd = []; push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n'; - push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2"); + push @$cmd, '-l', "snapshot.name=$snapname" + if $snapname && $src_format && $src_format eq "qcow2"; push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool'; push @$cmd, '-T', $cachemode if defined($cachemode); if ($src_is_iscsi) { push @$cmd, '--image-opts'; $src_path = convert_iscsi_path($src_path); - } else { + } elsif ($src_format) { push @$cmd, '-f', $src_format; } @@ -7022,7 +7060,7 @@ sub qemu_use_old_bios_files { $machine_type = $1; $use_old_bios_files = 1; } else { - my $version = PVE::QemuServer::Machine::extract_version($machine_type) // kvm_user_version(); + my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version()); # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we # load new efi bios files on migration. So this hack is required to allow # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when @@ -7045,8 +7083,9 @@ sub create_efidisk($$$$$) { PVE::Storage::activate_volumes($storecfg, [$volid]); qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0); + my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3); - return ($volid, $vars_size); + return ($volid, $size/1024); } sub vm_iothreads_list {