]> git.proxmox.com Git - pve-container.git/blame - src/PVE/API2/LXC/Snapshot.pm
depreacate pve-lxc-snapshot-name in favor of identical pve-snapshot-name
[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",
f8e1ccc2
DM
42 properties => {
43 name => {
44 description => "Snapshot identifier. Value 'current' identifies the current VM.",
45 type => 'string',
46 },
47 description => {
48 description => "Snapshot description.",
49 type => 'string',
50 },
51 snaptime => {
52 description => "Snapshot creation time",
53 type => 'integer',
54 renderer => 'timestamp',
55 optional => 1,
56 },
57 parent => {
58 description => "Parent snapshot identifier.",
59 type => 'string',
60 optional => 1,
61 },
62 },
52389a07
DM
63 },
64 links => [ { rel => 'child', href => "{name}" } ],
65 },
66 code => sub {
67 my ($param) = @_;
68
69 my $vmid = $param->{vmid};
70
67afe46e 71 my $conf = PVE::LXC::Config->load_config($vmid);
52389a07
DM
72 my $snaphash = $conf->{snapshots} || {};
73
74 my $res = [];
75
76 foreach my $name (keys %$snaphash) {
77 my $d = $snaphash->{$name};
78 my $item = {
79 name => $name,
80 snaptime => $d->{snaptime} || 0,
81 description => $d->{description} || '',
82 };
83 $item->{parent} = $d->{parent} if defined($d->{parent});
84 $item->{snapstate} = $d->{snapstate} if $d->{snapstate};
85 push @$res, $item;
86 }
87
88 my $running = PVE::LXC::check_running($vmid) ? 1 : 0;
f8e1ccc2
DM
89 my $current = {
90 name => 'current',
91 digest => $conf->{digest},
92 running => $running,
93 description => "You are here!",
94 };
52389a07
DM
95 $current->{parent} = $conf->{parent} if defined($conf->{parent});
96
97 push @$res, $current;
98
99 return $res;
100 }});
101
102use Data::Dumper; # fixme: remove
103__PACKAGE__->register_method({
104 name => 'snapshot',
105 path => '',
106 method => 'POST',
107 protected => 1,
108 proxyto => 'node',
109 description => "Snapshot a container.",
110 permissions => {
111 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
112 },
113 parameters => {
114 additionalProperties => 0,
115 properties => {
116 node => get_standard_option('pve-node'),
68e8f3c5 117 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
5ec3949c 118 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
119# vmstate => {
120# optional => 1,
121# type => 'boolean',
122# description => "Save the vmstate",
123# },
124 description => {
125 optional => 1,
126 type => 'string',
127 description => "A textual description or comment.",
128 },
129 },
130 },
131 returns => {
132 type => 'string',
133 description => "the task ID.",
134 },
135 code => sub {
136 my ($param) = @_;
137
138 my $rpcenv = PVE::RPCEnvironment::get();
139
140 my $authuser = $rpcenv->get_user();
141
142 my $node = extract_param($param, 'node');
143
144 my $vmid = extract_param($param, 'vmid');
145
146 my $snapname = extract_param($param, 'snapname');
147
148 die "unable to use snapshot name 'current' (reserved name)\n"
149 if $snapname eq 'current';
150
325d1c76
DC
151 die "unable to use snapshot name 'vzdump' (reserved name)\n"
152 if $snapname eq 'vzdump';
153
52389a07
DM
154 my $realcmd = sub {
155 PVE::Cluster::log_msg('info', $authuser, "snapshot container $vmid: $snapname");
4518000b 156 PVE::LXC::Config->snapshot_create($vmid, $snapname, 0, $param->{description});
52389a07
DM
157 };
158
e3aed0b8 159 return $rpcenv->fork_worker('vzsnapshot', $vmid, $authuser, $realcmd);
52389a07
DM
160 }});
161
162__PACKAGE__->register_method({
163 name => 'delsnapshot',
164 path => '{snapname}',
165 method => 'DELETE',
166 protected => 1,
167 proxyto => 'node',
168 description => "Delete a LXC snapshot.",
169 permissions => {
170 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
171 },
172 parameters => {
173 additionalProperties => 0,
174 properties => {
175 node => get_standard_option('pve-node'),
176 vmid => get_standard_option('pve-vmid'),
5ec3949c 177 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
178 force => {
179 optional => 1,
180 type => 'boolean',
181 description => "For removal from config file, even if removing disk snapshots fails.",
182 },
183 },
184 },
185 returns => {
186 type => 'string',
187 description => "the task ID.",
188 },
189 code => sub {
190 my ($param) = @_;
191
192 my $rpcenv = PVE::RPCEnvironment::get();
193
194 my $authuser = $rpcenv->get_user();
195
196 my $node = extract_param($param, 'node');
197
198 my $vmid = extract_param($param, 'vmid');
199
200 my $snapname = extract_param($param, 'snapname');
201
202 my $realcmd = sub {
203 PVE::Cluster::log_msg('info', $authuser, "delete snapshot VM $vmid: $snapname");
4518000b 204 PVE::LXC::Config->snapshot_delete($vmid, $snapname, $param->{force});
52389a07
DM
205 };
206
e3aed0b8 207 return $rpcenv->fork_worker('vzdelsnapshot', $vmid, $authuser, $realcmd);
52389a07
DM
208 }});
209
210__PACKAGE__->register_method({
211 name => 'snapshot_cmd_idx',
212 path => '{snapname}',
213 description => '',
214 method => 'GET',
215 permissions => {
216 user => 'all',
217 },
218 parameters => {
219 additionalProperties => 0,
220 properties => {
221 vmid => get_standard_option('pve-vmid'),
222 node => get_standard_option('pve-node'),
5ec3949c 223 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
224 },
225 },
226 returns => {
227 type => 'array',
228 items => {
229 type => "object",
230 properties => {},
231 },
232 links => [ { rel => 'child', href => "{cmd}" } ],
233 },
234 code => sub {
235 my ($param) = @_;
236
237 my $res = [];
238
239 push @$res, { cmd => 'rollback' };
240 push @$res, { cmd => 'config' };
241
242 return $res;
243 }});
244
245__PACKAGE__->register_method({
246 name => 'rollback',
247 path => '{snapname}/rollback',
248 method => 'POST',
249 protected => 1,
250 proxyto => 'node',
251 description => "Rollback LXC state to specified snapshot.",
252 permissions => {
f02fe600 253 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback' ], any => 1],
52389a07
DM
254 },
255 parameters => {
256 additionalProperties => 0,
257 properties => {
258 node => get_standard_option('pve-node'),
259 vmid => get_standard_option('pve-vmid'),
5ec3949c 260 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
261 },
262 },
263 returns => {
264 type => 'string',
265 description => "the task ID.",
266 },
267 code => sub {
268 my ($param) = @_;
269
270 my $rpcenv = PVE::RPCEnvironment::get();
271
272 my $authuser = $rpcenv->get_user();
273
274 my $node = extract_param($param, 'node');
275
276 my $vmid = extract_param($param, 'vmid');
277
278 my $snapname = extract_param($param, 'snapname');
279
280 my $realcmd = sub {
281 PVE::Cluster::log_msg('info', $authuser, "rollback snapshot LXC $vmid: $snapname");
4518000b 282 PVE::LXC::Config->snapshot_rollback($vmid, $snapname);
52389a07
DM
283 };
284
2618d993
WL
285 my $worker = sub {
286 # hold migration lock, this makes sure that nobody create replication snapshots
287 return PVE::GuestHelpers::guest_migration_lock($vmid, 10, $realcmd);
288 };
289
290 return $rpcenv->fork_worker('vzrollback', $vmid, $authuser, $worker);
52389a07
DM
291 }});
292
293__PACKAGE__->register_method({
294 name => 'update_snapshot_config',
295 path => '{snapname}/config',
296 method => 'PUT',
297 protected => 1,
298 proxyto => 'node',
299 description => "Update snapshot metadata.",
300 permissions => {
301 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]],
302 },
303 parameters => {
304 additionalProperties => 0,
305 properties => {
306 node => get_standard_option('pve-node'),
307 vmid => get_standard_option('pve-vmid'),
5ec3949c 308 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
309 description => {
310 optional => 1,
311 type => 'string',
312 description => "A textual description or comment.",
313 },
314 },
315 },
316 returns => { type => 'null' },
317 code => sub {
318 my ($param) = @_;
319
320 my $rpcenv = PVE::RPCEnvironment::get();
321
322 my $authuser = $rpcenv->get_user();
323
324 my $vmid = extract_param($param, 'vmid');
325
326 my $snapname = extract_param($param, 'snapname');
327
328 return undef if !defined($param->{description});
329
330 my $updatefn = sub {
331
67afe46e
FG
332 my $conf = PVE::LXC::Config->load_config($vmid);
333 PVE::LXC::Config->check_lock($conf);
52389a07
DM
334
335 my $snap = $conf->{snapshots}->{$snapname};
336
337 die "snapshot '$snapname' does not exist\n" if !defined($snap);
338
339 $snap->{description} = $param->{description} if defined($param->{description});
340
67afe46e 341 PVE::LXC::Config->write_config($vmid, $conf, 1);
52389a07
DM
342 };
343
67afe46e 344 PVE::LXC::Config->lock_config($vmid, $updatefn);
52389a07
DM
345
346 return undef;
347 }});
348
349__PACKAGE__->register_method({
350 name => 'get_snapshot_config',
351 path => '{snapname}/config',
352 method => 'GET',
353 proxyto => 'node',
354 description => "Get snapshot configuration",
355 permissions => {
f02fe600 356 check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback' ], any => 1],
52389a07
DM
357 },
358 parameters => {
359 additionalProperties => 0,
360 properties => {
361 node => get_standard_option('pve-node'),
362 vmid => get_standard_option('pve-vmid'),
5ec3949c 363 snapname => get_standard_option('pve-snapshot-name'),
52389a07
DM
364 },
365 },
366 returns => { type => "object" },
367 code => sub {
368 my ($param) = @_;
369
370 my $rpcenv = PVE::RPCEnvironment::get();
371
372 my $authuser = $rpcenv->get_user();
373
374 my $vmid = extract_param($param, 'vmid');
375
376 my $snapname = extract_param($param, 'snapname');
377
67afe46e 378 my $conf = PVE::LXC::Config->load_config($vmid);
52389a07
DM
379
380 my $snap = $conf->{snapshots}->{$snapname};
381
382 die "snapshot '$snapname' does not exist\n" if !defined($snap);
383
384 delete $snap->{lxc};
385
386 return $snap;
387 }});
388
3891;