]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2/VZDump.pm
update shipped appliance info index
[pve-manager.git] / PVE / API2 / VZDump.pm
CommitLineData
bf58f8dd
DM
1package PVE::API2::VZDump;
2
3use strict;
4use warnings;
2b5f3f98
TL
5
6use PVE::AccessControl;
7use PVE::Cluster;
31aef761 8use PVE::Exception qw(raise_param_exc);
bf58f8dd 9use PVE::INotify;
bf58f8dd 10use PVE::JSONSchema qw(get_standard_option);
2b5f3f98 11use PVE::RPCEnvironment;
bf58f8dd 12use PVE::Storage;
2b5f3f98 13use PVE::Tools qw(extract_param);
2424074e 14use PVE::VZDump::Common;
2b5f3f98
TL
15use PVE::VZDump;
16
2b233ecc 17use PVE::API2::Backup;
f3376261 18use PVE::API2Tools;
bf58f8dd
DM
19
20use Data::Dumper; # fixme: remove
21
bf58f8dd
DM
22use base qw(PVE::RESTHandler);
23
2b233ecc
FE
24my sub assert_param_permission_vzdump {
25 my ($rpcenv, $user, $param) = @_;
26 return if $user eq 'root@pam'; # always OK
27
28 PVE::API2::Backup::assert_param_permission_common($rpcenv, $user, $param);
29
43f83ad9
FE
30 if (defined($param->{maxfiles}) || defined($param->{'prune-backups'})) {
31 if (my $storeid = PVE::VZDump::get_storage_param($param)) {
32 $rpcenv->check($user, "/storage/$storeid", [ 'Datastore.Allocate' ]);
33 }
34 }
2b233ecc
FE
35}
36
bf58f8dd 37__PACKAGE__->register_method ({
60e049c2 38 name => 'vzdump',
bf58f8dd
DM
39 path => '',
40 method => 'POST',
41 description => "Create backup.",
98e84b16 42 permissions => {
93880785 43 description => "The user needs 'VM.Backup' permissions on any VM, and "
77266e29
FE
44 ."'Datastore.AllocateSpace' on the backup storage (and fleecing storage when fleecing "
45 ."is used). The 'tmpdir', 'dumpdir' and 'script' parameters are restricted to the "
46 ."'root\@pam' user. The 'maxfiles' and 'prune-backups' settings require "
47 ."'Datastore.Allocate' on the backup storage. The 'bwlimit', 'performance' and "
48 ."'ionice' parameters require 'Sys.Modify' on '/'.",
98e84b16
DM
49 user => 'all',
50 },
30edfad9 51 protected => 1,
49046e53 52 proxyto => 'node',
bf58f8dd 53 parameters => {
ff119724 54 additionalProperties => 0,
2424074e 55 properties => PVE::VZDump::Common::json_config_properties({
bf58f8dd
DM
56 stdout => {
57 type => 'boolean',
58 description => "Write tar to stdout, not to a file.",
59 optional => 1,
60 },
ac27b58d 61 }),
bf58f8dd
DM
62 },
63 returns => { type => 'string' },
64 code => sub {
65 my ($param) = @_;
66
67 my $rpcenv = PVE::RPCEnvironment::get();
68
69 my $user = $rpcenv->get_user();
70
71 my $nodename = PVE::INotify::nodename();
72
73 if ($rpcenv->{type} ne 'cli') {
74 raise_param_exc({ node => "option is only allowed on the command line interface."})
75 if $param->{node} && $param->{node} ne $nodename;
76
77 raise_param_exc({ stdout => "option is only allowed on the command line interface."})
78 if $param->{stdout};
79 }
80
2b233ecc 81 assert_param_permission_vzdump($rpcenv, $user, $param);
6d0507a8 82
31aef761 83 PVE::VZDump::verify_vzdump_parameters($param, 1);
bf58f8dd
DM
84
85 # silent exit if we run on wrong node
eab837c4 86 return 'OK' if $param->{node} && $param->{node} ne $nodename;
60e049c2 87
2424074e 88 my $cmdline = PVE::VZDump::Common::command_line($param);
df5875b4
AL
89
90 my $vmids_per_node = PVE::VZDump::get_included_guests($param);
91
92 my $local_vmids = delete $vmids_per_node->{$nodename} // [];
93
7f874148
FE
94 # include IDs for deleted guests, and visibly fail later
95 my $orphaned_vmids = delete $vmids_per_node->{''} // [];
96 push @{$local_vmids}, @{$orphaned_vmids};
97
df5875b4 98 my $skiplist = [ map { @$_ } values $vmids_per_node->%* ];
bf58f8dd 99
eab837c4
DM
100 if($param->{stop}){
101 PVE::VZDump::stop_running_backups();
df5875b4 102 return 'OK' if !scalar(@{$local_vmids});
eab837c4
DM
103 }
104
5c4da4c3 105 # silent exit if specified VMs run on other nodes
df5875b4 106 return "OK" if !scalar(@{$local_vmids}) && !$param->{all};
336ec53a 107
f8ed6af8 108 PVE::VZDump::parse_mailto_exclude_path($param);
bf58f8dd
DM
109
110 die "you can only backup a single VM with option --stdout\n"
df5875b4 111 if $param->{stdout} && scalar(@{$local_vmids}) != 1;
bf58f8dd 112
43f83ad9
FE
113 if (my $storeid = PVE::VZDump::get_storage_param($param)) {
114 $rpcenv->check($user, "/storage/$storeid", [ 'Datastore.AllocateSpace' ]);
115 }
4412265f 116
bf58f8dd 117 my $worker = sub {
eab837c4
DM
118 my $upid = shift;
119
bf58f8dd
DM
120 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
121 die "interrupted by signal\n";
122 };
123
df5875b4 124 $param->{vmids} = $local_vmids;
403761c4
WB
125 my $vzdump = PVE::VZDump->new($cmdline, $param, $skiplist);
126
875c2e5a 127 my $LOCK_FH = eval {
eab837c4 128 $vzdump->getlock($upid); # only one process allowed
6ec9de44 129 };
eab837c4 130 if (my $err = $@) {
c4afde55 131 $vzdump->send_notification([], 0, $err);
6ec9de44
SP
132 exit(-1);
133 }
bf58f8dd
DM
134
135 if (defined($param->{ionice})) {
136 if ($param->{ionice} > 7) {
137 PVE::VZDump::run_command(undef, "ionice -c3 -p $$");
138 } else {
139 PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$");
140 }
141 }
60e049c2 142 $vzdump->exec_backup($rpcenv, $user);
875c2e5a
FE
143
144 close($LOCK_FH);
60e049c2 145 };
bf58f8dd
DM
146
147 open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout};
148 open STDERR, '>/dev/null' if $param->{quiet};
149
150 if ($rpcenv->{type} eq 'cli') {
151 if ($param->{stdout}) {
152
153 open my $saved_stdout, ">&STDOUT"
154 || die "can't dup STDOUT: $!\n";
155
156 open STDOUT, '>&STDERR' ||
157 die "unable to redirect STDOUT: $!\n";
158
159 $param->{stdout} = $saved_stdout;
160 }
161 }
162
742d2ad2 163 my $taskid;
df5875b4 164 $taskid = $local_vmids->[0] if scalar(@{$local_vmids}) == 1;
742d2ad2
FG
165
166 return $rpcenv->fork_worker('vzdump', $taskid, $user, $worker);
bf58f8dd 167 }});
7619e4dd 168
5b9a4030
FE
169__PACKAGE__->register_method ({
170 name => 'defaults',
171 path => 'defaults',
172 method => 'GET',
173 description => "Get the currently configured vzdump defaults.",
174 permissions => {
175 description => "The user needs 'Datastore.Audit' or 'Datastore.AllocateSpace' " .
176 "permissions for the specified storage (or default storage if none specified). Some " .
177 "properties are only returned when the user has 'Sys.Audit' permissions for the node.",
178 user => 'all',
179 },
180 proxyto => 'node',
181 parameters => {
182 additionalProperties => 0,
183 properties => {
184 node => get_standard_option('pve-node'),
185 storage => get_standard_option('pve-storage-id', { optional => 1 }),
186 },
187 },
188 returns => {
189 type => 'object',
190 additionalProperties => 0,
191 properties => PVE::VZDump::Common::json_config_properties(),
192 },
193 code => sub {
194 my ($param) = @_;
195
196 my $node = extract_param($param, 'node');
197 my $storage = extract_param($param, 'storage');
198
199 my $rpcenv = PVE::RPCEnvironment::get();
200 my $authuser = $rpcenv->get_user();
201
202 my $res = PVE::VZDump::read_vzdump_defaults();
203
204 $res->{storage} = $storage if defined($storage);
205
206 if (!defined($res->{dumpdir}) && !defined($res->{storage})) {
207 $res->{storage} = 'local';
208 }
209
210 if (defined($res->{storage})) {
211 $rpcenv->check_any(
212 $authuser,
213 "/storage/$res->{storage}",
214 ['Datastore.Audit', 'Datastore.AllocateSpace'],
215 );
216
217 my $info = PVE::VZDump::storage_info($res->{storage});
218 for my $key (qw(dumpdir prune-backups)) {
219 $res->{$key} = $info->{$key} if defined($info->{$key});
220 }
221 }
222
223 if (defined($res->{'prune-backups'})) {
224 $res->{'prune-backups'} = PVE::JSONSchema::print_property_string(
225 $res->{'prune-backups'},
226 'prune-backups',
227 );
228 }
229
230 $res->{mailto} = join(",", @{$res->{mailto}})
231 if defined($res->{mailto});
232
233 $res->{'exclude-path'} = join(",", @{$res->{'exclude-path'}})
234 if defined($res->{'exclude-path'});
235
236 # normal backup users don't need to know these
237 if (!$rpcenv->check($authuser, "/nodes/$node", ['Sys.Audit'], 1)) {
238 delete $res->{mailto};
239 delete $res->{tmpdir};
240 delete $res->{dumpdir};
241 delete $res->{script};
242 delete $res->{ionice};
243 }
244
245 my $pool = $res->{pool};
246 if (defined($pool) &&
91db3ece 247 !$rpcenv->check($authuser, "/pool/$pool", ['Pool.Audit'], 1)) {
5b9a4030
FE
248 delete $res->{pool};
249 }
250
5b9a4030
FE
251 return $res;
252 }});
253
7619e4dd
FG
254__PACKAGE__->register_method ({
255 name => 'extractconfig',
256 path => 'extractconfig',
257 method => 'GET',
258 description => "Extract configuration from vzdump backup archive.",
259 permissions => {
260 description => "The user needs 'VM.Backup' permissions on the backed up guest ID, and 'Datastore.AllocateSpace' on the backup storage.",
261 user => 'all',
262 },
263 protected => 1,
264 proxyto => 'node',
265 parameters => {
266 additionalProperties => 0,
267 properties => {
268 node => get_standard_option('pve-node'),
269 volume => {
270 description => "Volume identifier",
271 type => 'string',
272 completion => \&PVE::Storage::complete_volume,
273 },
274 },
275 },
276 returns => { type => 'string' },
277 code => sub {
278 my ($param) = @_;
279
280 my $volume = extract_param($param, 'volume');
281
282 my $rpcenv = PVE::RPCEnvironment::get();
283 my $authuser = $rpcenv->get_user();
284
285 my $storage_cfg = PVE::Storage::config();
c53d5c5e
FE
286 PVE::Storage::check_volume_access(
287 $rpcenv,
288 $authuser,
289 $storage_cfg,
290 undef,
291 $volume,
292 'backup',
293 );
7619e4dd 294
0bd224e5
FE
295 if (PVE::Storage::parse_volume_id($volume, 1)) {
296 my (undef, undef, $ownervm) = PVE::Storage::parse_volname($storage_cfg, $volume);
297 $rpcenv->check($authuser, "/vms/$ownervm", ['VM.Backup']);
298 }
299
7619e4dd
FG
300 return PVE::Storage::extract_vzdump_config($storage_cfg, $volume);
301 }});
302
3031;