mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 23:25:24 +00:00
Move CONSLOE from webvirtmgr
This commit is contained in:
parent
25ccd6c3fd
commit
3ce2198790
4 changed files with 229 additions and 27 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
import django
|
import django
|
||||||
|
|
||||||
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
@ -21,14 +22,58 @@ django.setup()
|
||||||
import re
|
import re
|
||||||
import Cookie
|
import Cookie
|
||||||
import socket
|
import socket
|
||||||
from webvirtcloud.settings import WS_PORT
|
from webvirtcloud.settings import WS_PORT, WS_HOST, WS_CERT
|
||||||
from webvirtcloud.settings import WS_HOST
|
|
||||||
from webvirtcloud.settings import WS_CERT
|
|
||||||
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
||||||
from tunnel import Tunnel
|
from tunnel import Tunnel
|
||||||
|
|
||||||
if WS_CERT:
|
from optparse import OptionParser
|
||||||
CERT = WS_CERT
|
parser = OptionParser()
|
||||||
|
|
||||||
|
parser.add_option("-v",
|
||||||
|
"--verbose",
|
||||||
|
dest="verbose",
|
||||||
|
action="store_true",
|
||||||
|
help="Verbose mode",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_option("-d",
|
||||||
|
"--debug",
|
||||||
|
dest="debug",
|
||||||
|
action="store_true",
|
||||||
|
help="Debug mode",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_option("-H",
|
||||||
|
"--host",
|
||||||
|
dest="host",
|
||||||
|
action="store",
|
||||||
|
help="Listen host",
|
||||||
|
default=WS_HOST)
|
||||||
|
|
||||||
|
parser.add_option("-p",
|
||||||
|
"--port",
|
||||||
|
dest="port",
|
||||||
|
action="store",
|
||||||
|
help="Listen port",
|
||||||
|
default=WS_PORT or 6080)
|
||||||
|
|
||||||
|
parser.add_option("-c",
|
||||||
|
"--cert",
|
||||||
|
dest="cert",
|
||||||
|
action="store",
|
||||||
|
help="Certificate file path",
|
||||||
|
default=WS_CERT or CERT)
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
FORMAT="%(asctime)s - %(name)s - %(levelname)s : %(message)s"
|
||||||
|
if options.debug:
|
||||||
|
logging.basicConfig(level=logging.DEBUG,format=FORMAT)
|
||||||
|
options.verbose=True
|
||||||
|
elif options.verbose:
|
||||||
|
logging.basicConfig(level=logging.INFO,format=FORMAT)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(level=logging.WARNING,format=FORMAT)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from websockify import WebSocketProxy
|
from websockify import WebSocketProxy
|
||||||
|
@ -64,8 +109,8 @@ def get_connection_infos(token):
|
||||||
instance.compute.type,
|
instance.compute.type,
|
||||||
instance.name)
|
instance.name)
|
||||||
if instance.compute.hostname.count(':'):
|
if instance.compute.hostname.count(':'):
|
||||||
connhost = host.split(':')[0]
|
connhost = instance.compute.hostname.split(':')[0]
|
||||||
connport = host.split(':')[1]
|
connport = instance.compute.hostname.split(':')[1]
|
||||||
else:
|
else:
|
||||||
connhost = instance.compute.hostname
|
connhost = instance.compute.hostname
|
||||||
connport = 22
|
connport = 22
|
||||||
|
@ -74,14 +119,9 @@ def get_connection_infos(token):
|
||||||
console_host = conn.get_console_listen_addr()
|
console_host = conn.get_console_listen_addr()
|
||||||
console_port = conn.get_console_port()
|
console_port = conn.get_console_port()
|
||||||
console_socket = conn.get_console_socket()
|
console_socket = conn.get_console_socket()
|
||||||
except:
|
except Exception, e:
|
||||||
connhost = None
|
logging.error('Fail to retrieve console connexion infos for token %s : %s' % (token, e))
|
||||||
connport = None
|
raise
|
||||||
connuser = None
|
|
||||||
conntype = None
|
|
||||||
console_host = None
|
|
||||||
console_port = None
|
|
||||||
console_socket = None
|
|
||||||
return (connhost, connport, connuser, conntype, console_host,
|
return (connhost, connport, connuser, conntype, console_host,
|
||||||
console_port, console_socket)
|
console_port, console_socket)
|
||||||
|
|
||||||
|
@ -90,11 +130,24 @@ class CompatibilityMixIn(object):
|
||||||
def _new_client(self, daemon, socket_factory):
|
def _new_client(self, daemon, socket_factory):
|
||||||
cookie = Cookie.SimpleCookie()
|
cookie = Cookie.SimpleCookie()
|
||||||
cookie.load(self.headers.getheader('cookie'))
|
cookie.load(self.headers.getheader('cookie'))
|
||||||
|
if 'token' not in cookie:
|
||||||
|
self.msg('No token cookie found !')
|
||||||
|
return False
|
||||||
token = cookie['token'].value
|
token = cookie['token'].value
|
||||||
|
|
||||||
(connhost, connport, connuser, conntype, console_host, console_port,
|
(connhost, connport, connuser, conntype, console_host, console_port,
|
||||||
console_socket) = get_connection_infos(token)
|
console_socket) = get_connection_infos(token)
|
||||||
|
|
||||||
|
cnx_debug_msg = "Connexion infos :\n"
|
||||||
|
cnx_debug_msg += "- connhost : '%s'\n" % connhost
|
||||||
|
cnx_debug_msg += "- connport : '%s'\n" % connport
|
||||||
|
cnx_debug_msg += "- connuser : '%s'\n" % connuser
|
||||||
|
cnx_debug_msg += "- conntype : '%s'\n" % conntype
|
||||||
|
cnx_debug_msg += "- console_host : '%s'\n" % console_host
|
||||||
|
cnx_debug_msg += "- console_port : '%s'\n" % console_port
|
||||||
|
cnx_debug_msg += "- console_socket : '%s'\n" % console_socket
|
||||||
|
logging.debug(cnx_debug_msg)
|
||||||
|
|
||||||
if console_socket and conntype == CONN_SOCKET:
|
if console_socket and conntype == CONN_SOCKET:
|
||||||
# Local socket on local host
|
# Local socket on local host
|
||||||
self.msg('Try to open local socket %s' % console_socket)
|
self.msg('Try to open local socket %s' % console_socket)
|
||||||
|
@ -184,11 +237,11 @@ if __name__ == '__main__':
|
||||||
if USE_HANDLER:
|
if USE_HANDLER:
|
||||||
# Create the WebSocketProxy with NovaProxyRequestHandler handler
|
# Create the WebSocketProxy with NovaProxyRequestHandler handler
|
||||||
server = WebSocketProxy(RequestHandlerClass=NovaProxyRequestHandler,
|
server = WebSocketProxy(RequestHandlerClass=NovaProxyRequestHandler,
|
||||||
listen_host=WS_HOST,
|
listen_host=options.host,
|
||||||
listen_port=WS_PORT,
|
listen_port=options.port,
|
||||||
source_is_ipv6=False,
|
source_is_ipv6=False,
|
||||||
verbose=False,
|
verbose=options.verbose,
|
||||||
cert=CERT,
|
cert=options.cert,
|
||||||
key=None,
|
key=None,
|
||||||
ssl_only=False,
|
ssl_only=False,
|
||||||
daemon=False,
|
daemon=False,
|
||||||
|
@ -201,11 +254,11 @@ if __name__ == '__main__':
|
||||||
wrap_cmd=None)
|
wrap_cmd=None)
|
||||||
else:
|
else:
|
||||||
# Create the NovaWebSockets proxy
|
# Create the NovaWebSockets proxy
|
||||||
server = NovaWebSocketProxy(listen_host=WS_HOST,
|
server = NovaWebSocketProxy(listen_host=options.host,
|
||||||
listen_port=WS_PORT,
|
listen_port=options.port,
|
||||||
source_is_ipv6=False,
|
source_is_ipv6=False,
|
||||||
verbose=False,
|
verbose=options.verbose,
|
||||||
cert=CERT,
|
cert=options.cert,
|
||||||
key=None,
|
key=None,
|
||||||
ssl_only=False,
|
ssl_only=False,
|
||||||
daemon=False,
|
daemon=False,
|
||||||
|
|
|
@ -62,10 +62,92 @@
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#spice-menu {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border: 0px none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spice-menu li {
|
||||||
|
width: auto;
|
||||||
|
float: left;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 0px;
|
||||||
|
border: 0px none;
|
||||||
|
position: relative;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.2em;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spice-menu .spice-submenu {
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spice-menu .spice-submenu li {
|
||||||
|
float: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid white;
|
||||||
|
border-right: 1px solid white;
|
||||||
|
font: normal 14px sans-serif;
|
||||||
|
z-index: 100;
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 100px;
|
||||||
|
padding: 0.2em;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spice-menu li:hover > .spice-submenu {
|
||||||
|
opacity: 1;
|
||||||
|
display: block;
|
||||||
|
margin: 2px 0 0 -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spice-menu li:hover > .spice-submenu li {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="header">
|
||||||
|
<ul id='spice-menu'>
|
||||||
|
<li>Send key(s)
|
||||||
|
<ul class='spice-submenu'>
|
||||||
|
<li onclick='sendCtrlAltDel();'>Ctrl+Alt+Del</li>
|
||||||
|
<li onclick='sendCtrlAltFN(0);'>Ctrl+Alt+F1</li>
|
||||||
|
<li onclick='sendCtrlAltFN(1);'>Ctrl+Alt+F2</li>
|
||||||
|
<li onclick='sendCtrlAltFN(2);'>Ctrl+Alt+F3</li>
|
||||||
|
<li onclick='sendCtrlAltFN(3);'>Ctrl+Alt+F4</li>
|
||||||
|
<li onclick='sendCtrlAltFN(4);'>Ctrl+Alt+F5</li>
|
||||||
|
<li onclick='sendCtrlAltFN(5);'>Ctrl+Alt+F6</li>
|
||||||
|
<li onclick='sendCtrlAltFN(6);'>Ctrl+Alt+F7</li>
|
||||||
|
<li onclick='sendCtrlAltFN(7);'>Ctrl+Alt+F8</li>
|
||||||
|
<li onclick='sendCtrlAltFN(8);'>Ctrl+Alt+F9</li>
|
||||||
|
<li onclick='sendCtrlAltFN(9);'>Ctrl+Alt+F10</li>
|
||||||
|
<li onclick='sendCtrlAltFN(10);'>Ctrl+Alt+F11</li>
|
||||||
|
<li onclick='sendCtrlAltFN(11);'>Ctrl+Alt+F12</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li onclick='fullscreen()'>Fullscreen</li>
|
||||||
|
</ul>
|
||||||
<div id="status"></div>
|
<div id="status"></div>
|
||||||
|
</div>
|
||||||
<div id="spice-area">
|
<div id="spice-area">
|
||||||
<div id="spice-screen" class="spice-screen"></div>
|
<div id="spice-screen" class="spice-screen"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,7 +281,50 @@
|
||||||
log_info('Connected');
|
log_info('Connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
var uri = 'ws://{{ ws_host }}:{{ ws_port }}';
|
function sendCtrlAltFN(f) {
|
||||||
|
if (sc && sc.inputs && sc.inputs.state === "ready"){
|
||||||
|
var keys_code=[KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12];
|
||||||
|
|
||||||
|
if (keys_code[f]==undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var key = new SpiceMsgcKeyDown();
|
||||||
|
var msg = new SpiceMiniData();
|
||||||
|
|
||||||
|
update_modifier(true, KEY_LCtrl, sc);
|
||||||
|
update_modifier(true, KEY_Alt, sc);
|
||||||
|
|
||||||
|
key.code = keys_code[f];
|
||||||
|
msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
|
||||||
|
sc.inputs.send_msg(msg);
|
||||||
|
msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
|
||||||
|
sc.inputs.send_msg(msg);
|
||||||
|
|
||||||
|
if(Ctrl_state == false) update_modifier(false, KEY_LCtrl, sc);
|
||||||
|
if(Alt_state == false) update_modifier(false, KEY_Alt, sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fullscreen() {
|
||||||
|
var screen=document.getElementById('spice-screen');
|
||||||
|
if(screen.requestFullscreen) {
|
||||||
|
screen.requestFullscreen();
|
||||||
|
} else if(screen.mozRequestFullScreen) {
|
||||||
|
screen.mozRequestFullScreen();
|
||||||
|
} else if(screen.webkitRequestFullscreen) {
|
||||||
|
screen.webkitRequestFullscreen();
|
||||||
|
} else if(screen.msRequestFullscreen) {
|
||||||
|
screen.msRequestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri;
|
||||||
|
if (window.location.protocol === "https:") {
|
||||||
|
uri = 'wss://{{ ws_host }}:{{ ws_port }}';
|
||||||
|
} else {
|
||||||
|
uri = 'ws://{{ ws_host }}:{{ ws_port }}';
|
||||||
|
}
|
||||||
|
|
||||||
var password = '{{ console_passwd }}';
|
var password = '{{ console_passwd }}';
|
||||||
log_info('Connecting ...');
|
log_info('Connecting ...');
|
||||||
connect(uri,password);
|
connect(uri,password);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<td>
|
<td>
|
||||||
<div id="noVNC_status">{% trans "Loading..." %}</div>
|
<div id="noVNC_status">{% trans "Loading..." %}</div>
|
||||||
</td>
|
</td>
|
||||||
<td width="18%" style="text-align:right;">
|
<td width="32%" style="text-align:right;">
|
||||||
<div id="noVNC_buttons">
|
<div id="noVNC_buttons">
|
||||||
<!-- dirty fix for keyboard on iOS devices -->
|
<!-- dirty fix for keyboard on iOS devices -->
|
||||||
<input type="button" id="showKeyboard" value="Keyboard" title="Show Keyboard"/>
|
<input type="button" id="showKeyboard" value="Keyboard" title="Show Keyboard"/>
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
</textarea>
|
</textarea>
|
||||||
|
|
||||||
<input type=button value="Ctrl+Alt+Del" id="sendCtrlAltDelButton">
|
<input type=button value="Ctrl+Alt+Del" id="sendCtrlAltDelButton">
|
||||||
|
<input type=button value="Fullscreen" id="askFullscreen">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -101,10 +102,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateState(rfb, state, oldstate, msg) {
|
function updateState(rfb, state, oldstate, msg) {
|
||||||
var s, sb, cad, level;
|
var s, sb, cad, af, level;
|
||||||
s = $D('noVNC_status');
|
s = $D('noVNC_status');
|
||||||
sb = $D('noVNC_status_bar');
|
sb = $D('noVNC_status_bar');
|
||||||
cad = $D('sendCtrlAltDelButton');
|
cad = $D('sendCtrlAltDelButton');
|
||||||
|
af = $D('askFullscreen');
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'failed':
|
case 'failed':
|
||||||
level = "error";
|
level = "error";
|
||||||
|
@ -128,9 +130,11 @@
|
||||||
|
|
||||||
if (state === "normal") {
|
if (state === "normal") {
|
||||||
cad.disabled = false;
|
cad.disabled = false;
|
||||||
|
af.disabled = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cad.disabled = true;
|
cad.disabled = true;
|
||||||
|
af.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(msg) !== 'undefined') {
|
if (typeof(msg) !== 'undefined') {
|
||||||
|
@ -139,11 +143,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fullscreen() {
|
||||||
|
var screen=document.getElementById('noVNC_canvas');
|
||||||
|
if(screen.requestFullscreen) {
|
||||||
|
screen.requestFullscreen();
|
||||||
|
} else if(screen.mozRequestFullScreen) {
|
||||||
|
screen.mozRequestFullScreen();
|
||||||
|
} else if(screen.webkitRequestFullscreen) {
|
||||||
|
screen.webkitRequestFullscreen();
|
||||||
|
} else if(screen.msRequestFullscreen) {
|
||||||
|
screen.msRequestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.onscriptsload = function () {
|
window.onscriptsload = function () {
|
||||||
var host, port, password, path, token;
|
var host, port, password, path, token;
|
||||||
|
|
||||||
$D('sendCtrlAltDelButton').style.display = "inline";
|
$D('sendCtrlAltDelButton').style.display = "inline";
|
||||||
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
|
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
|
||||||
|
$D('askFullscreen').style.display = "inline";
|
||||||
|
$D('askFullscreen').onclick = fullscreen;
|
||||||
|
|
||||||
// dirty fix for keyboard on iOS devices
|
// dirty fix for keyboard on iOS devices
|
||||||
if (isTouchDevice) {
|
if (isTouchDevice) {
|
||||||
|
|
|
@ -391,6 +391,11 @@ class wvmInstance(wvmConnect):
|
||||||
def get_console_listen_addr(self):
|
def get_console_listen_addr(self):
|
||||||
listen_addr = util.get_xml_path(self._XMLDesc(0),
|
listen_addr = util.get_xml_path(self._XMLDesc(0),
|
||||||
"/domain/devices/graphics/@listen")
|
"/domain/devices/graphics/@listen")
|
||||||
|
if listen_addr is None:
|
||||||
|
listen_addr = util.get_xml_path(self._XMLDesc(0),
|
||||||
|
"/domain/devices/graphics/listen/@address")
|
||||||
|
if listen_addr is None:
|
||||||
|
return "127.0.0.1"
|
||||||
return listen_addr
|
return listen_addr
|
||||||
|
|
||||||
def get_console_socket(self):
|
def get_console_socket(self):
|
||||||
|
|
Loading…
Reference in a new issue