]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2/VZDump.pm
fix #1594: allow skipping VMIDs on other nodes from API
[pve-manager.git] / PVE / API2 / VZDump.pm
1 package PVE::API2::VZDump;
2
3 use strict;
4 use warnings;
5 use PVE::Exception qw(raise_param_exc);
6 use PVE::Tools qw(extract_param);
7 use PVE::Cluster qw(cfs_register_file cfs_read_file);
8 use PVE::INotify;
9 use PVE::RPCEnvironment;
10 use PVE::AccessControl;
11 use PVE::JSONSchema qw(get_standard_option);
12 use PVE::Storage;
13 use PVE::VZDump;
14 use PVE::API2Tools;
15
16 use Data::Dumper; # fixme: remove
17
18
19 use base qw(PVE::RESTHandler);
20
21 __PACKAGE__->register_method ({
22 name => 'vzdump',
23 path => '',
24 method => 'POST',
25 description => "Create backup.",
26 permissions => {
27 description => "The user needs 'VM.Backup' permissions on any VM, and 'Datastore.AllocateSpace' on the backup storage. The 'maxfiles', 'tmpdir', 'dumpdir', 'script', 'bwlimit' and 'ionice' parameters are restricted to the 'root\@pam' user.",
28 user => 'all',
29 },
30 protected => 1,
31 proxyto => 'node',
32 parameters => {
33 additionalProperties => 0,
34 properties => PVE::VZDump::json_config_properties({
35 stdout => {
36 type => 'boolean',
37 description => "Write tar to stdout, not to a file.",
38 optional => 1,
39 },
40 }),
41 },
42 returns => { type => 'string' },
43 code => sub {
44 my ($param) = @_;
45
46 my $rpcenv = PVE::RPCEnvironment::get();
47
48 my $user = $rpcenv->get_user();
49
50 my $nodename = PVE::INotify::nodename();
51
52 if ($rpcenv->{type} ne 'cli') {
53 raise_param_exc({ node => "option is only allowed on the command line interface."})
54 if $param->{node} && $param->{node} ne $nodename;
55
56 raise_param_exc({ stdout => "option is only allowed on the command line interface."})
57 if $param->{stdout};
58 }
59
60 foreach my $key (qw(maxfiles tmpdir dumpdir script bwlimit ionice)) {
61 raise_param_exc({ $key => "Only root may set this option."})
62 if defined($param->{$key}) && ($user ne 'root@pam');
63 }
64
65 PVE::VZDump::verify_vzdump_parameters($param, 1);
66
67 # silent exit if we run on wrong node
68 return 'OK' if $param->{node} && $param->{node} ne $nodename;
69
70 my $cmdline = PVE::VZDump::command_line($param);
71 my @vmids;
72 # convert string lists to arrays
73 if ($param->{pool}) {
74 @vmids = @{PVE::API2Tools::get_resource_pool_guest_members($param->{pool})};
75 } else {
76 @vmids = PVE::Tools::split_list(extract_param($param, 'vmid'));
77 }
78
79 if($param->{stop}){
80 PVE::VZDump::stop_running_backups();
81 return 'OK' if !scalar(@vmids);
82 }
83
84 my $skiplist = [];
85 if (!$param->{all}) {
86 if (!$param->{node} || $param->{node} eq $nodename) {
87 my $vmlist = PVE::Cluster::get_vmlist();
88 my @localvmids = ();
89 foreach my $vmid (@vmids) {
90 my $d = $vmlist->{ids}->{$vmid};
91 if ($d && ($d->{node} ne $nodename)) {
92 push @$skiplist, $vmid;
93 } else {
94 push @localvmids, $vmid;
95 }
96 }
97 @vmids = @localvmids;
98 # silent exit if specified VMs run on other nodes
99 return "OK" if !scalar(@vmids);
100 }
101
102 $param->{vmids} = PVE::VZDump::check_vmids(@vmids)
103 }
104
105 my @exclude = PVE::Tools::split_list(extract_param($param, 'exclude'));
106 $param->{exclude} = PVE::VZDump::check_vmids(@exclude);
107
108 # exclude-path list need to be 0 separated
109 if (defined($param->{'exclude-path'})) {
110 my @expaths = split(/\0/, $param->{'exclude-path'} || '');
111 $param->{'exclude-path'} = [ @expaths ];
112 }
113
114 if (defined($param->{mailto})) {
115 my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto'));
116 $param->{mailto} = [ @mailto ];
117 }
118
119 die "you can only backup a single VM with option --stdout\n"
120 if $param->{stdout} && scalar(@vmids) != 1;
121
122 $rpcenv->check($user, "/storage/$param->{storage}", [ 'Datastore.AllocateSpace' ])
123 if $param->{storage};
124
125 my $worker = sub {
126 my $upid = shift;
127
128 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
129 die "interrupted by signal\n";
130 };
131
132 my $vzdump = PVE::VZDump->new($cmdline, $param, $skiplist);
133
134 eval {
135 $vzdump->getlock($upid); # only one process allowed
136 };
137 if (my $err = $@) {
138 $vzdump->sendmail([], 0, $err);
139 exit(-1);
140 }
141
142 if (defined($param->{ionice})) {
143 if ($param->{ionice} > 7) {
144 PVE::VZDump::run_command(undef, "ionice -c3 -p $$");
145 } else {
146 PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$");
147 }
148 }
149 $vzdump->exec_backup($rpcenv, $user);
150 };
151
152 open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout};
153 open STDERR, '>/dev/null' if $param->{quiet};
154
155 if ($rpcenv->{type} eq 'cli') {
156 if ($param->{stdout}) {
157
158 open my $saved_stdout, ">&STDOUT"
159 || die "can't dup STDOUT: $!\n";
160
161 open STDOUT, '>&STDERR' ||
162 die "unable to redirect STDOUT: $!\n";
163
164 $param->{stdout} = $saved_stdout;
165 }
166 }
167
168 my $taskid;
169 $taskid = $vmids[0] if scalar(@vmids) == 1;
170
171 return $rpcenv->fork_worker('vzdump', $taskid, $user, $worker);
172 }});
173
174 __PACKAGE__->register_method ({
175 name => 'extractconfig',
176 path => 'extractconfig',
177 method => 'GET',
178 description => "Extract configuration from vzdump backup archive.",
179 permissions => {
180 description => "The user needs 'VM.Backup' permissions on the backed up guest ID, and 'Datastore.AllocateSpace' on the backup storage.",
181 user => 'all',
182 },
183 protected => 1,
184 proxyto => 'node',
185 parameters => {
186 additionalProperties => 0,
187 properties => {
188 node => get_standard_option('pve-node'),
189 volume => {
190 description => "Volume identifier",
191 type => 'string',
192 completion => \&PVE::Storage::complete_volume,
193 },
194 },
195 },
196 returns => { type => 'string' },
197 code => sub {
198 my ($param) = @_;
199
200 my $volume = extract_param($param, 'volume');
201
202 my $rpcenv = PVE::RPCEnvironment::get();
203 my $authuser = $rpcenv->get_user();
204
205 my $storage_cfg = PVE::Storage::config();
206 PVE::Storage::check_volume_access($rpcenv, $authuser, $storage_cfg, undef, $volume);
207
208 return PVE::Storage::extract_vzdump_config($storage_cfg, $volume);
209 }});
210
211 1;