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 <d.csa...@proxmox.com>
---
 PVE/API2/Qemu.pm          |  5 +++++
 PVE/QemuConfig.pm         |  4 ++++
 PVE/QemuServer.pm         | 23 +++++++++++++++++++++++
 PVE/QemuServer/Makefile   |  1 +
 PVE/QemuServer/VMGenID.pm | 29 +++++++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 PVE/QemuServer/VMGenID.pm

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index c1cc01b..6ac3110 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -2732,6 +2732,11 @@ __PACKAGE__->register_method({
            $smbios1->{uuid} = $uuid_str;
            $newconf->{smbios1} = PVE::QemuServer::print_smbios1($smbios1);
 
+           # auto generate a new vmgenid
+           if ($oldconf->{vmgenid}) {
+               $newconf->{vmgenid} = 'auto';
+           }
+
            delete $newconf->{template};
 
            if ($param->{name}) {
diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
index cd116bd..5a05c1b 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 (defined($conf->{vmgenid})) {
+           $conf->{vmgenid} = 'auto';
+       }
     }
 
     return;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index af0631d..1b68ddd 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -34,6 +34,7 @@ use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
 use PVE::QemuServer::Memory;
 use PVE::QemuServer::USB qw(parse_usb_device);
 use PVE::QemuServer::Cloudinit;
+use PVE::QemuServer::VMGenID;
 use PVE::Systemd;
 use Time::HiRes qw(gettimeofday);
 use File::Copy qw(copy);
@@ -559,6 +560,12 @@ EODESCR
        description => "Select BIOS implementation.",
        default => 'seabios',
     },
+    vmgenid => {
+       type => 'string',
+       pattern => 
'(?:auto)|(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12})',
+        description => "The VM Generation ID. Use the special value 'auto' to 
autogenerate one",
+       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, 
PVE::QemuServer::VMGenID::create_device($conf->{vmgenid}, 0);
+    }
+
     if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
        die "uefi base image not found\n" if ! -f $OVMF_CODE;
 
@@ -4593,6 +4604,14 @@ sub vmconfig_apply_pending {
     }
 }
 
+sub vmconfig_apply_vmgenid_generation {
+    my ($vmid, $conf) = @_;
+    if ($conf->{vmgenid}) {
+       $conf->{vmgenid} = 
PVE::QemuServer::VMGenID::create_or_parse($conf->{vmgenid});
+    }
+    PVE::QemuConfig->write_config($vmid, $conf);
+}
+
 my $safe_num_ne = sub {
     my ($a, $b) = @_;
 
@@ -4779,6 +4798,8 @@ sub vm_start {
 
        die "VM $vmid already running\n" if check_running($vmid, undef, 
$migratedfrom);
 
+       vmconfig_apply_vmgenid_generation($vmid, $conf);
+
        if (!$statefile && scalar(keys %{$conf->{pending}})) {
            vmconfig_apply_pending($vmid, $conf, $storecfg);
            $conf = PVE::QemuConfig->load_config($vmid); # update/reload
@@ -5554,6 +5575,8 @@ sub restore_update_config_line {
        } else {
            print $outfd $line;
        }
+    } elsif (($line =~ m/^(vmgenid: )(.*)/)) {
+       print $outfd $1.'auto';
     } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
        my ($uuid, $uuid_str);
        UUID::generate($uuid);
diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
index afc39a3..06f359b 100644
--- a/PVE/QemuServer/Makefile
+++ b/PVE/QemuServer/Makefile
@@ -5,6 +5,7 @@ SOURCES=PCI.pm          \
        OVF.pm          \
        Cloudinit.pm    \
        Agent.pm        \
+       VMGenID.pm      \
 
 .PHONY: install
 install: ${SOURCES}
diff --git a/PVE/QemuServer/VMGenID.pm b/PVE/QemuServer/VMGenID.pm
new file mode 100644
index 0000000..c1aa3e4
--- /dev/null
+++ b/PVE/QemuServer/VMGenID.pm
@@ -0,0 +1,29 @@
+package PVE::QemuServer::VMGenID;
+
+use strict;
+use warnings;
+
+use UUID;
+
+sub create_device {
+    my ($uuid) = @_;
+
+    my $id = create_or_parse($uuid);
+
+    return ('-device', "vmgenid,guid=$id");
+}
+
+sub create_or_parse {
+    my ($uuid) = @_;
+
+    my $id;
+    if ($uuid eq 'auto') {
+       return UUID::uuid();
+    } elsif (UUID::parse($uuid, $id) == 0) {
+       return $uuid;
+    }
+
+    die "invalid VM Generation ID\n";
+}
+
+1;
-- 
2.11.0


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to