]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2/VZDump.pm
VZDump: send an error email in case of lock failure
[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
15 use Data::Dumper; # fixme: remove
16
17
18 use base qw(PVE::RESTHandler);
19
20 __PACKAGE__->register_method ({
21 name => 'vzdump',
22 path => '',
23 method => 'POST',
24 description => "Create backup.",
25 permissions => {
26 description => "The user needs 'VM.Backup' permissions on any VM, and 'Datastore.AllocateSpace' on the backup storage.",
27 user => 'all',
28 },
29 protected => 1,
30 proxyto => 'node',
31 parameters => {
32 additionalProperties => 0,
33 properties => PVE::VZDump::json_config_properties({
34 stdout => {
35 type => 'boolean',
36 description => "Write tar to stdout, not to a file.",
37 optional => 1,
38 },
39 }),
40 },
41 returns => { type => 'string' },
42 code => sub {
43 my ($param) = @_;
44
45 my $rpcenv = PVE::RPCEnvironment::get();
46
47 my $user = $rpcenv->get_user();
48
49 my $nodename = PVE::INotify::nodename();
50
51 if ($rpcenv->{type} ne 'cli') {
52 raise_param_exc({ node => "option is only allowed on the command line interface."})
53 if $param->{node} && $param->{node} ne $nodename;
54
55 raise_param_exc({ stdout => "option is only allowed on the command line interface."})
56 if $param->{stdout};
57 }
58
59 # by default we set --rsyncable for gzip
60 local $ENV{GZIP} = "--rsyncable" if !$ENV{GZIP};
61
62 PVE::VZDump::verify_vzdump_parameters($param, 1);
63
64 # silent exit if we run on wrong node
65 exit(0) if $param->{node} && $param->{node} ne $nodename;
66
67 my $cmdline = PVE::VZDump::command_line($param);
68
69 # convert string lists to arrays
70 my @vmids = PVE::Tools::split_list(extract_param($param, 'vmid'));
71
72 my $skiplist = [];
73 if (!$param->{all}) {
74 if (!$param->{node}) {
75 my $vmlist = PVE::Cluster::get_vmlist();
76 my @localvmids = ();
77 foreach my $vmid (@vmids) {
78 my $d = $vmlist->{ids}->{$vmid};
79 if ($d && ($d->{node} ne $nodename)) {
80 push @$skiplist, $vmid;
81 } else {
82 push @localvmids, $vmid;
83 }
84 }
85 @vmids = @localvmids;
86 # silent exit if specified VMs run on other nodes
87 exit(0) if !scalar(@vmids);
88 }
89
90 $param->{vmids} = PVE::VZDump::check_vmids(@vmids)
91 }
92
93 my @exclude = PVE::Tools::split_list(extract_param($param, 'exclude'));
94 $param->{exclude} = PVE::VZDump::check_vmids(@exclude);
95
96 # exclude-path list need to be 0 separated
97 if (defined($param->{'exclude-path'})) {
98 my @expaths = split(/\0/, $param->{'exclude-path'} || '');
99 $param->{'exclude-path'} = [ @expaths ];
100 }
101
102 if (defined($param->{mailto})) {
103 my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto'));
104 $param->{mailto} = [ @mailto ];
105 }
106
107 die "you can only backup a single VM with option --stdout\n"
108 if $param->{stdout} && scalar(@vmids) != 1;
109
110 foreach my $key (qw(maxfiles tmpdir dumpdir script size bwlimit ionice)) {
111 raise_param_exc({ $key => "Only root may set this option."})
112 if defined($param->{$key}) && ($user ne 'root@pam');
113 }
114
115 $rpcenv->check($user, "/storage/$param->{storage}", [ 'Datastore.AllocateSpace' ])
116 if $param->{storage};
117
118 my $vzdump = PVE::VZDump->new($cmdline, $param, $skiplist);
119
120 my $worker = sub {
121 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
122 die "interrupted by signal\n";
123 };
124
125 eval {
126 $vzdump->getlock(); # only one process allowed
127 };
128 if ($@) {
129 $vzdump->sendmail([], 0, $@);
130 exit(-1);
131 }
132
133 if (defined($param->{ionice})) {
134 if ($param->{ionice} > 7) {
135 PVE::VZDump::run_command(undef, "ionice -c3 -p $$");
136 } else {
137 PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$");
138 }
139 }
140 $vzdump->exec_backup($rpcenv, $user);
141 };
142
143 open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout};
144 open STDERR, '>/dev/null' if $param->{quiet};
145
146 if ($rpcenv->{type} eq 'cli') {
147 if ($param->{stdout}) {
148
149 open my $saved_stdout, ">&STDOUT"
150 || die "can't dup STDOUT: $!\n";
151
152 open STDOUT, '>&STDERR' ||
153 die "unable to redirect STDOUT: $!\n";
154
155 $param->{stdout} = $saved_stdout;
156 }
157 }
158
159 return $rpcenv->fork_worker('vzdump', undef, $user, $worker);
160 }});