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