[pve-devel] [PATCH v10 qemu-server/cloudinit 8/8] add force_delete to [pending] to bring back -force

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Aug 11 15:51:55 CEST 2015


The -force flag didn't have any effect since the pending
changes didn't remember it before.
---
 PVE/API2/Qemu.pm  |  15 ++-----
 PVE/QemuServer.pm | 128 +++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 97 insertions(+), 46 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 4dcbb26..b5f817e 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -43,7 +43,7 @@ my $test_deallocate_drive = sub {
 
     if (!PVE::QemuServer::drive_is_cdrom($drive, 1)) {
 	my $volid = $drive->{file};
-	if ( PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
+	if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
 	    if ($force || $key =~ m/^unused/) {
 		my $sid = PVE::Storage::parse_volume_id($volid);
 		return $sid;
@@ -222,14 +222,7 @@ my $delete_drive = sub {
 	if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
 	    if ($force || $key =~ m/^unused/) {
 		eval {
-		    # check if the disk is really unused
-		    my $used_paths = PVE::QemuServer::get_used_paths($vmid, $storecfg, $conf, 1, $key);
-		    my $path = PVE::Storage::path($storecfg, $volid);
-
-		    die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
-			if $used_paths->{$path};
-
-		    PVE::Storage::vdisk_free($storecfg, $volid);
+		    PVE::QemuServer::delete_drive($vmid, $storecfg, $conf, $key, $volid);
 		};
 		die $@ if $@;
 	    } else {
@@ -964,10 +957,10 @@ my $update_vm_api  = sub {
 		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
 		    PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
 			if defined($conf->{pending}->{$opt});
-		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
+		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force);
 		    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
 		} else {
-		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
+		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force);
 		    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
 		}
 	    }
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index da33b04..1fad769 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -1517,34 +1517,45 @@ sub vm_is_volid_owner {
     return undef;
 }
 
-sub vmconfig_delete_pending_option {
-    my ($conf, $key) = @_;
-
-    delete $conf->{pending}->{$key};
-    my $pending_delete_hash = { $key => 1 };
-    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
-	$pending_delete_hash->{$opt} = 1;
-    }
-    $conf->{pending}->{delete} = join(',', keys %$pending_delete_hash);
-}
-
-sub vmconfig_undelete_pending_option {
-    my ($conf, $key) = @_;
+sub _vmconfig_undelete_pending_option {
+    my ($conf, $key, $del) = @_;
 
     my $pending_delete_hash = {};
-    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{$del})) {
 	$pending_delete_hash->{$opt} = 1;
     }
     delete $pending_delete_hash->{$key};
 
     my @keylist = keys %$pending_delete_hash;
     if (scalar(@keylist)) {
-	$conf->{pending}->{delete} = join(',', @keylist);
+	$conf->{pending}->{$del} = join(',', @keylist);
     } else {
-	delete $conf->{pending}->{delete};
+	delete $conf->{pending}->{$del};
     }
 }
 
+sub vmconfig_delete_pending_option {
+    my ($conf, $key, $force) = @_;
+
+    my $addto = $force ? 'force_delete' : 'delete';
+    my $removefrom = $force ? 'delete' : 'force_delete';
+
+    _vmconfig_undelete_pending_option($conf, $key, $removefrom);
+
+    delete $conf->{pending}->{$key};
+    my $pending_delete_hash = { $key => 1 };
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{$addto})) {
+	$pending_delete_hash->{$opt} = 1;
+    }
+    $conf->{pending}->{$addto} = join(',', keys %$pending_delete_hash);
+}
+
+sub vmconfig_undelete_pending_option {
+    my ($conf, $key) = @_;
+    _vmconfig_undelete_pending_option($conf, $key, 'delete');
+    _vmconfig_undelete_pending_option($conf, $key, 'force_delete');
+}
+
 sub vmconfig_register_unused_drive {
     my ($storecfg, $vmid, $conf, $drive) = @_;
 
@@ -1569,20 +1580,22 @@ sub vmconfig_cleanup_pending {
     }
 
     # remove delete if option is not set
-    my $pending_delete_hash = {};
-    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
-	if (defined($conf->{$opt})) {
-	    $pending_delete_hash->{$opt} = 1;
-	} else {
-	    $changes = 1;
+    foreach my $del (qw/force_delete delete/) {
+	my $pending_delete_hash = {};
+	foreach my $opt (PVE::Tools::split_list($conf->{pending}->{$del})) {
+	    if (defined($conf->{$opt})) {
+		$pending_delete_hash->{$opt} = 1;
+	    } else {
+		$changes = 1;
+	    }
 	}
-    }
 
-    my @keylist = keys %$pending_delete_hash;
-    if (scalar(@keylist)) {
-	$conf->{pending}->{delete} = join(',', @keylist);
-    } else {
-	delete $conf->{pending}->{delete};
+	my @keylist = keys %$pending_delete_hash;
+	if (scalar(@keylist)) {
+	    $conf->{pending}->{$del} = join(',', @keylist);
+	} else {
+	    delete $conf->{pending}->{$del};
+	}
     }
 
     return $changes;
@@ -2019,6 +2032,13 @@ sub parse_vm_config {
 	    } else {
 		warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
 	    }
+	} elsif ($line =~ m/^force_delete:\s*(.*\S)\s*$/) {
+	    my $value = $1;
+	    if ($section eq 'pending') {
+		$conf->{force_delete} = $value; # we parse this later
+	    } else {
+		warn "vm $vmid - propertry 'force_delete' is only allowed in [PENDING]\n";
+	    }
 	} elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
 	    my $key = $1;
 	    my $value = $2;
@@ -2083,8 +2103,8 @@ sub write_vm_config {
 	    next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
 		$key eq 'snapstate' || $key eq 'pending';
 	    my $value = $cref->{$key};
-	    if ($key eq 'delete') {
-		die "propertry 'delete' is only allowed in [PENDING]\n"
+	    if ($key =~ /^(?:force_)?delete$/) {
+		die "propertry '$key' is only allowed in [PENDING]\n"
 		    if !$pending;
 		# fixme: check syntax?
 		next;
@@ -3993,8 +4013,8 @@ sub vmconfig_hotplug_pending {
 
     my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
 
-    my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
-    foreach my $opt (@delete) {
+    my $delete_opt = sub {
+	my ($opt, $force) = @_;
 	next if $selection && !$selection->{$opt};
 	eval {
 	    if ($opt eq 'hotplug') {
@@ -4041,6 +4061,12 @@ sub vmconfig_hotplug_pending {
 	    update_config_nolock($vmid, $conf, 1);
 	    $conf = load_config($vmid); # update/reload
 	}
+    };
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{force_delete})) {
+	&$delete_opt($opt, 1);
+    }
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
+	&$delete_opt($opt);
     }
 
     foreach my $opt (keys %{$conf->{pending}}) {
@@ -4102,20 +4128,45 @@ sub vmconfig_hotplug_pending {
     }
 }
 
+sub delete_drive {
+    my ($vmid, $storecfg, $conf, $key, $volid) = @_;
+
+    # check if the disk is really unused
+    my $used_paths = PVE::QemuServer::get_used_paths($vmid, $storecfg, $conf, 1, $key);
+    my $path = PVE::Storage::path($storecfg, $volid);
+
+    die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
+	   if $used_paths->{$path};
+    PVE::Storage::vdisk_free($storecfg, $volid);
+}
+
 sub vmconfig_apply_pending {
     my ($vmid, $conf, $storecfg) = @_;
 
     # cold plug
+    my $rpcenv = PVE::RPCEnvironment::get();
+    my $authuser = $rpcenv->get_user();
 
-    my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
-    foreach my $opt (@delete) { # delete
+    my $delete_opt = sub {
+	my ($opt, $force) = @_;
 	die "internal error" if $opt =~ m/^unused/;
 	$conf = load_config($vmid); # update/reload
 	if (!defined($conf->{$opt})) {
 	    vmconfig_undelete_pending_option($conf, $opt);
 	    update_config_nolock($vmid, $conf, 1);
 	} elsif (valid_drivename($opt)) {
-	    vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}));
+	    my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
+	    if ($force) {
+		$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
+		my $volid = $drive->{file};
+		my $sid = PVE::Storage::parse_volume_id($volid);
+		if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
+		    $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
+		    delete_drive($vmid, $storecfg, $conf, $opt, $volid);
+		}
+	    } else {
+		vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
+	    }
 	    vmconfig_undelete_pending_option($conf, $opt);
 	    delete $conf->{$opt};
 	    update_config_nolock($vmid, $conf, 1);
@@ -4124,6 +4175,13 @@ sub vmconfig_apply_pending {
 	    delete $conf->{$opt};
 	    update_config_nolock($vmid, $conf, 1);
 	}
+    };
+
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{force_delete})) {
+	&$delete_opt($opt, 1);
+    }
+    foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
+	&$delete_opt($opt);
     }
 
     $conf = load_config($vmid); # update/reload
-- 
2.1.4





More information about the pve-devel mailing list