[pve-devel] [RFC qemu-server 6/6] restore: allow overriding settings upon restore

Fabian Ebner f.ebner at proxmox.com
Fri Apr 15 14:31:30 CEST 2022


Specifying a drive parameter causes the restore operation to skip it
and keep the current drive instead.

TODO add some limits to what can be changed?

Signed-off-by: Fabian Ebner <f.ebner at proxmox.com>
---
 PVE/API2/Qemu.pm  | 14 +++++++++++---
 PVE/QemuServer.pm | 44 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 976d1bd6..08b1a635 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -823,9 +823,6 @@ __PACKAGE__->register_method({
 	}
 
 	if ($archive) {
-	    my $keystr = join(' ', keys %$param);
-	    raise_param_exc({ archive => "option conflicts with other options ($keystr)"}) if $keystr;
-
 	    if ($archive eq '-') {
 		die "pipe requires cli environment\n" if $rpcenv->{type} ne 'cli';
 		$archive = { type => 'pipe' };
@@ -873,6 +870,16 @@ __PACKAGE__->register_method({
 
 	    die "$emsg vm is running\n" if PVE::QemuServer::check_running($vmid);
 
+	    for my $opt (sort keys $param->%*) {
+		next if !PVE::QemuServer::Drive::is_valid_drivename($opt);
+		my $drive = PVE::QemuServer::Drive::parse_drive($opt, $conf->{$opt});
+		my $newdrive = PVE::QemuServer::Drive::parse_drive($opt, $param->{$opt});
+		die "$opt - adding new drive during restore is not implemented\n" if !$drive;
+		die "$opt - unable to parse\n" if !$newdrive;
+		die "$opt - need to pass same volid to keep existing drive rather than restoring\n"
+		    if $drive->{file} ne $newdrive->{file};
+	    }
+
 	    my $realcmd = sub {
 		my $restore_options = {
 		    storage => $storage,
@@ -880,6 +887,7 @@ __PACKAGE__->register_method({
 		    unique => $unique,
 		    bwlimit => $bwlimit,
 		    live => $live_restore,
+		    override_conf => $param,
 		};
 		if ($archive->{type} eq 'file' || $archive->{type} eq 'pipe') {
 		    die "live-restore is only compatible with backup images from a Proxmox Backup Server\n"
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 741a5e89..95ca0444 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6295,6 +6295,7 @@ my $parse_backup_hints = sub {
     while (defined(my $line = <$fh>)) {
 	if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
 	    my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
+
 	    die "archive does not contain data for drive '$virtdev'\n"
 		if !$devinfo->{$devname};
 
@@ -6309,6 +6310,8 @@ my $parse_backup_hints = sub {
 	    $devinfo->{$devname}->{format} = $format;
 	    $devinfo->{$devname}->{storeid} = $storeid;
 
+	    next if $options->{override_conf}->{$virtdev}; # not being restored
+
 	    my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
 	    $check_storage->($storeid, $scfg); # permission and content type check
 
@@ -6476,6 +6479,17 @@ my $restore_destroy_volumes = sub {
     }
 };
 
+my $restore_merge_config = sub {
+    my ($filename, $backup_conf_raw, $override_conf) = @_;
+
+    my $backup_conf = parse_vm_config($filename, $backup_conf_raw);
+    for my $key (keys $override_conf->%*) {
+	$backup_conf->{$key} = $override_conf->{$key};
+    }
+
+    return $backup_conf;
+};
+
 sub scan_volids {
     my ($cfg, $vmid) = @_;
 
@@ -6785,8 +6799,10 @@ sub restore_proxmox_backup_archive {
 	$new_conf_raw .= "\nlock: create";
     }
 
-    PVE::Tools::file_set_contents($conffile, $new_conf_raw);
+    my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $options->{override_conf});
+    PVE::QemuConfig->write_config($vmid, $new_conf);
 
+    # TODO still needed with write_config?
     PVE::Cluster::cfs_update(); # make sure we read new file
 
     eval { rescan($vmid, 1); };
@@ -6808,6 +6824,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");
@@ -7000,8 +7022,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 "format=raw:0:$d->{devname}=/dev/null\n";
+		print "not restoring '$d->{devname}'\n";
+		next;
+	    }
+
 	    next if $d->{is_cloudinit}; # no need to restore cloudinit
 
 	    my $storeid = $d->{storeid};
@@ -7091,8 +7120,10 @@ sub restore_vma_archive {
 	die $err;
     }
 
-    PVE::Tools::file_set_contents($conffile, $new_conf_raw);
+    my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $opts->{override_conf});
+    PVE::QemuConfig->write_config($vmid, $new_conf);
 
+    # TODO still needed with write_config?
     PVE::Cluster::cfs_update(); # make sure we read new file
 
     eval { rescan($vmid, 1); };
@@ -7104,6 +7135,11 @@ sub restore_vma_archive {
 sub restore_tar_archive {
     my ($archive, $vmid, $user, $opts) = @_;
 
+    if (scalar(keys $opts->{override_conf}->%*) > 0) {
+	my $keystring = join(' ', keys $opts->{override_conf}->%*);
+	die "cannot pass along options ($keystring) when restoring from tar archive\n";
+    }
+
     if ($archive ne '-') {
 	my $firstfile = tar_archive_read_firstfile($archive);
 	die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
-- 
2.30.2






More information about the pve-devel mailing list