]> git.proxmox.com Git - pve-container.git/blob - src/PVE/API2/LXC/Status.pm
Refactor config-related methods into AbstractConfig
[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::HA::Env::PVE2;
19 use PVE::HA::Config;
20 use PVE::JSONSchema qw(get_standard_option);
21 use base qw(PVE::RESTHandler);
22
23 use Data::Dumper; # fixme: remove
24
25 __PACKAGE__->register_method({
26 name => 'vmcmdidx',
27 path => '',
28 method => 'GET',
29 proxyto => 'node',
30 description => "Directory index",
31 permissions => {
32 user => 'all',
33 },
34 parameters => {
35 additionalProperties => 0,
36 properties => {
37 node => get_standard_option('pve-node'),
38 vmid => get_standard_option('pve-vmid'),
39 },
40 },
41 returns => {
42 type => 'array',
43 items => {
44 type => "object",
45 properties => {
46 subdir => { type => 'string' },
47 },
48 },
49 links => [ { rel => 'child', href => "{subdir}" } ],
50 },
51 code => sub {
52 my ($param) = @_;
53
54 # test if VM exists
55 my $conf = PVE::LXC::Config->load_config($param->{vmid});
56
57 my $res = [
58 { subdir => 'current' },
59 { subdir => 'start' },
60 { subdir => 'stop' },
61 { subdir => 'shutdown' },
62 { subdir => 'migrate' },
63 ];
64
65 return $res;
66 }});
67
68 __PACKAGE__->register_method({
69 name => 'vm_status',
70 path => 'current',
71 method => 'GET',
72 proxyto => 'node',
73 protected => 1, # openvz /proc entries are only readable by root
74 description => "Get virtual machine status.",
75 permissions => {
76 check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
77 },
78 parameters => {
79 additionalProperties => 0,
80 properties => {
81 node => get_standard_option('pve-node'),
82 vmid => get_standard_option('pve-vmid'),
83 },
84 },
85 returns => { type => 'object' },
86 code => sub {
87 my ($param) = @_;
88
89 # test if VM exists
90 my $conf = PVE::LXC::Config->load_config($param->{vmid});
91
92 my $vmstatus = PVE::LXC::vmstatus($param->{vmid});
93 my $status = $vmstatus->{$param->{vmid}};
94
95 $status->{ha} = PVE::HA::Config::vm_is_ha_managed($param->{vmid}) ? 1 : 0;
96
97 return $status;
98 }});
99
100 __PACKAGE__->register_method({
101 name => 'vm_start',
102 path => 'start',
103 method => 'POST',
104 protected => 1,
105 proxyto => 'node',
106 description => "Start the container.",
107 permissions => {
108 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
109 },
110 parameters => {
111 additionalProperties => 0,
112 properties => {
113 node => get_standard_option('pve-node'),
114 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
115 skiplock => get_standard_option('skiplock'),
116 },
117 },
118 returns => {
119 type => 'string',
120 },
121 code => sub {
122 my ($param) = @_;
123
124 my $rpcenv = PVE::RPCEnvironment::get();
125
126 my $authuser = $rpcenv->get_user();
127
128 my $node = extract_param($param, 'node');
129
130 my $vmid = extract_param($param, 'vmid');
131
132 my $skiplock = extract_param($param, 'skiplock');
133 raise_param_exc({ skiplock => "Only root may use this option." })
134 if $skiplock && $authuser ne 'root@pam';
135
136 die "CT $vmid already running\n" if PVE::LXC::check_running($vmid);
137
138 PVE::Cluster::check_cfs_quorum();
139
140 if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') {
141
142 my $hacmd = sub {
143 my $upid = shift;
144
145 my $service = "ct:$vmid";
146
147 my $cmd = ['ha-manager', 'enable', $service];
148
149 print "Executing HA start for CT $vmid\n";
150
151 PVE::Tools::run_command($cmd);
152
153 return;
154 };
155
156 return $rpcenv->fork_worker('hastart', $vmid, $authuser, $hacmd);
157
158 } else {
159
160 my $lockcmd = sub {
161 my $realcmd = sub {
162 my $upid = shift;
163
164 syslog('info', "starting CT $vmid: $upid\n");
165
166 my $conf = PVE::LXC::Config->load_config($vmid);
167
168 die "you can't start a CT if it's a template\n"
169 if PVE::LXC::Config->is_template($conf);
170
171 if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) {
172 PVE::LXC::Config->check_lock($conf);
173 }
174
175 my $storage_cfg = cfs_read_file("storage.cfg");
176
177 PVE::LXC::update_lxc_config($storage_cfg, $vmid, $conf);
178
179 local $ENV{PVE_SKIPLOCK}=1 if $skiplock;
180
181 my $cmd = ['lxc-start', '-n', $vmid];
182
183 run_command($cmd);
184
185 return;
186 };
187
188 return $rpcenv->fork_worker('vzstart', $vmid, $authuser, $realcmd);
189 };
190
191 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
192 }
193 }});
194
195 __PACKAGE__->register_method({
196 name => 'vm_stop',
197 path => 'stop',
198 method => 'POST',
199 protected => 1,
200 proxyto => 'node',
201 description => "Stop the container.",
202 permissions => {
203 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
204 },
205 parameters => {
206 additionalProperties => 0,
207 properties => {
208 node => get_standard_option('pve-node'),
209 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
210 skiplock => get_standard_option('skiplock'),
211 },
212 },
213 returns => {
214 type => 'string',
215 },
216 code => sub {
217 my ($param) = @_;
218
219 my $rpcenv = PVE::RPCEnvironment::get();
220
221 my $authuser = $rpcenv->get_user();
222
223 my $node = extract_param($param, 'node');
224
225 my $vmid = extract_param($param, 'vmid');
226
227 my $skiplock = extract_param($param, 'skiplock');
228 raise_param_exc({ skiplock => "Only root may use this option." })
229 if $skiplock && $authuser ne 'root@pam';
230
231 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
232
233 if (PVE::HA::Config::vm_is_ha_managed($vmid) && $rpcenv->{type} ne 'ha') {
234
235 my $hacmd = sub {
236 my $upid = shift;
237
238 my $service = "ct:$vmid";
239
240 my $cmd = ['ha-manager', 'disable', $service];
241
242 print "Executing HA stop for CT $vmid\n";
243
244 PVE::Tools::run_command($cmd);
245
246 return;
247 };
248
249 return $rpcenv->fork_worker('hastop', $vmid, $authuser, $hacmd);
250
251 } else {
252
253 my $lockcmd = sub {
254 my $realcmd = sub {
255 my $upid = shift;
256
257 syslog('info', "stopping CT $vmid: $upid\n");
258
259 my $conf = PVE::LXC::Config->load_config($vmid);
260
261 if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) {
262 PVE::LXC::Config->check_lock($conf);
263 }
264
265 my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
266
267 run_command($cmd);
268
269 return;
270 };
271
272 return $rpcenv->fork_worker('vzstop', $vmid, $authuser, $realcmd);
273 };
274
275 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
276 }
277 }});
278
279 __PACKAGE__->register_method({
280 name => 'vm_shutdown',
281 path => 'shutdown',
282 method => 'POST',
283 protected => 1,
284 proxyto => 'node',
285 description => "Shutdown the container.",
286 permissions => {
287 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
288 },
289 parameters => {
290 additionalProperties => 0,
291 properties => {
292 node => get_standard_option('pve-node'),
293 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
294 timeout => {
295 description => "Wait maximal timeout seconds.",
296 type => 'integer',
297 minimum => 0,
298 optional => 1,
299 default => 60,
300 },
301 forceStop => {
302 description => "Make sure the Container stops.",
303 type => 'boolean',
304 optional => 1,
305 default => 0,
306 }
307 },
308 },
309 returns => {
310 type => 'string',
311 },
312 code => sub {
313 my ($param) = @_;
314
315 my $rpcenv = PVE::RPCEnvironment::get();
316
317 my $authuser = $rpcenv->get_user();
318
319 my $node = extract_param($param, 'node');
320
321 my $vmid = extract_param($param, 'vmid');
322
323 my $timeout = extract_param($param, 'timeout');
324
325 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
326
327 my $lockcmd = sub {
328 my $realcmd = sub {
329 my $upid = shift;
330
331 syslog('info', "shutdown CT $vmid: $upid\n");
332
333 my $cmd = ['lxc-stop', '-n', $vmid];
334
335 $timeout = 60 if !defined($timeout);
336
337 my $conf = PVE::LXC::Config->load_config($vmid);
338
339 PVE::LXC::Config->check_lock($conf);
340
341 my $storage_cfg = PVE::Storage::config();
342
343 push @$cmd, '--timeout', $timeout;
344
345 eval { run_command($cmd, timeout => $timeout+5); };
346 my $err = $@;
347 if ($err && $param->{forceStop}) {
348 $err = undef;
349 warn "shutdown failed - forcing stop now\n";
350
351 my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
352 run_command($cmd);
353 }
354
355 # make sure container is stopped
356 $cmd = ['lxc-wait', '-n', $vmid, '-t', 5, '-s', 'STOPPED'];
357 run_command($cmd);
358 $err = $@;
359
360 die $err if $err;
361
362 return;
363 };
364
365 return $rpcenv->fork_worker('vzshutdown', $vmid, $authuser, $realcmd);
366 };
367
368 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
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.",
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
396 my $authuser = $rpcenv->get_user();
397
398 my $node = extract_param($param, 'node');
399
400 my $vmid = extract_param($param, 'vmid');
401
402 die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
403
404 my $lockcmd = sub {
405 my $realcmd = sub {
406 my $upid = shift;
407
408 syslog('info', "suspend CT $vmid: $upid\n");
409
410 my $conf = PVE::LXC::Config->load_config($vmid);
411
412 PVE::LXC::Config->check_lock($conf);
413
414 my $cmd = ['lxc-checkpoint', '-n', $vmid, '-s', '-D', '/var/lib/vz/dump'];
415
416 run_command($cmd);
417
418 return;
419 };
420
421 return $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd);
422 };
423
424 return PVE::LXC::Config->lock_config($vmid, $lockcmd);
425 }});
426
427 __PACKAGE__->register_method({
428 name => 'vm_resume',
429 path => 'resume',
430 method => 'POST',
431 protected => 1,
432 proxyto => 'node',
433 description => "Resume the container.",
434 permissions => {
435 check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
436 },
437 parameters => {
438 additionalProperties => 0,
439 properties => {
440 node => get_standard_option('pve-node'),
441 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
442 },
443 },
444 returns => {
445 type => 'string',
446 },
447 code => sub {
448 my ($param) = @_;
449
450 my $rpcenv = PVE::RPCEnvironment::get();
451
452 my $authuser = $rpcenv->get_user();
453
454 my $node = extract_param($param, 'node');
455
456 my $vmid = extract_param($param, 'vmid');
457
458 die "CT $vmid already running\n" if PVE::LXC::check_running($vmid);
459
460 my $realcmd = sub {
461 my $upid = shift;
462
463 syslog('info', "resume CT $vmid: $upid\n");
464
465 my $cmd = ['lxc-checkpoint', '-n', $vmid, '-r', '--foreground',
466 '-D', '/var/lib/vz/dump'];
467
468 run_command($cmd);
469
470 return;
471 };
472
473 my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd);
474
475 return $upid;
476 }});
477
478 1;