]> git.proxmox.com Git - pve-container.git/blob - src/PVE/API2/LXC/Status.pm
2989e9b86efa26708b7d5b09dba0ce17be5fadb7
[pve-container.git] / src / PVE / API2 / LXC / Status.pm
1 package PVE::API2::LXC::Status;
2
3 use strict;
4 use warnings;
5
6 use PVE::SafeSyslog;
7 use PVE::Tools qw(extract_param run_command);
8 use PVE::Exception qw(raise raise_param_exc);
9 use PVE::INotify;
10 use PVE::Cluster qw(cfs_read_file);
11 use PVE::AccessControl;
12 use PVE::Firewall;
13 use PVE::Storage;
14 use PVE::RESTHandler;
15 use PVE::RPCEnvironment;
16 use PVE::LXC;
17 use PVE::LXC::Create;
18 use PVE::JSONSchema qw(get_standard_option);
19 use base qw(PVE::RESTHandler);
20
21 BEGIN {
22 if (!$ENV{PVE_GENERATING_DOCS}) {
23 require PVE::HA::Env::PVE2;
24 import PVE::HA::Env::PVE2;
25 require PVE::HA::Config;
26 import PVE::HA::Config;
27 }
28 }
29
30 __PACKAGE__->register_method({
31 name => 'vmcmdidx',
32 path => '',
33 method => 'GET',
34 proxyto => 'node',
35 description => "Directory index",
36 permissions => {
37 user => 'all',
38 },
39 parameters => {
40 additionalProperties => 0,
41 properties => {
42 node => get_standard_option('pve-node'),
43 vmid => get_standard_option('pve-vmid'),
44 },
45 },
46 returns => {
47 type => 'array',
48 items => {
49 type => "object",
50 properties => {
51 subdir => { type => 'string' },
52 },
53 },
54 links => [ { rel => 'child', href => "{subdir}" } ],
55 },
56 code => sub {
57 my ($param) = @_;
58
59 # test if VM exists
60 my $conf = PVE::LXC::Config->load_config($param->{vmid});
61
62 my $res = [
63 { subdir => 'current' },
64 { subdir => 'start' },
65 { subdir => 'stop' },
66 { subdir => 'shutdown' },
67 { subdir => 'migrate' },
68 ];
69
70 return $res;
71 }});
72
73 __PACKAGE__->register_method({
74 name => 'vm_status',
75 path => 'current',
76 method => 'GET',
77 proxyto => 'node',
78 protected => 1, # openvz /proc entries are only readable by root
79 description => "Get virtual machine status.",
80 permissions => {
81 check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
82 },
83 parameters => {
84 additionalProperties => 0,
85 properties => {
86 node => get_standard_option('pve-node'),
87 vmid => get_standard_option('pve-vmid'),
88 },
89 },
90 returns => { type => 'object' },
91 code => sub {
92 my ($param) = @_;
93
94 # test if VM exists
95 my $conf = PVE::LXC::Config->load_config($param->{vmid});
96
97 my $vmstatus = PVE::LXC::vmstatus($param->{vmid});
98 my $status = $vmstatus->{$param->{vmid}};
99
100 $status->{ha} = PVE::HA::Config::get_service_status("ct:$param->{vmid}");
101
102 return $status;
103 }});
104
105 __PACKAGE__->register_method({
106 name => 'vm_start',
107 path => 'start',
108 method => 'POST',
109 protected => 1,
110 proxyto => 'node',
111 description => "Start the container.",
112 permissions => {
113 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
114 },
115 parameters => {
116 additionalProperties => 0,
117 properties => {
118 node => get_standard_option('pve-node'),
119 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
120 skiplock => get_standard_option('skiplock'),
121 },
122 },
123 returns => {
124 type => 'string',
125 },
126 code => sub {
127 my ($param) = @_;
128
129 my $rpcenv = PVE::RPCEnvironment::get();
130
131 my $authuser = $rpcenv->get_user();
132
133 my $node = extract_param($param, 'node');
134
135 my $vmid = extract_param($param, 'vmid');
136
137 my $skiplock = extract_param($param, 'skiplock');
138 raise_param_exc({ skiplock => "Only root may use this option." })
139 if $skiplock && $authuser ne 'root@pam';
140
141 die "CT $vmid already running\n" if PVE::LXC::check_running($vmid);
142
143 PVE::Cluster::check_cfs_quorum();
144
145 if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') {
146
147 my $hacmd = sub {
148 my $upid = shift;
149
150 my $service = "ct:$vmid";
151
152 my $cmd = ['ha-manager', 'set', $service, '--state', 'started'];
153
154 print "Requesting HA start for CT $vmid\n";
155
156 PVE::Tools::run_command($cmd);
157
158 return;
159 };
160
161 return $rpcenv->fork_worker('hastart', $vmid, $authuser, $hacmd);
162
163 } else {
164
165 my $lockcmd = sub {
166 my $realcmd = sub {
167 my $upid = shift;
168
169 syslog('info', "starting CT $vmid: $upid\n");
170
171 my $conf = PVE::LXC::Config->load_config($vmid);
172
173 die "you can't start a CT if it's a template\n"
174 if PVE::LXC::Config->is_template($conf);
175
176 if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) {
177 PVE::LXC::Config->check_lock($conf);
178 }
179
180 if ($conf->{unprivileged}) {
181 PVE::LXC::Config->foreach_mountpoint($conf, sub {
182 my ($ms, $mountpoint) = @_;
183 die "Quotas are not supported by unprivileged containers.\n" if $mountpoint->{quota};
184 });
185
186 }
187
188 my $storage_cfg = cfs_read_file("storage.cfg");
189
190 PVE::LXC::update_lxc_config($vmid, $conf);
191
192 local $ENV{PVE_SKIPLOCK}=1 if $skiplock;
193
194 my $cmd = ['systemctl', 'start', "pve-container\@$vmid"];
195
196 run_command($cmd);
197
198 return;
199 };
200
201 return $rpcenv->fork_worker('vzstart', $vmid, $authuser, $realcmd);
202 };
203
204 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
205 }
206 }});
207
208 __PACKAGE__->register_method({
209 name => 'vm_stop',
210 path => 'stop',
211 method => 'POST',
212 protected => 1,
213 proxyto => 'node',
214 description => "Stop the container. This will abruptly stop all processes running in the container.",
215 permissions => {
216 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
217 },
218 parameters => {
219 additionalProperties => 0,
220 properties => {
221 node => get_standard_option('pve-node'),
222 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
223 skiplock => get_standard_option('skiplock'),
224 },
225 },
226 returns => {
227 type => 'string',
228 },
229 code => sub {
230 my ($param) = @_;
231
232 my $rpcenv = PVE::RPCEnvironment::get();
233
234 my $authuser = $rpcenv->get_user();
235
236 my $node = extract_param($param, 'node');
237
238 my $vmid = extract_param($param, 'vmid');
239
240 my $skiplock = extract_param($param, 'skiplock');
241 raise_param_exc({ skiplock => "Only root may use this option." })
242 if $skiplock && $authuser ne 'root@pam';
243
244 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
245
246 if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') {
247
248 my $hacmd = sub {
249 my $upid = shift;
250
251 my $service = "ct:$vmid";
252
253 my $cmd = ['ha-manager', 'set', $service, '--state', 'stopped'];
254
255 print "Requesting HA stop for CT $vmid\n";
256
257 PVE::Tools::run_command($cmd);
258
259 return;
260 };
261
262 return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd);
263
264 } else {
265
266 my $lockcmd = sub {
267 my $realcmd = sub {
268 my $upid = shift;
269
270 syslog('info', "stopping CT $vmid: $upid\n");
271
272 my $conf = PVE::LXC::Config->load_config($vmid);
273
274 if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) {
275 PVE::LXC::Config->check_lock($conf);
276 }
277
278 my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
279
280 run_command($cmd);
281
282 return;
283 };
284
285 return $rpcenv->fork_worker('vzstop', $vmid, $authuser, $realcmd);
286 };
287
288 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
289 }
290 }});
291
292 __PACKAGE__->register_method({
293 name => 'vm_shutdown',
294 path => 'shutdown',
295 method => 'POST',
296 protected => 1,
297 proxyto => 'node',
298 description => "Shutdown the container. This will trigger a clean shutdown " .
299 "of the container, see lxc-stop(1) for details.",
300 permissions => {
301 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
302 },
303 parameters => {
304 additionalProperties => 0,
305 properties => {
306 node => get_standard_option('pve-node'),
307 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
308 timeout => {
309 description => "Wait maximal timeout seconds.",
310 type => 'integer',
311 minimum => 0,
312 optional => 1,
313 default => 60,
314 },
315 forceStop => {
316 description => "Make sure the Container stops.",
317 type => 'boolean',
318 optional => 1,
319 default => 0,
320 }
321 },
322 },
323 returns => {
324 type => 'string',
325 },
326 code => sub {
327 my ($param) = @_;
328
329 my $rpcenv = PVE::RPCEnvironment::get();
330
331 my $authuser = $rpcenv->get_user();
332
333 my $node = extract_param($param, 'node');
334
335 my $vmid = extract_param($param, 'vmid');
336
337 my $timeout = extract_param($param, 'timeout');
338
339 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
340
341 if (PVE::HA::Config::vm_is_ha_managed($vmid) &&
342 $rpcenv->{type} ne 'ha') {
343
344 my $hacmd = sub {
345 my $upid = shift;
346
347 my $service = "ct:$vmid";
348
349 my $cmd = ['ha-manager', 'set', $service, '--state', 'stopped'];
350
351 print "Requesting HA stop for CT $vmid\n";
352
353 PVE::Tools::run_command($cmd);
354
355 return;
356 };
357
358 return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd);
359 }
360
361 my $lockcmd = sub {
362 my $realcmd = sub {
363 my $upid = shift;
364
365 syslog('info', "shutdown CT $vmid: $upid\n");
366
367 my $cmd = ['lxc-stop', '-n', $vmid];
368
369 $timeout = 60 if !defined($timeout);
370
371 my $conf = PVE::LXC::Config->load_config($vmid);
372
373 PVE::LXC::Config->check_lock($conf);
374
375 my $storage_cfg = PVE::Storage::config();
376
377 push @$cmd, '--timeout', $timeout;
378
379 eval { run_command($cmd, timeout => $timeout+5); };
380 my $err = $@;
381 if ($err && $param->{forceStop}) {
382 $err = undef;
383 warn "shutdown failed - forcing stop now\n";
384
385 my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
386 run_command($cmd);
387 }
388
389 # make sure container is stopped
390 $cmd = ['lxc-wait', '-n', $vmid, '-t', 5, '-s', 'STOPPED'];
391 run_command($cmd);
392 $err = $@;
393
394 die $err if $err;
395
396 return;
397 };
398
399 return $rpcenv->fork_worker('vzshutdown', $vmid, $authuser, $realcmd);
400 };
401
402 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
403 }});
404
405 __PACKAGE__->register_method({
406 name => 'vm_suspend',
407 path => 'suspend',
408 method => 'POST',
409 protected => 1,
410 proxyto => 'node',
411 description => "Suspend the container.",
412 permissions => {
413 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
414 },
415 parameters => {
416 additionalProperties => 0,
417 properties => {
418 node => get_standard_option('pve-node'),
419 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
420 },
421 },
422 returns => {
423 type => 'string',
424 },
425 code => sub {
426 my ($param) = @_;
427
428 my $rpcenv = PVE::RPCEnvironment::get();
429
430 my $authuser = $rpcenv->get_user();
431
432 my $node = extract_param($param, 'node');
433
434 my $vmid = extract_param($param, 'vmid');
435
436 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
437
438 my $lockcmd = sub {
439 my $realcmd = sub {
440 my $upid = shift;
441
442 syslog('info', "suspend CT $vmid: $upid\n");
443
444 my $conf = PVE::LXC::Config->load_config($vmid);
445
446 PVE::LXC::Config->check_lock($conf);
447
448 my $cmd = ['lxc-checkpoint', '-n', $vmid, '-s', '-D', '/var/lib/vz/dump'];
449
450 run_command($cmd);
451
452 return;
453 };
454
455 return $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd);
456 };
457
458 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
459 }});
460
461 __PACKAGE__->register_method({
462 name => 'vm_resume',
463 path => 'resume',
464 method => 'POST',
465 protected => 1,
466 proxyto => 'node',
467 description => "Resume the container.",
468 permissions => {
469 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
470 },
471 parameters => {
472 additionalProperties => 0,
473 properties => {
474 node => get_standard_option('pve-node'),
475 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
476 },
477 },
478 returns => {
479 type => 'string',
480 },
481 code => sub {
482 my ($param) = @_;
483
484 my $rpcenv = PVE::RPCEnvironment::get();
485
486 my $authuser = $rpcenv->get_user();
487
488 my $node = extract_param($param, 'node');
489
490 my $vmid = extract_param($param, 'vmid');
491
492 die "CT $vmid already running\n" if PVE::LXC::check_running($vmid);
493
494 my $realcmd = sub {
495 my $upid = shift;
496
497 syslog('info', "resume CT $vmid: $upid\n");
498
499 my $cmd = ['lxc-checkpoint', '-n', $vmid, '-r', '--foreground',
500 '-D', '/var/lib/vz/dump'];
501
502 run_command($cmd);
503
504 return;
505 };
506
507 my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd);
508
509 return $upid;
510 }});
511
512 1;