From 6ee499fff8f9cce556ebc2fdaa11b8475d0eceb4 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Wed, 19 Sep 2018 11:35:11 +0200 Subject: [PATCH] fix #1908: add vmgenid config/device this adds a VM Generation ID device uses by Windows (Server) to determine some specific actions that may have happened with the vm such as rollback, restore, etc. see: https://docs.microsoft.com/en-us/windows/desktop/hyperv_v2/virtual-machine-generation-identifier for details on how it works and when it should change Signed-off-by: Dominik Csapak --- PVE/API2/Qemu.pm | 18 ++++++++++++++---- PVE/CLI/qm.pm | 1 + PVE/QemuConfig.pm | 4 ++++ PVE/QemuServer.pm | 26 ++++++++++++++++++++++++-- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index c1cc01b4..52f4a5fd 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -599,6 +599,10 @@ __PACKAGE__->register_method({ $conf->{smbios1} = PVE::QemuServer::generate_smbios1_uuid(); } + if (!defined($conf->{vmgenid}) || $conf->{vmgenid} eq '1') { + $conf->{vmgenid} = PVE::QemuServer::generate_uuid(); + } + PVE::QemuConfig->write_config($vmid, $conf); }; @@ -1091,6 +1095,10 @@ my $update_vm_api = sub { # add macaddr my $net = PVE::QemuServer::parse_net($param->{$opt}); $param->{$opt} = PVE::QemuServer::print_net($net); + } elsif ($opt eq 'vmgenid') { + if ($param->{$opt} eq '1') { + $param->{$opt} = PVE::QemuServer::generate_uuid(); + } } } @@ -2725,13 +2733,15 @@ __PACKAGE__->register_method({ } # auto generate a new uuid - my ($uuid, $uuid_str); - UUID::generate($uuid); - UUID::unparse($uuid, $uuid_str); my $smbios1 = PVE::QemuServer::parse_smbios1($newconf->{smbios1} || ''); - $smbios1->{uuid} = $uuid_str; + $smbios1->{uuid} = PVE::QemuServer::generate_uuid(); $newconf->{smbios1} = PVE::QemuServer::print_smbios1($smbios1); + # auto generate a new vmgenid if the option was set + if ($newconf->{vmgenid}) { + $newconf->{vmgenid} = PVE::QemuServer::generate_uuid(); + } + delete $newconf->{template}; if ($param->{name}) { diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm index 84b8531c..46a7e2fd 100755 --- a/PVE/CLI/qm.pm +++ b/PVE/CLI/qm.pm @@ -621,6 +621,7 @@ __PACKAGE__->register_method ({ eval { # order matters, as do_import() will load_config() internally + $conf->{vmgenid} = PVE::QemuServer::generate_uuid(); $conf->{smbios1} = PVE::QemuServer::generate_smbios1_uuid(); PVE::QemuConfig->write_config($vmid, $conf); diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm index cd116bd4..03b2a70c 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -300,6 +300,10 @@ sub __snapshot_rollback_hook { # in the original config. delete $conf->{machine} if $snap->{vmstate} && !defined($data->{oldmachine}); } + + if ($conf->{vmgenid}) { + $conf->{vmgenid} = PVE::QemuServer::generate_uuid(); + } } return; diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index af0631dc..6785b027 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -559,6 +559,13 @@ EODESCR description => "Select BIOS implementation.", default => 'seabios', }, + vmgenid => { + type => 'string', + pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])', + format_description => 'UUID', + description => "Set VM Generation ID UUID. Use special value 1 to autogenerate one (API only). Use special value 0 to disable explicitly.", + optional => 1, + }, }; my $confdesc_cloudinit = { @@ -3191,6 +3198,10 @@ sub config_to_command { push @$cmd, '-smbios', "type=1,$conf->{smbios1}"; } + if ($conf->{vmgenid}) { + push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid}; + } + if ($conf->{bios} && $conf->{bios} eq 'ovmf') { die "uefi base image not found\n" if ! -f $OVMF_CODE; @@ -5554,6 +5565,13 @@ sub restore_update_config_line { } else { print $outfd $line; } + } elsif (($line =~ m/^(vmgenid: )(.*)/)) { + # always generate a new vmgenid + my $vmgenid = $2; + if ($vmgenid ne '0') { + $vmgenid = generate_uuid(); + } + print $outfd $1.$vmgenid."\n"; } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) { my ($uuid, $uuid_str); UUID::generate($uuid); @@ -6756,11 +6774,15 @@ sub resolve_first_disk { return $firstdisk; } -sub generate_smbios1_uuid { +sub generate_uuid { my ($uuid, $uuid_str); UUID::generate($uuid); UUID::unparse($uuid, $uuid_str); - return "uuid=$uuid_str"; + return $uuid_str; +} + +sub generate_smbios1_uuid { + return "uuid=".generate_uuid(); } # bash completion helper