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 <aderum...@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 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel