Preserving a drive means:
  * The disk it references will not be touched by the restore
    operation.
  * The drive will be left as is in the VM configuration.
  * If the drive is present in the backup, that disk will not be
    restored.

A drive that is not present in the backup was/is re-added as unused by
default, but when preserving, it's kept configured instead.

If a drive is not currently configured and passed as part of preserve,
restore is skipped and its entry in the restored config will be
removed.

Signed-off-by: Fabian Ebner <f.eb...@proxmox.com>
---

Dependency bump for pve-qemu is needed.

Changes from v1:
  * Allow skipping restore of drive that's not currently configured
    (see below).
  * Adapt to skip=<devname> syntax when passing drive map to VMA.
  * When merging configs, remove key from the final config if value
    is explicitly undef.
  * Add 'preserve-drives' parameter instead of treating passing
    existing disk in a special way. While this makes it less
    flexible, the advantages are:
      * Can be used to skip restoring a disk that's not currently
        configured.
      * Less automagic behavior, it might not be intuitive what
        passing existing disk will do.
      * No conflict with currently existing syntax for containers.
      * No need to specify the disk's options again. The disk will
        be preserved like it's currently in the config.

 PVE/API2/Qemu.pm  | 25 ++++++++++++++++++++++++-
 PVE/QemuServer.pm | 34 +++++++++++++++++++++++++++++++---
 2 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 8df2cc8d..86359cef 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -749,6 +749,14 @@ __PACKAGE__->register_method({
                    description => "Start the VM immediately from the backup 
and restore in background. PBS only.",
                    requires => 'archive',
                },
+               'preserve-drives' => {
+                   optional => 1,
+                   type => 'string',
+                   format => 'pve-configid-list',
+                   description => "List of drives (e.g. scsi0) for which to 
preserve the current ".
+                       "configuration and disk contents.",
+                   requires => 'archive',
+               },
                pool => {
                    optional => 1,
                    type => 'string', format => 'pve-poolid',
@@ -793,6 +801,7 @@ __PACKAGE__->register_method({
        my $storage = extract_param($param, 'storage');
        my $unique = extract_param($param, 'unique');
        my $live_restore = extract_param($param, 'live-restore');
+       my $preserve_drives = extract_param($param, 'preserve-drives');
 
        if (defined(my $ssh_keys = $param->{sshkeys})) {
                $ssh_keys = URI::Escape::uri_unescape($ssh_keys);
@@ -825,10 +834,18 @@ __PACKAGE__->register_method({
        if ($archive) {
            for my $opt (sort keys $param->%*) {
                if (PVE::QemuServer::Drive::is_valid_drivename($opt)) {
-                   raise_param_exc({ $opt => "option conflicts with option 
'archive'" });
+                   raise_param_exc({
+                       $opt => "option conflicts with option 'archive' (do you 
mean to use ".
+                           "'preserve-drives'?)",
+                   });
                }
            }
 
+           for my $opt (PVE::Tools::split_list($preserve_drives)) {
+               raise_param_exc({ 'preserve-drives' => "$opt - not a drive key" 
})
+                   if !PVE::QemuServer::Drive::is_valid_drivename($opt);
+           }
+
            if ($archive eq '-') {
                die "pipe requires cli environment\n" if $rpcenv->{type} ne 
'cli';
                $archive = { type => 'pipe' };
@@ -876,6 +893,12 @@ __PACKAGE__->register_method({
 
            die "$emsg vm is running\n" if 
PVE::QemuServer::check_running($vmid);
 
+           for my $opt (PVE::Tools::split_list($preserve_drives)) {
+               die "internal error - expected drive key\n"
+                   if !PVE::QemuServer::Drive::is_valid_drivename($opt);
+               $param->{$opt} = $conf->{$opt};
+           }
+
            my $realcmd = sub {
                my $restore_options = {
                    storage => $storage,
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index e64a9c7a..affdd0bb 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6206,6 +6206,15 @@ sub tar_restore_cleanup {
     }
 }
 
+# Possilbe options are
+# $format: archive format
+# $storage: target storage
+# $pool: add VM to this pool
+# $unique: make VM unique (mac addressses, vmgenid)
+# $bwlimit: limit restore speed
+# $live: live restore (PBS only)
+# $override_conf: Settings that will be overwritten. If a key is explicitly 
set to undef, it will be
+#     deleted from the final config. Drives whose keys appear in this config 
are not restored.
 sub restore_file_archive {
     my ($archive, $vmid, $user, $opts) = @_;
 
@@ -6309,6 +6318,8 @@ my $parse_backup_hints = sub {
            $devinfo->{$devname}->{format} = $format;
            $devinfo->{$devname}->{storeid} = $storeid;
 
+           next if exists($options->{override_conf}->{$virtdev}); # not being 
restored
+
            my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
            $check_storage->($storeid, $scfg); # permission and content type 
check
 
@@ -6481,7 +6492,11 @@ my $restore_merge_config = sub {
 
     my $backup_conf = parse_vm_config($filename, $backup_conf_raw);
     for my $key (keys $override_conf->%*) {
-       $backup_conf->{$key} = $override_conf->{$key};
+       if (defined($override_conf->{$key})) {
+           $backup_conf->{$key} = $override_conf->{$key};
+       } else {
+           delete $backup_conf->{$key};
+       }
     }
 
     return $backup_conf;
@@ -6818,6 +6833,12 @@ sub restore_proxmox_backup_archive {
        # these special drives are already restored before start
        delete $devinfo->{'drive-efidisk0'};
        delete $devinfo->{'drive-tpmstate0-backup'};
+
+       for my $key (keys $options->{override_conf}->%*) {
+           next if !is_valid_drivename($key);
+           delete $devinfo->{"drive-$key"};
+       }
+
        pbs_live_restore($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, 
$pbs_backup_name);
 
        PVE::QemuConfig->remove_lock($vmid, "create");
@@ -7010,8 +7031,15 @@ sub restore_vma_archive {
        my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
 
        # print restore information to $fifofh
-       foreach my $virtdev (sort keys %$virtdev_hash) {
-           my $d = $virtdev_hash->{$virtdev};
+       for my $devname (sort keys $devinfo->%*) {
+           my $d = $devinfo->{$devname};
+
+           if (!$virtdev_hash->{$d->{virtdev}}) { # skipped
+               print $fifofh "skip=$d->{devname}\n";
+               print "not restoring '$d->{devname}', but keeping current 
disk\n";
+               next;
+           }
+
            next if $d->{is_cloudinit}; # no need to restore cloudinit
 
            my $storeid = $d->{storeid};
-- 
2.30.2



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

Reply via email to