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