[pve-devel] r5166 - qemu-server/pve2
svn-commits at proxmox.com
svn-commits at proxmox.com
Thu Sep 16 15:21:10 CEST 2010
Author: dietmar
Date: 2010-09-16 13:21:10 +0000 (Thu, 16 Sep 2010)
New Revision: 5166
Added:
qemu-server/pve2/qm
qemu-server/pve2/qm.old
Removed:
qemu-server/pve2/nqm
qemu-server/pve2/qm
Modified:
qemu-server/pve2/ChangeLog
qemu-server/pve2/Makefile
Log:
* nqm: renamed to qm
* qm: renamed to qm.old.
Modified: qemu-server/pve2/ChangeLog
===================================================================
--- qemu-server/pve2/ChangeLog 2010-09-16 13:17:19 UTC (rev 5165)
+++ qemu-server/pve2/ChangeLog 2010-09-16 13:21:10 UTC (rev 5166)
@@ -1,5 +1,9 @@
2010-09-16 Proxmox Support Team <support at proxmox.com>
+ * nqm: renamed to qm
+
+ * qm: renamed to qm.old.
+
* PVE/QemuServer.pm (disknames): removed - no longer needed
(parse_config): remove diskinfo
(config_to_command): also return volume ID list
Modified: qemu-server/pve2/Makefile
===================================================================
--- qemu-server/pve2/Makefile 2010-09-16 13:17:19 UTC (rev 5165)
+++ qemu-server/pve2/Makefile 2010-09-16 13:21:10 UTC (rev 5166)
@@ -76,7 +76,7 @@
rm -rf debian
mkdir debian
make DESTDIR=${CURDIR}/debian install
- perl -I. ./nqm verifyapi
+ perl -I. ./qm verifyapi
install -d -m 0755 debian/DEBIAN
install -m 0644 control debian/DEBIAN
install -m 0755 postinst debian/DEBIAN
Deleted: qemu-server/pve2/nqm
===================================================================
--- qemu-server/pve2/nqm 2010-09-16 13:17:19 UTC (rev 5165)
+++ qemu-server/pve2/nqm 2010-09-16 13:21:10 UTC (rev 5166)
@@ -1,447 +0,0 @@
-#!/usr/bin/perl -w
-
-use strict;
-use Getopt::Long;
-use Fcntl ':flock';
-use File::Path;
-use IO::Socket::UNIX;
-use IO::Select;
-
-use PVE::INotify qw(read_file);
-use PVE::RPCEnvironment;
-use PVE::QemuServer;
-use PVE::API2::Qemu::Config;
-use PVE::API2::Qemu::Status;
-use PVE::JSONSchema qw(get_standard_option);
-use Term::ReadLine;
-
-use PVE::CLIHandler;
-
-use base qw(PVE::CLIHandler);
-
-$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
-
-die "please run as root\n" if $> != 0;
-
-PVE::INotify::inotify_init();
-
-my $rpcenv = PVE::RPCEnvironment->init('cli');
-
-$rpcenv->set_language($ENV{LANG});
-
-$rpcenv->set_user('root');
-
-my $hostname = $rpcenv->get_hostname();
-
-sub run_vnc_proxy {
- my ($vmid) = @_;
-
- my $path = PVE::QemuServer::vnc_socket ($vmid);
-
- my $s = IO::Socket::UNIX->new (Peer => $path, Timeout => 120);
-
- die "unable to connect to socket '$path' - $!" if !$s;
-
- my $select = new IO::Select;
-
- $select->add (\*STDIN);
- $select->add ($s);
-
- my $timeout = 60*15; # 15 minutes
-
- my @handles;
- while ($select->count &&
- scalar (@handles = $select->can_read ($timeout))) {
- foreach my $h (@handles) {
- my $buf;
- my $n = $h->sysread ($buf, 4096);
-
- if ($h == \*STDIN) {
- if ($n) {
- syswrite ($s, $buf);
- } else {
- exit (0);
- }
- } elsif ($h == $s) {
- if ($n) {
- syswrite (\*STDOUT, $buf);
- } else {
- exit (0);
- }
- }
- }
- }
- exit (0);
-}
-
-__PACKAGE__->register_method ({
- name => 'showcmd',
- path => 'showcmd',
- method => 'GET',
- description => "Show command line which is used to start the VM (debug info).",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $storecfg = read_file('storagecfg');
- print PVE::QemuServer::vm_commandline ($storecfg, $param->{vmid}) . "\n";
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'status',
- path => 'status',
- method => 'GET',
- description => "Show VM status.",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $status = 'unknown';
-
- eval {
- if (PVE::QemuServer::check_running($param->{vmid})) {
- $status = 'running';
- } else {
- $status = 'stopped';
- }
- };
-
- print "$status\n";
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'vncticket',
- path => 'vncticket',
- method => 'PUT',
- description => "Create and set a VNC authentication ticket.",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = $param->{vmid};
-
- my $ticket = PVE::QemuServer::vm_vncticket ($vmid);
- print "TICKET:$ticket\n";
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'vncproxy',
- path => 'vncproxy',
- method => 'PUT',
- description => "Proxy VM VNC traffic to stdin/stdout",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- ticket => get_standard_option('pve-vncticket', { optional => 1 }),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = $param->{vmid};
- my $ticket = $param->{ticket};
-
- if ($ticket) {
- PVE::QemuServer::vm_vncticket ($vmid, $ticket);
- }
-
- run_vnc_proxy ($vmid, $ticket);
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'unlock',
- path => 'unlock',
- method => 'PUT',
- description => "Unlock the VM.",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = $param->{vmid};
-
- PVE::QemuServer::lock_config ($vmid, sub {
- PVE::QemuServer::change_config_nolock ($vmid, {}, { lock => 1 }, 1);
- });
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'mtunnel',
- path => 'mtunnel',
- method => 'POST',
- description => "Used by vzmigrate - do not use manually.",
- parameters => {
- additionalProperties => 0,
- properties => {},
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- print "tunnel online\n";
- *STDOUT->flush();
-
- while (my $line = <>) {
- chomp $line;
- last if $line =~ m/^quit$/;
- }
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'startall',
- path => 'startall',
- method => 'POST',
- description => "Start all virtual machines (when onboot=1).",
- parameters => {
- additionalProperties => 0,
- properties => {},
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vzlist = PVE::QemuServer::vzlist();
- my $storecfg = read_file('storagecfg');
-
- foreach my $vmid (keys %$vzlist) {
- next if $vzlist->{$vmid}->{pid}; # already running
-
- eval {
- my $conf = PVE::QemuServer::load_config ($vmid);
- if ($conf->{onboot}) {
- print STDERR "Starting Qemu VM $vmid\n";
- vm_start ($storecfg, $vmid);
- }
- };
- print STDERR $@ if $@;
- }
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'stopall',
- path => 'stopall',
- method => 'POST',
- description => "Stop all virtual machines.",
- parameters => {
- additionalProperties => 0,
- properties => {
- timeout => {
- description => "Timeout in seconds. Default is to wait 3 minutes.",
- type => 'integer',
- minimum => 1,
- optional => 1,
- }
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $timeout = $param->{timeout};
-
- PVE::QemuServer::vm_stopall($timeout);
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'wait',
- path => 'wait',
- method => 'GET',
- description => "Wait until the VM is stopped.",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- timeout => {
- description => "Timeout in seconds. Default is to wait forever.",
- type => 'integer',
- minimum => 1,
- optional => 1,
- }
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = $param->{vmid};
- my $timeout = $param->{timeout};
-
- my $pid = PVE::QemuServer::check_running ($vmid);
- return if !$pid;
-
- print "waiting until VM $vmid stopps (PID $pid)\n";
-
- my $count = 0;
- while ((!$timeout || ($count < $timeout)) && PVE::QemuServer::check_running ($vmid)) {
- $count++;
- sleep 1;
- }
-
- die "wait failed - got timeout\n" if PVE::QemuServer::check_running ($vmid);
-
- return undef;
- }});
-
-__PACKAGE__->register_method ({
- name => 'monitor',
- path => 'monitor',
- method => 'POST',
- description => "Enter Qemu Monitor interface.",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid'),
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = $param->{vmid};
-
- my $conf = PVE::QemuServer::load_config ($vmid); # check if VM exists
-
- print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
-
- my $term = new Term::ReadLine ('qm');
-
- my $input;
- while (defined ($input = $term->readline('qm> '))) {
- chomp $input;
-
- next if $input =~ m/^\s*$/;
-
- last if $input =~ m/^\s*q(uit)?\s*$/;
-
- eval {
- print PVE::QemuServer::vm_monitor_command ($vmid, $input);
- };
- print "ERROR: $@" if $@;
- }
-
- return undef;
-
- }});
-
-# fixme: unlink
-
-my $cmddef = {
- list => [ "PVE::API2::Qemu::Config", 'vmlist', [],
- { node => $hostname }, sub {
- my $vmlist = shift;
-
- exit 0 if (!scalar(@$vmlist));
-
- printf "%10s %-20s %-10s %-10s %12s %-10s\n",
- qw(VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID);
-
- foreach my $rec (sort { $a->{vmid} <=> $b->{vmid} } @$vmlist) {
- printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $rec->{vmid}, $rec->{name},
- $rec->{status}, $rec->{maxmem}, $rec->{maxdisk}||0, $rec->{pid}||0;
- }
-
-
- } ],
-
- create => [ "PVE::API2::Qemu::Config", 'create_vm', ['vmid'], { node => $hostname } ],
-
- destroy => [ "PVE::API2::Qemu::Config", 'destroy_vm', ['vmid'], { node => $hostname } ],
-
- set => [ "PVE::API2::Qemu::Config", 'update_vm', ['vmid'], { node => $hostname } ],
-
- config => [ "PVE::API2::Qemu::Config", 'vm_config', ['vmid'],
- { node => $hostname }, sub {
- my $config = shift;
- foreach my $k (sort (keys %$config)) {
- my $v = $config->{$k};
- print "$k: $v\n";
- }
- }],
-
- showcmd => [ __PACKAGE__, 'showcmd', ['vmid']],
-
- status => [ __PACKAGE__, 'status', ['vmid']],
-
- vncticket => [ __PACKAGE__, 'vncticket', ['vmid']],
-
- vncproxy => [ __PACKAGE__, 'vncproxy', ['vmid', 'ticket']],
-
- wait => [ __PACKAGE__, 'wait', ['vmid']],
-
- unlock => [ __PACKAGE__, 'unlock', ['vmid']],
-
- monitor => [ __PACKAGE__, 'monitor', ['vmid']],
-
- startall => [ __PACKAGE__, 'startall', []],
-
- stopall => [ __PACKAGE__, 'stopall', []],
-
- mtunnel => [ __PACKAGE__, 'mtunnel', []],
-
-
- start => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'start' } ],
- stop => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'stop' } ],
- reset => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'reset' } ],
- suspend => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'suspend' } ],
- resume => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'resume' } ],
- cad => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
- { node => $hostname, command => 'cad' } ],
-
-};
-
-my $cmd = shift;
-
-if ($cmd && $cmd eq 'verifyapi') {
- PVE::RESTHandler::validate_method_schemas();
- exit 0;
-}
-
-PVE::CLIHandler::handle_cmd($cmddef, "qm", $cmd, \@ARGV);
-
-exit 0;
Deleted: qemu-server/pve2/qm
===================================================================
--- qemu-server/pve2/qm 2010-09-16 13:17:19 UTC (rev 5165)
+++ qemu-server/pve2/qm 2010-09-16 13:21:10 UTC (rev 5166)
@@ -1,1073 +0,0 @@
-#!/usr/bin/perl -w
-
-use strict;
-
-use Term::ReadLine;
-use PVE::QemuServer;
-use IO::Socket::INET;
-use File::Path;
-use Sys::Syslog;
-use PVE::Storage;
-
-# VNC proxy example:
-# nc -l -p 5900 -w 20 -c "/usr/sbin/qm vncproxy 200 <ticket>"
-# where ticket(password) is an arbitrary string containing
-# [A-Za-z0-9\+\/] (base64 charset)
-# simple vncproxy example: nc -l -p 5900 -c "qm vncproxy 200 test"
-
-
-# command used by the vnc option
-my $vnccmd = "echo -e '__TICKET__\\n__TICKET__' |vncpasswd __TMPFILE__;vncviewer localhost:__DISPLAY__ -passwd __TMPFILE__";
-
-openlog ('qm', 'cons,pid', 'daemon');
-
-sub print_usage {
- my ($msg) = @_;
-
- if ($msg) {
- print STDERR "ERROR: $msg\n";
- }
- print STDERR "qm <command> <vmid> [OPTIONS]\n";
- print STDERR "qm [create|set] <vmid>\n";
- print STDERR "\t--memory <MBYTES> memory in MB (64 - 8192)\n";
- print STDERR "\t--sockets <N> set number of CPU sockets <N>\n";
- print STDERR "\t--cores <N> set cores per socket to <N>\n";
- print STDERR "\t--ostype NAME specify OS type\n";
- print STDERR "\t--onboot [yes|no] start at boot\n";
- print STDERR "\t--keyboard XX set vnc keyboard layout\n";
- print STDERR "\t--cpuunits <num> CPU weight for a VM\n";
- print STDERR "\t--name <text> set a name for the VM\n";
- print STDERR "\t--description <text> set VM description\n";
- print STDERR "\t--boot [a|c|d|n] specify boot order\n";
- print STDERR "\t--bootdisk <disk> enable booting from <disk>\n";
- print STDERR "\t--acpi (yes|no) enable/disable ACPI\n";
- print STDERR "\t--kvm (yes|no) enable/disable KVM\n";
- print STDERR "\t--tdf (yes|no) enable/disable time drift fix\n";
- print STDERR "\t--localtime (yes|no) set the RTC to local time\n";
- print STDERR "\t--vga (gd5446|vesa) specify VGA type\n";
-
- print STDERR "\n";
- print STDERR "\t--vlan[0-9u] MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]\n";
-
- print STDERR "\n";
- print STDERR "\t--ide<N> [volume=]volume,[,media=cdrom|disk]\n";
- print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
- print STDERR "\t [,cache=none|writethrough|writeback]\n";
- print STDERR "\t [,snapshot=on|off][,cache=on|off][,format=f]\n";
- print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
- print STDERR "\t [,rerror=ignore|report|stop]\n";
- print STDERR "\t--ide<N> <GBYTES> create new disk\n";
- print STDERR "\t--ide<N> delete remove drive - destroy image\n";
- print STDERR "\t--ide<N> undef remove drive - keep image\n";
-
- print STDERR "\t--cdrom <file> is an alias for --ide2 <file>,media=cdrom\n";
-
- print STDERR "\n";
- print STDERR "\t--scsi<N> [volume=]volume,[,media=cdrom|disk]\n";
- print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
- print STDERR "\t [,snapshot=on|off][,format=f]\n";
- print STDERR "\t [,cache=none|writethrough|writeback]\n";
- print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
- print STDERR "\t--scsi<N> <GBYTES> create new disk\n";
- print STDERR "\t--scsi<N> delete remove drive - destroy image\n";
- print STDERR "\t--scsi<N> undef remove drive - keep image\n";
-
- print STDERR "\n";
- print STDERR "\t--virtio<N> [volume=]volume,[,media=cdrom|disk]\n";
- print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
- print STDERR "\t [,snapshot=on|off][,format=f]\n";
- print STDERR "\t [,cache=none|writethrough|writeback]\n";
- print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
- print STDERR "\t [,rerror=ignore|report|stop]\n";
- print STDERR "\t--virtio<N> <GBYTES> create new disk\n";
- print STDERR "\t--virtio<N> delete remove drive - destroy image\n";
- print STDERR "\t--virtio<N> undef remove drive - keep image\n";
-
- print STDERR "\n";
-
- print STDERR "qm monitor <vmid> connect to vm control monitor\n";
- print STDERR "qm start <vmid> start vm\n";
- print STDERR "qm shutdown <vmid> gracefully stop vm (send poweroff)\n";
- print STDERR "qm wait <vmid> [time] wait until vm is stopped\n";
- print STDERR "qm stop <vmid> kill vm (immediate stop)\n";
- print STDERR "qm reset <vmid> reset vm (stop, start)\n";
- print STDERR "qm suspend <vmid> suspend vm\n";
- print STDERR "qm resume <vmid> resume vm\n";
- print STDERR "qm cad <vmid> sendkey ctrl-alt-delete\n";
- print STDERR "qm destroy <vmid> destroy vm (delete all used/owned volumes)\n";
- print STDERR "qm unlock <vmid> clear migrate/backup lock\n";
- print STDERR "qm status <vmid> shows the container status\n";
-
- print STDERR "\n";
- print STDERR "qm cdrom <vmid> [<device>] <path> set cdrom path. <device is ide2 by default>\n";
- print STDERR "qm cdrom <vmid> [<device>] eject eject cdrom\n";
-
- print STDERR "\n";
- print STDERR "qm unlink <vmid> <volume> delete unused disk images\n";
-
- print STDERR "qm vncproxy <vmid> <ticket> open vnc proxy\n";
- print STDERR "qm vnc <vmid> start (X11) vncviewer (experimental)\n";
- print STDERR "qm showcmd <vmid> show command line (debug info)\n";
- print STDERR "qm list list all virtual machines\n";
-
- print STDERR "\n";
- print STDERR "qm startall start all virtual machines (when onboot=1)\n";
- print STDERR "qm stopall [timeout] stop all virtual machines (default timeout is 3 minutes)
-\n";
-
-}
-
-sub __next_vnc_port {
-
- for (my $p = 5900; $p < 6000; $p++) {
-
- my $sock = IO::Socket::INET->new (Listen => 5,
- LocalAddr => 'localhost',
- LocalPort => $p,
- ReuseAddr => 1,
- Proto => 0);
-
- if ($sock) {
- close ($sock);
- return $p;
- }
- }
-
- die "unable to find free vnc port";
-}
-
-sub run_vnc_proxy {
- my ($vmid) = @_;
-
- my $path = PVE::QemuServer::vnc_socket ($vmid);
-
- my $s = IO::Socket::UNIX->new (Peer => $path, Timeout => 120);
-
- die "unable to connect to socket '$path' - $!" if !$s;
-
- my $select = new IO::Select;
-
- $select->add (\*STDIN);
- $select->add ($s);
-
- my $timeout = 60*15; # 15 minutes
-
- my @handles;
- while ($select->count &&
- scalar (@handles = $select->can_read ($timeout))) {
- foreach my $h (@handles) {
- my $buf;
- my $n = $h->sysread ($buf, 4096);
-
- if ($h == \*STDIN) {
- if ($n) {
- syswrite ($s, $buf);
- } else {
- exit (0);
- }
- } elsif ($h == $s) {
- if ($n) {
- syswrite (\*STDOUT, $buf);
- } else {
- exit (0);
- }
- }
- }
- }
- exit (0);
-}
-
-
-if (scalar (@ARGV) == 0) {
- print_usage ();
- exit (-1);
-}
-
-my $cmd = shift @ARGV;
-
-my $skiplock;
-if ($cmd =~ m/^--?skiplock$/) {
- $skiplock = 1;
- $cmd = shift @ARGV;
-}
-
-my $shortcmds = {
- list => 1,
- startall => 1,
- stopall => 1,
- mtunnel => 1,
-};
-
-my $vmid;
-
-my @disks = PVE::QemuServer::disknames();
-
-my $qm = PVE::QemuServer->new();
-
-if (!defined ($shortcmds->{$cmd})) {
- if (scalar (@ARGV) == 0) {
- print_usage ("no <vmid>");
- exit (-1);
- }
- $vmid = shift @ARGV;
-
- if ($vmid !~ m/^\d+$/) {
- print_usage ("unable to parse <vmid>");
- exit (-1);
- }
-}
-
-sub add_random_macs {
- my ($settings) = @_;
-
- foreach my $opt (keys %$settings) {
- next if $opt !~ m/^vlan(\d+|u)$/;
- my $vlan = PVE::QemuServer::parse_vlan ($settings->{$opt});
- next if !$vlan;
- $settings->{$opt} = PVE::QemuServer::print_vlan ($vlan);
- }
-}
-
-sub create_disks {
- my ($storecfg, $vmid, $settings) = @_;
-
- my $vollist = [];
-
- eval {
- foreach my $ds (@disks) {
- next if !$settings->{$ds};
-
- my $disk = PVE::QemuServer::parse_drive ($ds, $settings->{$ds});
-
- next if PVE::QemuServer::drive_is_cdrom ($disk);
-
- my $file = $disk->{file};
-
- if ($file =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
- my $storeid = $2 || 'local';
- my $size = $3;
- my $defformat = PVE::Storage::storage_default_format ($storecfg, $storeid);
- my $fmt = $disk->{format} || $defformat;
- syslog ('info', "VM $vmid creating new disk - size is $size GB");
-
- my $volid = PVE::Storage::vdisk_alloc ($storecfg, $storeid, $vmid,
- $fmt, undef, $size*1024*1024);
-
- $disk->{file} = $volid;
- delete ($disk->{format}); # no longer needed
- push @$vollist, $volid;
- $settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
- } else {
- my $path;
- if ($disk->{file} =~ m|^/dev/.+|) {
- $path = $disk->{file};
- } else {
- $path = PVE::Storage::path ($storecfg, $disk->{file});
- }
- if (!(-f $path || -b $path)) {
- die "image '$path' does not exists\n";
- }
- }
- }
- };
-
- my $err = $@;
-
- if ($err) {
- syslog ('err', "VM $vmid create disk failed - $err");
- foreach my $volid (@$vollist) {
- PVE::Storage::vdisk_free ($storecfg, $volid);
- }
- die $err;
- }
-
- return $vollist;
-}
-
-if ($cmd eq 'set') {
-
- my $settings;
- if (!($settings = $qm->parse_options ($vmid, 0))) {
- exit (-1);
- }
-
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::lock_config ($vmid, sub {
-
- my $conf = PVE::QemuServer::load_config ($vmid);
-
- PVE::QemuServer::check_lock ($conf) if !$skiplock;
-
- my $unset = {};
- foreach my $opt (keys %$settings) {
- my $value = $settings->{$opt};
- next if !defined ($value);
- if ($value eq 'delete') {
- foreach my $ds (@disks) {
- next if $ds ne $opt;
- my $disk = $conf->{diskinfo}->{$opt};
- next if !$disk;
- if (!PVE::QemuServer::drive_is_cdrom ($disk)) {
- PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $disk->{file});
- }
- last;
- }
- $unset->{$opt} = 1;
- delete $settings->{$opt};
- } elsif ($value eq '' || $value eq 'undef') {
- $unset->{$opt} = 1;
- delete $settings->{$opt};
- }
- }
-
- add_random_macs ($settings);
-
- create_disks ($qm->{storecfg}, $vmid, $settings);
-
- PVE::QemuServer::change_config_nolock ($vmid, $settings, $unset, 1);
-
- });
-
- my $err = $@;
-
- die "setting parameters failed - $err" if $err;
-
- exit (0);
-
-} elsif ($cmd eq 'create') {
-
- my $vollist = [];
-
- my $filename = PVE::QemuServer::config_file ($vmid);
-
- my $settings;
-
- # first test (befor locking)
- die "unable to create vm $vmid: config file already exists\n"
- if -f $filename;
-
- if (!($settings = $qm->parse_options ($vmid, 1))) {
- exit (-1);
- }
-
- add_random_macs ($settings);
-
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- syslog ('info', "VM $vmid creating new virtual machine");
-
- PVE::QemuServer::lock_config ($vmid, sub {
-
- # second test (after locking test is accurate)
- die "unable to create vm $vmid: config file already exists\n"
- if -f $filename;
-
- $vollist = create_disks ($qm->{storecfg}, $vmid, $settings);
-
- # try to be smart about bootdisk
- my @disks = PVE::QemuServer::disknames();
- my $firstdisk;
- foreach my $ds (reverse @disks) {
- next if !$settings->{$ds};
- my $disk = PVE::QemuServer::parse_drive ($ds, $settings->{$ds});
- next if PVE::QemuServer::drive_is_cdrom ($disk);
- $firstdisk = $ds;
- }
-
- if (!$settings->{bootdisk} && $firstdisk) {
- $settings->{bootdisk} = $firstdisk;
- }
-
- PVE::QemuServer::create_conf_nolock ($vmid, $settings);
- });
-
- my $err = $@;
-
- if ($err) {
- syslog ('err', "VM $vmid create failed - $err");
- foreach my $volid (@$vollist) {
- eval { PVE::Storage::vdisk_free ($qm->{storecfg}, $volid); };
- warn $@ if $@;
- }
- die "create failed - $err";
- }
-
- exit (0);
-
-} elsif ($cmd eq 'unlink') {
-
- if (scalar (@ARGV) == 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::lock_config ($vmid, sub {
-
- my $conf = PVE::QemuServer::load_config ($vmid);
-
- PVE::QemuServer::check_lock ($conf) if !$skiplock;
-
- my $di = $conf->{diskinfo} || {};
-
- foreach my $file (@ARGV) {
- my $found;
- foreach my $ds (keys %$di) {
- if ($di->{$ds}->{file} eq $file) {
- $found = 1;
- last;
- }
- }
- die "disk image '$file' is used - unable to unlink\n" if $found;
-
- PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $file);
- }
- });
-
- die $@ if $@;
-
- exit 0;
-}
-
-if ($cmd eq 'monitor') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
-
- my $term = new Term::ReadLine ('qm');
-
- my $input;
- while (defined ($input = $term->readline('qm> '))) {
- chomp $input;
-
- next if $input =~ m/^\s*$/;
-
- if ($input =~ m/^\s*q(uit)?\s*$/) {
- exit (0);
- }
- eval {
- print PVE::QemuServer::vm_monitor_command ($vmid, $input);
- };
- print "ERROR: $@" if $@;
- }
-
-} elsif ($cmd eq 'showcmd') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- print vm_commandline ($qm->{storecfg}, $vmid) . "\n";
-
-} elsif ($cmd eq 'start') {
- my $statefile;
- if (scalar (@ARGV) == 2 && ($ARGV[0] =~ m/^\-\-?i(ncoming)?$/)) {
- $statefile = $ARGV[1];
- } elsif (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_start ($qm->{storecfg}, $vmid, $statefile, $skiplock);
-
-} elsif ($cmd eq 'startall') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- $qm->vm_startall_old ();
-
-} elsif ($cmd eq 'reset') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_reset ($vmid, $skiplock);
-
-} elsif ($cmd eq 'shutdown') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- vm_shutdown ($vmid, $skiplock);
-
-} elsif ($cmd eq 'wait') {
- my $timeout = shift || 0;
-
- if ($timeout !~ m/^\d+$/) {
- print_usage ("timeout must be numeric");
- exit (-1);
- }
-
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- $qm->vm_wait_old ($vmid, $timeout);
-
-} elsif ($cmd eq 'stopall') {
- my $timeout = shift || 0;
-
- if ($timeout !~ m/^\d+$/) {
- print_usage ("timeout must be numeric");
- exit (-1);
- }
-
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_stopall($timeout);
-
-} elsif ($cmd eq 'stop') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- vm_stop ($vmid, $skiplock);
-
-} elsif ($cmd eq 'destroy') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_destroy ($qm->{storecfg}, $vmid, $skiplock);
-
-} elsif ($cmd eq 'suspend') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_suspend ($vmid, $skiplock);
-
-} elsif ($cmd eq 'resume') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_resume ($vmid, $skiplock);
-
-} elsif ($cmd eq 'cad') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- PVE::QemuServer::vm_cad ($vmid, $skiplock);
-
-} elsif ($cmd eq 'vncticket') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- my $ticket = PVE::QemuServer::vm_vncticket ($vmid);
- print "TICKET:$ticket\n";
-
-} elsif ($cmd eq 'cdrom') {
-
- my ($device, $path);
-
- if (scalar (@ARGV) == 1) {
- $path = shift @ARGV;
- $device = 'ide2';
- } elsif (scalar (@ARGV) == 2) {
- my $dev;
- ($dev, $path) = @ARGV;
- foreach my $ds (@disks) {
- if (($ds eq $dev) || ("-$ds" eq $dev) || ("--$ds" eq $dev)) {
- $device = $ds;
- last;
- }
- }
- } else {
- print_usage ();
- exit (-1);
- }
-
- if (!$path || !$device) {
- print_usage ();
- exit (-1);
- }
-
- $path = 'none' if $path eq 'eject';
-
- if (!($path eq 'none' || $path eq 'cdrom')) {
-
- my ($vtype, $volid) = PVE::Storage::path_to_volume_id ($qm->{storecfg}, $path);
-
- if (!($vtype eq 'iso')) {
- die "path '$path' does not point to a valid cdrom image\n";
- }
-
- $path = $volid;
- }
-
- $qm->vm_cdrom ($vmid, $device, $path);
-
-} elsif ($cmd eq 'vncproxy') {
- my $ticket = shift @ARGV;
-
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- if ($ticket) {
- die "illegal characters in ticket\n" if $ticket =~ m/[^A-Za-z0-9\+\/]/;
- $qm->vm_vncticket ($vmid, $ticket);
- }
-
- run_vnc_proxy ($vmid, $ticket);
-
-} elsif ($cmd eq 'vnc') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- my $port = __next_vnc_port();
- my $display = $port - 5900;
-
- my $ticket = $qm->vm_vncticket ($vmid);
- $ticket = substr ($ticket, 0, 8);
- my $mpf = "/tmp/.qmvncpw$$";
-
- $vnccmd =~ s/__TICKET__/$ticket/g;
- $vnccmd =~ s/__TMPFILE__/$mpf/g;
- $vnccmd =~ s/__DISPLAY__/$display/g;
- $vnccmd =~ s/__PORT__/$port/g;
-
- system ("$vnccmd &");
- system ("nc -l -p $port -c 'qm vncproxy $vmid'");
- unlink $mpf;
-
-} elsif ($cmd eq 'list') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- my $vzlist = PVE::QemuServer::vzlist();
-
- exit 0 if (!scalar(keys %$vzlist));
-
- printf "%10s %-20s %-10s %-10s %12s %-10s\n",
- qw(VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID);
-
- foreach my $vmid (sort keys %$vzlist) {
- my $conf = PVE::QemuServer::load_config ($vmid);
- my $name = $conf->{name} || '-';
-
- my $status = $vzlist->{$vmid}->{pid} ? 'running' : 'stopped';
- my $pid = $vzlist->{$vmid}->{pid} || 0;
- printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $vmid, $name, $status,
- $conf->{memory}||0, $conf->{disksize}||0, $pid;
- }
-
-} elsif ($cmd eq 'unlock') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
- PVE::QemuServer::lock_config ($vmid, sub {
- PVE::QemuServer::change_config_nolock ($vmid, {}, { lock => 1 }, 1);
- });
-
- die $@ if $@;
-
-} elsif ($cmd eq 'status') {
- if (scalar (@ARGV) != 0) {
- print_usage ();
- exit (-1);
- }
-
- my $status = 'unknown';
-
- eval {
- if (PVE::QemuServer::check_running($vmid)) {
- $status = 'running';
- } else {
- $status = 'stopped';
- }
- };
-
- print "$status\n";
-
-} elsif ($cmd eq 'mtunnel') {
-
- print "tunnel online\n";
- *STDOUT->flush();
-
- while (my $line = <>) {
- chomp $line;
- last if $line =~ m/^quit$/;
- }
-
- exit (0);
-
-} else {
- print_usage ();
- exit (-1);
-}
-
-exit (0);
-
-__END__
-
-=head1 NAME
-
-qm - qemu/kvm manager
-
-=head1 SYNOPSIS
-
-qm [--skiplock] <command> <vmid> [OPTIONS]
-
-type qm to see a list of valid commands
-
-=head1 DESCRIPTION
-
-qm is a script to manage virtual machines with qemu/kvm. You can
-create and destroy virtual machines, and control execution
-(start/stop/suspend/resume). Besides that, you can use qm to set
-parameters in the associated config file. It is also possible to
-create and delete virtual disks.
-
-=head1 CONFIGURATION
-
-Global server configuration is stored in /etc/pve/qemu-server.cfg.
-
-All configuration files consists of lines in the form
-
- PARAMETER: value
-
-The following defaults can be specified:
-
-=over 1
-
-=item keyboard: XX
-
-Keybord layout used for vnc server (for example C<fr> for French)
-
-=item onboot: (yes|no)
-
-Specifies whether a VM will be started during system bootup.
-Default is no, meaning the VM will not be started if ONBOOT
-parameter is omitted.
-
-=item autostart: (yes|no)
-
-Automatic restart after crash. Default is no. This value is
-currently ignored (because we have no monitor).
-
-=item memory: num
-
-Amount of RAM for the VM in MB. Default value is 512.
-
-=item cpuunits: num
-
-CPU weight for a VM. Argument is positive non-zero number, passed to
-and used in the kernel fair scheduler. The larger the number is,
-the more CPU time this VM gets. Maximum value is 500000, minimal
-is 8. Number is relative to weights of all the other running VMs.
-If cpuunits are not specified, default value of 1000 is used.
-
-NOTE: You can disable fair-scheduler configuration by setting this to 0.
-
-=item vga: (std|cirrus)
-
-Select VGA type. Default is a Cirrus Logic GD5446 PCI VGA card (cirrus).
-If you want to use high resolution modes (>= 1280x1024x16) then you should
-use option C<std>.
-
-=item tdf: (yes|no)
-
-enable/disable time drift fix [default=yes]
-
-=item tablet: (yes|no)
-
-enable/disable the usb tablet device [default=yes]. This device is usually
-needed to allow absolute mouse positioning. Else the mouse runs out of
-sync with normal vnc clients. If you're running lots of console-only guests
-on one host, you may consider setting "tablet: no" to save some context switches.
-
-=item migrate_downtime: num
-
-set maximum tolerated downtime (in seconds) for migrations. [default=1]
-
-=item migrate_speed: num
-
-set maximum speed (in MB/s) for migrations. [default=0 (no limit)]
-
-=back
-
-=head1 VM CONFIGURATION
-
-Each VM is identified by an unique ID (integer). Configuration for
-a VM is stored at C</etc/qemu-server/ID.conf>
-
-Currently, the following parameters are supported:
-
-=over 1
-
-=item keyboard: XX
-
-Default is read from global configuration file.
-
-=item onboot: (yes|no)
-
-Default is read from global configuration file.
-
-=item autostart: (yes|no)
-
-Default is read from global configuration file.
-
-=item memory: num
-
-Default is read from global configuration file.
-
-=item cpuunits: num
-
-Default is read from global configuration file.
-
-=item migrate_downtime: num
-
-Default is read from global configuration file.
-
-=item migrate_speed: num
-
-Default is read from global configuration file.
-
-=item reboot: (yes|no)
-
-Exit instead of rebooting.
-
-=item name: text
-
-Set a name for the VM. Only used on the configuration
-web interface.
-
-=item description: text
-
-Description for the VM. Only used on the configuration
-web interface.
-
-=item boot: [a|c|d|n]
-
-boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)
-
-default is C<cad> (disk, floppy, cdrom)
-
-=item bootdisk: <disk>
-
-enable booting from <disk>
-
-<disk> = <ide0|ide1|ide2|ide3|scsi0|scsi1|scsi2|...
-
-=item smp: num (please use C<sockets> instead)
-
-set the number of CPUs to C<num> [default=1]
-
-=item sockets: num
-
-set the number of CPU sockets to C<num> [default=1]
-
-=item cores: num
-
-set the number of cores per socket to C<num> [default=1]
-
-=item acpi: (yes|no)
-
-enable/disable ACPI [default=yes]
-
-=item kvm: (yes|no)
-
-enable/disable KVM hardware virtualization [default=yes]
-
-=item tdf: (yes|no)
-
-Default is read from global configuration file.
-
-=item tablet: (yes|no)
-
-Default is read from global configuration file.
-
-=item localtime: (yes|no)
-
-set the real time clock to local time
-
-=item startdate: (now|YYYY-MM-DD|YYYY-MM-DDTHH-MM-SS)
-
-Set the initial date of the real time clock. Valid format
-for date are: C<now> or C<2006-06-17T16:01:21> or C<2006-06-17>.
-The default value is C<now>.
-
-=item freeze: (yes|no)
-
-freeze CPU at startup (use C<c> monitor command to start execution)
-
-=item vlan0: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
-
-Specify network devices connected to vlan0. Currently, vlan0 is
-connected to vmbr0.
-
-MODEL is one of: ne2k_pci e1000 rtl8139 pcnet virtio
-ne2k_isa i82551 i82557b i82559er
-
-XX:XX:XX:XX:XX:XX should be an unique MAC address
-
-=item vlan[1-4094]: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
-
-Same as vlan0, but vlanX is bridged to vmbrX
-
-=item vlanu: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
-
-Same as vlan0, but vlanu uses user mode network stack (NAT).
-Provides DHCP and DNS services. The following addresses are used:
-
- 10.0.2.2 Gateway
- 10.0.2.3 DNS Server
- 10.0.2.4 SMB Server
-
-The DHCP server assign addresses to the hosts starting from 10.0.2.15.
-
-=item ostype: (other|wxp|w2k|w2k3|w2k8|wvista|l24|l26)
-
-Used to enable special optimization/features for specific
-operating systems:
-
- other => unspecified OS
- wxp => Microsoft Windows XP
- w2k => Microsoft Windows 2000
- w2k3 => Microsoft Windows 2003
- w2k8 => Microsoft Windows 2008
- wvista => Microsoft Windows Vista
- l24 => Linux 2.4 Kernel
- l26 => Linux 2.6 Kernel
-
- other|l24|l26 ... no special behaviour
- wxp|w2k|w2k3|w2k8|wvista ... use --localtime switch
-
-=item vga: (std|cirrus)
-
-Default is read from global configuration file.
-
-=item ide0 - ide3: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
-
-Use volume as IDE hard disk or CD-ROM.
-
-=item scsi0 - scsi15: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
-
-Use volume as SCSI hard disk or CD-ROM.
-
-=item virtio0 - virtio15: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
-
-Use file as VIRTIO hard disk.
-
-=item hostpci: [HOSTPCIDEVICE][,HOSTPCIDEVICE]*
-
-Map host pci devices. HOSTPCIDEVICE syntax is:
-
-C<bus:dev.func> (hexadecimal numbers)
-
-You can us the C<lspci> command to list existing pci devices.
-
-Note: This option allows direct access to host hardware. So it is no
-longer possible to migrate such machines - use with special care.
-
-Experimental: user reported problems with this option
-
-=item hostusb: [HOSTUSBDEVICE][,HOSTUSBDEVICE]*
-
-Map host usb devices. HOSTUSBDEVICE syntax is:
-
-C<bus.addr> (decimal numbers) or C<vendor_id:product_id> (hexadeciaml numbers)
-
-You can us the C<lsusb> command to list existing usb devices (or take a
-look at C</proc/bus/usb/devices>).
-
-Note: This option allows direct access to host hardware. So it is no
-longer possible to migrate such machines - use with special care.
-
-=item serial: [SERIALDEVICE][,SERIALDEVICE]*
-
-Experimental: user reported problems with this option
-
-Map host serial devices. SERIALDEVICE syntax is /dev/ttyS*
-
-Note: This option allows direct access to host hardware. So it is no
-longer possible to migrate such machines - use with special care.
-
-=item parallel: [PARALLELDEVICE][,PARALLELDEVICE]*
-
-Experimental: user reported problems with this option
-
-Map host parallel devices. PARALLELDEVICE syntax is /dev/parport*
-
-Note: This option allows direct access to host hardware. So it is no
-longer possible to migrate such machines - use with special care.
-
-=item args: ...
-
-Note: this option is for experts only. It allows you to pass arbitrary
-arguments to kvm, for example:
-
- args: -no-reboot -no-hpet
-
-=item lock: (migrate|backup)
-
-This value is set during online migration (migrate) and vzdump
-(backup).
-
-=back
-
-=head1 Locks
-
-Online migration and backups (vzdump) set a lock to prevent
-unintentional action on such VMs. Sometimes you need remove such lock
-manually (power failure).
-
- qm unlock <vmid>
-
-=head1 EXAMPLES
-
-# create a new VM with 4 GB ide disk
-
-qm create 300 -ide0 4 -vlan0 e1000 -cdrom proxmox-mailgateway_2.1.iso
-
-# start the new VM
-
-qm start 300
-
-# send shutdown, then wait until VM is stopped
-
-qm shutdown 300 && qm wait 300
-
-# same as above, but only wait for 40 seconds
-
-qm shutdown 300 && qm wait 300 40
-
-
-
-
-
-
-
Copied: qemu-server/pve2/qm (from rev 5165, qemu-server/pve2/nqm)
===================================================================
--- qemu-server/pve2/qm (rev 0)
+++ qemu-server/pve2/qm 2010-09-16 13:21:10 UTC (rev 5166)
@@ -0,0 +1,447 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Long;
+use Fcntl ':flock';
+use File::Path;
+use IO::Socket::UNIX;
+use IO::Select;
+
+use PVE::INotify qw(read_file);
+use PVE::RPCEnvironment;
+use PVE::QemuServer;
+use PVE::API2::Qemu::Config;
+use PVE::API2::Qemu::Status;
+use PVE::JSONSchema qw(get_standard_option);
+use Term::ReadLine;
+
+use PVE::CLIHandler;
+
+use base qw(PVE::CLIHandler);
+
+$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
+
+die "please run as root\n" if $> != 0;
+
+PVE::INotify::inotify_init();
+
+my $rpcenv = PVE::RPCEnvironment->init('cli');
+
+$rpcenv->set_language($ENV{LANG});
+
+$rpcenv->set_user('root');
+
+my $hostname = $rpcenv->get_hostname();
+
+sub run_vnc_proxy {
+ my ($vmid) = @_;
+
+ my $path = PVE::QemuServer::vnc_socket ($vmid);
+
+ my $s = IO::Socket::UNIX->new (Peer => $path, Timeout => 120);
+
+ die "unable to connect to socket '$path' - $!" if !$s;
+
+ my $select = new IO::Select;
+
+ $select->add (\*STDIN);
+ $select->add ($s);
+
+ my $timeout = 60*15; # 15 minutes
+
+ my @handles;
+ while ($select->count &&
+ scalar (@handles = $select->can_read ($timeout))) {
+ foreach my $h (@handles) {
+ my $buf;
+ my $n = $h->sysread ($buf, 4096);
+
+ if ($h == \*STDIN) {
+ if ($n) {
+ syswrite ($s, $buf);
+ } else {
+ exit (0);
+ }
+ } elsif ($h == $s) {
+ if ($n) {
+ syswrite (\*STDOUT, $buf);
+ } else {
+ exit (0);
+ }
+ }
+ }
+ }
+ exit (0);
+}
+
+__PACKAGE__->register_method ({
+ name => 'showcmd',
+ path => 'showcmd',
+ method => 'GET',
+ description => "Show command line which is used to start the VM (debug info).",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $storecfg = read_file('storagecfg');
+ print PVE::QemuServer::vm_commandline ($storecfg, $param->{vmid}) . "\n";
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'status',
+ path => 'status',
+ method => 'GET',
+ description => "Show VM status.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $status = 'unknown';
+
+ eval {
+ if (PVE::QemuServer::check_running($param->{vmid})) {
+ $status = 'running';
+ } else {
+ $status = 'stopped';
+ }
+ };
+
+ print "$status\n";
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'vncticket',
+ path => 'vncticket',
+ method => 'PUT',
+ description => "Create and set a VNC authentication ticket.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+
+ my $ticket = PVE::QemuServer::vm_vncticket ($vmid);
+ print "TICKET:$ticket\n";
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'vncproxy',
+ path => 'vncproxy',
+ method => 'PUT',
+ description => "Proxy VM VNC traffic to stdin/stdout",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ ticket => get_standard_option('pve-vncticket', { optional => 1 }),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+ my $ticket = $param->{ticket};
+
+ if ($ticket) {
+ PVE::QemuServer::vm_vncticket ($vmid, $ticket);
+ }
+
+ run_vnc_proxy ($vmid, $ticket);
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'unlock',
+ path => 'unlock',
+ method => 'PUT',
+ description => "Unlock the VM.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+
+ PVE::QemuServer::lock_config ($vmid, sub {
+ PVE::QemuServer::change_config_nolock ($vmid, {}, { lock => 1 }, 1);
+ });
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'mtunnel',
+ path => 'mtunnel',
+ method => 'POST',
+ description => "Used by vzmigrate - do not use manually.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {},
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ print "tunnel online\n";
+ *STDOUT->flush();
+
+ while (my $line = <>) {
+ chomp $line;
+ last if $line =~ m/^quit$/;
+ }
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'startall',
+ path => 'startall',
+ method => 'POST',
+ description => "Start all virtual machines (when onboot=1).",
+ parameters => {
+ additionalProperties => 0,
+ properties => {},
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vzlist = PVE::QemuServer::vzlist();
+ my $storecfg = read_file('storagecfg');
+
+ foreach my $vmid (keys %$vzlist) {
+ next if $vzlist->{$vmid}->{pid}; # already running
+
+ eval {
+ my $conf = PVE::QemuServer::load_config ($vmid);
+ if ($conf->{onboot}) {
+ print STDERR "Starting Qemu VM $vmid\n";
+ vm_start ($storecfg, $vmid);
+ }
+ };
+ print STDERR $@ if $@;
+ }
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'stopall',
+ path => 'stopall',
+ method => 'POST',
+ description => "Stop all virtual machines.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ timeout => {
+ description => "Timeout in seconds. Default is to wait 3 minutes.",
+ type => 'integer',
+ minimum => 1,
+ optional => 1,
+ }
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $timeout = $param->{timeout};
+
+ PVE::QemuServer::vm_stopall($timeout);
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'wait',
+ path => 'wait',
+ method => 'GET',
+ description => "Wait until the VM is stopped.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ timeout => {
+ description => "Timeout in seconds. Default is to wait forever.",
+ type => 'integer',
+ minimum => 1,
+ optional => 1,
+ }
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+ my $timeout = $param->{timeout};
+
+ my $pid = PVE::QemuServer::check_running ($vmid);
+ return if !$pid;
+
+ print "waiting until VM $vmid stopps (PID $pid)\n";
+
+ my $count = 0;
+ while ((!$timeout || ($count < $timeout)) && PVE::QemuServer::check_running ($vmid)) {
+ $count++;
+ sleep 1;
+ }
+
+ die "wait failed - got timeout\n" if PVE::QemuServer::check_running ($vmid);
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'monitor',
+ path => 'monitor',
+ method => 'POST',
+ description => "Enter Qemu Monitor interface.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ vmid => get_standard_option('pve-vmid'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+
+ my $conf = PVE::QemuServer::load_config ($vmid); # check if VM exists
+
+ print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
+
+ my $term = new Term::ReadLine ('qm');
+
+ my $input;
+ while (defined ($input = $term->readline('qm> '))) {
+ chomp $input;
+
+ next if $input =~ m/^\s*$/;
+
+ last if $input =~ m/^\s*q(uit)?\s*$/;
+
+ eval {
+ print PVE::QemuServer::vm_monitor_command ($vmid, $input);
+ };
+ print "ERROR: $@" if $@;
+ }
+
+ return undef;
+
+ }});
+
+# fixme: unlink
+
+my $cmddef = {
+ list => [ "PVE::API2::Qemu::Config", 'vmlist', [],
+ { node => $hostname }, sub {
+ my $vmlist = shift;
+
+ exit 0 if (!scalar(@$vmlist));
+
+ printf "%10s %-20s %-10s %-10s %12s %-10s\n",
+ qw(VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID);
+
+ foreach my $rec (sort { $a->{vmid} <=> $b->{vmid} } @$vmlist) {
+ printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $rec->{vmid}, $rec->{name},
+ $rec->{status}, $rec->{maxmem}, $rec->{maxdisk}||0, $rec->{pid}||0;
+ }
+
+
+ } ],
+
+ create => [ "PVE::API2::Qemu::Config", 'create_vm', ['vmid'], { node => $hostname } ],
+
+ destroy => [ "PVE::API2::Qemu::Config", 'destroy_vm', ['vmid'], { node => $hostname } ],
+
+ set => [ "PVE::API2::Qemu::Config", 'update_vm', ['vmid'], { node => $hostname } ],
+
+ config => [ "PVE::API2::Qemu::Config", 'vm_config', ['vmid'],
+ { node => $hostname }, sub {
+ my $config = shift;
+ foreach my $k (sort (keys %$config)) {
+ my $v = $config->{$k};
+ print "$k: $v\n";
+ }
+ }],
+
+ showcmd => [ __PACKAGE__, 'showcmd', ['vmid']],
+
+ status => [ __PACKAGE__, 'status', ['vmid']],
+
+ vncticket => [ __PACKAGE__, 'vncticket', ['vmid']],
+
+ vncproxy => [ __PACKAGE__, 'vncproxy', ['vmid', 'ticket']],
+
+ wait => [ __PACKAGE__, 'wait', ['vmid']],
+
+ unlock => [ __PACKAGE__, 'unlock', ['vmid']],
+
+ monitor => [ __PACKAGE__, 'monitor', ['vmid']],
+
+ startall => [ __PACKAGE__, 'startall', []],
+
+ stopall => [ __PACKAGE__, 'stopall', []],
+
+ mtunnel => [ __PACKAGE__, 'mtunnel', []],
+
+
+ start => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'start' } ],
+ stop => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'stop' } ],
+ reset => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'reset' } ],
+ suspend => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'suspend' } ],
+ resume => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'resume' } ],
+ cad => [ "PVE::API2::Qemu::Status", 'vm_command', ['vmid'],
+ { node => $hostname, command => 'cad' } ],
+
+};
+
+my $cmd = shift;
+
+if ($cmd && $cmd eq 'verifyapi') {
+ PVE::RESTHandler::validate_method_schemas();
+ exit 0;
+}
+
+PVE::CLIHandler::handle_cmd($cmddef, "qm", $cmd, \@ARGV);
+
+exit 0;
Copied: qemu-server/pve2/qm.old (from rev 5165, qemu-server/pve2/qm)
===================================================================
--- qemu-server/pve2/qm.old (rev 0)
+++ qemu-server/pve2/qm.old 2010-09-16 13:21:10 UTC (rev 5166)
@@ -0,0 +1,1073 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Term::ReadLine;
+use PVE::QemuServer;
+use IO::Socket::INET;
+use File::Path;
+use Sys::Syslog;
+use PVE::Storage;
+
+# VNC proxy example:
+# nc -l -p 5900 -w 20 -c "/usr/sbin/qm vncproxy 200 <ticket>"
+# where ticket(password) is an arbitrary string containing
+# [A-Za-z0-9\+\/] (base64 charset)
+# simple vncproxy example: nc -l -p 5900 -c "qm vncproxy 200 test"
+
+
+# command used by the vnc option
+my $vnccmd = "echo -e '__TICKET__\\n__TICKET__' |vncpasswd __TMPFILE__;vncviewer localhost:__DISPLAY__ -passwd __TMPFILE__";
+
+openlog ('qm', 'cons,pid', 'daemon');
+
+sub print_usage {
+ my ($msg) = @_;
+
+ if ($msg) {
+ print STDERR "ERROR: $msg\n";
+ }
+ print STDERR "qm <command> <vmid> [OPTIONS]\n";
+ print STDERR "qm [create|set] <vmid>\n";
+ print STDERR "\t--memory <MBYTES> memory in MB (64 - 8192)\n";
+ print STDERR "\t--sockets <N> set number of CPU sockets <N>\n";
+ print STDERR "\t--cores <N> set cores per socket to <N>\n";
+ print STDERR "\t--ostype NAME specify OS type\n";
+ print STDERR "\t--onboot [yes|no] start at boot\n";
+ print STDERR "\t--keyboard XX set vnc keyboard layout\n";
+ print STDERR "\t--cpuunits <num> CPU weight for a VM\n";
+ print STDERR "\t--name <text> set a name for the VM\n";
+ print STDERR "\t--description <text> set VM description\n";
+ print STDERR "\t--boot [a|c|d|n] specify boot order\n";
+ print STDERR "\t--bootdisk <disk> enable booting from <disk>\n";
+ print STDERR "\t--acpi (yes|no) enable/disable ACPI\n";
+ print STDERR "\t--kvm (yes|no) enable/disable KVM\n";
+ print STDERR "\t--tdf (yes|no) enable/disable time drift fix\n";
+ print STDERR "\t--localtime (yes|no) set the RTC to local time\n";
+ print STDERR "\t--vga (gd5446|vesa) specify VGA type\n";
+
+ print STDERR "\n";
+ print STDERR "\t--vlan[0-9u] MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]\n";
+
+ print STDERR "\n";
+ print STDERR "\t--ide<N> [volume=]volume,[,media=cdrom|disk]\n";
+ print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
+ print STDERR "\t [,cache=none|writethrough|writeback]\n";
+ print STDERR "\t [,snapshot=on|off][,cache=on|off][,format=f]\n";
+ print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
+ print STDERR "\t [,rerror=ignore|report|stop]\n";
+ print STDERR "\t--ide<N> <GBYTES> create new disk\n";
+ print STDERR "\t--ide<N> delete remove drive - destroy image\n";
+ print STDERR "\t--ide<N> undef remove drive - keep image\n";
+
+ print STDERR "\t--cdrom <file> is an alias for --ide2 <file>,media=cdrom\n";
+
+ print STDERR "\n";
+ print STDERR "\t--scsi<N> [volume=]volume,[,media=cdrom|disk]\n";
+ print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
+ print STDERR "\t [,snapshot=on|off][,format=f]\n";
+ print STDERR "\t [,cache=none|writethrough|writeback]\n";
+ print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
+ print STDERR "\t--scsi<N> <GBYTES> create new disk\n";
+ print STDERR "\t--scsi<N> delete remove drive - destroy image\n";
+ print STDERR "\t--scsi<N> undef remove drive - keep image\n";
+
+ print STDERR "\n";
+ print STDERR "\t--virtio<N> [volume=]volume,[,media=cdrom|disk]\n";
+ print STDERR "\t [,cyls=c,heads=h,secs=s[,trans=t]]\n";
+ print STDERR "\t [,snapshot=on|off][,format=f]\n";
+ print STDERR "\t [,cache=none|writethrough|writeback]\n";
+ print STDERR "\t [,werror=enospc|ignore|report|stop]\n";
+ print STDERR "\t [,rerror=ignore|report|stop]\n";
+ print STDERR "\t--virtio<N> <GBYTES> create new disk\n";
+ print STDERR "\t--virtio<N> delete remove drive - destroy image\n";
+ print STDERR "\t--virtio<N> undef remove drive - keep image\n";
+
+ print STDERR "\n";
+
+ print STDERR "qm monitor <vmid> connect to vm control monitor\n";
+ print STDERR "qm start <vmid> start vm\n";
+ print STDERR "qm shutdown <vmid> gracefully stop vm (send poweroff)\n";
+ print STDERR "qm wait <vmid> [time] wait until vm is stopped\n";
+ print STDERR "qm stop <vmid> kill vm (immediate stop)\n";
+ print STDERR "qm reset <vmid> reset vm (stop, start)\n";
+ print STDERR "qm suspend <vmid> suspend vm\n";
+ print STDERR "qm resume <vmid> resume vm\n";
+ print STDERR "qm cad <vmid> sendkey ctrl-alt-delete\n";
+ print STDERR "qm destroy <vmid> destroy vm (delete all used/owned volumes)\n";
+ print STDERR "qm unlock <vmid> clear migrate/backup lock\n";
+ print STDERR "qm status <vmid> shows the container status\n";
+
+ print STDERR "\n";
+ print STDERR "qm cdrom <vmid> [<device>] <path> set cdrom path. <device is ide2 by default>\n";
+ print STDERR "qm cdrom <vmid> [<device>] eject eject cdrom\n";
+
+ print STDERR "\n";
+ print STDERR "qm unlink <vmid> <volume> delete unused disk images\n";
+
+ print STDERR "qm vncproxy <vmid> <ticket> open vnc proxy\n";
+ print STDERR "qm vnc <vmid> start (X11) vncviewer (experimental)\n";
+ print STDERR "qm showcmd <vmid> show command line (debug info)\n";
+ print STDERR "qm list list all virtual machines\n";
+
+ print STDERR "\n";
+ print STDERR "qm startall start all virtual machines (when onboot=1)\n";
+ print STDERR "qm stopall [timeout] stop all virtual machines (default timeout is 3 minutes)
+\n";
+
+}
+
+sub __next_vnc_port {
+
+ for (my $p = 5900; $p < 6000; $p++) {
+
+ my $sock = IO::Socket::INET->new (Listen => 5,
+ LocalAddr => 'localhost',
+ LocalPort => $p,
+ ReuseAddr => 1,
+ Proto => 0);
+
+ if ($sock) {
+ close ($sock);
+ return $p;
+ }
+ }
+
+ die "unable to find free vnc port";
+}
+
+sub run_vnc_proxy {
+ my ($vmid) = @_;
+
+ my $path = PVE::QemuServer::vnc_socket ($vmid);
+
+ my $s = IO::Socket::UNIX->new (Peer => $path, Timeout => 120);
+
+ die "unable to connect to socket '$path' - $!" if !$s;
+
+ my $select = new IO::Select;
+
+ $select->add (\*STDIN);
+ $select->add ($s);
+
+ my $timeout = 60*15; # 15 minutes
+
+ my @handles;
+ while ($select->count &&
+ scalar (@handles = $select->can_read ($timeout))) {
+ foreach my $h (@handles) {
+ my $buf;
+ my $n = $h->sysread ($buf, 4096);
+
+ if ($h == \*STDIN) {
+ if ($n) {
+ syswrite ($s, $buf);
+ } else {
+ exit (0);
+ }
+ } elsif ($h == $s) {
+ if ($n) {
+ syswrite (\*STDOUT, $buf);
+ } else {
+ exit (0);
+ }
+ }
+ }
+ }
+ exit (0);
+}
+
+
+if (scalar (@ARGV) == 0) {
+ print_usage ();
+ exit (-1);
+}
+
+my $cmd = shift @ARGV;
+
+my $skiplock;
+if ($cmd =~ m/^--?skiplock$/) {
+ $skiplock = 1;
+ $cmd = shift @ARGV;
+}
+
+my $shortcmds = {
+ list => 1,
+ startall => 1,
+ stopall => 1,
+ mtunnel => 1,
+};
+
+my $vmid;
+
+my @disks = PVE::QemuServer::disknames();
+
+my $qm = PVE::QemuServer->new();
+
+if (!defined ($shortcmds->{$cmd})) {
+ if (scalar (@ARGV) == 0) {
+ print_usage ("no <vmid>");
+ exit (-1);
+ }
+ $vmid = shift @ARGV;
+
+ if ($vmid !~ m/^\d+$/) {
+ print_usage ("unable to parse <vmid>");
+ exit (-1);
+ }
+}
+
+sub add_random_macs {
+ my ($settings) = @_;
+
+ foreach my $opt (keys %$settings) {
+ next if $opt !~ m/^vlan(\d+|u)$/;
+ my $vlan = PVE::QemuServer::parse_vlan ($settings->{$opt});
+ next if !$vlan;
+ $settings->{$opt} = PVE::QemuServer::print_vlan ($vlan);
+ }
+}
+
+sub create_disks {
+ my ($storecfg, $vmid, $settings) = @_;
+
+ my $vollist = [];
+
+ eval {
+ foreach my $ds (@disks) {
+ next if !$settings->{$ds};
+
+ my $disk = PVE::QemuServer::parse_drive ($ds, $settings->{$ds});
+
+ next if PVE::QemuServer::drive_is_cdrom ($disk);
+
+ my $file = $disk->{file};
+
+ if ($file =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
+ my $storeid = $2 || 'local';
+ my $size = $3;
+ my $defformat = PVE::Storage::storage_default_format ($storecfg, $storeid);
+ my $fmt = $disk->{format} || $defformat;
+ syslog ('info', "VM $vmid creating new disk - size is $size GB");
+
+ my $volid = PVE::Storage::vdisk_alloc ($storecfg, $storeid, $vmid,
+ $fmt, undef, $size*1024*1024);
+
+ $disk->{file} = $volid;
+ delete ($disk->{format}); # no longer needed
+ push @$vollist, $volid;
+ $settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
+ } else {
+ my $path;
+ if ($disk->{file} =~ m|^/dev/.+|) {
+ $path = $disk->{file};
+ } else {
+ $path = PVE::Storage::path ($storecfg, $disk->{file});
+ }
+ if (!(-f $path || -b $path)) {
+ die "image '$path' does not exists\n";
+ }
+ }
+ }
+ };
+
+ my $err = $@;
+
+ if ($err) {
+ syslog ('err', "VM $vmid create disk failed - $err");
+ foreach my $volid (@$vollist) {
+ PVE::Storage::vdisk_free ($storecfg, $volid);
+ }
+ die $err;
+ }
+
+ return $vollist;
+}
+
+if ($cmd eq 'set') {
+
+ my $settings;
+ if (!($settings = $qm->parse_options ($vmid, 0))) {
+ exit (-1);
+ }
+
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::lock_config ($vmid, sub {
+
+ my $conf = PVE::QemuServer::load_config ($vmid);
+
+ PVE::QemuServer::check_lock ($conf) if !$skiplock;
+
+ my $unset = {};
+ foreach my $opt (keys %$settings) {
+ my $value = $settings->{$opt};
+ next if !defined ($value);
+ if ($value eq 'delete') {
+ foreach my $ds (@disks) {
+ next if $ds ne $opt;
+ my $disk = $conf->{diskinfo}->{$opt};
+ next if !$disk;
+ if (!PVE::QemuServer::drive_is_cdrom ($disk)) {
+ PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $disk->{file});
+ }
+ last;
+ }
+ $unset->{$opt} = 1;
+ delete $settings->{$opt};
+ } elsif ($value eq '' || $value eq 'undef') {
+ $unset->{$opt} = 1;
+ delete $settings->{$opt};
+ }
+ }
+
+ add_random_macs ($settings);
+
+ create_disks ($qm->{storecfg}, $vmid, $settings);
+
+ PVE::QemuServer::change_config_nolock ($vmid, $settings, $unset, 1);
+
+ });
+
+ my $err = $@;
+
+ die "setting parameters failed - $err" if $err;
+
+ exit (0);
+
+} elsif ($cmd eq 'create') {
+
+ my $vollist = [];
+
+ my $filename = PVE::QemuServer::config_file ($vmid);
+
+ my $settings;
+
+ # first test (befor locking)
+ die "unable to create vm $vmid: config file already exists\n"
+ if -f $filename;
+
+ if (!($settings = $qm->parse_options ($vmid, 1))) {
+ exit (-1);
+ }
+
+ add_random_macs ($settings);
+
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ syslog ('info', "VM $vmid creating new virtual machine");
+
+ PVE::QemuServer::lock_config ($vmid, sub {
+
+ # second test (after locking test is accurate)
+ die "unable to create vm $vmid: config file already exists\n"
+ if -f $filename;
+
+ $vollist = create_disks ($qm->{storecfg}, $vmid, $settings);
+
+ # try to be smart about bootdisk
+ my @disks = PVE::QemuServer::disknames();
+ my $firstdisk;
+ foreach my $ds (reverse @disks) {
+ next if !$settings->{$ds};
+ my $disk = PVE::QemuServer::parse_drive ($ds, $settings->{$ds});
+ next if PVE::QemuServer::drive_is_cdrom ($disk);
+ $firstdisk = $ds;
+ }
+
+ if (!$settings->{bootdisk} && $firstdisk) {
+ $settings->{bootdisk} = $firstdisk;
+ }
+
+ PVE::QemuServer::create_conf_nolock ($vmid, $settings);
+ });
+
+ my $err = $@;
+
+ if ($err) {
+ syslog ('err', "VM $vmid create failed - $err");
+ foreach my $volid (@$vollist) {
+ eval { PVE::Storage::vdisk_free ($qm->{storecfg}, $volid); };
+ warn $@ if $@;
+ }
+ die "create failed - $err";
+ }
+
+ exit (0);
+
+} elsif ($cmd eq 'unlink') {
+
+ if (scalar (@ARGV) == 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::lock_config ($vmid, sub {
+
+ my $conf = PVE::QemuServer::load_config ($vmid);
+
+ PVE::QemuServer::check_lock ($conf) if !$skiplock;
+
+ my $di = $conf->{diskinfo} || {};
+
+ foreach my $file (@ARGV) {
+ my $found;
+ foreach my $ds (keys %$di) {
+ if ($di->{$ds}->{file} eq $file) {
+ $found = 1;
+ last;
+ }
+ }
+ die "disk image '$file' is used - unable to unlink\n" if $found;
+
+ PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $file);
+ }
+ });
+
+ die $@ if $@;
+
+ exit 0;
+}
+
+if ($cmd eq 'monitor') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ print "Entering Qemu Monitor for VM $vmid - type 'help' for help\n";
+
+ my $term = new Term::ReadLine ('qm');
+
+ my $input;
+ while (defined ($input = $term->readline('qm> '))) {
+ chomp $input;
+
+ next if $input =~ m/^\s*$/;
+
+ if ($input =~ m/^\s*q(uit)?\s*$/) {
+ exit (0);
+ }
+ eval {
+ print PVE::QemuServer::vm_monitor_command ($vmid, $input);
+ };
+ print "ERROR: $@" if $@;
+ }
+
+} elsif ($cmd eq 'showcmd') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ print vm_commandline ($qm->{storecfg}, $vmid) . "\n";
+
+} elsif ($cmd eq 'start') {
+ my $statefile;
+ if (scalar (@ARGV) == 2 && ($ARGV[0] =~ m/^\-\-?i(ncoming)?$/)) {
+ $statefile = $ARGV[1];
+ } elsif (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_start ($qm->{storecfg}, $vmid, $statefile, $skiplock);
+
+} elsif ($cmd eq 'startall') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ $qm->vm_startall_old ();
+
+} elsif ($cmd eq 'reset') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_reset ($vmid, $skiplock);
+
+} elsif ($cmd eq 'shutdown') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ vm_shutdown ($vmid, $skiplock);
+
+} elsif ($cmd eq 'wait') {
+ my $timeout = shift || 0;
+
+ if ($timeout !~ m/^\d+$/) {
+ print_usage ("timeout must be numeric");
+ exit (-1);
+ }
+
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ $qm->vm_wait_old ($vmid, $timeout);
+
+} elsif ($cmd eq 'stopall') {
+ my $timeout = shift || 0;
+
+ if ($timeout !~ m/^\d+$/) {
+ print_usage ("timeout must be numeric");
+ exit (-1);
+ }
+
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_stopall($timeout);
+
+} elsif ($cmd eq 'stop') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ vm_stop ($vmid, $skiplock);
+
+} elsif ($cmd eq 'destroy') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_destroy ($qm->{storecfg}, $vmid, $skiplock);
+
+} elsif ($cmd eq 'suspend') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_suspend ($vmid, $skiplock);
+
+} elsif ($cmd eq 'resume') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_resume ($vmid, $skiplock);
+
+} elsif ($cmd eq 'cad') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ PVE::QemuServer::vm_cad ($vmid, $skiplock);
+
+} elsif ($cmd eq 'vncticket') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ my $ticket = PVE::QemuServer::vm_vncticket ($vmid);
+ print "TICKET:$ticket\n";
+
+} elsif ($cmd eq 'cdrom') {
+
+ my ($device, $path);
+
+ if (scalar (@ARGV) == 1) {
+ $path = shift @ARGV;
+ $device = 'ide2';
+ } elsif (scalar (@ARGV) == 2) {
+ my $dev;
+ ($dev, $path) = @ARGV;
+ foreach my $ds (@disks) {
+ if (($ds eq $dev) || ("-$ds" eq $dev) || ("--$ds" eq $dev)) {
+ $device = $ds;
+ last;
+ }
+ }
+ } else {
+ print_usage ();
+ exit (-1);
+ }
+
+ if (!$path || !$device) {
+ print_usage ();
+ exit (-1);
+ }
+
+ $path = 'none' if $path eq 'eject';
+
+ if (!($path eq 'none' || $path eq 'cdrom')) {
+
+ my ($vtype, $volid) = PVE::Storage::path_to_volume_id ($qm->{storecfg}, $path);
+
+ if (!($vtype eq 'iso')) {
+ die "path '$path' does not point to a valid cdrom image\n";
+ }
+
+ $path = $volid;
+ }
+
+ $qm->vm_cdrom ($vmid, $device, $path);
+
+} elsif ($cmd eq 'vncproxy') {
+ my $ticket = shift @ARGV;
+
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ if ($ticket) {
+ die "illegal characters in ticket\n" if $ticket =~ m/[^A-Za-z0-9\+\/]/;
+ $qm->vm_vncticket ($vmid, $ticket);
+ }
+
+ run_vnc_proxy ($vmid, $ticket);
+
+} elsif ($cmd eq 'vnc') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ my $port = __next_vnc_port();
+ my $display = $port - 5900;
+
+ my $ticket = $qm->vm_vncticket ($vmid);
+ $ticket = substr ($ticket, 0, 8);
+ my $mpf = "/tmp/.qmvncpw$$";
+
+ $vnccmd =~ s/__TICKET__/$ticket/g;
+ $vnccmd =~ s/__TMPFILE__/$mpf/g;
+ $vnccmd =~ s/__DISPLAY__/$display/g;
+ $vnccmd =~ s/__PORT__/$port/g;
+
+ system ("$vnccmd &");
+ system ("nc -l -p $port -c 'qm vncproxy $vmid'");
+ unlink $mpf;
+
+} elsif ($cmd eq 'list') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ my $vzlist = PVE::QemuServer::vzlist();
+
+ exit 0 if (!scalar(keys %$vzlist));
+
+ printf "%10s %-20s %-10s %-10s %12s %-10s\n",
+ qw(VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID);
+
+ foreach my $vmid (sort keys %$vzlist) {
+ my $conf = PVE::QemuServer::load_config ($vmid);
+ my $name = $conf->{name} || '-';
+
+ my $status = $vzlist->{$vmid}->{pid} ? 'running' : 'stopped';
+ my $pid = $vzlist->{$vmid}->{pid} || 0;
+ printf "%10s %-20s %-10s %-10s %12.2f %-10s\n", $vmid, $name, $status,
+ $conf->{memory}||0, $conf->{disksize}||0, $pid;
+ }
+
+} elsif ($cmd eq 'unlock') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+ PVE::QemuServer::lock_config ($vmid, sub {
+ PVE::QemuServer::change_config_nolock ($vmid, {}, { lock => 1 }, 1);
+ });
+
+ die $@ if $@;
+
+} elsif ($cmd eq 'status') {
+ if (scalar (@ARGV) != 0) {
+ print_usage ();
+ exit (-1);
+ }
+
+ my $status = 'unknown';
+
+ eval {
+ if (PVE::QemuServer::check_running($vmid)) {
+ $status = 'running';
+ } else {
+ $status = 'stopped';
+ }
+ };
+
+ print "$status\n";
+
+} elsif ($cmd eq 'mtunnel') {
+
+ print "tunnel online\n";
+ *STDOUT->flush();
+
+ while (my $line = <>) {
+ chomp $line;
+ last if $line =~ m/^quit$/;
+ }
+
+ exit (0);
+
+} else {
+ print_usage ();
+ exit (-1);
+}
+
+exit (0);
+
+__END__
+
+=head1 NAME
+
+qm - qemu/kvm manager
+
+=head1 SYNOPSIS
+
+qm [--skiplock] <command> <vmid> [OPTIONS]
+
+type qm to see a list of valid commands
+
+=head1 DESCRIPTION
+
+qm is a script to manage virtual machines with qemu/kvm. You can
+create and destroy virtual machines, and control execution
+(start/stop/suspend/resume). Besides that, you can use qm to set
+parameters in the associated config file. It is also possible to
+create and delete virtual disks.
+
+=head1 CONFIGURATION
+
+Global server configuration is stored in /etc/pve/qemu-server.cfg.
+
+All configuration files consists of lines in the form
+
+ PARAMETER: value
+
+The following defaults can be specified:
+
+=over 1
+
+=item keyboard: XX
+
+Keybord layout used for vnc server (for example C<fr> for French)
+
+=item onboot: (yes|no)
+
+Specifies whether a VM will be started during system bootup.
+Default is no, meaning the VM will not be started if ONBOOT
+parameter is omitted.
+
+=item autostart: (yes|no)
+
+Automatic restart after crash. Default is no. This value is
+currently ignored (because we have no monitor).
+
+=item memory: num
+
+Amount of RAM for the VM in MB. Default value is 512.
+
+=item cpuunits: num
+
+CPU weight for a VM. Argument is positive non-zero number, passed to
+and used in the kernel fair scheduler. The larger the number is,
+the more CPU time this VM gets. Maximum value is 500000, minimal
+is 8. Number is relative to weights of all the other running VMs.
+If cpuunits are not specified, default value of 1000 is used.
+
+NOTE: You can disable fair-scheduler configuration by setting this to 0.
+
+=item vga: (std|cirrus)
+
+Select VGA type. Default is a Cirrus Logic GD5446 PCI VGA card (cirrus).
+If you want to use high resolution modes (>= 1280x1024x16) then you should
+use option C<std>.
+
+=item tdf: (yes|no)
+
+enable/disable time drift fix [default=yes]
+
+=item tablet: (yes|no)
+
+enable/disable the usb tablet device [default=yes]. This device is usually
+needed to allow absolute mouse positioning. Else the mouse runs out of
+sync with normal vnc clients. If you're running lots of console-only guests
+on one host, you may consider setting "tablet: no" to save some context switches.
+
+=item migrate_downtime: num
+
+set maximum tolerated downtime (in seconds) for migrations. [default=1]
+
+=item migrate_speed: num
+
+set maximum speed (in MB/s) for migrations. [default=0 (no limit)]
+
+=back
+
+=head1 VM CONFIGURATION
+
+Each VM is identified by an unique ID (integer). Configuration for
+a VM is stored at C</etc/qemu-server/ID.conf>
+
+Currently, the following parameters are supported:
+
+=over 1
+
+=item keyboard: XX
+
+Default is read from global configuration file.
+
+=item onboot: (yes|no)
+
+Default is read from global configuration file.
+
+=item autostart: (yes|no)
+
+Default is read from global configuration file.
+
+=item memory: num
+
+Default is read from global configuration file.
+
+=item cpuunits: num
+
+Default is read from global configuration file.
+
+=item migrate_downtime: num
+
+Default is read from global configuration file.
+
+=item migrate_speed: num
+
+Default is read from global configuration file.
+
+=item reboot: (yes|no)
+
+Exit instead of rebooting.
+
+=item name: text
+
+Set a name for the VM. Only used on the configuration
+web interface.
+
+=item description: text
+
+Description for the VM. Only used on the configuration
+web interface.
+
+=item boot: [a|c|d|n]
+
+boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)
+
+default is C<cad> (disk, floppy, cdrom)
+
+=item bootdisk: <disk>
+
+enable booting from <disk>
+
+<disk> = <ide0|ide1|ide2|ide3|scsi0|scsi1|scsi2|...
+
+=item smp: num (please use C<sockets> instead)
+
+set the number of CPUs to C<num> [default=1]
+
+=item sockets: num
+
+set the number of CPU sockets to C<num> [default=1]
+
+=item cores: num
+
+set the number of cores per socket to C<num> [default=1]
+
+=item acpi: (yes|no)
+
+enable/disable ACPI [default=yes]
+
+=item kvm: (yes|no)
+
+enable/disable KVM hardware virtualization [default=yes]
+
+=item tdf: (yes|no)
+
+Default is read from global configuration file.
+
+=item tablet: (yes|no)
+
+Default is read from global configuration file.
+
+=item localtime: (yes|no)
+
+set the real time clock to local time
+
+=item startdate: (now|YYYY-MM-DD|YYYY-MM-DDTHH-MM-SS)
+
+Set the initial date of the real time clock. Valid format
+for date are: C<now> or C<2006-06-17T16:01:21> or C<2006-06-17>.
+The default value is C<now>.
+
+=item freeze: (yes|no)
+
+freeze CPU at startup (use C<c> monitor command to start execution)
+
+=item vlan0: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
+
+Specify network devices connected to vlan0. Currently, vlan0 is
+connected to vmbr0.
+
+MODEL is one of: ne2k_pci e1000 rtl8139 pcnet virtio
+ne2k_isa i82551 i82557b i82559er
+
+XX:XX:XX:XX:XX:XX should be an unique MAC address
+
+=item vlan[1-4094]: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
+
+Same as vlan0, but vlanX is bridged to vmbrX
+
+=item vlanu: MODEL=XX:XX:XX:XX:XX:XX[,MODEL=YY:YY:YY:YY:YY:YY]
+
+Same as vlan0, but vlanu uses user mode network stack (NAT).
+Provides DHCP and DNS services. The following addresses are used:
+
+ 10.0.2.2 Gateway
+ 10.0.2.3 DNS Server
+ 10.0.2.4 SMB Server
+
+The DHCP server assign addresses to the hosts starting from 10.0.2.15.
+
+=item ostype: (other|wxp|w2k|w2k3|w2k8|wvista|l24|l26)
+
+Used to enable special optimization/features for specific
+operating systems:
+
+ other => unspecified OS
+ wxp => Microsoft Windows XP
+ w2k => Microsoft Windows 2000
+ w2k3 => Microsoft Windows 2003
+ w2k8 => Microsoft Windows 2008
+ wvista => Microsoft Windows Vista
+ l24 => Linux 2.4 Kernel
+ l26 => Linux 2.6 Kernel
+
+ other|l24|l26 ... no special behaviour
+ wxp|w2k|w2k3|w2k8|wvista ... use --localtime switch
+
+=item vga: (std|cirrus)
+
+Default is read from global configuration file.
+
+=item ide0 - ide3: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
+
+Use volume as IDE hard disk or CD-ROM.
+
+=item scsi0 - scsi15: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
+
+Use volume as SCSI hard disk or CD-ROM.
+
+=item virtio0 - virtio15: [volume=]volume,][,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough"|writeback] [,format=f]
+
+Use file as VIRTIO hard disk.
+
+=item hostpci: [HOSTPCIDEVICE][,HOSTPCIDEVICE]*
+
+Map host pci devices. HOSTPCIDEVICE syntax is:
+
+C<bus:dev.func> (hexadecimal numbers)
+
+You can us the C<lspci> command to list existing pci devices.
+
+Note: This option allows direct access to host hardware. So it is no
+longer possible to migrate such machines - use with special care.
+
+Experimental: user reported problems with this option
+
+=item hostusb: [HOSTUSBDEVICE][,HOSTUSBDEVICE]*
+
+Map host usb devices. HOSTUSBDEVICE syntax is:
+
+C<bus.addr> (decimal numbers) or C<vendor_id:product_id> (hexadeciaml numbers)
+
+You can us the C<lsusb> command to list existing usb devices (or take a
+look at C</proc/bus/usb/devices>).
+
+Note: This option allows direct access to host hardware. So it is no
+longer possible to migrate such machines - use with special care.
+
+=item serial: [SERIALDEVICE][,SERIALDEVICE]*
+
+Experimental: user reported problems with this option
+
+Map host serial devices. SERIALDEVICE syntax is /dev/ttyS*
+
+Note: This option allows direct access to host hardware. So it is no
+longer possible to migrate such machines - use with special care.
+
+=item parallel: [PARALLELDEVICE][,PARALLELDEVICE]*
+
+Experimental: user reported problems with this option
+
+Map host parallel devices. PARALLELDEVICE syntax is /dev/parport*
+
+Note: This option allows direct access to host hardware. So it is no
+longer possible to migrate such machines - use with special care.
+
+=item args: ...
+
+Note: this option is for experts only. It allows you to pass arbitrary
+arguments to kvm, for example:
+
+ args: -no-reboot -no-hpet
+
+=item lock: (migrate|backup)
+
+This value is set during online migration (migrate) and vzdump
+(backup).
+
+=back
+
+=head1 Locks
+
+Online migration and backups (vzdump) set a lock to prevent
+unintentional action on such VMs. Sometimes you need remove such lock
+manually (power failure).
+
+ qm unlock <vmid>
+
+=head1 EXAMPLES
+
+# create a new VM with 4 GB ide disk
+
+qm create 300 -ide0 4 -vlan0 e1000 -cdrom proxmox-mailgateway_2.1.iso
+
+# start the new VM
+
+qm start 300
+
+# send shutdown, then wait until VM is stopped
+
+qm shutdown 300 && qm wait 300
+
+# same as above, but only wait for 40 seconds
+
+qm shutdown 300 && qm wait 300 40
+
+
+
+
+
+
+
More information about the pve-devel
mailing list