]>
git.proxmox.com Git - qemu-server.git/blob - PVE/CLI/qm.pm
6 # Note: disable '+' prefix for Getopt::Long (for resize command)
7 use Getopt
::Long
qw(:config no_getopt_compat);
14 use PVE
::Tools
qw(extract_param);
18 use PVE
::RPCEnvironment
;
21 use PVE
::JSONSchema
qw(get_standard_option);
26 use base
qw(PVE::CLIHandler);
30 my $status = PVE
::Tools
::upid_read_status
($upid);
31 exit($status eq 'OK' ?
0 : -1);
34 my $nodename = PVE
::INotify
::nodename
();
40 while ( ++$c < 10 && !-e
$path ) { sleep(1); }
42 my $s = IO
::Socket
::UNIX-
>new(Peer
=> $path, Timeout
=> 120);
44 die "unable to connect to socket '$path' - $!" if !$s;
46 my $select = new IO
::Select
;
48 $select->add(\
*STDIN
);
51 my $timeout = 60*15; # 15 minutes
54 while ($select->count &&
55 scalar(@handles = $select->can_read ($timeout))) {
56 foreach my $h (@handles) {
58 my $n = $h->sysread($buf, 4096);
68 syswrite(\
*STDOUT
, $buf);
78 __PACKAGE__-
>register_method ({
82 description
=> "Show command line which is used to start the VM (debug info).",
84 additionalProperties
=> 0,
86 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid
}),
89 returns
=> { type
=> 'null'},
93 my $storecfg = PVE
::Storage
::config
();
94 print PVE
::QemuServer
::vm_commandline
($storecfg, $param->{vmid
}) . "\n";
99 __PACKAGE__-
>register_method ({
103 description
=> "Show VM status.",
105 additionalProperties
=> 0,
107 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid
}),
109 description
=> "Verbose output format",
115 returns
=> { type
=> 'null'},
120 my $conf = PVE
::QemuServer
::load_config
($param->{vmid
});
122 my $vmstatus = PVE
::QemuServer
::vmstatus
($param->{vmid
}, 1);
123 my $stat = $vmstatus->{$param->{vmid
}};
124 if ($param->{verbose
}) {
125 foreach my $k (sort (keys %$stat)) {
126 next if $k eq 'cpu' || $k eq 'relcpu'; # always 0
128 next if !defined($v);
132 my $status = $stat->{qmpstatus
} || 'unknown';
133 print "status: $status\n";
139 __PACKAGE__-
>register_method ({
143 description
=> "Proxy VM VNC traffic to stdin/stdout",
145 additionalProperties
=> 0,
147 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid_running
}),
150 returns
=> { type
=> 'null'},
154 my $vmid = $param->{vmid
};
155 my $vnc_socket = PVE
::QemuServer
::vnc_socket
($vmid);
157 if (my $ticket = $ENV{LC_PVE_TICKET
}) { # NOTE: ssh on debian only pass LC_* variables
158 PVE
::QemuServer
::vm_mon_cmd
($vmid, "change", device
=> 'vnc', target
=> "unix:$vnc_socket,password");
159 PVE
::QemuServer
::vm_mon_cmd
($vmid, "set_password", protocol
=> 'vnc', password
=> $ticket);
160 PVE
::QemuServer
::vm_mon_cmd
($vmid, "expire_password", protocol
=> 'vnc', time => "+30");
162 PVE
::QemuServer
::vm_mon_cmd
($vmid, "change", device
=> 'vnc', target
=> "unix:$vnc_socket,x509,password");
165 run_vnc_proxy
($vnc_socket);
170 __PACKAGE__-
>register_method ({
174 description
=> "Unlock the VM.",
176 additionalProperties
=> 0,
178 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid
}),
181 returns
=> { type
=> 'null'},
185 my $vmid = $param->{vmid
};
187 PVE
::QemuServer
::lock_config
($vmid, sub {
188 my $conf = PVE
::QemuServer
::load_config
($vmid);
189 delete $conf->{lock};
190 delete $conf->{pending
}->{lock} if $conf->{pending
}; # just to be sure
191 PVE
::QemuServer
::write_config
($vmid, $conf);
197 __PACKAGE__-
>register_method ({
201 description
=> "Used by qmigrate - do not use manually.",
203 additionalProperties
=> 0,
206 returns
=> { type
=> 'null'},
210 if (!PVE
::Cluster
::check_cfs_quorum
(1)) {
215 print "tunnel online\n";
218 while (my $line = <>) {
220 last if $line =~ m/^quit$/;
226 __PACKAGE__-
>register_method ({
230 description
=> "Wait until the VM is stopped.",
232 additionalProperties
=> 0,
234 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid_running
}),
236 description
=> "Timeout in seconds. Default is to wait forever.",
243 returns
=> { type
=> 'null'},
247 my $vmid = $param->{vmid
};
248 my $timeout = $param->{timeout
};
250 my $pid = PVE
::QemuServer
::check_running
($vmid);
253 print "waiting until VM $vmid stopps (PID $pid)\n";
256 while ((!$timeout || ($count < $timeout)) && PVE
::QemuServer
::check_running
($vmid)) {
261 die "wait failed - got timeout\n" if PVE
::QemuServer
::check_running
($vmid);
266 __PACKAGE__-
>register_method ({
270 description
=> "Enter Qemu Monitor interface.",
272 additionalProperties
=> 0,
274 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid_running
}),
277 returns
=> { type
=> 'null'},
281 my $vmid = $param->{vmid
};
283 my $conf = PVE
::QemuServer
::load_config
($vmid); # check if VM exists
285 print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
287 my $term = new Term
::ReadLine
('qm');
290 while (defined ($input = $term->readline('qm> '))) {
293 next if $input =~ m/^\s*$/;
295 last if $input =~ m/^\s*q(uit)?\s*$/;
298 print PVE
::QemuServer
::vm_human_monitor_command
($vmid, $input);
300 print "ERROR: $@" if $@;
307 __PACKAGE__-
>register_method ({
311 description
=> "Rescan all storages and update disk sizes and unused disk images.",
313 additionalProperties
=> 0,
315 vmid
=> get_standard_option
('pve-vmid', {
317 completion
=> \
&PVE
::QemuServer
::complete_vmid
,
321 returns
=> { type
=> 'null'},
325 PVE
::QemuServer
::rescan
($param->{vmid
});
330 __PACKAGE__-
>register_method ({
334 description
=> "Open a terminal using a serial device (The VM need to have a serial device configured, for example 'serial0: socket')",
336 additionalProperties
=> 0,
338 vmid
=> get_standard_option
('pve-vmid', { completion
=> \
&PVE
::QemuServer
::complete_vmid_running
}),
340 description
=> "Select the serial device. By default we simply use the first suitable device.",
343 enum
=> [qw(serial0 serial1 serial2 serial3)],
347 returns
=> { type
=> 'null'},
351 my $vmid = $param->{vmid
};
353 my $conf = PVE
::QemuServer
::load_config
($vmid); # check if VM exists
355 my $iface = $param->{iface
};
358 die "serial interface '$iface' is not configured\n" if !$conf->{$iface};
359 die "wrong serial type on interface '$iface'\n" if $conf->{$iface} ne 'socket';
361 foreach my $opt (qw(serial0 serial1 serial2 serial3)) {
362 if ($conf->{$opt} && ($conf->{$opt} eq 'socket')) {
367 die "unable to find a serial interface\n" if !$iface;
370 die "VM $vmid not running\n" if !PVE
::QemuServer
::check_running
($vmid);
372 my $socket = "/var/run/qemu-server/${vmid}.$iface";
374 my $cmd = "socat UNIX-CONNECT:$socket STDIO,raw,echo=0,escape=0x0f";
376 print "starting serial terminal on interface $iface (press control-O to exit)\n";
384 list
=> [ "PVE::API2::Qemu", 'vmlist', [],
385 { node
=> $nodename }, sub {
388 exit 0 if (!scalar(@$vmlist));
390 printf "%10s %-20s %-10s %-10s %12s %-10s\n",
391 qw(VMID NAME STATUS MEM(MB) BOOTDISK
(GB
) PID
);
393 foreach my $rec (sort { $a->{vmid
} <=> $b->{vmid
} } @$vmlist) {
394 printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $rec->{vmid
}, $rec->{name
},
395 $rec->{qmpstatus
} || $rec->{status
},
396 ($rec->{maxmem
} || 0)/(1024*1024),
397 ($rec->{maxdisk
} || 0)/(1024*1024*1024),
404 create
=> [ "PVE::API2::Qemu", 'create_vm', ['vmid'], { node
=> $nodename }, $upid_exit ],
406 destroy
=> [ "PVE::API2::Qemu", 'destroy_vm', ['vmid'], { node
=> $nodename }, $upid_exit ],
408 clone
=> [ "PVE::API2::Qemu", 'clone_vm', ['vmid', 'newid'], { node
=> $nodename }, $upid_exit ],
410 migrate
=> [ "PVE::API2::Qemu", 'migrate_vm', ['vmid', 'target'], { node
=> $nodename }, $upid_exit ],
412 set
=> [ "PVE::API2::Qemu", 'update_vm', ['vmid'], { node
=> $nodename } ],
414 resize
=> [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { node
=> $nodename } ],
416 move_disk
=> [ "PVE::API2::Qemu", 'move_vm_disk', ['vmid', 'disk', 'storage'], { node
=> $nodename }, $upid_exit ],
418 unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid'], { node
=> $nodename } ],
420 config
=> [ "PVE::API2::Qemu", 'vm_config', ['vmid'],
421 { node
=> $nodename }, sub {
423 foreach my $k (sort (keys %$config)) {
424 next if $k eq 'digest';
425 my $v = $config->{$k};
426 if ($k eq 'description') {
427 $v = PVE
::Tools
::encode_text
($v);
433 pending
=> [ "PVE::API2::Qemu", 'vm_pending', ['vmid'],
434 { node
=> $nodename }, sub {
436 foreach my $item (sort { $a->{key
} cmp $b->{key
}} @$data) {
437 my $k = $item->{key
};
438 next if $k eq 'digest';
439 my $v = $item->{value
};
440 my $p = $item->{pending
};
441 if ($k eq 'description') {
442 $v = PVE
::Tools
::encode_text
($v) if defined($v);
443 $p = PVE
::Tools
::encode_text
($p) if defined($p);
446 if ($item->{delete}) {
447 print "del $k: $v\n";
448 } elsif (defined($p)) {
449 print "cur $k: $v\n";
450 print "new $k: $p\n";
452 print "cur $k: $v\n";
454 } elsif (defined($p)) {
455 print "new $k: $p\n";
460 showcmd
=> [ __PACKAGE__
, 'showcmd', ['vmid']],
462 status
=> [ __PACKAGE__
, 'status', ['vmid']],
464 snapshot
=> [ "PVE::API2::Qemu", 'snapshot', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
466 delsnapshot
=> [ "PVE::API2::Qemu", 'delsnapshot', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
468 rollback
=> [ "PVE::API2::Qemu", 'rollback', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
470 template
=> [ "PVE::API2::Qemu", 'template', ['vmid'], { node
=> $nodename }],
472 start
=> [ "PVE::API2::Qemu", 'vm_start', ['vmid'], { node
=> $nodename } , $upid_exit ],
474 stop
=> [ "PVE::API2::Qemu", 'vm_stop', ['vmid'], { node
=> $nodename }, $upid_exit ],
476 reset => [ "PVE::API2::Qemu", 'vm_reset', ['vmid'], { node
=> $nodename }, $upid_exit ],
478 shutdown => [ "PVE::API2::Qemu", 'vm_shutdown', ['vmid'], { node
=> $nodename }, $upid_exit ],
480 suspend
=> [ "PVE::API2::Qemu", 'vm_suspend', ['vmid'], { node
=> $nodename }, $upid_exit ],
482 resume
=> [ "PVE::API2::Qemu", 'vm_resume', ['vmid'], { node
=> $nodename }, $upid_exit ],
484 sendkey
=> [ "PVE::API2::Qemu", 'vm_sendkey', ['vmid', 'key'], { node
=> $nodename } ],
486 vncproxy
=> [ __PACKAGE__
, 'vncproxy', ['vmid']],
488 wait => [ __PACKAGE__
, 'wait', ['vmid']],
490 unlock
=> [ __PACKAGE__
, 'unlock', ['vmid']],
492 rescan
=> [ __PACKAGE__
, 'rescan', []],
494 monitor
=> [ __PACKAGE__
, 'monitor', ['vmid']],
496 mtunnel
=> [ __PACKAGE__
, 'mtunnel', []],
498 terminal
=> [ __PACKAGE__
, 'terminal', ['vmid']],
507 qm - qemu/kvm virtual machine manager
515 qm is a script to manage virtual machines with qemu/kvm. You can
516 create and destroy virtual machines, and control execution
517 (start/stop/suspend/resume). Besides that, you can use qm to set
518 parameters in the associated config file. It is also possible to
519 create and delete virtual disks.
523 All configuration files consists of lines in the form
527 See L<vm.conf|vm.conf> for a complete list of options.
529 Configuration files are stored inside the Proxmox configuration file system, and can be access at F</etc/pve/qemu-server/C<VMID>.conf>.
531 The default for option 'keyboard' is read from
532 F</etc/pve/datacenter.conf>.
536 Online migration and backups (vzdump) set a lock to prevent
537 unintentional action on such VMs. Sometimes you need remove such lock
538 manually (power failure).
544 # create a new VM with 4 GB ide disk
545 qm create 300 -ide0 4 -net0 e1000 -cdrom proxmox-mailgateway_2.1.iso
550 # send shutdown, then wait until VM is stopped
551 qm shutdown 300 && qm wait 300
553 # same as above, but only wait for 40 seconds
554 qm shutdown 300 && qm wait 300 -timeout 40
557 =include pve_copyright