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