]> git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/Backup.pm
dkim: add QID in warnings
[pmg-api.git] / src / PMG / API2 / Backup.pm
1 package PMG::API2::Backup;
2
3 use strict;
4 use warnings;
5 use Time::Local;
6 use Data::Dumper;
7
8 use PVE::SafeSyslog;
9 use PVE::Tools;
10 use PVE::JSONSchema qw(get_standard_option);
11 use PVE::RESTHandler;
12 use PVE::INotify;
13
14 use PMG::RESTEnvironment;
15 use PMG::Config;
16 use PMG::Backup;
17
18 use base qw(PVE::RESTHandler);
19
20 my $backup_dir = "/var/lib/pmg/backup";
21 my $backup_filename_pattern = 'pmg-backup_[0-9A-Za-z_-]+\.tgz';
22
23 my $backup_filename_property = {
24 description => "The backup file name.",
25 type => "string",
26 pattern => $backup_filename_pattern,
27 minLength => 4,
28 maxLength => 256,
29 };
30
31 __PACKAGE__->register_method ({
32 name => 'list',
33 path => '',
34 method => 'GET',
35 description => "List all stored backups (files named proxmox-backup_{DATE}.tgz).",
36 permissions => { check => [ 'admin', 'audit' ] },
37 proxyto => 'node',
38 protected => 1,
39 parameters => {
40 additionalProperties => 0,
41 properties => {
42 node => get_standard_option('pve-node'),
43 },
44 },
45 returns => {
46 type => "array",
47 items => {
48 type => "object",
49 properties => {
50 filename => $backup_filename_property,
51 size => {
52 description => "Size of backup file in bytes.",
53 type => 'integer',
54 },
55 timestamp => {
56 description => "Backup timestamp (Unix epoch).",
57 type => 'integer',
58 },
59 },
60 },
61 links => [ { rel => 'child', href => "{filename}" } ],
62 },
63 code => sub {
64 my ($param) = @_;
65
66 my $res = [];
67
68 PVE::Tools::dir_glob_foreach(
69 $backup_dir,
70 $backup_filename_pattern,
71 sub {
72 my ($filename) = @_;
73
74 my $path = "$backup_dir/$filename";
75 my @sa = stat($path);
76
77 my $timestamp = $sa[9] // 0; # mtime
78 my $size = $sa[7] // 0; # size
79
80 # prefer timestamp from filename
81 if ($filename =~ m/.*_([0-9A-F]+)\.tgz/) {
82 $timestamp = hex($1);
83 }
84
85 push @$res, {
86 filename => $filename,
87 size => $size,
88 timestamp => $timestamp,
89 };
90 });
91
92 return $res;
93 }});
94
95 __PACKAGE__->register_method ({
96 name => 'backup',
97 path => '',
98 method => 'POST',
99 description => "Backup the system configuration.",
100 permissions => { check => [ 'admin' ] },
101 proxyto => 'node',
102 protected => 1,
103 parameters => {
104 additionalProperties => 0,
105 properties => {
106 node => get_standard_option('pve-node'),
107 statistic => {
108 description => "Backup statistic databases.",
109 type => 'boolean',
110 optional => 1,
111 default => 1,
112 },
113 },
114 },
115 returns => { type => "string" },
116 code => sub {
117 my ($param) = @_;
118
119 my $rpcenv = PMG::RESTEnvironment->get();
120 my $authuser = $rpcenv->get_user();
121
122 $param->{statistic} //= 1;
123
124 my $ctime = time();
125 my (undef, undef, undef, $mday, $mon, $year) = localtime($ctime);
126 my $bkfile = sprintf("pmg-backup_%04d_%02d_%02d_%08X.tgz", $year + 1900, $mon + 1, $mday, $ctime);
127 my $filename = "${backup_dir}/$bkfile";
128
129 my $worker = sub {
130 my $upid = shift;
131
132 print "starting backup to: $filename\n";
133
134 PMG::Backup::pmg_backup_pack($filename, $param->{statistic});
135
136 print "backup finished\n";
137
138 return;
139 };
140
141 return $rpcenv->fork_worker('backup', undef, $authuser, $worker);
142 }});
143
144 __PACKAGE__->register_method ({
145 name => 'download',
146 path => '{filename}',
147 method => 'GET',
148 description => "Download a backup file.",
149 permissions => { check => [ 'admin' ] },
150 proxyto => 'node',
151 protected => 1,
152 parameters => {
153 additionalProperties => 0,
154 properties => {
155 node => get_standard_option('pve-node'),
156 filename => $backup_filename_property,
157 },
158 },
159 download => 1,
160 returns => { type => "string" },
161 code => sub {
162 my ($param) = @_;
163
164 my $filename = "${backup_dir}/$param->{filename}";
165
166 return $filename;
167 }});
168
169 __PACKAGE__->register_method ({
170 name => 'delete',
171 path => '{filename}',
172 method => 'DELETE',
173 description => "Delete a backup file.",
174 permissions => { check => [ 'admin' ] },
175 proxyto => 'node',
176 protected => 1,
177 parameters => {
178 additionalProperties => 0,
179 properties => {
180 node => get_standard_option('pve-node'),
181 filename => $backup_filename_property,
182 },
183 },
184 returns => { type => "null" },
185 code => sub {
186 my ($param) = @_;
187
188 my $filename = "${backup_dir}/$param->{filename}";
189 unlink($filename) || die "delete backup file '$filename' failed - $!\n";
190
191 return undef;
192 }});
193
194 __PACKAGE__->register_method ({
195 name => 'restore',
196 path => '{filename}',
197 method => 'POST',
198 description => "Restore the system configuration.",
199 permissions => { check => [ 'admin' ] },
200 proxyto => 'node',
201 protected => 1,
202 parameters => {
203 additionalProperties => 0,
204 properties => {
205 PMG::Backup::get_restore_options(),
206 node => get_standard_option('pve-node'),
207 filename => $backup_filename_property,
208 },
209 },
210 returns => { type => "string" },
211 code => sub {
212 my ($param) = @_;
213
214 my $rpcenv = PMG::RESTEnvironment->get();
215 my $authuser = $rpcenv->get_user();
216
217 my $filename = "${backup_dir}/$param->{filename}";
218 -f $filename || die "backup file '$filename' does not exist - $!\n";
219
220 $param->{database} //= 1;
221
222 die "nothing selected - please select what you want to restore (config or database?)\n"
223 if !($param->{database} || $param->{config});
224
225 my $worker = sub {
226 my $upid = shift;
227
228 print "starting restore: $filename\n";
229
230 PMG::Backup::pmg_restore($filename, $param->{database},
231 $param->{config}, $param->{statistic});
232 print "restore finished\n";
233
234 return;
235 };
236
237 return $rpcenv->fork_worker('restore', undef, $authuser, $worker);
238 }});
239
240 1;