include spiceterm

This commit is contained in:
Dietmar Maurer 2013-12-10 07:33:09 +01:00
parent e1bae24c4c
commit 2d802f8c3b
7 changed files with 224 additions and 13 deletions

View File

@ -83,7 +83,7 @@ __PACKAGE__->register_method ({
path => 'version',
method => 'GET',
permissions => { user => 'all' },
description => "API version details",
description => "API version details. The result also includes the global datacenter confguration.",
parameters => {
additionalProperties => 0,
properties => {},
@ -99,6 +99,13 @@ __PACKAGE__->register_method ({
code => sub {
my ($resp, $param) = @_;
return PVE::pvecfg::version_info();
my $res = PVE::Cluster::cfs_read_file('datacenter.cfg');
my $vi = PVE::pvecfg::version_info();
foreach my $k (qw(version release repoid)) {
$res->{$k} = $vi->{$k};
}
return $res;
}});
1;

View File

@ -119,6 +119,7 @@ __PACKAGE__->register_method ({
{ name => 'rrd' }, # fixme: remove?
{ name => 'rrddata' },# fixme: remove?
{ name => 'vncshell' },
{ name => 'spiceshell' },
{ name => 'time' },
{ name => 'dns' },
{ name => 'services' },
@ -767,6 +768,137 @@ __PACKAGE__->register_method ({
};
}});
__PACKAGE__->register_method ({
name => 'spiceshell',
path => 'spiceshell',
method => 'POST',
protected => 1,
proxyto => 'node',
permissions => {
description => "Restricted to users on realm 'pam'",
check => ['perm', '/nodes/{node}', [ 'Sys.Console' ]],
},
description => "Creates a spice shell.",
parameters => {
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
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,
},
upgrade => {
type => 'boolean',
description => "Run 'apt-get dist-upgrade' instead of normal shell.",
optional => 1,
default => 0,
},
},
},
returns => {
description => "Returned values can be directly passed to the 'remote-viewer' application.",
additionalProperties => 1,
properties => {
type => { type => 'string' },
password => { type => 'string' },
proxy => { type => 'string' },
host => { type => 'string' },
'tls-port' => { type => 'integer' },
},
},
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my ($user, undef, $realm) = PVE::AccessControl::verify_username($authuser);
raise_perm_exc("realm != pam") if $realm ne 'pam';
raise_perm_exc('user != root@pam') if $param->{upgrade} && $user ne 'root@pam';
my $node = $param->{node};
my $proxy = $param->{proxy};
if (!$proxy) {
my $host = `hostname -f` || PVE::INotify::nodename();
chomp $host;
$proxy = $host;
}
my $authpath = "/nodes/$node";
my ($ticket, $proxyticket) = PVE::AccessControl::assemble_spice_ticket($authuser, 0, $node);
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;
my $port = PVE::Tools::next_spice_port();
my $shcmd;
if ($user eq 'root@pam') {
if ($param->{upgrade}) {
my $upgradecmd = "pveupgrade --shell";
$shcmd = [ '/bin/bash', '-c', $upgradecmd ];
} else {
$shcmd = [ '/bin/bash', '-l' ];
}
} else {
$shcmd = [ '/bin/login' ];
}
my $timeout = 10;
my $cmd = ['/usr/bin/spiceterm', '--port', $port, '--addr', '127.0.0.1',
'--timeout', $timeout, '--authpath', $authpath,
'--permissions', 'Sys.Console', '--', @$shcmd];
my $realcmd = sub {
my $upid = shift;
syslog ('info', "starting spiceterm $upid\n");
my $cmdstr = join (' ', @$cmd);
syslog ('info', "launch command: $cmdstr");
eval {
foreach my $k (keys %ENV) {
next if $k eq 'PATH' || $k eq 'TERM' || $k eq 'USER' || $k eq 'HOME';
delete $ENV{$k};
}
$ENV{PWD} = '/';
$ENV{SPICE_TICKET} = $ticket;
PVE::Tools::run_command($cmd, errmsg => "spiceterm failed");
};
if (my $err = $@) {
syslog ('err', $err);
}
return;
};
my $upid = $rpcenv->fork_worker('spiceshell', "", $user, $realcmd);
PVE::Tools::wait_for_vnc_port($port);
return {
type => 'spice',
title => "Shell on '$node'",
host => $proxyticket, # this break tls hostname verification, so we need to use 'host-subject'
proxy => "http://$proxy:3128",
'tls-port' => $port,
'host-subject' => $subject,
ca => $cacert,
password => $ticket,
'delete-this-file' => 1,
};
}});
__PACKAGE__->register_method({
name => 'dns',
path => 'dns',

2
debian/control.in vendored
View File

@ -3,7 +3,7 @@ Version: @VERSION@-@PACKAGERELEASE@
Section: admin
Priority: optional
Architecture: amd64
Depends: perl (>= 5.10.0-19), libtimedate-perl, libauthen-pam-perl, libintl-perl, rsync, libjson-perl, liblockfile-simple-perl, vncterm, qemu-server (>= 1.1-1), libwww-perl (>= 6.04-1), libnet-http-perl (>= 6.06-1), libhttp-daemon-perl, wget, libnet-dns-perl, vlan, ifenslave-2.6 (>= 1.1.0-10), liblinux-inotify2-perl, debconf (>= 0.5) | debconf-2.0, netcat-traditional, pve-cluster (>= 1.0-29), libpve-common-perl, libpve-storage-perl, libterm-readline-gnu-perl, libpve-access-control (>= 3.0-2), libio-socket-ssl-perl, libfilesys-df-perl, libfile-readbackwards-perl, libfile-sync-perl, redhat-cluster-pve, resource-agents-pve, fence-agents-pve, cstream, postfix | mail-transport-agent, libxml-parser-perl, lzop, dtach, libanyevent-perl, liburi-perl, logrotate, libanyevent-http-perl, apt-transport-https, libapt-pkg-perl, libcrypt-ssleay-perl, liblwp-protocol-https-perl
Depends: perl (>= 5.10.0-19), libtimedate-perl, libauthen-pam-perl, libintl-perl, rsync, libjson-perl, liblockfile-simple-perl, vncterm, qemu-server (>= 1.1-1), libwww-perl (>= 6.04-1), libnet-http-perl (>= 6.06-1), libhttp-daemon-perl, wget, libnet-dns-perl, vlan, ifenslave-2.6 (>= 1.1.0-10), liblinux-inotify2-perl, debconf (>= 0.5) | debconf-2.0, netcat-traditional, pve-cluster (>= 1.0-29), libpve-common-perl, libpve-storage-perl, libterm-readline-gnu-perl, libpve-access-control (>= 3.0-2), libio-socket-ssl-perl, libfilesys-df-perl, libfile-readbackwards-perl, libfile-sync-perl, redhat-cluster-pve, resource-agents-pve, fence-agents-pve, cstream, postfix | mail-transport-agent, libxml-parser-perl, lzop, dtach, libanyevent-perl, liburi-perl, logrotate, libanyevent-http-perl, apt-transport-https, libapt-pkg-perl, libcrypt-ssleay-perl, liblwp-protocol-https-perl, spiceterm
Conflicts: netcat-openbsd, vzdump
Replaces: vzdump
Provides: vzdump

View File

@ -250,6 +250,18 @@ Ext.define('PVE.Utils', { statics: {
return data;
},
render_console_viewer: function(value) {
if (!value) {
return PVE.Utils.defaultText + ' (Java VNC Applet)';
} else if (value === 'applet') {
return 'Java VNC Applet';
} else if (value === 'vv') {
return 'SPICE (remote-viewer)';
} else {
return value;
}
},
language_map: {
zh_CN: 'Chinese',
ca: 'Catalan',
@ -507,6 +519,7 @@ Ext.define('PVE.Utils', { statics: {
vncproxy: [ 'VM/CT', gettext('Console') ],
spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
vncshell: [ '', gettext('Shell') ],
spiceshell: [ '', gettext('Shell') + ' (Spice)' ],
qmsnapshot: [ 'VM', gettext('Snapshot') ],
qmrollback: [ 'VM', gettext('Rollback') ],
qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
@ -911,6 +924,31 @@ Ext.define('PVE.Utils', { statics: {
nw.focus();
},
defaultViewer: function(){
return PVE.VersionInfo.console || 'applet';
},
openSpiceViewer: function(url, params){
PVE.Utils.API2Request({
url: url,
params: params,
method: 'POST',
failure: function(response, opts){
Ext.Msg.alert('Error', response.htmlStatus);
},
success: function(response, opts){
var raw = "[virt-viewer]\n";
Ext.Object.each(response.result.data, function(k, v) {
raw += k + "=" + v + "\n";
});
var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
encodeURIComponent(raw);
window.open(url, "_top");
}
});
},
// comp.setLoading() is buggy in ExtJS 4.0.7, so we
// use el.mask() instead
setErrorMask: function(comp, msg) {

View File

@ -45,6 +45,35 @@ Ext.define('PVE.dc.KeyboardEdit', {
}
});
Ext.define('PVE.dc.ConsoleViewerEdit', {
extend: 'PVE.window.Edit',
initComponent : function() {
var me = this;
var data = [];
Ext.Array.each(['', 'applet', 'vv'], function(value) {
data.push([value, PVE.Utils.render_console_viewer(value)]);
});
Ext.applyIf(me, {
subject: gettext('Console Viewer'),
items: {
xtype: 'pveKVComboBox',
name: 'console',
data: data,
value: '',
fieldLabel: gettext('Console Viewer')
}
});
me.callParent();
me.load();
}
});
Ext.define('PVE.dc.OptionView', {
extend: 'PVE.grid.ObjectGrid',
alias: ['widget.pveDcOptionView'],
@ -75,6 +104,12 @@ Ext.define('PVE.dc.OptionView', {
}
return value;
}
},
console: {
header: gettext('Console Viewer'),
editor: 'PVE.dc.ConsoleViewerEdit',
required: true,
renderer: PVE.Utils.render_console_viewer
}
};

View File

@ -51,13 +51,12 @@ Ext.define('PVE.node.Config', {
text: gettext('Shell'),
disabled: !caps.nodes['Sys.Console'],
handler: function() {
var url = Ext.urlEncode({
console: 'shell',
node: nodename
});
var nw = window.open("?" + url, '_blank',
"innerWidth=745,innerheight=427");
nw.focus();
if (PVE.Utils.defaultViewer() === 'vv') {
var params = { proxy: window.location.hostname };
PVE.Utils.openSpiceViewer('/nodes/' + nodename + '/spiceshell', params);
} else {
PVE.Utils.openConoleWindow('shell', undefined, nodename);
}
}
});

View File

@ -145,10 +145,10 @@ Ext.define('PVE.qemu.Config', {
text: gettext('Console'),
disabled: !caps.vms['VM.Console'],
handler: function() {
if (spice) {
openSpiceConsole(vmid, nodename, vmname);
} else {
if (PVE.VersionInfo.console === 'applet' || !spice) {
PVE.Utils.openConoleWindow('kvm', vmid, nodename, vmname);
} else {
openSpiceConsole(vmid, nodename, vmname);
}
},
menu: new Ext.menu.Menu({