]> git.proxmox.com Git - pve-container.git/blame - src/PVE/API2/LXC/Snapshot.pm
Refactor lock_container into lock_config_[xx]
[pve-container.git] / src / PVE / API2 / LXC / Snapshot.pm
CommitLineData
52389a07
DM
1package PVE::API2::LXC::Snapshot;
2
3use strict;
4use warnings;
5
6use PVE::SafeSyslog;
7use PVE::Tools qw(extract_param run_command);
8use PVE::Exception qw(raise raise_param_exc);
9use PVE::INotify;
10use PVE::Cluster qw(cfs_read_file);
11use PVE::AccessControl;
12use PVE::Firewall;
13use PVE::Storage;
14use PVE::RESTHandler;
15use PVE::RPCEnvironment;
16use PVE::LXC;
17use PVE::LXC::Create;
52389a07
DM
18use PVE::JSONSchema qw(get_standard_option);
19use base qw(PVE::RESTHandler);
20
21__PACKAGE__->register_method({
56ec6fef 22 name => 'list',
52389a07
DM
23 path => '',
24 method => 'GET',
25 description => "List all snapshots.",
26 permissions => {
27 check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
28 },
29 proxyto => 'node',
30 protected => 1, # lxc pid files are only readable by root
31 parameters => {
32 additionalProperties => 0,
33 properties => {
68e8f3c5 34 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
52389a07
DM
35 node => get_standard_option('pve-node'),
36 },
37 },
38 returns => {
39 type => 'array',
40 items => {
41 type => "object",
42 properties => {},
43 },
44 links => [ { rel => 'child', href => "{name}" } ],
45 },
46 code => sub {
47 my ($param) = @_;
48
49 my $vmid = $param->{vmid};
50
51 my $conf = PVE::LXC::load_config($vmid);
52 my $snaphash = $conf->{snapshots} || {};
53
54 my $res = [];
55
56 foreach my $name (keys %$snaphash) {
57 my $d = $snaphash->{$name};
58 my $item = {
59 name => $name,
60 snaptime => $d->{snaptime} || 0,
61 description => $d->{description} || '',
62 };
63 $item->{parent} = $d->{parent} if defined($d->{parent});
64 $item->{snapstate} = $d->{snapstate} if $d->{snapstate};
65 push @$res, $item;
66 }
67
68 my $running = PVE::LXC::check_running($vmid) ? 1 : 0;
69 my $current = { name => 'current', digest => $conf->{digest}, running => $running };
70 $current->{parent} = $conf->{parent} if defined($conf->{parent});
71
72 push @$res, $current;
73
74 return $res;
75 }});
76
77use Data::Dumper; # fixme: remove
78__PACKAGE__->register_method({
79 name => 'snapshot',
80 path => '',
81 method => 'POST',
82 protected => 1,
83 proxyto => 'node',
84 description => "Snapshot a container.",
85 permissions => {
86 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
87 },
88 parameters => {
89 additionalProperties => 0,
90 properties => {
91 node => get_standard_option('pve-node'),
68e8f3c5 92 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
52389a07
DM
93 snapname => get_standard_option('pve-lxc-snapshot-name'),
94# vmstate => {
95# optional => 1,
96# type => 'boolean',
97# description => "Save the vmstate",
98# },
99 description => {
100 optional => 1,
101 type => 'string',
102 description => "A textual description or comment.",
103 },
104 },
105 },
106 returns => {
107 type => 'string',
108 description => "the task ID.",
109 },
110 code => sub {
111 my ($param) = @_;
112
113 my $rpcenv = PVE::RPCEnvironment::get();
114
115 my $authuser = $rpcenv->get_user();
116
117 my $node = extract_param($param, 'node');
118
119 my $vmid = extract_param($param, 'vmid');
120
121 my $snapname = extract_param($param, 'snapname');
122
123 die "unable to use snapshot name 'current' (reserved name)\n"
124 if $snapname eq 'current';
125
325d1c76
DC
126 die "unable to use snapshot name 'vzdump' (reserved name)\n"
127 if $snapname eq 'vzdump';
128
52389a07
DM
129 my $realcmd = sub {
130 PVE::Cluster::log_msg('info', $authuser, "snapshot container $vmid: $snapname");
131 PVE::LXC::snapshot_create($vmid, $snapname, $param->{description});
132 };
133
134 return $rpcenv->fork_worker('pctsnapshot', $vmid, $authuser, $realcmd);
135 }});
136
137__PACKAGE__->register_method({
138 name => 'delsnapshot',
139 path => '{snapname}',
140 method => 'DELETE',
141 protected => 1,
142 proxyto => 'node',
143 description => "Delete a LXC snapshot.",
144 permissions => {
145 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
146 },
147 parameters => {
148 additionalProperties => 0,
149 properties => {
150 node => get_standard_option('pve-node'),
151 vmid => get_standard_option('pve-vmid'),
152 snapname => get_standard_option('pve-lxc-snapshot-name'),
153 force => {
154 optional => 1,
155 type => 'boolean',
156 description => "For removal from config file, even if removing disk snapshots fails.",
157 },
158 },
159 },
160 returns => {
161 type => 'string',
162 description => "the task ID.",
163 },
164 code => sub {
165 my ($param) = @_;
166
167 my $rpcenv = PVE::RPCEnvironment::get();
168
169 my $authuser = $rpcenv->get_user();
170
171 my $node = extract_param($param, 'node');
172
173 my $vmid = extract_param($param, 'vmid');
174
175 my $snapname = extract_param($param, 'snapname');
176
177 my $realcmd = sub {
178 PVE::Cluster::log_msg('info', $authuser, "delete snapshot VM $vmid: $snapname");
179 PVE::LXC::snapshot_delete($vmid, $snapname, $param->{force});
180 };
181
182 return $rpcenv->fork_worker('lxcdelsnapshot', $vmid, $authuser, $realcmd);
183 }});
184
185__PACKAGE__->register_method({
186 name => 'snapshot_cmd_idx',
187 path => '{snapname}',
188 description => '',
189 method => 'GET',
190 permissions => {
191 user => 'all',
192 },
193 parameters => {
194 additionalProperties => 0,
195 properties => {
196 vmid => get_standard_option('pve-vmid'),
197 node => get_standard_option('pve-node'),
198 snapname => get_standard_option('pve-lxc-snapshot-name'),
199 },
200 },
201 returns => {
202 type => 'array',
203 items => {
204 type => "object",
205 properties => {},
206 },
207 links => [ { rel => 'child', href => "{cmd}" } ],
208 },
209 code => sub {
210 my ($param) = @_;
211
212 my $res = [];
213
214 push @$res, { cmd => 'rollback' };
215 push @$res, { cmd => 'config' };
216
217 return $res;
218 }});
219
220__PACKAGE__->register_method({
221 name => 'rollback',
222 path => '{snapname}/rollback',
223 method => 'POST',
224 protected => 1,
225 proxyto => 'node',
226 description => "Rollback LXC state to specified snapshot.",
227 permissions => {
228 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
229 },
230 parameters => {
231 additionalProperties => 0,
232 properties => {
233 node => get_standard_option('pve-node'),
234 vmid => get_standard_option('pve-vmid'),
235 snapname => get_standard_option('pve-lxc-snapshot-name'),
236 },
237 },
238 returns => {
239 type => 'string',
240 description => "the task ID.",
241 },
242 code => sub {
243 my ($param) = @_;
244
245 my $rpcenv = PVE::RPCEnvironment::get();
246
247 my $authuser = $rpcenv->get_user();
248
249 my $node = extract_param($param, 'node');
250
251 my $vmid = extract_param($param, 'vmid');
252
253 my $snapname = extract_param($param, 'snapname');
254
255 my $realcmd = sub {
256 PVE::Cluster::log_msg('info', $authuser, "rollback snapshot LXC $vmid: $snapname");
257 PVE::LXC::snapshot_rollback($vmid, $snapname);
258 };
259
260 return $rpcenv->fork_worker('lxcrollback', $vmid, $authuser, $realcmd);
261 }});
262
263__PACKAGE__->register_method({
264 name => 'update_snapshot_config',
265 path => '{snapname}/config',
266 method => 'PUT',
267 protected => 1,
268 proxyto => 'node',
269 description => "Update snapshot metadata.",
270 permissions => {
271 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
272 },
273 parameters => {
274 additionalProperties => 0,
275 properties => {
276 node => get_standard_option('pve-node'),
277 vmid => get_standard_option('pve-vmid'),
278 snapname => get_standard_option('pve-lxc-snapshot-name'),
279 description => {
280 optional => 1,
281 type => 'string',
282 description => "A textual description or comment.",
283 },
284 },
285 },
286 returns => { type => 'null' },
287 code => sub {
288 my ($param) = @_;
289
290 my $rpcenv = PVE::RPCEnvironment::get();
291
292 my $authuser = $rpcenv->get_user();
293
294 my $vmid = extract_param($param, 'vmid');
295
296 my $snapname = extract_param($param, 'snapname');
297
298 return undef if !defined($param->{description});
299
300 my $updatefn = sub {
301
302 my $conf = PVE::LXC::load_config($vmid);
303 PVE::LXC::check_lock($conf);
304
305 my $snap = $conf->{snapshots}->{$snapname};
306
307 die "snapshot '$snapname' does not exist\n" if !defined($snap);
308
309 $snap->{description} = $param->{description} if defined($param->{description});
310
311 PVE::LXC::write_config($vmid, $conf, 1);
312 };
313
3cc56749 314 PVE::LXC::lock_config($vmid, $updatefn);
52389a07
DM
315
316 return undef;
317 }});
318
319__PACKAGE__->register_method({
320 name => 'get_snapshot_config',
321 path => '{snapname}/config',
322 method => 'GET',
323 proxyto => 'node',
324 description => "Get snapshot configuration",
325 permissions => {
326 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
327 },
328 parameters => {
329 additionalProperties => 0,
330 properties => {
331 node => get_standard_option('pve-node'),
332 vmid => get_standard_option('pve-vmid'),
333 snapname => get_standard_option('pve-lxc-snapshot-name'),
334 },
335 },
336 returns => { type => "object" },
337 code => sub {
338 my ($param) = @_;
339
340 my $rpcenv = PVE::RPCEnvironment::get();
341
342 my $authuser = $rpcenv->get_user();
343
344 my $vmid = extract_param($param, 'vmid');
345
346 my $snapname = extract_param($param, 'snapname');
347
348 my $conf = PVE::LXC::load_config($vmid);
349
350 my $snap = $conf->{snapshots}->{$snapname};
351
352 die "snapshot '$snapname' does not exist\n" if !defined($snap);
353
354 delete $snap->{lxc};
355
356 return $snap;
357 }});
358
3591;