1 package PVE
::API2
::VZDump
;
6 use PVE
::AccessControl
;
8 use PVE
::Exception
qw(raise_param_exc);
10 use PVE
::JSONSchema
qw(get_standard_option);
11 use PVE
::RPCEnvironment
;
13 use PVE
::Tools
qw(extract_param);
14 use PVE
::VZDump
::Common
;
17 use PVE
::API2
::Backup
;
20 use Data
::Dumper
; # fixme: remove
22 use base
qw(PVE::RESTHandler);
24 my sub assert_param_permission_vzdump
{
25 my ($rpcenv, $user, $param) = @_;
26 return if $user eq 'root@pam'; # always OK
28 PVE
::API2
::Backup
::assert_param_permission_common
($rpcenv, $user, $param);
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' ]);
37 __PACKAGE__-
>register_method ({
41 description
=> "Create backup.",
43 description
=> "The user needs 'VM.Backup' permissions on any VM, and "
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 '/'.",
54 additionalProperties
=> 0,
55 properties
=> PVE
::VZDump
::Common
::json_config_properties
({
58 description
=> "Write tar to stdout, not to a file.",
63 returns
=> { type
=> 'string' },
67 my $rpcenv = PVE
::RPCEnvironment
::get
();
69 my $user = $rpcenv->get_user();
71 my $nodename = PVE
::INotify
::nodename
();
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;
77 raise_param_exc
({ stdout
=> "option is only allowed on the command line interface."})
81 assert_param_permission_vzdump
($rpcenv, $user, $param);
83 PVE
::VZDump
::verify_vzdump_parameters
($param, 1);
85 # silent exit if we run on wrong node
86 return 'OK' if $param->{node
} && $param->{node
} ne $nodename;
88 my $cmdline = PVE
::VZDump
::Common
::command_line
($param);
90 my $vmids_per_node = PVE
::VZDump
::get_included_guests
($param);
92 my $local_vmids = delete $vmids_per_node->{$nodename} // [];
94 # include IDs for deleted guests, and visibly fail later
95 my $orphaned_vmids = delete $vmids_per_node->{''} // [];
96 push @{$local_vmids}, @{$orphaned_vmids};
98 my $skiplist = [ map { @$_ } values $vmids_per_node->%* ];
101 PVE
::VZDump
::stop_running_backups
();
102 return 'OK' if !scalar(@{$local_vmids});
105 # silent exit if specified VMs run on other nodes
106 return "OK" if !scalar(@{$local_vmids}) && !$param->{all
};
108 PVE
::VZDump
::parse_mailto_exclude_path
($param);
110 die "you can only backup a single VM with option --stdout\n"
111 if $param->{stdout
} && scalar(@{$local_vmids}) != 1;
113 if (my $storeid = PVE
::VZDump
::get_storage_param
($param)) {
114 $rpcenv->check($user, "/storage/$storeid", [ 'Datastore.AllocateSpace' ]);
120 $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
121 die "interrupted by signal\n";
124 $param->{vmids
} = $local_vmids;
125 my $vzdump = PVE
::VZDump-
>new($cmdline, $param, $skiplist);
128 $vzdump->getlock($upid); # only one process allowed
131 $vzdump->send_notification([], 0, $err);
135 if (defined($param->{ionice
})) {
136 if ($param->{ionice
} > 7) {
137 PVE
::VZDump
::run_command
(undef, "ionice -c3 -p $$");
139 PVE
::VZDump
::run_command
(undef, "ionice -c2 -n$param->{ionice} -p $$");
142 $vzdump->exec_backup($rpcenv, $user);
147 open STDOUT
, '>/dev/null' if $param->{quiet
} && !$param->{stdout
};
148 open STDERR
, '>/dev/null' if $param->{quiet
};
150 if ($rpcenv->{type
} eq 'cli') {
151 if ($param->{stdout
}) {
153 open my $saved_stdout, ">&STDOUT"
154 || die "can't dup STDOUT: $!\n";
156 open STDOUT
, '>&STDERR' ||
157 die "unable to redirect STDOUT: $!\n";
159 $param->{stdout
} = $saved_stdout;
164 $taskid = $local_vmids->[0] if scalar(@{$local_vmids}) == 1;
166 return $rpcenv->fork_worker('vzdump', $taskid, $user, $worker);
169 __PACKAGE__-
>register_method ({
173 description
=> "Get the currently configured vzdump defaults.",
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.",
182 additionalProperties
=> 0,
184 node
=> get_standard_option
('pve-node'),
185 storage
=> get_standard_option
('pve-storage-id', { optional
=> 1 }),
190 additionalProperties
=> 0,
191 properties
=> PVE
::VZDump
::Common
::json_config_properties
(),
196 my $node = extract_param
($param, 'node');
197 my $storage = extract_param
($param, 'storage');
199 my $rpcenv = PVE
::RPCEnvironment
::get
();
200 my $authuser = $rpcenv->get_user();
202 my $res = PVE
::VZDump
::read_vzdump_defaults
();
204 $res->{storage
} = $storage if defined($storage);
206 if (!defined($res->{dumpdir
}) && !defined($res->{storage
})) {
207 $res->{storage
} = 'local';
210 if (defined($res->{storage
})) {
213 "/storage/$res->{storage}",
214 ['Datastore.Audit', 'Datastore.AllocateSpace'],
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});
223 if (defined($res->{'prune-backups'})) {
224 $res->{'prune-backups'} = PVE
::JSONSchema
::print_property_string
(
225 $res->{'prune-backups'},
230 $res->{mailto
} = join(",", @{$res->{mailto
}})
231 if defined($res->{mailto
});
233 $res->{'exclude-path'} = join(",", @{$res->{'exclude-path'}})
234 if defined($res->{'exclude-path'});
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
};
245 my $pool = $res->{pool
};
246 if (defined($pool) &&
247 !$rpcenv->check($authuser, "/pool/$pool", ['Pool.Audit'], 1)) {
254 __PACKAGE__-
>register_method ({
255 name
=> 'extractconfig',
256 path
=> 'extractconfig',
258 description
=> "Extract configuration from vzdump backup archive.",
260 description
=> "The user needs 'VM.Backup' permissions on the backed up guest ID, and 'Datastore.AllocateSpace' on the backup storage.",
266 additionalProperties
=> 0,
268 node
=> get_standard_option
('pve-node'),
270 description
=> "Volume identifier",
272 completion
=> \
&PVE
::Storage
::complete_volume
,
276 returns
=> { type
=> 'string' },
280 my $volume = extract_param
($param, 'volume');
282 my $rpcenv = PVE
::RPCEnvironment
::get
();
283 my $authuser = $rpcenv->get_user();
285 my $storage_cfg = PVE
::Storage
::config
();
286 PVE
::Storage
::check_volume_access
(
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']);
300 return PVE
::Storage
::extract_vzdump_config
($storage_cfg, $volume);