]> git.proxmox.com Git - qemu-server.git/commitdiff
add spice proxy API
authorDietmar Maurer <dietmar@proxmox.com>
Tue, 25 Jun 2013 10:09:05 +0000 (12:09 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Tue, 25 Jun 2013 10:09:05 +0000 (12:09 +0200)
This is experimental code, spice connections are not encryped and thus insecure.
We use ticket passwords for spice auth, and do direct spice connections to
the nodes instead of using a tunnel.

PVE/API2/Qemu.pm
PVE/QemuServer.pm

index 076356c7f266ee9bddc0e71ada73a3d8588f6bbe..53629b35f9806525ca7e93fd9bbf1aced64975cd 100644 (file)
@@ -497,6 +497,7 @@ __PACKAGE__->register_method({
            { subdir => 'rrddata' },
            { subdir => 'monitor' },
            { subdir => 'snapshot' },
+           { subdir => 'spiceproxy' },
            ];
 
        return $res;
@@ -1321,6 +1322,118 @@ __PACKAGE__->register_method({
        };
     }});
 
+__PACKAGE__->register_method({
+    name => 'spiceproxy',
+    path => '{vmid}/spiceproxy',
+    method => 'GET', # fixme: should be POST, but howto handle that in the HTML client
+    protected => 1,
+    proxyto => 'node', # fixme: use direct connections or ssh tunnel?
+    permissions => {
+       check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]],
+    },
+    description => "Returns a SPICE configuration to connect to the VM.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+       },
+    },
+    returns => {
+       additionalProperties => 1,
+       properties => {
+           type => { type => 'string' },
+           password => { type => 'string' },
+           host => { type => 'string' },
+           port => { type => 'integer' },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $authuser = $rpcenv->get_user();
+
+       my $vmid = $param->{vmid};
+       my $node = $param->{node};
+
+       my $port = PVE::Tools::next_vnc_port();
+
+        my $remip;
+
+       # Note: we currectly use "proxyto => 'node'", so this code will never trigger
+        if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) {
+            $remip = PVE::Cluster::remote_node_ip($node);
+        }
+
+       my $authpath = "/vms/$vmid";
+
+       my $ticket = PVE::AccessControl::assemble_spice_ticket($authuser, $authpath);
+
+       my $timeout = 10;
+
+       # Note: this only works if VM is on local node
+       PVE::QemuServer::vm_mon_cmd($vmid, "set_password", protocol => 'spice', password => $ticket);
+       PVE::QemuServer::vm_mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
+
+       my $remcmd = []; #fixme
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "starting spice proxy $upid\n");
+       
+           my $socket = PVE::QemuServer::spice_socket($vmid);
+       
+           my $cmd = ['/usr/bin/socat', '-d', '-d', 
+                      "TCP-LISTEN:$port,reuseaddr,fork" ];
+
+           if ($remip) {
+               push @$cmd, "EXEC:'ssh root@$remip socat STDIO UNIX-CONNECT:$socket";
+           } else {
+               push @$cmd, "UNIX-CONNECT:$socket";
+           }
+
+           my $conn_count = 0;
+
+           my $parser = sub {
+               my $line = shift;
+               print "$line\n";
+               if ($line =~ /successfully connected from/) {
+                   $conn_count++;
+               } elsif ($line =~ /exiting with status/) {
+                   $conn_count--;
+                   # Note: counting connections seems unreliable here
+                   die "client exit\n"; # if $conn_count <= 0;
+               }
+           };
+           
+           eval { PVE::Tools::run_command($cmd, errfunc => $parser, outfunc => sub{}); };
+           if (my $err = $@) {
+               die $err if $err !~ m/client exit$/;
+           }
+
+           return;
+       };
+
+       my $upid = $rpcenv->fork_worker('spiceproxy', $vmid, $authuser, $realcmd);
+
+       PVE::Tools::wait_for_vnc_port($port);
+
+       # fimxe: ??
+       my $host = `hostname -f` || PVE::INotify::nodename();
+       chomp $host;
+
+       return {
+           type => 'spice',
+           host => $host,
+           port => $port,
+           password => $ticket,
+           upid => $upid,
+       };
+    }});
+
 __PACKAGE__->register_method({
     name => 'vmcmdidx',
     path => '{vmid}/status',
index e2b6ec83bf68607762c1c17806ed124d47c094b1..31d8103b689c928a1d9eb79ff602421926686aff 100644 (file)
@@ -2424,7 +2424,7 @@ sub config_to_command {
 
        my $socket = spice_socket($vmid);
 
-       push @$cmd, '-spice', "disable-ticketing,unix=$socket";
+       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";