]> git.proxmox.com Git - pmg-api.git/blame - src/PMG/API2/PBS/Job.pm
pbs: schema style fixes
[pmg-api.git] / src / PMG / API2 / PBS / Job.pm
CommitLineData
a0208dbd
SI
1package PMG::API2::PBS::Job;
2
3use strict;
4use warnings;
5
6use POSIX qw(strftime);
7
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::RESTHandler;
10use PVE::SafeSyslog;
11use PVE::Tools qw(extract_param);
12use PVE::PBSClient;
13
14use PMG::RESTEnvironment;
15use PMG::Backup;
16use PMG::PBSConfig;
7251cc51 17use PMG::PBSSchedule;
a0208dbd
SI
18
19use base qw(PVE::RESTHandler);
20
21__PACKAGE__->register_method ({
22 name => 'list',
23 path => '',
24 method => 'GET',
25 description => "List all configured Proxmox Backup Server jobs.",
26 permissions => { check => [ 'admin', 'audit' ] },
27 proxyto => 'node',
28 protected => 1,
29 parameters => {
30 additionalProperties => 0,
31 properties => {
32 node => get_standard_option('pve-node'),
33 },
34 },
35 returns => {
2ea79c2a
TL
36 type => "array",
37 items => PMG::PBSConfig->createSchema(1),
38 links => [ { rel => 'child', href => "{remote}" } ],
a0208dbd
SI
39 },
40 code => sub {
41 my ($param) = @_;
42
43 my $res = [];
44
45 my $conf = PMG::PBSConfig->new();
2ea79c2a
TL
46 return $res if !defined($conf);
47
48 foreach my $remote (keys %{$conf->{ids}}) {
49 my $d = $conf->{ids}->{$remote};
50 push @$res, {
51 remote => $remote,
52 server => $d->{server},
53 datastore => $d->{datastore},
54 };
a0208dbd
SI
55 }
56
57 return $res;
58 }});
59
60__PACKAGE__->register_method ({
61 name => 'remote_index',
62 path => '{remote}',
63 method => 'GET',
64 description => "Backup Job index.",
65 parameters => {
66 additionalProperties => 0,
67 properties => {
68 node => get_standard_option('pve-node'),
69 remote => {
70 description => "Proxmox Backup Server ID.",
71 type => 'string', format => 'pve-configid',
72 },
73 },
74 },
75 returns => {
76 type => 'array',
77 items => {
78 type => "object",
79 properties => { section => { type => 'string'} },
80 },
81 links => [ { rel => 'child', href => "{section}" } ],
82 },
83 code => sub {
84 my ($param) = @_;
85
86 my $result = [
0e368d37 87 { section => 'snapshot' },
a0208dbd
SI
88 { section => 'timer' },
89 ];
90 return $result;
91}});
92
0e368d37
TL
93
94my sub get_snapshots {
95 my ($remote, $group) = @_;
96
97 my $conf = PMG::PBSConfig->new();
98
99 my $remote_config = $conf->{ids}->{$remote};
100 die "PBS remote '$remote' does not exist\n" if !$remote_config;
101
102 my $res = [];
103 return $res if $remote_config->{disable};
104
105 my $pbs = PVE::PBSClient->new($remote_config, $remote, $conf->{secret_dir});
106
107 my $snapshots = $pbs->get_snapshots($group);
108 foreach my $item (@$snapshots) {
109 my ($type, $id, $time) = $item->@{qw(backup-type backup-id backup-time)};
110 next if $type ne 'host';
111
112 my @pxar = grep { $_->{filename} eq 'pmgbackup.pxar.didx' } @{$item->{files}};
113 next if (scalar(@pxar) != 1);
114
115 my $time_rfc3339 = strftime("%FT%TZ", gmtime($time));
116
117 push @$res, {
118 'backup-id' => $id,
119 'backup-time' => $time_rfc3339,
120 ctime => $time,
121 size => $item->{size} // 1,
122 };
123 }
124 return $res;
125}
126
a0208dbd
SI
127__PACKAGE__->register_method ({
128 name => 'get_snapshots',
0e368d37 129 path => '{remote}/snapshot',
a0208dbd
SI
130 method => 'GET',
131 description => "Get snapshots stored on remote.",
132 proxyto => 'node',
133 protected => 1,
134 permissions => { check => [ 'admin', 'audit' ] },
135 parameters => {
136 additionalProperties => 0,
137 properties => {
138 node => get_standard_option('pve-node'),
139 remote => {
140 description => "Proxmox Backup Server ID.",
141 type => 'string', format => 'pve-configid',
142 },
143 },
144 },
145 returns => {
146 type => 'array',
147 items => {
148 type => "object",
149 properties => {
0e368d37
TL
150 'backup-time' => { type => 'string'},
151 'backup-id' => { type => 'string'},
a0208dbd
SI
152 ctime => { type => 'string'},
153 size => { type => 'integer'},
154 },
155 },
0e368d37 156 links => [ { rel => 'child', href => "{backup-id}" } ],
a0208dbd
SI
157 },
158 code => sub {
159 my ($param) = @_;
160
0e368d37
TL
161 return get_snapshots($param->{remote});
162 }});
a0208dbd 163
0e368d37
TL
164__PACKAGE__->register_method ({
165 name => 'get_group_snapshots',
166 path => '{remote}/snapshot/{backup-id}',
167 method => 'GET',
168 description => "Get snapshots from a specific ID stored on remote.",
169 proxyto => 'node',
170 protected => 1,
171 permissions => { check => [ 'admin', 'audit' ] },
172 parameters => {
173 additionalProperties => 0,
174 properties => {
175 node => get_standard_option('pve-node'),
176 remote => {
177 description => "Proxmox Backup Server ID.",
178 type => 'string', format => 'pve-configid',
179 },
180 'backup-id' => {
181 description => "ID (hostname) of backup snapshot",
182 type => 'string',
183 },
184 },
185 },
186 returns => {
187 type => 'array',
188 items => {
189 type => "object",
190 properties => {
191 'backup-time' => { type => 'string'},
192 'backup-id' => { type => 'string'},
193 ctime => { type => 'string'},
194 size => { type => 'integer'},
195 },
196 },
197 links => [ { rel => 'child', href => "{backup-time}" } ],
198 },
199 code => sub {
200 my ($param) = @_;
a0208dbd 201
0e368d37 202 return get_snapshots($param->{remote}, "host/$param->{node}");
a0208dbd
SI
203 }});
204
205__PACKAGE__->register_method ({
206 name => 'forget_snapshot',
0e368d37 207 path => '{remote}/snapshot/{backup-id}/{backup-time}',
a0208dbd
SI
208 method => 'DELETE',
209 description => "Forget a snapshot",
210 proxyto => 'node',
211 protected => 1,
212 permissions => { check => [ 'admin', 'audit' ] },
213 parameters => {
214 additionalProperties => 0,
215 properties => {
216 node => get_standard_option('pve-node'),
217 remote => {
218 description => "Proxmox Backup Server ID.",
219 type => 'string', format => 'pve-configid',
220 },
0e368d37
TL
221 'backup-id' => {
222 description => "ID (hostname) of backup snapshot",
223 type => 'string',
224 },
225 'backup-time' => {
a6fd44eb 226 description => "Backup time in RFC 3339 format",
a0208dbd
SI
227 type => 'string',
228 },
229 },
230 },
231 returns => {type => 'null' },
232 code => sub {
233 my ($param) = @_;
234
235 my $remote = $param->{remote};
0e368d37
TL
236 my $id = $param->{'backup-id'};
237 my $time = $param->{'backup-time'};
a0208dbd
SI
238
239 my $conf = PMG::PBSConfig->new();
a0208dbd
SI
240 my $remote_config = $conf->{ids}->{$remote};
241 die "PBS remote '$remote' does not exist\n" if !$remote_config;
242 die "PBS remote '$remote' is disabled\n" if $remote_config->{disable};
243
244 my $pbs = PVE::PBSClient->new($remote_config, $remote, $conf->{secret_dir});
245
0e368d37 246 eval { $pbs->forget_snapshot("host/$id/$time") };
a0208dbd
SI
247 die "Forgetting backup failed: $@" if $@;
248
249 return;
250
251 }});
252
253__PACKAGE__->register_method ({
254 name => 'run_backup',
0e368d37 255 path => '{remote}/snapshot',
a0208dbd 256 method => 'POST',
0e368d37 257 description => "Create a new backup and prune the backup group afterwards, if configured.",
a0208dbd
SI
258 proxyto => 'node',
259 protected => 1,
260 permissions => { check => [ 'admin', 'audit' ] },
261 parameters => {
262 additionalProperties => 0,
263 properties => {
264 node => get_standard_option('pve-node'),
265 remote => {
266 description => "Proxmox Backup Server ID.",
267 type => 'string', format => 'pve-configid',
268 },
269 },
270 },
271 returns => { type => "string" },
272 code => sub {
273 my ($param) = @_;
274
275 my $rpcenv = PMG::RESTEnvironment->get();
276 my $authuser = $rpcenv->get_user();
277
278 my $remote = $param->{remote};
279 my $node = $param->{node};
280
281 my $conf = PMG::PBSConfig->new();
282
283 my $remote_config = $conf->{ids}->{$remote};
284 die "PBS remote '$remote' does not exist\n" if !$remote_config;
285 die "PBS remote '$remote' is disabled\n" if $remote_config->{disable};
286
287 my $pbs = PVE::PBSClient->new($remote_config, $remote, $conf->{secret_dir});
288 my $backup_dir = "/var/lib/pmg/backup/current";
289
290 my $worker = sub {
291 my $upid = shift;
292
293 print "starting update of current backup state\n";
294
295 -d $backup_dir || mkdir $backup_dir;
296 PMG::Backup::pmg_backup($backup_dir, $param->{statistic});
a0208dbd 297
0339f810 298 $pbs->backup_fs_tree($backup_dir, $node, 'pmgbackup');
a0208dbd
SI
299
300 print "backup finished\n";
301
302 my $group = "host/$node";
d423685c
TL
303 if (defined(my $prune_opts = $conf->prune_options($remote))) {
304 print "starting prune of $group\n";
305 my $res = $pbs->prune_group(undef, $prune_opts, $group);
306
307 foreach my $pruned (@$res){
308 my $time = strftime("%FT%TZ", gmtime($pruned->{'backup-time'}));
309 my $snap = $pruned->{'backup-type'} . '/' . $pruned->{'backup-id'} . '/' . $time;
310 print "pruned snapshot: $snap\n";
311 }
312 print "prune finished\n";
a0208dbd
SI
313 }
314
a0208dbd
SI
315 return;
316 };
317
318 return $rpcenv->fork_worker('pbs_backup', undef, $authuser, $worker);
319
320 }});
321
322__PACKAGE__->register_method ({
323 name => 'restore',
0e368d37 324 path => '{remote}/snapshot/{backup-id}/{backup-time}',
a0208dbd
SI
325 method => 'POST',
326 description => "Restore the system configuration.",
327 permissions => { check => [ 'admin' ] },
328 proxyto => 'node',
329 protected => 1,
330 parameters => {
331 additionalProperties => 0,
332 properties => {
333 PMG::Backup::get_restore_options(),
334 remote => {
335 description => "Proxmox Backup Server ID.",
336 type => 'string', format => 'pve-configid',
337 },
0e368d37
TL
338 'backup-time' => {
339 description=> "backup-time to restore",
340 type => 'string'
a0208dbd 341 },
0e368d37
TL
342 'backup-id' => {
343 description => "backup-id (hostname) of backup snapshot",
344 type => 'string'
a0208dbd
SI
345 },
346 },
347 },
348 returns => { type => "string" },
349 code => sub {
350 my ($param) = @_;
351
352 my $rpcenv = PMG::RESTEnvironment->get();
353 my $authuser = $rpcenv->get_user();
354
355 my $remote = $param->{remote};
0e368d37
TL
356 my $id = $param->{'backup-id'};
357 my $time = $param->{'backup-time'};
358 my $snapshot = "host/$id/$time";
a0208dbd
SI
359
360 my $conf = PMG::PBSConfig->new();
361
362 my $remote_config = $conf->{ids}->{$remote};
363 die "PBS remote '$remote' does not exist\n" if !$remote_config;
364 die "PBS remote '$remote' is disabled\n" if $remote_config->{disable};
365
366 my $pbs = PVE::PBSClient->new($remote_config, $remote, $conf->{secret_dir});
367
ffd8e031
TL
368 my $now = time;
369 my $dirname = "/tmp/proxrestore_$$.$now";
a0208dbd
SI
370
371 $param->{database} //= 1;
372
373 die "nothing selected - please select what you want to restore (config or database?)\n"
374 if !($param->{database} || $param->{config});
375
a0208dbd 376 my $worker = sub {
a0208dbd
SI
377 print "starting restore of $snapshot from $remote\n";
378
dc4b50da 379 $pbs->restore_pxar($snapshot, 'pmgbackup', $dirname);
a0208dbd 380 print "starting restore of PMG config\n";
0e368d37
TL
381 PMG::Backup::pmg_restore(
382 $dirname,
383 $param->{database},
384 $param->{config},
385 $param->{statistic}
386 );
a0208dbd 387 print "restore finished\n";
a0208dbd
SI
388 };
389
390 return $rpcenv->fork_worker('pbs_restore', undef, $authuser, $worker);
391 }});
392
7251cc51
SI
393__PACKAGE__->register_method ({
394 name => 'create_timer',
395 path => '{remote}/timer',
396 method => 'POST',
397 description => "Create backup schedule",
398 proxyto => 'node',
399 protected => 1,
400 permissions => { check => [ 'admin', 'audit' ] },
401 parameters => {
402 additionalProperties => 0,
403 properties => {
404 node => get_standard_option('pve-node'),
405 remote => {
406 description => "Proxmox Backup Server ID.",
407 type => 'string', format => 'pve-configid',
408 },
409 schedule => {
410 description => "Schedule for the backup (OnCalendar setting of the systemd.timer)",
411 type => 'string', pattern => '[0-9a-zA-Z*.:,\-/ ]+',
412 default => 'daily', optional => 1,
413 },
414 delay => {
415 description => "Randomized delay to add to the starttime (RandomizedDelaySec setting of the systemd.timer)",
416 type => 'string', pattern => '[0-9a-zA-Z. ]+',
a6fd44eb 417 default => '5min', optional => 1,
7251cc51
SI
418 },
419 },
420 },
421 returns => { type => 'null' },
422 code => sub {
423 my ($param) = @_;
424
425 my $remote = $param->{remote};
426 my $schedule = $param->{schedule} // 'daily';
427 my $delay = $param->{delay} // '5min';
428
429 my $conf = PMG::PBSConfig->new();
430
431 my $remote_config = $conf->{ids}->{$remote};
432 die "PBS remote '$remote' does not exist\n" if !$remote_config;
433 die "PBS remote '$remote' is disabled\n" if $remote_config->{disable};
434
435 PMG::PBSSchedule::create_schedule($remote, $schedule, $delay);
436
437 }});
438
439__PACKAGE__->register_method ({
440 name => 'delete_timer',
441 path => '{remote}/timer',
442 method => 'DELETE',
443 description => "Delete backup schedule",
444 proxyto => 'node',
445 protected => 1,
446 permissions => { check => [ 'admin', 'audit' ] },
447 parameters => {
448 additionalProperties => 0,
449 properties => {
450 node => get_standard_option('pve-node'),
451 remote => {
452 description => "Proxmox Backup Server ID.",
453 type => 'string', format => 'pve-configid',
454 },
455 },
456 },
457 returns => { type => 'null' },
458 code => sub {
459 my ($param) = @_;
460
461 my $remote = $param->{remote};
462
463 PMG::PBSSchedule::delete_schedule($remote);
464
465 }});
466
467__PACKAGE__->register_method ({
468 name => 'list_timer',
469 path => '{remote}/timer',
470 method => 'GET',
471 description => "Get timer specification",
472 proxyto => 'node',
473 protected => 1,
474 permissions => { check => [ 'admin', 'audit' ] },
475 parameters => {
476 additionalProperties => 0,
477 properties => {
478 node => get_standard_option('pve-node'),
479 remote => {
480 description => "Proxmox Backup Server ID.",
481 type => 'string', format => 'pve-configid',
482 },
483 },
484 },
edce8f57
TL
485 returns => {
486 type => 'object',
487 properties => {
7251cc51 488 remote => {
edce8f57 489 description => "Proxmox Backup Server remote ID.",
7251cc51
SI
490 type => 'string', format => 'pve-configid',
491 optional => 1,
492 },
493 schedule => {
494 description => "Schedule for the backup (OnCalendar setting of the systemd.timer)",
495 type => 'string', pattern => '[0-9a-zA-Z*.:,\-/ ]+',
496 default => 'daily', optional => 1,
497 },
498 delay => {
499 description => "Randomized delay to add to the starttime (RandomizedDelaySec setting of the systemd.timer)",
500 type => 'string', pattern => '[0-9a-zA-Z. ]+',
a6fd44eb 501 default => '5min', optional => 1,
7251cc51
SI
502 },
503 unitfile => {
504 description => "unit file for the systemd.timer unit",
505 type => 'string', optional => 1,
506 },
edce8f57
TL
507 }
508 },
7251cc51
SI
509 code => sub {
510 my ($param) = @_;
511
512 my $remote = $param->{remote};
513
514 my $schedules = PMG::PBSSchedule::get_schedules();
515 my @data = grep {$_->{remote} eq $remote} @$schedules;
516
517 my $res = {};
518 if (scalar(@data) == 1) {
519 $res = $data[0];
520 }
521
522 return $res
523 }});
524
a0208dbd 5251;