]>
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'), |
cc9967d2 TL |
133 | debug => { |
134 | optional => 1, | |
135 | type => 'boolean', | |
136 | description => "If set, enables very verbose debug log-level on start.", | |
137 | default => 0, | |
138 | }, | |
52389a07 DM |
139 | }, |
140 | }, | |
141 | returns => { | |
142 | type => 'string', | |
143 | }, | |
144 | code => sub { | |
145 | my ($param) = @_; | |
146 | ||
147 | my $rpcenv = PVE::RPCEnvironment::get(); | |
52389a07 DM |
148 | my $authuser = $rpcenv->get_user(); |
149 | ||
150 | my $node = extract_param($param, 'node'); | |
52389a07 DM |
151 | my $vmid = extract_param($param, 'vmid'); |
152 | ||
2de0b3d4 WB |
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 | ||
52389a07 DM |
157 | die "CT $vmid already running\n" if PVE::LXC::check_running($vmid); |
158 | ||
1e56e83e WB |
159 | PVE::Cluster::check_cfs_quorum(); |
160 | ||
52389a07 DM |
161 | if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') { |
162 | ||
163 | my $hacmd = sub { | |
164 | my $upid = shift; | |
165 | ||
545dd4e1 | 166 | print "Requesting HA start for CT $vmid\n"; |
52389a07 | 167 | |
35d2a4e4 | 168 | my $cmd = ['ha-manager', 'set', "ct:$vmid", '--state', 'started']; |
52389a07 | 169 | PVE::Tools::run_command($cmd); |
52389a07 DM |
170 | }; |
171 | ||
172 | return $rpcenv->fork_worker('hastart', $vmid, $authuser, $hacmd); | |
173 | ||
174 | } else { | |
175 | ||
6a4e5293 TL |
176 | my $realcmd = sub { |
177 | my $upid = shift; | |
52389a07 | 178 | |
7a735681 FW |
179 | PVE::LXC::Config->lock_config($vmid, sub { |
180 | syslog('info', "starting CT $vmid: $upid\n"); | |
52389a07 | 181 | |
7a735681 | 182 | my $conf = PVE::LXC::Config->load_config($vmid); |
894aa229 | 183 | |
7a735681 FW |
184 | die "you can't start a CT if it's a template\n" |
185 | if PVE::LXC::Config->is_template($conf); | |
894aa229 | 186 | |
7a735681 FW |
187 | if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { |
188 | PVE::LXC::Config->check_lock($conf); | |
189 | } | |
52389a07 | 190 | |
7a735681 FW |
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 | } | |
f053a616 | 198 | |
7a735681 FW |
199 | PVE::LXC::vm_start($vmid, $conf, $skiplock, $param->{debug}); |
200 | }); | |
52389a07 DM |
201 | }; |
202 | ||
7a735681 | 203 | return $rpcenv->fork_worker('vzstart', $vmid, $authuser, $realcmd); |
52389a07 DM |
204 | } |
205 | }}); | |
206 | ||
207 | __PACKAGE__->register_method({ | |
208 | name => 'vm_stop', | |
209 | path => 'stop', | |
210 | method => 'POST', | |
211 | protected => 1, | |
212 | proxyto => 'node', | |
52eb76e5 | 213 | description => "Stop the container. This will abruptly stop all processes running in the container.", |
52389a07 DM |
214 | permissions => { |
215 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
216 | }, | |
217 | parameters => { | |
17f1dc40 | 218 | additionalProperties => 0, |
52389a07 DM |
219 | properties => { |
220 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 221 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
2de0b3d4 | 222 | skiplock => get_standard_option('skiplock'), |
d5fab92b | 223 | 'overrule-shutdown' => { |
9dfcefb1 | 224 | description => "Try to abort active 'vzshutdown' tasks before stopping.", |
d5fab92b FW |
225 | optional => 1, |
226 | type => 'boolean', | |
227 | default => 0, | |
228 | } | |
52389a07 DM |
229 | }, |
230 | }, | |
231 | returns => { | |
232 | type => 'string', | |
233 | }, | |
234 | code => sub { | |
235 | my ($param) = @_; | |
236 | ||
237 | my $rpcenv = PVE::RPCEnvironment::get(); | |
52389a07 | 238 | my $authuser = $rpcenv->get_user(); |
52389a07 | 239 | my $node = extract_param($param, 'node'); |
52389a07 DM |
240 | my $vmid = extract_param($param, 'vmid'); |
241 | ||
2de0b3d4 WB |
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 | ||
d5fab92b FW |
246 | my $overrule_shutdown = extract_param($param, 'overrule-shutdown'); |
247 | ||
52389a07 DM |
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 | ||
d5fab92b FW |
252 | raise_param_exc({ 'overrule-shutdown' => "Not applicable for HA resources." }) |
253 | if $overrule_shutdown; | |
254 | ||
52389a07 DM |
255 | my $hacmd = sub { |
256 | my $upid = shift; | |
257 | ||
545dd4e1 | 258 | print "Requesting HA stop for CT $vmid\n"; |
52389a07 | 259 | |
f7a6910a | 260 | my $cmd = ['ha-manager', 'crm-command', 'stop', "ct:$vmid", '0']; |
52389a07 | 261 | PVE::Tools::run_command($cmd); |
52389a07 DM |
262 | }; |
263 | ||
264 | return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd); | |
265 | ||
266 | } else { | |
267 | ||
6a4e5293 TL |
268 | my $realcmd = sub { |
269 | my $upid = shift; | |
fdf71adb | 270 | |
d5fab92b FW |
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 | ||
7a735681 FW |
279 | PVE::LXC::Config->lock_config($vmid, sub { |
280 | syslog('info', "stopping CT $vmid: $upid\n"); | |
fdf71adb | 281 | |
7a735681 FW |
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 | } | |
f053a616 | 286 | |
7a735681 FW |
287 | PVE::LXC::vm_stop($vmid, 1); |
288 | }); | |
52389a07 DM |
289 | }; |
290 | ||
7a735681 | 291 | return $rpcenv->fork_worker('vzstop', $vmid, $authuser, $realcmd); |
52389a07 DM |
292 | } |
293 | }}); | |
294 | ||
295 | __PACKAGE__->register_method({ | |
296 | name => 'vm_shutdown', | |
297 | path => 'shutdown', | |
298 | method => 'POST', | |
299 | protected => 1, | |
300 | proxyto => 'node', | |
52eb76e5 EK |
301 | description => "Shutdown the container. This will trigger a clean shutdown " . |
302 | "of the container, see lxc-stop(1) for details.", | |
52389a07 DM |
303 | permissions => { |
304 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], | |
305 | }, | |
306 | parameters => { | |
17f1dc40 | 307 | additionalProperties => 0, |
52389a07 DM |
308 | properties => { |
309 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 310 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
52389a07 DM |
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(); | |
52389a07 DM |
333 | my $authuser = $rpcenv->get_user(); |
334 | ||
335 | my $node = extract_param($param, 'node'); | |
52389a07 DM |
336 | my $vmid = extract_param($param, 'vmid'); |
337 | ||
6a4e5293 | 338 | my $timeout = extract_param($param, 'timeout') // 60; |
52389a07 DM |
339 | |
340 | die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid); | |
341 | ||
35d2a4e4 | 342 | if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') { |
5bcdc2ac DM |
343 | my $hacmd = sub { |
344 | my $upid = shift; | |
345 | ||
545dd4e1 | 346 | print "Requesting HA stop for CT $vmid\n"; |
5bcdc2ac | 347 | |
f7a6910a | 348 | my $cmd = ['ha-manager', 'crm-command', 'stop', "ct:$vmid", "$timeout"]; |
5bcdc2ac | 349 | PVE::Tools::run_command($cmd); |
5bcdc2ac DM |
350 | }; |
351 | ||
352 | return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd); | |
353 | } | |
354 | ||
6a4e5293 TL |
355 | my $realcmd = sub { |
356 | my $upid = shift; | |
52389a07 | 357 | |
7a735681 FW |
358 | PVE::LXC::Config->lock_config($vmid, sub { |
359 | syslog('info', "shutdown CT $vmid: $upid\n"); | |
f053a616 | 360 | |
7a735681 FW |
361 | my $conf = PVE::LXC::Config->load_config($vmid); |
362 | PVE::LXC::Config->check_lock($conf); | |
52389a07 | 363 | |
7a735681 FW |
364 | PVE::LXC::vm_stop($vmid, 0, $timeout, $param->{forceStop}); |
365 | }); | |
f053a616 | 366 | }; |
52389a07 | 367 | |
7a735681 | 368 | return $rpcenv->fork_worker('vzshutdown', $vmid, $authuser, $realcmd); |
52389a07 DM |
369 | }}); |
370 | ||
371 | __PACKAGE__->register_method({ | |
372 | name => 'vm_suspend', | |
373 | path => 'suspend', | |
374 | method => 'POST', | |
375 | protected => 1, | |
376 | proxyto => 'node', | |
692c79d9 | 377 | description => "Suspend the container. This is experimental.", |
52389a07 | 378 | permissions => { |
4de00d82 | 379 | check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], |
52389a07 DM |
380 | }, |
381 | parameters => { | |
17f1dc40 TL |
382 | additionalProperties => 0, |
383 | properties => { | |
4de00d82 | 384 | node => get_standard_option('pve-node'), |
68e8f3c5 | 385 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), |
17f1dc40 | 386 | }, |
52389a07 DM |
387 | }, |
388 | returns => { | |
17f1dc40 | 389 | type => 'string', |
52389a07 DM |
390 | }, |
391 | code => sub { | |
4de00d82 | 392 | my ($param) = @_; |
52389a07 | 393 | |
4de00d82 TL |
394 | my $rpcenv = PVE::RPCEnvironment::get(); |
395 | my $authuser = $rpcenv->get_user(); | |
52389a07 | 396 | |
4de00d82 TL |
397 | my $node = extract_param($param, 'node'); |
398 | my $vmid = extract_param($param, 'vmid'); | |
52389a07 | 399 | |
4de00d82 | 400 | die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid); |
52389a07 | 401 | |
6a4e5293 TL |
402 | my $realcmd = sub { |
403 | my $upid = shift; | |
52389a07 | 404 | |
7a735681 FW |
405 | PVE::LXC::Config->lock_config($vmid, sub { |
406 | syslog('info', "suspend CT $vmid: $upid\n"); | |
52389a07 | 407 | |
7a735681 FW |
408 | my $conf = PVE::LXC::Config->load_config($vmid); |
409 | PVE::LXC::Config->check_lock($conf); | |
52389a07 | 410 | |
7a735681 FW |
411 | my $cmd = ['lxc-checkpoint', '-n', $vmid, '-s', '-D', '/var/lib/vz/dump']; |
412 | run_command($cmd); | |
413 | }); | |
f053a616 | 414 | }; |
52389a07 | 415 | |
7a735681 | 416 | return $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd); |
52389a07 DM |
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 => { | |
17f1dc40 TL |
430 | additionalProperties => 0, |
431 | properties => { | |
432 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 433 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), |
17f1dc40 | 434 | }, |
52389a07 DM |
435 | }, |
436 | returns => { | |
17f1dc40 | 437 | type => 'string', |
52389a07 DM |
438 | }, |
439 | code => sub { | |
4de00d82 | 440 | my ($param) = @_; |
52389a07 | 441 | |
4de00d82 TL |
442 | my $rpcenv = PVE::RPCEnvironment::get(); |
443 | my $authuser = $rpcenv->get_user(); | |
52389a07 | 444 | |
4de00d82 TL |
445 | my $node = extract_param($param, 'node'); |
446 | my $vmid = extract_param($param, 'vmid'); | |
52389a07 | 447 | |
4de00d82 | 448 | die "CT $vmid already running\n" if PVE::LXC::check_running($vmid); |
52389a07 | 449 | |
6a4e5293 TL |
450 | my $realcmd = sub { |
451 | my $upid = shift; | |
52389a07 | 452 | |
6a4e5293 | 453 | syslog('info', "resume CT $vmid: $upid\n"); |
52389a07 | 454 | |
6a4e5293 | 455 | my $cmd = ['lxc-checkpoint', '-n', $vmid, '-r', '--foreground', '-D', '/var/lib/vz/dump']; |
52389a07 | 456 | run_command($cmd); |
6a4e5293 | 457 | }; |
52389a07 | 458 | |
6a4e5293 | 459 | my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd); |
52389a07 | 460 | |
4de00d82 | 461 | return $upid; |
52389a07 DM |
462 | }}); |
463 | ||
f5fe1125 OB |
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 | ||
52389a07 | 515 | 1; |