]>
git.proxmox.com Git - qemu-server.git/blob - qm
11 use PVE
::Tools
qw(extract_param);
15 use PVE
::RPCEnvironment
;
18 use PVE
::JSONSchema
qw(get_standard_option);
23 use base
qw(PVE::CLIHandler);
25 $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
29 die "please run as root\n" if $> != 0;
31 PVE
::INotify
::inotify_init
();
33 my $rpcenv = PVE
::RPCEnvironment-
>init('cli');
35 $rpcenv->init_request();
36 $rpcenv->set_language($ENV{LANG
});
37 $rpcenv->set_user('root@pam');
41 my $status = PVE
::Tools
::upid_read_status
($upid);
42 exit($status eq 'OK' ?
0 : -1);
45 my $nodename = PVE
::INotify
::nodename
();
51 while ( ++$c < 10 && !-e
$path ) { sleep(1); }
53 my $s = IO
::Socket
::UNIX-
>new(Peer
=> $path, Timeout
=> 120);
55 die "unable to connect to socket '$path' - $!" if !$s;
57 my $select = new IO
::Select
;
59 $select->add(\
*STDIN
);
62 my $timeout = 60*15; # 15 minutes
65 while ($select->count &&
66 scalar(@handles = $select->can_read ($timeout))) {
67 foreach my $h (@handles) {
69 my $n = $h->sysread($buf, 4096);
79 syswrite(\
*STDOUT
, $buf);
89 __PACKAGE__-
>register_method ({
93 description
=> "Show command line which is used to start the VM (debug info).",
95 additionalProperties
=> 0,
97 vmid
=> get_standard_option
('pve-vmid'),
100 returns
=> { type
=> 'null'},
104 my $storecfg = PVE
::Storage
::config
();
105 print PVE
::QemuServer
::vm_commandline
($storecfg, $param->{vmid
}) . "\n";
110 __PACKAGE__-
>register_method ({
114 description
=> "Show VM status.",
116 additionalProperties
=> 0,
118 vmid
=> get_standard_option
('pve-vmid'),
120 description
=> "Verbose output format",
126 returns
=> { type
=> 'null'},
131 my $conf = PVE
::QemuServer
::load_config
($param->{vmid
});
133 my $vmstatus = PVE
::QemuServer
::vmstatus
($param->{vmid
});
134 my $stat = $vmstatus->{$param->{vmid
}};
135 if ($param->{verbose
}) {
136 foreach my $k (sort (keys %$stat)) {
137 next if $k eq 'cpu' || $k eq 'relcpu'; # always 0
139 next if !defined($v);
143 my $status = $stat->{status
} || 'unknown';
144 print "status: $status\n";
150 __PACKAGE__-
>register_method ({
154 description
=> "Proxy VM VNC traffic to stdin/stdout",
156 additionalProperties
=> 0,
158 vmid
=> get_standard_option
('pve-vmid'),
161 returns
=> { type
=> 'null'},
165 my $vmid = $param->{vmid
};
166 my $vnc_socket = PVE
::QemuServer
::vnc_socket
($vmid);
168 if (my $ticket = $ENV{LC_PVE_TICKET
}) { # NOTE: ssh on debian only pass LC_* variables
169 PVE
::QemuServer
::vm_mon_cmd
($vmid, "change", device
=> 'vnc', target
=> "unix:$vnc_socket,password");
170 PVE
::QemuServer
::vm_mon_cmd
($vmid, "set_password", protocol
=> 'vnc', password
=> $ticket);
171 PVE
::QemuServer
::vm_mon_cmd
($vmid, "expire_password", protocol
=> 'vnc', time => "+30");
173 PVE
::QemuServer
::vm_mon_cmd
($vmid, "change", device
=> 'vnc', target
=> "unix:$vnc_socket,x509,password");
176 run_vnc_proxy
($vnc_socket);
181 __PACKAGE__-
>register_method ({
185 description
=> "Unlock the VM.",
187 additionalProperties
=> 0,
189 vmid
=> get_standard_option
('pve-vmid'),
192 returns
=> { type
=> 'null'},
196 my $vmid = $param->{vmid
};
198 PVE
::QemuServer
::lock_config
($vmid, sub {
199 my $conf = PVE
::QemuServer
::load_config
($vmid);
200 delete $conf->{lock};
201 delete $conf->{pending
}->{lock} if $conf->{pending
}; # just to be sure
202 PVE
::QemuServer
::update_config_nolock
($vmid, $conf, 1);
208 __PACKAGE__-
>register_method ({
212 description
=> "Used by qmigrate - do not use manually.",
214 additionalProperties
=> 0,
217 returns
=> { type
=> 'null'},
221 if (!PVE
::Cluster
::check_cfs_quorum
(1)) {
226 print "tunnel online\n";
229 while (my $line = <>) {
231 last if $line =~ m/^quit$/;
237 __PACKAGE__-
>register_method ({
241 description
=> "Wait until the VM is stopped.",
243 additionalProperties
=> 0,
245 vmid
=> get_standard_option
('pve-vmid'),
247 description
=> "Timeout in seconds. Default is to wait forever.",
254 returns
=> { type
=> 'null'},
258 my $vmid = $param->{vmid
};
259 my $timeout = $param->{timeout
};
261 my $pid = PVE
::QemuServer
::check_running
($vmid);
264 print "waiting until VM $vmid stopps (PID $pid)\n";
267 while ((!$timeout || ($count < $timeout)) && PVE
::QemuServer
::check_running
($vmid)) {
272 die "wait failed - got timeout\n" if PVE
::QemuServer
::check_running
($vmid);
277 __PACKAGE__-
>register_method ({
281 description
=> "Enter Qemu Monitor interface.",
283 additionalProperties
=> 0,
285 vmid
=> get_standard_option
('pve-vmid'),
288 returns
=> { type
=> 'null'},
292 my $vmid = $param->{vmid
};
294 my $conf = PVE
::QemuServer
::load_config
($vmid); # check if VM exists
296 print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
298 my $term = new Term
::ReadLine
('qm');
301 while (defined ($input = $term->readline('qm> '))) {
304 next if $input =~ m/^\s*$/;
306 last if $input =~ m/^\s*q(uit)?\s*$/;
309 print PVE
::QemuServer
::vm_human_monitor_command
($vmid, $input);
311 print "ERROR: $@" if $@;
318 __PACKAGE__-
>register_method ({
322 description
=> "Rescan all storages and update disk sizes and unused disk images.",
324 additionalProperties
=> 0,
326 vmid
=> get_standard_option
('pve-vmid', {optional
=> 1}),
329 returns
=> { type
=> 'null'},
333 PVE
::QemuServer
::rescan
($param->{vmid
});
338 __PACKAGE__-
>register_method ({
342 description
=> "Open a terminal using a serial device (The VM need to have a serial device configured, for example 'serial0: socket')",
344 additionalProperties
=> 0,
346 vmid
=> get_standard_option
('pve-vmid'),
348 description
=> "Select the serial device. By default we simply use the first suitable device.",
351 enum
=> [qw(serial0 serial1 serial2 serial3)],
355 returns
=> { type
=> 'null'},
359 my $vmid = $param->{vmid
};
361 my $conf = PVE
::QemuServer
::load_config
($vmid); # check if VM exists
363 my $iface = $param->{iface
};
366 die "serial interface '$iface' is not configured\n" if !$conf->{$iface};
367 die "wrong serial type on interface '$iface'\n" if $conf->{$iface} ne 'socket';
369 foreach my $opt (qw(serial0 serial1 serial2 serial3)) {
370 if ($conf->{$opt} && ($conf->{$opt} eq 'socket')) {
375 die "unable to find a serial interface\n" if !$iface;
378 die "VM $vmid not running\n" if !PVE
::QemuServer
::check_running
($vmid);
380 my $socket = "/var/run/qemu-server/${vmid}.$iface";
382 my $cmd = "socat UNIX-CONNECT:$socket STDIO,raw,echo=0,escape=0x0f";
384 print "starting serial terminal on interface $iface (press control-O to exit)\n";
392 list
=> [ "PVE::API2::Qemu", 'vmlist', [],
393 { node
=> $nodename }, sub {
396 exit 0 if (!scalar(@$vmlist));
398 printf "%10s %-20s %-10s %-10s %12s %-10s\n",
399 qw(VMID NAME STATUS MEM(MB) BOOTDISK
(GB
) PID
);
401 foreach my $rec (sort { $a->{vmid
} <=> $b->{vmid
} } @$vmlist) {
402 printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $rec->{vmid
}, $rec->{name
},
404 ($rec->{maxmem
} || 0)/(1024*1024),
405 ($rec->{maxdisk
} || 0)/(1024*1024*1024),
412 create
=> [ "PVE::API2::Qemu", 'create_vm', ['vmid'], { node
=> $nodename }, $upid_exit ],
414 destroy
=> [ "PVE::API2::Qemu", 'destroy_vm', ['vmid'], { node
=> $nodename }, $upid_exit ],
416 clone
=> [ "PVE::API2::Qemu", 'clone_vm', ['vmid', 'newid'], { node
=> $nodename }, $upid_exit ],
418 migrate
=> [ "PVE::API2::Qemu", 'migrate_vm', ['vmid', 'target'], { node
=> $nodename }, $upid_exit ],
420 set
=> [ "PVE::API2::Qemu", 'update_vm', ['vmid'], { node
=> $nodename } ],
422 resize
=> [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { node
=> $nodename } ],
424 move_disk
=> [ "PVE::API2::Qemu", 'move_vm_disk', ['vmid', 'disk', 'storage'], { node
=> $nodename }, $upid_exit ],
426 unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid'], { node
=> $nodename } ],
428 config
=> [ "PVE::API2::Qemu", 'vm_config', ['vmid'],
429 { node
=> $nodename }, sub {
431 foreach my $k (sort (keys %$config)) {
432 next if $k eq 'digest';
433 my $v = $config->{$k};
434 if ($k eq 'description') {
435 $v = PVE
::Tools
::encode_text
($v);
441 pending
=> [ "PVE::API2::Qemu", 'vm_pending', ['vmid'],
442 { node
=> $nodename }, sub {
444 foreach my $item (sort { $a->{key
} cmp $b->{key
}} @$data) {
445 my $k = $item->{key
};
446 next if $k eq 'digest';
447 my $v = $item->{value
};
448 my $p = $item->{pending
};
449 if ($k eq 'description') {
450 $v = PVE
::Tools
::encode_text
($v) if defined($v);
451 $p = PVE
::Tools
::encode_text
($p) if defined($p);
454 if ($item->{delete}) {
455 print "del $k: $v\n";
456 } elsif (defined($p)) {
457 print "cur $k: $v\n";
458 print "new $k: $p\n";
460 print "cur $k: $v\n";
462 } elsif (defined($p)) {
463 print "new $k: $p\n";
468 showcmd
=> [ __PACKAGE__
, 'showcmd', ['vmid']],
470 status
=> [ __PACKAGE__
, 'status', ['vmid']],
472 snapshot
=> [ "PVE::API2::Qemu", 'snapshot', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
474 delsnapshot
=> [ "PVE::API2::Qemu", 'delsnapshot', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
476 rollback
=> [ "PVE::API2::Qemu", 'rollback', ['vmid', 'snapname'], { node
=> $nodename } , $upid_exit ],
478 template
=> [ "PVE::API2::Qemu", 'template', ['vmid'], { node
=> $nodename }],
480 start
=> [ "PVE::API2::Qemu", 'vm_start', ['vmid'], { node
=> $nodename } , $upid_exit ],
482 stop
=> [ "PVE::API2::Qemu", 'vm_stop', ['vmid'], { node
=> $nodename }, $upid_exit ],
484 reset => [ "PVE::API2::Qemu", 'vm_reset', ['vmid'], { node
=> $nodename }, $upid_exit ],
486 shutdown => [ "PVE::API2::Qemu", 'vm_shutdown', ['vmid'], { node
=> $nodename }, $upid_exit ],
488 suspend
=> [ "PVE::API2::Qemu", 'vm_suspend', ['vmid'], { node
=> $nodename }, $upid_exit ],
490 resume
=> [ "PVE::API2::Qemu", 'vm_resume', ['vmid'], { node
=> $nodename }, $upid_exit ],
492 sendkey
=> [ "PVE::API2::Qemu", 'vm_sendkey', ['vmid', 'key'], { node
=> $nodename } ],
494 vncproxy
=> [ __PACKAGE__
, 'vncproxy', ['vmid']],
496 wait => [ __PACKAGE__
, 'wait', ['vmid']],
498 unlock
=> [ __PACKAGE__
, 'unlock', ['vmid']],
500 rescan
=> [ __PACKAGE__
, 'rescan', []],
502 monitor
=> [ __PACKAGE__
, 'monitor', ['vmid']],
504 mtunnel
=> [ __PACKAGE__
, 'mtunnel', []],
506 terminal
=> [ __PACKAGE__
, 'terminal', ['vmid']],
511 # Note: disable '+' prefix for Getopt::Long (for resize command)
512 use Getopt
::Long
qw(:config no_getopt_compat);
514 PVE
::CLIHandler
::handle_cmd
($cmddef, "qm", $cmd, \
@ARGV, undef, $0);
522 qm - qemu/kvm virtual machine manager
530 qm is a script to manage virtual machines with qemu/kvm. You can
531 create and destroy virtual machines, and control execution
532 (start/stop/suspend/resume). Besides that, you can use qm to set
533 parameters in the associated config file. It is also possible to
534 create and delete virtual disks.
538 All configuration files consists of lines in the form
542 See L<vm.conf|vm.conf> for a complete list of options.
544 Configuration files are stored inside the Proxmox configuration file system, and can be access at F</etc/pve/qemu-server/C<VMID>.conf>.
546 The default for option 'keyboard' is read from
547 F</etc/pve/datacenter.conf>.
551 Online migration and backups (vzdump) set a lock to prevent
552 unintentional action on such VMs. Sometimes you need remove such lock
553 manually (power failure).
559 # create a new VM with 4 GB ide disk
560 qm create 300 -ide0 4 -net0 e1000 -cdrom proxmox-mailgateway_2.1.iso
565 # send shutdown, then wait until VM is stopped
566 qm shutdown 300 && qm wait 300
568 # same as above, but only wait for 40 seconds
569 qm shutdown 300 && qm wait 300 -timeout 40
572 =include pve_copyright