]>
Commit | Line | Data |
---|---|---|
52389a07 DM |
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; | |
52389a07 | 18 | use PVE::JSONSchema qw(get_standard_option); |
17f1dc40 | 19 | |
52389a07 DM |
20 | use base qw(PVE::RESTHandler); |
21 | ||
6c2e9377 WB |
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 | } | |
52389a07 DM |
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 => { | |
17f1dc40 | 41 | additionalProperties => 0, |
52389a07 DM |
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 | |
67afe46e | 61 | my $conf = PVE::LXC::Config->load_config($param->{vmid}); |
52389a07 DM |
62 | |
63 | my $res = [ | |
64 | { subdir => 'current' }, | |
65 | { subdir => 'start' }, | |
66 | { subdir => 'stop' }, | |
67 | { subdir => 'shutdown' }, | |
f5fe1125 | 68 | { subdir => 'reboot' }, |
52389a07 | 69 | { subdir => 'migrate' }, |
17f1dc40 | 70 | ]; |
52389a07 DM |
71 | |
72 | return $res; | |
73 | }}); | |
74 | ||
75 | __PACKAGE__->register_method({ | |
76 | name => 'vm_status', | |
77 | path => 'current', | |
78 | method => 'GET', | |
79 | proxyto => 'node', | |
17f1dc40 | 80 | protected => 1, # /proc entries are only readable by root |
52389a07 DM |
81 | description => "Get virtual machine status.", |
82 | permissions => { | |
83 | check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], | |
84 | }, | |
85 | parameters => { | |
17f1dc40 | 86 | additionalProperties => 0, |
52389a07 DM |
87 | properties => { |
88 | node => get_standard_option('pve-node'), | |
89 | vmid => get_standard_option('pve-vmid'), | |
90 | }, | |
91 | }, | |
8233d33d DM |
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 | }, | |
52389a07 DM |
102 | code => sub { |
103 | my ($param) = @_; | |
104 | ||
105 | # test if VM exists | |
c83c9007 TL |
106 | my $vmid = $param->{vmid}; |
107 | my $conf = PVE::LXC::Config->load_config($vmid); | |
52389a07 | 108 | |
c83c9007 TL |
109 | my $vmstatus = PVE::LXC::vmstatus($vmid); |
110 | my $status = $vmstatus->{$vmid}; | |
52389a07 | 111 | |
c83c9007 | 112 | $status->{ha} = PVE::HA::Config::get_service_status("ct:$vmid"); |
52389a07 DM |
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 => { | |
17f1dc40 | 128 | additionalProperties => 0, |
52389a07 DM |
129 | properties => { |
130 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 131 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), |
2de0b3d4 | 132 | skiplock => get_standard_option('skiplock'), |
52389a07 DM |
133 | }, |
134 | }, | |
135 | returns => { | |
136 | type => 'string', | |
137 | }, | |
138 | code => sub { | |
139 | my ($param) = @_; | |
140 | ||
141 | my $rpcenv = PVE::RPCEnvironment::get(); | |
52389a07 DM |
142 | my $authuser = $rpcenv->get_user(); |
143 | ||
144 | my $node = extract_param($param, 'node'); | |
52389a07 DM |
145 | my $vmid = extract_param($param, 'vmid'); |
146 | ||
2de0b3d4 WB |
147 | my $skiplock = extract_param($param, 'skiplock'); |
148 | raise_param_exc({ skiplock => "Only root may use this option." }) | |
149 | if $skiplock && $authuser ne 'root@pam'; | |
150 | ||
52389a07 DM |
151 | die "CT $vmid already running\n" if PVE::LXC::check_running($vmid); |
152 | ||
1e56e83e WB |
153 | PVE::Cluster::check_cfs_quorum(); |
154 | ||
52389a07 DM |
155 | if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') { |
156 | ||
157 | my $hacmd = sub { | |
158 | my $upid = shift; | |
159 | ||
545dd4e1 | 160 | print "Requesting HA start for CT $vmid\n"; |
52389a07 | 161 | |
35d2a4e4 | 162 | my $cmd = ['ha-manager', 'set', "ct:$vmid", '--state', 'started']; |
52389a07 | 163 | PVE::Tools::run_command($cmd); |
52389a07 DM |
164 | }; |
165 | ||
166 | return $rpcenv->fork_worker('hastart', $vmid, $authuser, $hacmd); | |
167 | ||
168 | } else { | |
169 | ||
6a4e5293 TL |
170 | my $realcmd = sub { |
171 | my $upid = shift; | |
52389a07 | 172 | |
6a4e5293 | 173 | syslog('info', "starting CT $vmid: $upid\n"); |
52389a07 | 174 | |
6a4e5293 | 175 | my $conf = PVE::LXC::Config->load_config($vmid); |
fdf71adb | 176 | |
6a4e5293 TL |
177 | die "you can't start a CT if it's a template\n" |
178 | if PVE::LXC::Config->is_template($conf); | |
894aa229 | 179 | |
6a4e5293 TL |
180 | if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { |
181 | PVE::LXC::Config->check_lock($conf); | |
182 | } | |
894aa229 | 183 | |
6a4e5293 | 184 | if ($conf->{unprivileged}) { |
015740e6 | 185 | PVE::LXC::Config->foreach_volume($conf, sub { |
6a4e5293 TL |
186 | my ($ms, $mountpoint) = @_; |
187 | die "Quotas are not supported by unprivileged containers.\n" if $mountpoint->{quota}; | |
188 | }); | |
189 | } | |
52389a07 | 190 | |
6a4e5293 TL |
191 | PVE::LXC::vm_start($vmid, $conf, $skiplock); |
192 | }; | |
f053a616 | 193 | |
6a4e5293 | 194 | my $lockcmd = sub { |
f053a616 | 195 | return $rpcenv->fork_worker('vzstart', $vmid, $authuser, $realcmd); |
52389a07 DM |
196 | }; |
197 | ||
67afe46e | 198 | return PVE::LXC::Config->lock_config($vmid, $lockcmd); |
52389a07 DM |
199 | } |
200 | }}); | |
201 | ||
202 | __PACKAGE__->register_method({ | |
203 | name => 'vm_stop', | |
204 | path => 'stop', | |
205 | method => 'POST', | |
206 | protected => 1, | |
207 | proxyto => 'node', | |
52eb76e5 | 208 | description => "Stop the container. This will abruptly stop all processes running in the container.", |
52389a07 DM |
209 | permissions => { |
210 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
211 | }, | |
212 | parameters => { | |
17f1dc40 | 213 | additionalProperties => 0, |
52389a07 DM |
214 | properties => { |
215 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 216 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
2de0b3d4 | 217 | skiplock => get_standard_option('skiplock'), |
52389a07 DM |
218 | }, |
219 | }, | |
220 | returns => { | |
221 | type => 'string', | |
222 | }, | |
223 | code => sub { | |
224 | my ($param) = @_; | |
225 | ||
226 | my $rpcenv = PVE::RPCEnvironment::get(); | |
227 | ||
228 | my $authuser = $rpcenv->get_user(); | |
229 | ||
230 | my $node = extract_param($param, 'node'); | |
231 | ||
232 | my $vmid = extract_param($param, 'vmid'); | |
233 | ||
2de0b3d4 WB |
234 | my $skiplock = extract_param($param, 'skiplock'); |
235 | raise_param_exc({ skiplock => "Only root may use this option." }) | |
236 | if $skiplock && $authuser ne 'root@pam'; | |
237 | ||
52389a07 DM |
238 | die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid); |
239 | ||
240 | if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') { | |
241 | ||
242 | my $hacmd = sub { | |
243 | my $upid = shift; | |
244 | ||
545dd4e1 | 245 | print "Requesting HA stop for CT $vmid\n"; |
52389a07 | 246 | |
f7a6910a | 247 | my $cmd = ['ha-manager', 'crm-command', 'stop', "ct:$vmid", '0']; |
52389a07 | 248 | PVE::Tools::run_command($cmd); |
52389a07 DM |
249 | }; |
250 | ||
251 | return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd); | |
252 | ||
253 | } else { | |
254 | ||
6a4e5293 TL |
255 | my $realcmd = sub { |
256 | my $upid = shift; | |
fdf71adb | 257 | |
6a4e5293 | 258 | syslog('info', "stopping CT $vmid: $upid\n"); |
fdf71adb | 259 | |
6a4e5293 TL |
260 | my $conf = PVE::LXC::Config->load_config($vmid); |
261 | if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { | |
262 | PVE::LXC::Config->check_lock($conf); | |
263 | } | |
52389a07 | 264 | |
6a4e5293 TL |
265 | PVE::LXC::vm_stop($vmid, 1); |
266 | }; | |
f053a616 | 267 | |
6a4e5293 | 268 | my $lockcmd = sub { |
f053a616 | 269 | return $rpcenv->fork_worker('vzstop', $vmid, $authuser, $realcmd); |
52389a07 DM |
270 | }; |
271 | ||
67afe46e | 272 | return PVE::LXC::Config->lock_config($vmid, $lockcmd); |
52389a07 DM |
273 | } |
274 | }}); | |
275 | ||
276 | __PACKAGE__->register_method({ | |
277 | name => 'vm_shutdown', | |
278 | path => 'shutdown', | |
279 | method => 'POST', | |
280 | protected => 1, | |
281 | proxyto => 'node', | |
52eb76e5 EK |
282 | description => "Shutdown the container. This will trigger a clean shutdown " . |
283 | "of the container, see lxc-stop(1) for details.", | |
52389a07 DM |
284 | permissions => { |
285 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
286 | }, | |
287 | parameters => { | |
17f1dc40 | 288 | additionalProperties => 0, |
52389a07 DM |
289 | properties => { |
290 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 291 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
52389a07 DM |
292 | timeout => { |
293 | description => "Wait maximal timeout seconds.", | |
294 | type => 'integer', | |
295 | minimum => 0, | |
296 | optional => 1, | |
297 | default => 60, | |
298 | }, | |
299 | forceStop => { | |
300 | description => "Make sure the Container stops.", | |
301 | type => 'boolean', | |
302 | optional => 1, | |
303 | default => 0, | |
304 | } | |
305 | }, | |
306 | }, | |
307 | returns => { | |
308 | type => 'string', | |
309 | }, | |
310 | code => sub { | |
311 | my ($param) = @_; | |
312 | ||
313 | my $rpcenv = PVE::RPCEnvironment::get(); | |
52389a07 DM |
314 | my $authuser = $rpcenv->get_user(); |
315 | ||
316 | my $node = extract_param($param, 'node'); | |
52389a07 DM |
317 | my $vmid = extract_param($param, 'vmid'); |
318 | ||
6a4e5293 | 319 | my $timeout = extract_param($param, 'timeout') // 60; |
52389a07 DM |
320 | |
321 | die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid); | |
322 | ||
35d2a4e4 | 323 | if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') { |
5bcdc2ac DM |
324 | my $hacmd = sub { |
325 | my $upid = shift; | |
326 | ||
545dd4e1 | 327 | print "Requesting HA stop for CT $vmid\n"; |
5bcdc2ac | 328 | |
f7a6910a | 329 | my $cmd = ['ha-manager', 'crm-command', 'stop', "ct:$vmid", "$timeout"]; |
5bcdc2ac | 330 | PVE::Tools::run_command($cmd); |
5bcdc2ac DM |
331 | }; |
332 | ||
333 | return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd); | |
334 | } | |
335 | ||
6a4e5293 TL |
336 | my $realcmd = sub { |
337 | my $upid = shift; | |
52389a07 | 338 | |
6a4e5293 | 339 | syslog('info', "shutdown CT $vmid: $upid\n"); |
f053a616 | 340 | |
6a4e5293 TL |
341 | my $conf = PVE::LXC::Config->load_config($vmid); |
342 | PVE::LXC::Config->check_lock($conf); | |
52389a07 | 343 | |
6a4e5293 TL |
344 | PVE::LXC::vm_stop($vmid, 0, $timeout, $param->{forceStop}); |
345 | }; | |
52389a07 | 346 | |
6a4e5293 | 347 | my $lockcmd = sub { |
f053a616 FG |
348 | return $rpcenv->fork_worker('vzshutdown', $vmid, $authuser, $realcmd); |
349 | }; | |
52389a07 | 350 | |
67afe46e | 351 | return PVE::LXC::Config->lock_config($vmid, $lockcmd); |
52389a07 DM |
352 | }}); |
353 | ||
354 | __PACKAGE__->register_method({ | |
355 | name => 'vm_suspend', | |
356 | path => 'suspend', | |
357 | method => 'POST', | |
358 | protected => 1, | |
359 | proxyto => 'node', | |
360 | description => "Suspend the container.", | |
361 | permissions => { | |
4de00d82 | 362 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], |
52389a07 DM |
363 | }, |
364 | parameters => { | |
17f1dc40 TL |
365 | additionalProperties => 0, |
366 | properties => { | |
4de00d82 | 367 | node => get_standard_option('pve-node'), |
68e8f3c5 | 368 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
17f1dc40 | 369 | }, |
52389a07 DM |
370 | }, |
371 | returns => { | |
17f1dc40 | 372 | type => 'string', |
52389a07 DM |
373 | }, |
374 | code => sub { | |
4de00d82 | 375 | my ($param) = @_; |
52389a07 | 376 | |
4de00d82 TL |
377 | my $rpcenv = PVE::RPCEnvironment::get(); |
378 | my $authuser = $rpcenv->get_user(); | |
52389a07 | 379 | |
4de00d82 TL |
380 | my $node = extract_param($param, 'node'); |
381 | my $vmid = extract_param($param, 'vmid'); | |
52389a07 | 382 | |
4de00d82 | 383 | die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid); |
52389a07 | 384 | |
6a4e5293 TL |
385 | my $realcmd = sub { |
386 | my $upid = shift; | |
52389a07 | 387 | |
6a4e5293 | 388 | syslog('info', "suspend CT $vmid: $upid\n"); |
52389a07 | 389 | |
6a4e5293 TL |
390 | my $conf = PVE::LXC::Config->load_config($vmid); |
391 | PVE::LXC::Config->check_lock($conf); | |
52389a07 | 392 | |
6a4e5293 TL |
393 | my $cmd = ['lxc-checkpoint', '-n', $vmid, '-s', '-D', '/var/lib/vz/dump']; |
394 | run_command($cmd); | |
395 | }; | |
52389a07 | 396 | |
6a4e5293 | 397 | my $lockcmd = sub { |
f053a616 FG |
398 | return $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd); |
399 | }; | |
52389a07 | 400 | |
67afe46e | 401 | return PVE::LXC::Config->lock_config($vmid, $lockcmd); |
52389a07 DM |
402 | }}); |
403 | ||
404 | __PACKAGE__->register_method({ | |
405 | name => 'vm_resume', | |
406 | path => 'resume', | |
407 | method => 'POST', | |
408 | protected => 1, | |
409 | proxyto => 'node', | |
410 | description => "Resume the container.", | |
411 | permissions => { | |
412 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
413 | }, | |
414 | parameters => { | |
17f1dc40 TL |
415 | additionalProperties => 0, |
416 | properties => { | |
417 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 418 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), |
17f1dc40 | 419 | }, |
52389a07 DM |
420 | }, |
421 | returns => { | |
17f1dc40 | 422 | type => 'string', |
52389a07 DM |
423 | }, |
424 | code => sub { | |
4de00d82 | 425 | my ($param) = @_; |
52389a07 | 426 | |
4de00d82 TL |
427 | my $rpcenv = PVE::RPCEnvironment::get(); |
428 | my $authuser = $rpcenv->get_user(); | |
52389a07 | 429 | |
4de00d82 TL |
430 | my $node = extract_param($param, 'node'); |
431 | my $vmid = extract_param($param, 'vmid'); | |
52389a07 | 432 | |
4de00d82 | 433 | die "CT $vmid already running\n" if PVE::LXC::check_running($vmid); |
52389a07 | 434 | |
6a4e5293 TL |
435 | my $realcmd = sub { |
436 | my $upid = shift; | |
52389a07 | 437 | |
6a4e5293 | 438 | syslog('info', "resume CT $vmid: $upid\n"); |
52389a07 | 439 | |
6a4e5293 | 440 | my $cmd = ['lxc-checkpoint', '-n', $vmid, '-r', '--foreground', '-D', '/var/lib/vz/dump']; |
52389a07 | 441 | run_command($cmd); |
6a4e5293 | 442 | }; |
52389a07 | 443 | |
6a4e5293 | 444 | my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd); |
52389a07 | 445 | |
4de00d82 | 446 | return $upid; |
52389a07 DM |
447 | }}); |
448 | ||
f5fe1125 OB |
449 | __PACKAGE__->register_method({ |
450 | name => 'vm_reboot', | |
451 | path => 'reboot', | |
452 | method => 'POST', | |
453 | protected => 1, | |
454 | proxyto => 'node', | |
455 | description => "Reboot the container by shutting it down, and starting it again. Applies pending changes.", | |
456 | permissions => { | |
457 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
458 | }, | |
459 | parameters => { | |
460 | additionalProperties => 0, | |
461 | properties => { | |
462 | node => get_standard_option('pve-node'), | |
463 | vmid => get_standard_option('pve-vmid', | |
464 | { completion => \&PVE::LXC::complete_ctid_running }), | |
465 | timeout => { | |
466 | description => "Wait maximal timeout seconds for the shutdown.", | |
467 | type => 'integer', | |
468 | minimum => 0, | |
469 | optional => 1, | |
470 | }, | |
471 | }, | |
472 | }, | |
473 | returns => { | |
474 | type => 'string', | |
475 | }, | |
476 | code => sub { | |
477 | my ($param) = @_; | |
478 | ||
479 | my $rpcenv = PVE::RPCEnvironment::get(); | |
480 | my $authuser = $rpcenv->get_user(); | |
481 | ||
482 | my $node = extract_param($param, 'node'); | |
483 | my $vmid = extract_param($param, 'vmid'); | |
484 | ||
485 | die "VM $vmid not running\n" if !PVE::LXC::check_running($vmid); | |
486 | ||
487 | my $realcmd = sub { | |
488 | my $upid = shift; | |
489 | ||
490 | syslog('info', "requesting reboot of CT $vmid: $upid\n"); | |
491 | PVE::LXC::vm_reboot($vmid, $param->{timeout}); | |
492 | return; | |
493 | }; | |
494 | ||
495 | return $rpcenv->fork_worker('vzreboot', $vmid, $authuser, $realcmd); | |
496 | }}); | |
497 | ||
498 | ||
499 | ||
52389a07 | 500 | 1; |