]>
Commit | Line | Data |
---|---|---|
bf58f8dd DM |
1 | package PVE::API2::VZDump; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
31aef761 | 5 | use PVE::Exception qw(raise_param_exc); |
bf58f8dd DM |
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; | |
2424074e | 14 | use PVE::VZDump::Common; |
f3376261 | 15 | use PVE::API2Tools; |
bf58f8dd DM |
16 | |
17 | use Data::Dumper; # fixme: remove | |
18 | ||
19 | ||
20 | use base qw(PVE::RESTHandler); | |
21 | ||
22 | __PACKAGE__->register_method ({ | |
60e049c2 | 23 | name => 'vzdump', |
bf58f8dd DM |
24 | path => '', |
25 | method => 'POST', | |
26 | description => "Create backup.", | |
98e84b16 | 27 | permissions => { |
e6946086 | 28 | description => "The user needs 'VM.Backup' permissions on any VM, and 'Datastore.AllocateSpace' on the backup storage. The 'maxfiles', 'prune-backups', 'tmpdir', 'dumpdir', 'script', 'bwlimit' and 'ionice' parameters are restricted to the 'root\@pam' user.", |
98e84b16 DM |
29 | user => 'all', |
30 | }, | |
30edfad9 | 31 | protected => 1, |
49046e53 | 32 | proxyto => 'node', |
bf58f8dd DM |
33 | parameters => { |
34 | additionalProperties => 0, | |
2424074e | 35 | properties => PVE::VZDump::Common::json_config_properties({ |
bf58f8dd DM |
36 | stdout => { |
37 | type => 'boolean', | |
38 | description => "Write tar to stdout, not to a file.", | |
39 | optional => 1, | |
40 | }, | |
ac27b58d | 41 | }), |
bf58f8dd DM |
42 | }, |
43 | returns => { type => 'string' }, | |
44 | code => sub { | |
45 | my ($param) = @_; | |
46 | ||
47 | my $rpcenv = PVE::RPCEnvironment::get(); | |
48 | ||
49 | my $user = $rpcenv->get_user(); | |
50 | ||
51 | my $nodename = PVE::INotify::nodename(); | |
52 | ||
53 | if ($rpcenv->{type} ne 'cli') { | |
54 | raise_param_exc({ node => "option is only allowed on the command line interface."}) | |
55 | if $param->{node} && $param->{node} ne $nodename; | |
56 | ||
57 | raise_param_exc({ stdout => "option is only allowed on the command line interface."}) | |
58 | if $param->{stdout}; | |
59 | } | |
60 | ||
e6946086 | 61 | foreach my $key (qw(maxfiles prune-backups tmpdir dumpdir script bwlimit ionice)) { |
6d0507a8 FG |
62 | raise_param_exc({ $key => "Only root may set this option."}) |
63 | if defined($param->{$key}) && ($user ne 'root@pam'); | |
64 | } | |
65 | ||
31aef761 | 66 | PVE::VZDump::verify_vzdump_parameters($param, 1); |
bf58f8dd DM |
67 | |
68 | # silent exit if we run on wrong node | |
eab837c4 | 69 | return 'OK' if $param->{node} && $param->{node} ne $nodename; |
60e049c2 | 70 | |
2424074e | 71 | my $cmdline = PVE::VZDump::Common::command_line($param); |
df5875b4 AL |
72 | |
73 | my $vmids_per_node = PVE::VZDump::get_included_guests($param); | |
74 | ||
75 | my $local_vmids = delete $vmids_per_node->{$nodename} // []; | |
76 | ||
7f874148 FE |
77 | # include IDs for deleted guests, and visibly fail later |
78 | my $orphaned_vmids = delete $vmids_per_node->{''} // []; | |
79 | push @{$local_vmids}, @{$orphaned_vmids}; | |
80 | ||
df5875b4 | 81 | my $skiplist = [ map { @$_ } values $vmids_per_node->%* ]; |
bf58f8dd | 82 | |
eab837c4 DM |
83 | if($param->{stop}){ |
84 | PVE::VZDump::stop_running_backups(); | |
df5875b4 | 85 | return 'OK' if !scalar(@{$local_vmids}); |
eab837c4 DM |
86 | } |
87 | ||
5c4da4c3 | 88 | # silent exit if specified VMs run on other nodes |
df5875b4 | 89 | return "OK" if !scalar(@{$local_vmids}) && !$param->{all}; |
336ec53a | 90 | |
bf58f8dd | 91 | # exclude-path list need to be 0 separated |
336ec53a DM |
92 | if (defined($param->{'exclude-path'})) { |
93 | my @expaths = split(/\0/, $param->{'exclude-path'} || ''); | |
94 | $param->{'exclude-path'} = [ @expaths ]; | |
95 | } | |
bf58f8dd | 96 | |
336ec53a DM |
97 | if (defined($param->{mailto})) { |
98 | my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto')); | |
99 | $param->{mailto} = [ @mailto ]; | |
100 | } | |
bf58f8dd DM |
101 | |
102 | die "you can only backup a single VM with option --stdout\n" | |
df5875b4 | 103 | if $param->{stdout} && scalar(@{$local_vmids}) != 1; |
bf58f8dd | 104 | |
4412265f DM |
105 | $rpcenv->check($user, "/storage/$param->{storage}", [ 'Datastore.AllocateSpace' ]) |
106 | if $param->{storage}; | |
107 | ||
bf58f8dd | 108 | my $worker = sub { |
eab837c4 DM |
109 | my $upid = shift; |
110 | ||
bf58f8dd DM |
111 | $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub { |
112 | die "interrupted by signal\n"; | |
113 | }; | |
114 | ||
df5875b4 | 115 | $param->{vmids} = $local_vmids; |
403761c4 WB |
116 | my $vzdump = PVE::VZDump->new($cmdline, $param, $skiplist); |
117 | ||
6ec9de44 | 118 | eval { |
eab837c4 | 119 | $vzdump->getlock($upid); # only one process allowed |
6ec9de44 | 120 | }; |
eab837c4 DM |
121 | if (my $err = $@) { |
122 | $vzdump->sendmail([], 0, $err); | |
6ec9de44 SP |
123 | exit(-1); |
124 | } | |
bf58f8dd DM |
125 | |
126 | if (defined($param->{ionice})) { | |
127 | if ($param->{ionice} > 7) { | |
128 | PVE::VZDump::run_command(undef, "ionice -c3 -p $$"); | |
129 | } else { | |
130 | PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$"); | |
131 | } | |
132 | } | |
60e049c2 TM |
133 | $vzdump->exec_backup($rpcenv, $user); |
134 | }; | |
bf58f8dd DM |
135 | |
136 | open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout}; | |
137 | open STDERR, '>/dev/null' if $param->{quiet}; | |
138 | ||
139 | if ($rpcenv->{type} eq 'cli') { | |
140 | if ($param->{stdout}) { | |
141 | ||
142 | open my $saved_stdout, ">&STDOUT" | |
143 | || die "can't dup STDOUT: $!\n"; | |
144 | ||
145 | open STDOUT, '>&STDERR' || | |
146 | die "unable to redirect STDOUT: $!\n"; | |
147 | ||
148 | $param->{stdout} = $saved_stdout; | |
149 | } | |
150 | } | |
151 | ||
742d2ad2 | 152 | my $taskid; |
df5875b4 | 153 | $taskid = $local_vmids->[0] if scalar(@{$local_vmids}) == 1; |
742d2ad2 FG |
154 | |
155 | return $rpcenv->fork_worker('vzdump', $taskid, $user, $worker); | |
bf58f8dd | 156 | }}); |
7619e4dd FG |
157 | |
158 | __PACKAGE__->register_method ({ | |
159 | name => 'extractconfig', | |
160 | path => 'extractconfig', | |
161 | method => 'GET', | |
162 | description => "Extract configuration from vzdump backup archive.", | |
163 | permissions => { | |
164 | description => "The user needs 'VM.Backup' permissions on the backed up guest ID, and 'Datastore.AllocateSpace' on the backup storage.", | |
165 | user => 'all', | |
166 | }, | |
167 | protected => 1, | |
168 | proxyto => 'node', | |
169 | parameters => { | |
170 | additionalProperties => 0, | |
171 | properties => { | |
172 | node => get_standard_option('pve-node'), | |
173 | volume => { | |
174 | description => "Volume identifier", | |
175 | type => 'string', | |
176 | completion => \&PVE::Storage::complete_volume, | |
177 | }, | |
178 | }, | |
179 | }, | |
180 | returns => { type => 'string' }, | |
181 | code => sub { | |
182 | my ($param) = @_; | |
183 | ||
184 | my $volume = extract_param($param, 'volume'); | |
185 | ||
186 | my $rpcenv = PVE::RPCEnvironment::get(); | |
187 | my $authuser = $rpcenv->get_user(); | |
188 | ||
189 | my $storage_cfg = PVE::Storage::config(); | |
989f3c7e | 190 | PVE::Storage::check_volume_access($rpcenv, $authuser, $storage_cfg, undef, $volume); |
7619e4dd FG |
191 | |
192 | return PVE::Storage::extract_vzdump_config($storage_cfg, $volume); | |
193 | }}); | |
194 | ||
195 | 1; |