]> git.proxmox.com Git - pve-container.git/blob - src/PVE/CLI/pct.pm
pct enter: check if container runs before lxc-attach
[pve-container.git] / src / PVE / CLI / pct.pm
1 package PVE::CLI::pct;
2
3 use strict;
4 use warnings;
5
6 use PVE::SafeSyslog;
7 use PVE::Tools qw(extract_param);
8 use PVE::Cluster;
9 use PVE::INotify;
10 use PVE::RPCEnvironment;
11 use PVE::JSONSchema qw(get_standard_option);
12 use PVE::CLIHandler;
13 use PVE::API2::LXC;
14 use PVE::API2::LXC::Config;
15 use PVE::API2::LXC::Status;
16 use PVE::API2::LXC::Snapshot;
17
18 use Data::Dumper;
19
20 use base qw(PVE::CLIHandler);
21
22 my $nodename = PVE::INotify::nodename();
23
24 my $upid_exit = sub {
25 my $upid = shift;
26 my $status = PVE::Tools::upid_read_status($upid);
27 exit($status eq 'OK' ? 0 : -1);
28 };
29
30 __PACKAGE__->register_method ({
31 name => 'unlock',
32 path => 'unlock',
33 method => 'PUT',
34 description => "Unlock the VM.",
35 parameters => {
36 additionalProperties => 0,
37 properties => {
38 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
39 },
40 },
41 returns => { type => 'null'},
42 code => sub {
43 my ($param) = @_;
44
45 my $vmid = $param->{vmid};
46
47 PVE::LXC::lock_config($vmid, sub {
48 my $conf = PVE::LXC::load_config($vmid);
49 delete $conf->{lock};
50 PVE::LXC::write_config($vmid, $conf);
51 });
52
53 return undef;
54 }});
55
56 __PACKAGE__->register_method ({
57 name => 'console',
58 path => 'console',
59 method => 'GET',
60 description => "Launch a console for the specified container.",
61 parameters => {
62 additionalProperties => 0,
63 properties => {
64 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
65 },
66 },
67 returns => { type => 'null' },
68
69 code => sub {
70 my ($param) = @_;
71
72 # test if container exists on this node
73 my $conf = PVE::LXC::load_config($param->{vmid});
74
75 my $cmd = PVE::LXC::get_console_command($param->{vmid}, $conf);
76 exec(@$cmd);
77 }});
78
79 __PACKAGE__->register_method ({
80 name => 'enter',
81 path => 'enter',
82 method => 'GET',
83 description => "Launch a shell for the specified container.",
84 parameters => {
85 additionalProperties => 0,
86 properties => {
87 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
88 },
89 },
90 returns => { type => 'null' },
91
92 code => sub {
93 my ($param) = @_;
94
95 my $vmid = $param->{vmid};
96
97 # test if container exists on this node
98 PVE::LXC::load_config($vmid);
99
100 die "Error: container '$vmid' not running!\n" if !PVE::LXC::check_running($vmid);
101
102 exec('lxc-attach', '-n', $vmid);
103 }});
104
105 __PACKAGE__->register_method ({
106 name => 'exec',
107 path => 'exec',
108 method => 'GET',
109 description => "Launch a command inside the specified container.",
110 parameters => {
111 additionalProperties => 0,
112 properties => {
113 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }),
114 'extra-args' => get_standard_option('extra-args'),
115 },
116 },
117 returns => { type => 'null' },
118
119 code => sub {
120 my ($param) = @_;
121
122 # test if container exists on this node
123 PVE::LXC::load_config($param->{vmid});
124
125 if (!@{$param->{'extra-args'}}) {
126 die "missing command";
127 }
128 exec('lxc-attach', '-n', $param->{vmid}, '--', @{$param->{'extra-args'}});
129 }});
130
131 __PACKAGE__->register_method ({
132 name => 'fsck',
133 path => 'fsck',
134 method => 'PUT',
135 description => "Run a filesystem check (fsck) on a container volume.",
136 parameters => {
137 additionalProperties => 0,
138 properties => {
139 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
140 force => {
141 optional => 1,
142 type => 'boolean',
143 description => "Force checking, even if the filesystem seems clean",
144 default => 0,
145 },
146 device => {
147 optional => 1,
148 type => 'string',
149 description => "A volume on which to run the filesystem check",
150 enum => [PVE::LXC::mountpoint_names()],
151 },
152 },
153 },
154 returns => { type => 'null' },
155 code => sub {
156
157 my ($param) = @_;
158 my $vmid = $param->{'vmid'};
159 my $device = defined($param->{'device'}) ? $param->{'device'} : 'rootfs';
160
161 my $command = ['fsck', '-a', '-l'];
162 push(@$command, '-f') if $param->{force};
163
164 # critical path: all of this will be done while the container is locked
165 my $do_fsck = sub {
166
167 my $conf = PVE::LXC::load_config($vmid);
168 my $storage_cfg = PVE::Storage::config();
169
170 defined($conf->{$device}) || die "cannot run command on unexisting mountpoint $device\n";
171
172 my $mount_point = $device eq 'rootfs' ? PVE::LXC::parse_ct_rootfs($conf->{$device}) :
173 PVE::LXC::parse_ct_mountpoint($conf->{$device});
174
175 my $volid = $mount_point->{volume};
176
177 my $path;
178 my $storage_id = PVE::Storage::parse_volume_id($volid, 1);
179
180 if ($storage_id) {
181 my (undef, undef, undef, undef, undef, undef, $format) =
182 PVE::Storage::parse_volname($storage_cfg, $volid);
183
184 die "unable to run fsck for '$volid' (format == $format)\n"
185 if $format ne 'raw';
186
187 $path = PVE::Storage::path($storage_cfg, $volid);
188
189 } else {
190 if (($volid =~ m|^/.+|) && (-b $volid)) {
191 # pass block devices directly
192 $path = $volid;
193 } else {
194 die "path '$volid' does not point to a block device\n";
195 }
196 }
197
198 push(@$command, $path);
199
200 PVE::LXC::check_running($vmid) &&
201 die "cannot run fsck on active container\n";
202
203 PVE::Tools::run_command($command);
204 };
205
206 PVE::LXC::lock_config($vmid, $do_fsck);
207 return undef;
208 }});
209
210 our $cmddef = {
211 list=> [ 'PVE::API2::LXC', 'vmlist', [], { node => $nodename }, sub {
212 my $res = shift;
213 return if !scalar(@$res);
214 my $format = "%-10s %-10s %-20s\n";
215 printf($format, 'VMID', 'Status', 'Name');
216 foreach my $d (sort {$a->{vmid} <=> $b->{vmid} } @$res) {
217 printf($format, $d->{vmid}, $d->{status}, $d->{name});
218 }
219 }],
220 config => [ "PVE::API2::LXC::Config", 'vm_config', ['vmid'],
221 { node => $nodename }, sub {
222 my $config = shift;
223 foreach my $k (sort (keys %$config)) {
224 next if $k eq 'digest';
225 my $v = $config->{$k};
226 if ($k eq 'description') {
227 $v = PVE::Tools::encode_text($v);
228 }
229 print "$k: $v\n";
230 }
231 }],
232 set => [ 'PVE::API2::LXC::Config', 'update_vm', ['vmid'], { node => $nodename }],
233
234 resize => [ "PVE::API2::LXC", 'resize_vm', ['vmid', 'disk', 'size'], { node => $nodename } ],
235
236 create => [ 'PVE::API2::LXC', 'create_vm', ['vmid', 'ostemplate'], { node => $nodename }, $upid_exit ],
237 restore => [ 'PVE::API2::LXC', 'create_vm', ['vmid', 'ostemplate'], { node => $nodename, restore => 1 }, $upid_exit ],
238
239 start => [ 'PVE::API2::LXC::Status', 'vm_start', ['vmid'], { node => $nodename }, $upid_exit],
240 suspend => [ 'PVE::API2::LXC::Status', 'vm_suspend', ['vmid'], { node => $nodename }, $upid_exit],
241 resume => [ 'PVE::API2::LXC::Status', 'vm_resume', ['vmid'], { node => $nodename }, $upid_exit],
242 shutdown => [ 'PVE::API2::LXC::Status', 'vm_shutdown', ['vmid'], { node => $nodename }, $upid_exit],
243 stop => [ 'PVE::API2::LXC::Status', 'vm_stop', ['vmid'], { node => $nodename }, $upid_exit],
244
245 clone => [ "PVE::API2::LXC", 'clone_vm', ['vmid', 'newid'], { node => $nodename }, $upid_exit ],
246 migrate => [ "PVE::API2::LXC", 'migrate_vm', ['vmid', 'target'], { node => $nodename }, $upid_exit],
247
248 console => [ __PACKAGE__, 'console', ['vmid']],
249 enter => [ __PACKAGE__, 'enter', ['vmid']],
250 unlock => [ __PACKAGE__, 'unlock', ['vmid']],
251 exec => [ __PACKAGE__, 'exec', ['vmid', 'extra-args']],
252 fsck => [ __PACKAGE__, 'fsck', ['vmid']],
253
254 destroy => [ 'PVE::API2::LXC', 'destroy_vm', ['vmid'],
255 { node => $nodename }, $upid_exit ],
256
257 snapshot => [ "PVE::API2::LXC::Snapshot", 'snapshot', ['vmid', 'snapname'],
258 { node => $nodename } , $upid_exit ],
259
260 delsnapshot => [ "PVE::API2::LXC::Snapshot", 'delsnapshot', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
261
262 listsnapshot => [ "PVE::API2::LXC::Snapshot", 'list', ['vmid'], { node => $nodename },
263 sub {
264 my $res = shift;
265 foreach my $e (@$res) {
266 my $headline = $e->{description} || 'no-description';
267 $headline =~ s/\n.*//sg;
268 my $parent = $e->{parent} // 'no-parent';
269 printf("%-20s %-20s %s\n", $e->{name}, $parent, $headline);
270 }
271 }],
272
273 rollback => [ "PVE::API2::LXC::Snapshot", 'rollback', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
274
275 template => [ "PVE::API2::LXC", 'template', ['vmid'], { node => $nodename }],
276 };
277
278
279 1;
280
281 __END__
282
283 =head1 NAME
284
285 pct - Tool to manage Linux Containers (LXC) on Proxmox VE
286
287 =head1 SYNOPSIS
288
289 =include synopsis
290
291 =head1 DESCRIPTION
292
293 pct is a tool to manages Linux Containers (LXC). You can create
294 and destroy containers, and control execution
295 (start/stop/suspend/resume). Besides that, you can use pct to set
296 parameters in the associated config file, like network configuration or
297 memory.
298
299 =head1 EXAMPLES
300
301 Create a container based on a Debian template
302 (provided you downloaded the template via the webgui before)
303
304 pct create 100 /var/lib/vz/template/cache/debian-8.0-standard_8.0-1_amd64.tar.gz
305
306 Start a container
307
308 pct start 100
309
310 Start a login session via getty
311
312 pct console 100
313
314 Enter the lxc namespace and run a shell as root user
315
316 pct enter 100
317
318 Display the configuration
319
320 pct config 100
321
322 Add a network interface called eth0, bridged to the host bridge vmbr0,
323 set the address and gateway, while it's running
324
325 pct set 100 -net0 name=eth0,bridge=vmbr0,ip=192.168.15.147/24,gw=192.168.15.1
326
327 Reduce the memory of the container to 512MB
328
329 pct set -memory 512 100
330
331 =head1 FILES
332
333 /etc/pve/lxc/<vmid>.conf
334
335 Configuration file for the container <vmid>
336
337 =head1 SEE ALSO
338
339 L<B<qm(1)>>, L<B<pvesh(1)>>
340
341 =include pve_copyright