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