From 288eeea8ae099120ef3fd992fc898c7cf13cbac5 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 25 Jun 2013 12:09:05 +0200 Subject: [PATCH] add spice proxy API 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 | 113 ++++++++++++++++++++++++++++++++++++++++++++++ PVE/QemuServer.pm | 2 +- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 076356c7..53629b35 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -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', diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index e2b6ec83..31d8103b 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -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";