]> git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/Backup.pm
bump version to 8.1.4
[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 notify => {
114 description => "Specify when to notify via e-mail",
115 type => 'string',
116 enum => [ 'always', 'error', 'never' ],
117 optional => 1,
118 default => 'never',
119 },
120 },
121 },
122 returns => { type => "string" },
123 code => sub {
124 my ($param) = @_;
125
126 my $rpcenv = PMG::RESTEnvironment->get();
127 my $authuser = $rpcenv->get_user();
128
129 $param->{statistic} //= 1;
130
131 my $ctime = time();
132 my (undef, undef, undef, $mday, $mon, $year) = localtime($ctime);
133 my $bkfile = sprintf("pmg-backup_%04d_%02d_%02d_%08X.tgz", $year + 1900, $mon + 1, $mday, $ctime);
134 my $filename = "${backup_dir}/$bkfile";
135
136 my $worker = sub {
137 my $upid = shift;
138
139 my $full_log = "";
140 my $log = sub { print "$_[0]\n"; $full_log .= "$_[0]\n"; };
141
142 $log->("starting backup to: $filename");
143
144 eval { PMG::Backup::pmg_backup_pack($filename, $param->{statistic}) };
145 if (my $err = $@) {
146 $log->($err);
147 PMG::Backup::send_backup_notification($param->{notify}, undef, $full_log, $err);
148 die "backup failed: $err\n";
149 }
150
151 $log->("backup finished");
152
153 PMG::Backup::send_backup_notification($param->{notify}, undef, $full_log, undef);
154
155 return;
156 };
157
158 return $rpcenv->fork_worker('backup', undef, $authuser, $worker);
159 }});
160
161 __PACKAGE__->register_method ({
162 name => 'download',
163 path => '{filename}',
164 method => 'GET',
165 description => "Download a backup file.",
166 permissions => { check => [ 'admin' ] },
167 proxyto => 'node',
168 protected => 1,
169 parameters => {
170 additionalProperties => 0,
171 properties => {
172 node => get_standard_option('pve-node'),
173 filename => $backup_filename_property,
174 },
175 },
176 download => 1,
177 returns => { type => "string" },
178 code => sub {
179 my ($param) = @_;
180
181 my $filename = "${backup_dir}/$param->{filename}";
182
183 return $filename;
184 }});
185
186 __PACKAGE__->register_method ({
187 name => 'delete',
188 path => '{filename}',
189 method => 'DELETE',
190 description => "Delete a backup file.",
191 permissions => { check => [ 'admin' ] },
192 proxyto => 'node',
193 protected => 1,
194 parameters => {
195 additionalProperties => 0,
196 properties => {
197 node => get_standard_option('pve-node'),
198 filename => $backup_filename_property,
199 },
200 },
201 returns => { type => "null" },
202 code => sub {
203 my ($param) = @_;
204
205 my $filename = "${backup_dir}/$param->{filename}";
206 unlink($filename) || die "delete backup file '$filename' failed - $!\n";
207
208 return undef;
209 }});
210
211 __PACKAGE__->register_method ({
212 name => 'restore',
213 path => '{filename}',
214 method => 'POST',
215 description => "Restore the system configuration.",
216 permissions => { check => [ 'admin' ] },
217 proxyto => 'node',
218 protected => 1,
219 parameters => {
220 additionalProperties => 0,
221 properties => {
222 PMG::Backup::get_restore_options(),
223 node => get_standard_option('pve-node'),
224 filename => $backup_filename_property,
225 },
226 },
227 returns => { type => "string" },
228 code => sub {
229 my ($param) = @_;
230
231 my $rpcenv = PMG::RESTEnvironment->get();
232 my $authuser = $rpcenv->get_user();
233
234 my $filename = "${backup_dir}/$param->{filename}";
235 -f $filename || die "backup file '$filename' does not exist - $!\n";
236
237 $param->{database} //= 1;
238
239 die "nothing selected - please select what you want to restore (config or database?)\n"
240 if !($param->{database} || $param->{config});
241
242 return $rpcenv->fork_worker('restore', undef, $authuser, sub {
243 print "starting restore: $filename\n";
244 PMG::Backup::pmg_restore($filename, $param->{database}, $param->{config}, $param->{statistic});
245 print "restore finished\n";
246 return;
247 });
248 }});
249
250 1;