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.
This commit is contained in:
Dietmar Maurer 2013-06-25 12:09:05 +02:00
parent 1011b57090
commit 288eeea8ae
2 changed files with 114 additions and 1 deletions

View File

@ -497,6 +497,7 @@ __PACKAGE__->register_method({
{ subdir => 'rrddata' }, { subdir => 'rrddata' },
{ subdir => 'monitor' }, { subdir => 'monitor' },
{ subdir => 'snapshot' }, { subdir => 'snapshot' },
{ subdir => 'spiceproxy' },
]; ];
return $res; 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({ __PACKAGE__->register_method({
name => 'vmcmdidx', name => 'vmcmdidx',
path => '{vmid}/status', path => '{vmid}/status',

View File

@ -2424,7 +2424,7 @@ sub config_to_command {
my $socket = spice_socket($vmid); 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, '-device', "virtio-serial,id=spice$pciaddr";
push @$cmd, '-chardev', "spicevmc,id=vdagent,name=vdagent"; push @$cmd, '-chardev', "spicevmc,id=vdagent,name=vdagent";
push @$cmd, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0"; push @$cmd, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";