]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
bump version to 3.1-1
[qemu-server.git] / PVE / QemuServer.pm
index 321f6a982a9859b25523c1f942b296f9166e77d8..3c9c54dc7125e38c535848019f29f1efeb9cdf25 100644 (file)
@@ -335,8 +335,8 @@ EODESC
     vga => {
        optional => 1,
        type => 'string',
-       description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and 'cirrur' for other OS types. Option 'qxl' enables the SPICE display sever.",
-       enum => [qw(std cirrus vmware qxl)],
+       description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and 'cirrur' for other OS types. Option 'qxl' enables the SPICE display sever. You can also run without any graphic card using a serial devive as terminal.",
+       enum => [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3)],
     },
     watchdog => {
        optional => 1,
@@ -377,7 +377,7 @@ EODESCR
        optional => 1,
        type => 'boolean',
        default => 1,
-       description => "Enable/disable the usb tablet device. 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 disabling this to save some context switches.",
+       description => "Enable/disable the usb tablet device. This device is usually needed to allow absolute mouse positioning with VNC. 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 disabling this to save some context switches. This is turned of by default if you use spice (vga=qxl).",
     },
     migrate_speed => {
        optional => 1,
@@ -535,7 +535,7 @@ PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
 my $usbdesc = {
     optional => 1,
     type => 'string', format => 'pve-qm-usb-device',
-    typetext => 'host=HOSTUSBDEVICE',
+    typetext => 'host=HOSTUSBDEVICE|spice',
     description => <<EODESCR,
 Configure an USB device (n is 0 to 4). This can be used to
 pass-through usb devices to the guest. HOSTUSBDEVICE syntax is:
@@ -547,6 +547,8 @@ You can use the 'lsusb -t' command to list existing 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.
 
+The value 'spice' can be used to add a usb redirection devices for spice.
+
 EODESCR
 };
 PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
@@ -572,9 +574,9 @@ PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
 my $serialdesc = {
        optional => 1,
        type => 'string',
-       pattern => '/dev/ttyS\d+',
+       pattern => '(/dev/ttyS\d+|socket)',
        description =>  <<EODESCR,
-Map host serial devices (n is 0 to 3).
+Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device, or create a unix socket on the host side (use 'qm terminal' to open a terminal connection).
 
 Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
 
@@ -585,7 +587,7 @@ EODESCR
 my $paralleldesc= {
        optional => 1,
        type => 'string',
-       pattern => '/dev/parport\d+',
+        pattern => '/dev/parport\d+|/dev/usb/lp\d+',
        description =>  <<EODESCR,
 Map host parallel devices (n is 0 to 2).
 
@@ -1411,6 +1413,9 @@ sub parse_usb_device {
            $found = 1;
            $res->{hostbus} = $1;
            $res->{hostport} = $2;
+       } elsif ($v =~ m/^spice$/) {
+           $found = 1;
+           $res->{spice} = 1;
        } else {
            return undef;
        }
@@ -2226,6 +2231,12 @@ sub foreach_volid {
     }
 }
 
+sub vga_conf_has_spice {
+    my ($vga) = @_;
+
+    return $vga && ($vga eq 'qxl');
+}
+
 sub config_to_command {
     my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
 
@@ -2277,8 +2288,27 @@ sub config_to_command {
     # include usb device config
     push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2;
 
+    my $vga = $conf->{vga};
+    if (!$vga) {
+       if ($conf->{ostype} && ($conf->{ostype} eq 'win8' || 
+                               $conf->{ostype} eq 'win7' || 
+                               $conf->{ostype} eq 'w2k8')) {
+           $vga = 'std';
+       } else {
+           $vga = 'cirrus';
+       }
+    }
+
     # enable absolute mouse coordinates (needed by vnc)
-    my $tablet = defined($conf->{tablet}) ? $conf->{tablet} : $defaults->{tablet};
+    my $tablet;
+    if (defined($conf->{tablet})) {
+       $tablet = $conf->{tablet};
+    } else {
+       $tablet = $defaults->{tablet};
+       $tablet = 0 if vga_conf_has_spice($vga); # disable for spice because it is not needed
+       $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
+    }
+
     push @$devices, '-device', 'usb-tablet,id=tablet,bus=uhci.0,port=1' if $tablet;
 
     # host pci devices
@@ -2297,15 +2327,25 @@ sub config_to_command {
            push @$devices, '-device', "usb-host,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
        } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
            push @$devices, '-device', "usb-host,hostbus=$d->{hostbus},hostport=$d->{hostport}";
+       } elsif ($d->{spice}) {
+           # usb redir support for spice
+           push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
+           push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
        }
     }
 
     # serial devices
     for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
        if (my $path = $conf->{"serial$i"}) {
-           die "no such serial device\n" if ! -c $path;
-           push @$devices, '-chardev', "tty,id=serial$i,path=$path";
-           push @$devices, '-device', "isa-serial,chardev=serial$i";
+           if ($path eq 'socket') {
+               my $socket = "/var/run/qemu-server/${vmid}.serial$i";
+               push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
+               push @$devices, '-device', "isa-serial,chardev=serial$i";
+           } else {
+               die "no such serial device\n" if ! -c $path;
+               push @$devices, '-chardev', "tty,id=serial$i,path=$path";
+               push @$devices, '-device', "isa-serial,chardev=serial$i";
+           }
        }
     }
 
@@ -2346,16 +2386,7 @@ sub config_to_command {
 
     push @$cmd, '-no-reboot' if  defined($conf->{reboot}) && $conf->{reboot} == 0;
 
-    my $vga = $conf->{vga};
-    if (!$vga) {
-       if ($conf->{ostype} && ($conf->{ostype} eq 'win8' || $conf->{ostype} eq 'win7' || $conf->{ostype} eq 'w2k8')) {
-           $vga = 'std';
-       } else {
-           $vga = 'cirrus';
-       }
-    }
-
-    push @$cmd, '-vga', $vga if $vga; # for kvm 77 and later
+    push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
 
     # time drift fix
     my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
@@ -2437,16 +2468,14 @@ sub config_to_command {
        push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
     }
 
-    if ($vga eq 'qxl') {
+    my $spice_port;
+    if (vga_conf_has_spice($vga)) {
        my $pciaddr = print_pci_addr("spice", $bridges);
 
-       # todo: enable tls
-       #my $x509 = "x509-key-file=/etc/pve/local/pve-ssl.key";
-       #$x509 .= ",x509-cert-file=/etc/pve/local/pve-ssl.pem";
-       #$x509 .= ",x509-cacert-file=/etc/pve/pve-root-ca.pem";
+       $spice_port = PVE::Tools::next_unused_port(61000, 61099);
+
+       push @$cmd, '-spice', "tls-port=${spice_port},addr=127.0.0.1,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
 
-       my $socket = spice_socket($vmid);
-       push @$cmd, '-spice', "unix=$socket";
        push @$cmd, '-device', "virtio-serial,id=spice$pciaddr";
        push @$cmd, '-chardev', "spicevmc,id=vdagent,name=vdagent";
        push @$cmd, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
@@ -2567,7 +2596,7 @@ sub config_to_command {
     push @$cmd, '-global', join(',', @$globalFlags)
        if scalar(@$globalFlags);
 
-    return wantarray ? ($cmd, $vollist) : $cmd;
+    return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
 }
 
 sub vnc_socket {
@@ -2575,9 +2604,12 @@ sub vnc_socket {
     return "${var_run_tmpdir}/$vmid.vnc";
 }
 
-sub spice_socket {
+sub spice_port {
     my ($vmid) = @_;
-    return "${var_run_tmpdir}/$vmid.spice";
+
+    my $res = vm_mon_cmd($vmid, 'query-spice');
+
+    return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
 }
 
 sub qmp_socket {
@@ -3009,7 +3041,7 @@ sub qga_unfreezefs {
 }
 
 sub vm_start {
-    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine) = @_;
+    my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine, $spice_ticket) = @_;
 
     lock_config($vmid, sub {
        my $conf = load_config($vmid, $migratedfrom);
@@ -3025,14 +3057,20 @@ sub vm_start {
        # set environment variable useful inside network script
        $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
 
-       my ($cmd, $vollist) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
+       my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
 
        my $migrate_port = 0;
-
+       my $migrate_uri;
        if ($statefile) {
            if ($statefile eq 'tcp') {
+               my $localip = "localhost";
+               my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
+               if ($datacenterconf->{migration_unsecure}) {
+                       my $nodename = PVE::INotify::nodename();
+                       $localip = PVE::Cluster::remote_node_ip($nodename, 1);
+               }
                $migrate_port = PVE::Tools::next_migrate_port();
-               my $migrate_uri = "tcp:localhost:${migrate_port}";
+               $migrate_uri = "tcp:${localip}:${migrate_port}";
                push @$cmd, '-incoming', $migrate_uri;
                push @$cmd, '-S';
            } else {
@@ -3060,20 +3098,29 @@ sub vm_start {
        my $err = $@;
        die "start failed: $err" if $err;
 
-       print "migration listens on port $migrate_port\n" if $migrate_port;
+       print "migration listens on $migrate_uri\n" if $migrate_uri;
 
        if ($statefile && $statefile ne 'tcp')  {
            eval { vm_mon_cmd_nocheck($vmid, "cont"); };
            warn $@ if $@;
        }
 
-       if($migratedfrom) {
+       if ($migratedfrom) {
            my $capabilities = {};
            $capabilities->{capability} =  "xbzrle";
            $capabilities->{state} = JSON::true;
            eval { vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => [$capabilities]); };
-       }
-       else{
+           warn $@ if $@;
+           
+           if ($spice_port) {
+               print "spice listens on port $spice_port\n";
+               if ($spice_ticket) {
+                   PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice', password => $spice_ticket);
+                   PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice', time => "+30");
+               }
+           }
+
+       } else {
 
            if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
                vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
@@ -4833,4 +4880,21 @@ sub get_current_qemu_machine {
     return $current || $default || 'pc';
 }
 
+sub read_x509_subject_spice {
+    my ($filename) = @_;
+
+    # read x509 subject
+    my $bio = Net::SSLeay::BIO_new_file($filename, 'r');
+    my $x509 = Net::SSLeay::PEM_read_bio_X509($bio);
+    Net::SSLeay::BIO_free($bio);
+    my $nameobj = Net::SSLeay::X509_get_subject_name($x509);
+    my $subject = Net::SSLeay::X509_NAME_oneline($nameobj);
+    Net::SSLeay::X509_free($x509);
+  
+    # remote-viewer wants comma as seperator (not '/')
+    $subject =~ s!^/!!;
+    $subject =~ s!/(\w+=)!,$1!g;
+
+    return $subject;
+}
 1;