pending-delete: remember force-deletes

The -force flag didn't have any effect since the pending
changes didn't carry over the the flag.
Now forced deletes have an exclamation mark prepended to the
option name.
This commit is contained in:
Wolfgang Bumiller 2015-08-12 13:38:36 +02:00 committed by Dietmar Maurer
parent b0ec896e43
commit 3dc38fbb74
2 changed files with 78 additions and 74 deletions

View File

@ -38,22 +38,6 @@ my $resolve_cdrom_alias = sub {
} }
}; };
my $test_deallocate_drive = sub {
my ($storecfg, $vmid, $key, $drive, $force) = @_;
if (!PVE::QemuServer::drive_is_cdrom($drive)) {
my $volid = $drive->{file};
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;
}
}
}
return undef;
};
my $check_storage_access = sub { my $check_storage_access = sub {
my ($rpcenv, $authuser, $storecfg, $vmid, $settings, $default_storage) = @_; my ($rpcenv, $authuser, $storecfg, $vmid, $settings, $default_storage) = @_;
@ -189,34 +173,6 @@ my $create_disks = sub {
return $vollist; return $vollist;
}; };
my $delete_drive = sub {
my ($conf, $storecfg, $vmid, $key, $drive, $force) = @_;
if (!PVE::QemuServer::drive_is_cdrom($drive)) {
my $volid = $drive->{file};
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);
};
die $@ if $@;
} else {
PVE::QemuServer::add_unused_volume($conf, $volid, $vmid);
}
}
}
delete $conf->{$key};
};
my $check_vm_modify_config_perm = sub { my $check_vm_modify_config_perm = sub {
my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_; my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
@ -931,19 +887,18 @@ my $update_vm_api = sub {
if ($opt =~ m/^unused/) { if ($opt =~ m/^unused/) {
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']); $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt}); my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
if (my $sid = &$test_deallocate_drive($storecfg, $vmid, $opt, $drive, $force)) { if (PVE::QemuServer::try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser)) {
$rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']); delete $conf->{$opt};
&$delete_drive($conf, $storecfg, $vmid, $opt, $drive);
PVE::QemuServer::update_config_nolock($vmid, $conf, 1); PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
} }
} elsif (PVE::QemuServer::valid_drivename($opt)) { } elsif (PVE::QemuServer::valid_drivename($opt)) {
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']); $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})) PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
if defined($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); PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
} else { } 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); PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
} }
} }

View File

@ -1427,29 +1427,35 @@ sub vm_is_volid_owner {
return undef; return undef;
} }
sub split_flagged_list {
my $text = shift || '';
$text =~ s/[,;]/ /g;
$text =~ s/^\s+//;
return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
}
sub join_flagged_list {
my ($how, $lst) = @_;
join $how, map { $lst->{$_} . $_ } keys %$lst;
}
sub vmconfig_delete_pending_option { sub vmconfig_delete_pending_option {
my ($conf, $key) = @_; my ($conf, $key, $force) = @_;
delete $conf->{pending}->{$key}; delete $conf->{pending}->{$key};
my $pending_delete_hash = { $key => 1 }; my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) { $pending_delete_hash->{$key} = $force ? '!' : '';
$pending_delete_hash->{$opt} = 1; $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
}
$conf->{pending}->{delete} = join(',', keys %$pending_delete_hash);
} }
sub vmconfig_undelete_pending_option { sub vmconfig_undelete_pending_option {
my ($conf, $key) = @_; my ($conf, $key) = @_;
my $pending_delete_hash = {}; my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
$pending_delete_hash->{$opt} = 1;
}
delete $pending_delete_hash->{$key}; delete $pending_delete_hash->{$key};
my @keylist = keys %$pending_delete_hash; if (%$pending_delete_hash) {
if (scalar(@keylist)) { $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
$conf->{pending}->{delete} = join(',', @keylist);
} else { } else {
delete $conf->{pending}->{delete}; delete $conf->{pending}->{delete};
} }
@ -1478,19 +1484,18 @@ sub vmconfig_cleanup_pending {
} }
} }
# remove delete if option is not set my $current_delete_hash = split_flagged_list($conf->{pending}->{delete});
my $pending_delete_hash = {}; my $pending_delete_hash = {};
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) { while (my ($opt, $force) = each %$current_delete_hash) {
if (defined($conf->{$opt})) { if (defined($conf->{$opt})) {
$pending_delete_hash->{$opt} = 1; $pending_delete_hash->{$opt} = $force;
} else { } else {
$changes = 1; $changes = 1;
} }
} }
my @keylist = keys %$pending_delete_hash; if (%$pending_delete_hash) {
if (scalar(@keylist)) { $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
$conf->{pending}->{delete} = join(',', @keylist);
} else { } else {
delete $conf->{pending}->{delete}; delete $conf->{pending}->{delete};
} }
@ -3908,8 +3913,8 @@ sub vmconfig_hotplug_pending {
my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1'); my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
my @delete = PVE::Tools::split_list($conf->{pending}->{delete}); my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
foreach my $opt (@delete) { while (my ($opt, $force) = each %$pending_delete_hash) {
next if $selection && !$selection->{$opt}; next if $selection && !$selection->{$opt};
eval { eval {
if ($opt eq 'hotplug') { if ($opt eq 'hotplug') {
@ -3935,7 +3940,7 @@ sub vmconfig_hotplug_pending {
} elsif (valid_drivename($opt)) { } elsif (valid_drivename($opt)) {
die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/; die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
vm_deviceunplug($vmid, $conf, $opt); vm_deviceunplug($vmid, $conf, $opt);
vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt})); vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
} elsif ($opt =~ m/^memory$/) { } elsif ($opt =~ m/^memory$/) {
die "skip\n" if !$hotplug_features->{memory}; die "skip\n" if !$hotplug_features->{memory};
qemu_memory_hotplug($vmid, $conf, $defaults, $opt); qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
@ -4017,20 +4022,64 @@ 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 try_deallocate_drive {
my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
my $volid = $drive->{file};
if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
my $sid = PVE::Storage::parse_volume_id($volid);
$rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
delete_drive($vmid, $storecfg, $conf, $key, $drive->{file});
return 1;
}
}
return undef;
}
sub vmconfig_delete_or_detach_drive {
my ($vmid, $storecfg, $conf, $opt, $force) = @_;
my $drive = parse_drive($opt, $conf->{$opt});
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
if ($force) {
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
} else {
vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
}
}
sub vmconfig_apply_pending { sub vmconfig_apply_pending {
my ($vmid, $conf, $storecfg) = @_; my ($vmid, $conf, $storecfg) = @_;
# cold plug # cold plug
my @delete = PVE::Tools::split_list($conf->{pending}->{delete}); my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
foreach my $opt (@delete) { # delete while (my ($opt, $force) = each %$pending_delete_hash) {
die "internal error" if $opt =~ m/^unused/; die "internal error" if $opt =~ m/^unused/;
$conf = load_config($vmid); # update/reload $conf = load_config($vmid); # update/reload
if (!defined($conf->{$opt})) { if (!defined($conf->{$opt})) {
vmconfig_undelete_pending_option($conf, $opt); vmconfig_undelete_pending_option($conf, $opt);
update_config_nolock($vmid, $conf, 1); update_config_nolock($vmid, $conf, 1);
} elsif (valid_drivename($opt)) { } elsif (valid_drivename($opt)) {
vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt})); vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
vmconfig_undelete_pending_option($conf, $opt); vmconfig_undelete_pending_option($conf, $opt);
delete $conf->{$opt}; delete $conf->{$opt};
update_config_nolock($vmid, $conf, 1); update_config_nolock($vmid, $conf, 1);