diff --git a/PVE/API2/VZDump.pm b/PVE/API2/VZDump.pm index 9a55dc22..2eda973e 100644 --- a/PVE/API2/VZDump.pm +++ b/PVE/API2/VZDump.pm @@ -69,18 +69,20 @@ __PACKAGE__->register_method ({ return 'OK' if $param->{node} && $param->{node} ne $nodename; my $cmdline = PVE::VZDump::Common::command_line($param); - my ($vmids, $skiplist) = PVE::VZDump::get_included_guests($param); + + my $vmids_per_node = PVE::VZDump::get_included_guests($param); + + my $local_vmids = delete $vmids_per_node->{$nodename} // []; + + my $skiplist = [ map { @$_ } values $vmids_per_node->%* ]; if($param->{stop}){ PVE::VZDump::stop_running_backups(); - return 'OK' if !scalar(@{$vmids}); + return 'OK' if !scalar(@{$local_vmids}); } # silent exit if specified VMs run on other nodes - return "OK" if !scalar(@{$vmids}) && !$param->{all}; - - my @exclude = PVE::Tools::split_list(extract_param($param, 'exclude')); - $param->{exclude} = PVE::VZDump::check_vmids(@exclude); + return "OK" if !scalar(@{$local_vmids}) && !$param->{all}; # exclude-path list need to be 0 separated if (defined($param->{'exclude-path'})) { @@ -94,7 +96,7 @@ __PACKAGE__->register_method ({ } die "you can only backup a single VM with option --stdout\n" - if $param->{stdout} && scalar(@{$vmids}) != 1; + if $param->{stdout} && scalar(@{$local_vmids}) != 1; $rpcenv->check($user, "/storage/$param->{storage}", [ 'Datastore.AllocateSpace' ]) if $param->{storage}; @@ -106,6 +108,7 @@ __PACKAGE__->register_method ({ die "interrupted by signal\n"; }; + $param->{vmids} = $local_vmids; my $vzdump = PVE::VZDump->new($cmdline, $param, $skiplist); eval { @@ -143,7 +146,7 @@ __PACKAGE__->register_method ({ } my $taskid; - $taskid = $vmids->[0] if scalar(@{$vmids}) == 1; + $taskid = $local_vmids->[0] if scalar(@{$local_vmids}) == 1; return $rpcenv->fork_worker('vzdump', $taskid, $user, $worker); }}); diff --git a/PVE/VZDump.pm b/PVE/VZDump.pm index bdbf641e..2f477606 100644 --- a/PVE/VZDump.pm +++ b/PVE/VZDump.pm @@ -1044,29 +1044,23 @@ sub exec_backup { if scalar(@{$self->{skiplist}}); my $tasklist = []; + my $vzdump_plugins = {}; + foreach my $plugin (@{$self->{plugins}}) { + my $type = $plugin->type(); + next if exists $vzdump_plugins->{$type}; + $vzdump_plugins->{$type} = $plugin; + } - if ($opts->{all}) { - foreach my $plugin (@{$self->{plugins}}) { - my $vmlist = $plugin->vmlist(); - foreach my $vmid (sort @$vmlist) { - next if grep { $_ eq $vmid } @{$opts->{exclude}}; - next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Backup' ], 1); - push @$tasklist, { vmid => $vmid, state => 'todo', plugin => $plugin, mode => $opts->{mode} }; - } - } - } else { - foreach my $vmid (sort @{$opts->{vmids}}) { - my $plugin; - foreach my $pg (@{$self->{plugins}}) { - my $vmlist = $pg->vmlist(); - if (grep { $_ eq $vmid } @$vmlist) { - $plugin = $pg; - last; - } - } - $rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Backup' ]); - push @$tasklist, { vmid => $vmid, state => 'todo', plugin => $plugin, mode => $opts->{mode} }; - } + my $vmlist = PVE::Cluster::get_vmlist(); + foreach my $vmid (sort @{$opts->{vmids}}) { + my $guest_type = $vmlist->{ids}->{$vmid}->{type}; + my $plugin = $vzdump_plugins->{$guest_type}; + next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Backup' ], $opts->{all}); + push @$tasklist, { + vmid => $vmid, + state => 'todo', + plugin => $plugin, + mode => $opts->{mode} }; } # Use in-memory files for the outer hook logs to pass them to sendmail. @@ -1174,34 +1168,38 @@ sub get_included_guests { my $nodename = PVE::INotify::nodename(); my $vmids = []; + my $vmids_per_node = {}; + + my $vmlist = PVE::Cluster::get_vmlist(); - # convert string lists to arrays if ($job->{pool}) { $vmids = PVE::API2Tools::get_resource_pool_guest_members($job->{pool}); + } elsif ($job->{vmid}) { + $vmids = [ PVE::Tools::split_list($job->{vmid}) ]; } else { - $vmids = [ PVE::Tools::split_list(extract_param($job, 'vmid')) ]; - } + # all or exclude + my @exclude = PVE::Tools::split_list($job->{exclude}); + @exclude = @{PVE::VZDump::check_vmids(@exclude)}; + my $excludehash = { map { $_ => 1 } @exclude }; - my $skiplist = []; - if (!$job->{all}) { - if (!$job->{node} || $job->{node} eq $nodename) { - my $vmlist = PVE::Cluster::get_vmlist(); - my $localvmids = []; - foreach my $vmid (@{$vmids}) { - my $d = $vmlist->{ids}->{$vmid}; - if ($d && ($d->{node} ne $nodename)) { - push @{$skiplist}, $vmid; - } else { - push @{$localvmids}, $vmid; - } - } - $vmids = $localvmids; + for my $id (keys %{ $vmlist->{ids} }) { + next if $excludehash->{$id}; + push @$vmids, $id; } + } + $vmids = [ sort {$a <=> $b} @$vmids]; - $job->{vmids} = PVE::VZDump::check_vmids(@{$vmids}) + $vmids = PVE::VZDump::check_vmids(@$vmids); + + foreach my $vmid (@$vmids) { + my $vmid_data = $vmlist->{ids}->{$vmid}; + my $node = $vmid_data->{node}; + + next if (defined $job->{node} && $job->{node} ne $node); + push @{$vmids_per_node->{$node}}, $vmid; } - return ($vmids, $skiplist); + return $vmids_per_node; } 1;