[pve-devel] [PATCH 2/3] api2 : add spiceproxy

Alexandre Derumier aderumier at odiso.com
Wed Apr 10 13:08:10 CEST 2013


create a tunnel with socat.

then call "qm spiceticket" to remote host to generate the ticket. (ticket is returned with json)

fixme:

- Each spice connections need 4 channels,so socat use fork.
  They are no  concurrent connection limit in current debian socat.
  Last socat version have a max-worker option.

- I don't known how to close socat if connection is not established

Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/API2/Qemu.pm |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 62e8d0d..ebf502a 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -1,8 +1,10 @@
+
 package PVE::API2::Qemu;
 
 use strict;
 use warnings;
 use Cwd 'abs_path';
+use JSON;
 
 use PVE::Cluster qw (cfs_read_file cfs_write_file);;
 use PVE::SafeSyslog;
@@ -639,6 +641,7 @@ __PACKAGE__->register_method({
 	    { subdir => 'rrddata' },
 	    { subdir => 'monitor' },
 	    { subdir => 'snapshot' },
+	    { subdir => 'spiceproxy' },
 	    ];
 
 	return $res;
@@ -731,6 +734,85 @@ __PACKAGE__->register_method({
 	    "pve2-vm/$param->{vmid}", $param->{timeframe}, $param->{cf});
     }});
 
+__PACKAGE__->register_method({
+    name => 'spiceproxy',
+    path => '{vmid}/spiceproxy',
+    method => 'GET',
+    protected => 1,
+    permissions => {
+        check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]],
+    },
+    description => "Create a proxy for spice socket and return spice config",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    vmid => get_standard_option('pve-vmid'),
+	},
+    },
+    returns => { type => 'object' },
+    code => sub {
+	my ($param) = @_;
+
+        my $node = extract_param($param, 'node');
+        my $vmid = extract_param($param, 'vmid');
+
+        my $rpcenv = PVE::RPCEnvironment::get();
+        my $authuser = $rpcenv->get_user();
+
+        my $remip;
+
+        if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) {
+            $remip = PVE::Cluster::remote_node_ip($node);
+        }
+
+	my $socket = PVE::QemuServer::spice_socket($vmid);
+	my $port = PVE::Tools::next_vnc_port();
+
+        my $realcmd = sub {
+            my $upid = shift;
+
+            syslog('info', "starting spice proxy $upid\n");
+
+	    #socat 1.7.2.1 support max-children, we need 4 channels for spice. (debian package is too old)
+	    #my $cmd = ['/usr/bin/socat', '-d', '-d', "TCP-LISTEN:$port,reuseaddr,fork,max-children=4"];
+
+	    my $cmd = ['/usr/bin/socat', '-d', '-d', "TCP-LISTEN:$port,reuseaddr,fork"];
+	    my $remotesocket = $remip ? "EXEC:'ssh root@$remip socat STDIO UNIX-CONNECT:$socket'" : "UNIX-CONNECT:$socket";
+	    push @$cmd, $remotesocket;
+
+	    my $parser = sub {
+		my $line = shift;
+		print $line."\n";
+		die "Client is disconnect" if ($line =~ /exiting with status 0/);
+	    };
+
+	    #fixme : how to setup a connect wait timeout ?
+	    PVE::Tools::run_command($cmd, errfunc => $parser, outfunc => sub{});
+
+            return;
+        };
+
+        my $upid = $rpcenv->fork_worker('spiceproxy', $vmid, $authuser, $realcmd);
+
+
+        my $remcmd = $remip ? ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes', $remip] : [];
+	my $qmcmd = [@$remcmd, "/usr/sbin/qm", 'spiceticket', $vmid];
+	my $qmstr = join(' ', @$qmcmd);
+	my $out = "";
+	PVE::Tools::run_command($qmstr, outfunc => sub { $out .= shift; });
+
+	my $config = from_json($out);
+	my $proxyname = `hostname -f` || PVE::INotify::nodename();
+	chomp $proxyname;
+
+	$config->{type} = 'spice';
+	$config->{proxy} = "http://$proxyname:3128";
+	$config->{host} = 'localhost';
+	$config->{port} = $port;
+	return $config;
+
+    }});
 
 __PACKAGE__->register_method({
     name => 'vm_config',
-- 
1.7.10.4



More information about the pve-devel mailing list