use strict;
use warnings;
use Cwd 'abs_path';
+use Net::SSLeay;
use PVE::Cluster qw (cfs_read_file cfs_write_file);;
use PVE::SafeSyslog;
my $vmid = $param->{vmid};
my $node = $param->{node};
+ my $conf = PVE::QemuServer::load_config($vmid, $node); # check if VM exists
+
my $authpath = "/vms/$vmid";
my $ticket = PVE::AccessControl::assemble_vnc_ticket($authuser, $authpath);
my $port = PVE::Tools::next_vnc_port();
my $remip;
+ my $remcmd = [];
if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) {
$remip = PVE::Cluster::remote_node_ip($node);
+ # NOTE: kvm VNC traffic is already TLS encrypted
+ $remcmd = ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes', $remip];
}
- # NOTE: kvm VNC traffic is already TLS encrypted
- my $remcmd = $remip ? ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes', $remip] : [];
-
my $timeout = 10;
my $realcmd = sub {
syslog('info', "starting vnc proxy $upid\n");
- my $qmcmd = [@$remcmd, "/usr/sbin/qm", 'vncproxy', $vmid];
+ my $cmd;
+
+ if ($conf->{vga} =~ m/^serial\d+$/) {
+
+ my $termcmd = [ '/usr/sbin/qm', 'terminal', $vmid, '-iface', $conf->{vga} ];
+ #my $termcmd = "/usr/bin/qm terminal -iface $conf->{vga}";
+ $cmd = ['/usr/bin/vncterm', '-rfbport', $port,
+ '-timeout', $timeout, '-authpath', $authpath,
+ '-perm', 'Sys.Console', '-c', @$remcmd, @$termcmd];
+ } else {
+
+ my $qmcmd = [@$remcmd, "/usr/sbin/qm", 'vncproxy', $vmid];
- my $qmstr = join(' ', @$qmcmd);
+ my $qmstr = join(' ', @$qmcmd);
- # also redirect stderr (else we get RFB protocol errors)
- my $cmd = ['/bin/nc', '-l', '-p', $port, '-w', $timeout, '-c', "$qmstr 2>/dev/null"];
+ # also redirect stderr (else we get RFB protocol errors)
+ $cmd = ['/bin/nc', '-l', '-p', $port, '-w', $timeout, '-c', "$qmstr 2>/dev/null"];
+ }
PVE::Tools::run_command($cmd);
properties => {
node => get_standard_option('pve-node'),
vmid => get_standard_option('pve-vmid'),
+ proxy => {
+ description => "This can be used by the client to specify the proxy server. All nodes in a cluster runs 'spiceproxy', so it is up to the client to choose one. By default, we return the node where the VM is currently running. As resonable setting is to use same node you use to connect to the API (This is window.location.hostname for the JS GUI).",
+ type => 'string', format => 'dns-name',
+ optional => 1,
+ },
},
},
returns => {
+ description => "Returned values can be directly passed to the 'remote-viewer' application.",
additionalProperties => 1,
properties => {
type => { type => 'string' },
my $vmid = $param->{vmid};
my $node = $param->{node};
-
- 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 $proxy = $param->{proxy};
my ($ticket, $proxyticket) = PVE::AccessControl::assemble_spice_ticket($authuser, $vmid, $node);
my $timeout = 10;
- # Note: this only works if VM is on local node
my $port = PVE::QemuServer::spice_port($vmid);
PVE::QemuServer::vm_mon_cmd($vmid, "set_password", protocol => 'spice', password => $ticket);
PVE::QemuServer::vm_mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
- # fimxe: ??
- my $host = `hostname -f` || PVE::INotify::nodename();
- chomp $host;
+ if (!$proxy) {
+ my $host = `hostname -f` || PVE::INotify::nodename();
+ chomp $host;
+ $proxy = $host;
+ }
- my $subject = "OU=PVE Cluster Node, O=Proxmox Virtual Environment, CN=$host";
+ my $filename = "/etc/pve/local/pve-ssl.pem";
+ my $subject = PVE::QemuServer::read_x509_subject_spice($filename);
my $cacert = PVE::Tools::file_get_contents("/etc/pve/pve-root-ca.pem", 8192);
$cacert =~ s/\n/\\n/g;
type => 'spice',
title => "VM $vmid",
host => $proxyticket, # this break tls hostname verification, so we need to use 'host-subject'
- proxy => "http://$host:3128",
+ proxy => "http://$proxy:3128",
'tls-port' => $port,
'host-subject' => $subject,
ca => $cacert,
$status->{ha} = &$vm_is_ha_managed($param->{vmid});
- if ($conf->{vga} && ($conf->{vga} eq 'qxl')) {
- $status->{spice} = 1;
- }
+ $status->{spice} = 1 if PVE::QemuServer::vga_conf_has_spice($conf->{vga});
return $status;
}});
raise_param_exc({ migratedfrom => "Only root may use this option." })
if $migratedfrom && $authuser ne 'root@pam';
+ # read spice ticket from STDIN
+ my $spice_ticket;
+ if ($stateuri && ($stateuri eq 'tcp') && $migratedfrom && ($rpcenv->{type} eq 'cli')) {
+ my $line = <>;
+ chomp $line;
+ $spice_ticket = $line if $line;
+ }
+
my $storecfg = PVE::Storage::config();
if (&$vm_is_ha_managed($vmid) && !$stateuri &&
syslog('info', "start VM $vmid: $upid\n");
- PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom, undef, $machine);
+ PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom, undef,
+ $machine, $spice_ticket);
return;
};