Commit 4c75210a authored by Anthony Young's avatar Anthony Young

Add nova-novncproxy

 * Adds the nova-novncproxy binary, to provide support for vnc + OpensStack nova
 * Adds the ability to pass an auth token in via url, which is subsequently
   passed back to the proxy as a cookie.
parent f84504bc
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 Openstack, LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#!/usr/bin/env python
'''
Websocket proxy that is compatible with Openstack Nova.
Leverages wsproxy.py by Joel Martin
'''
import Cookie
import socket
import sys
import wsproxy
from nova import context
from nova import flags
from nova import rpc
from nova import utils
from nova.openstack.common import cfg
opts = [
cfg.BoolOpt('record',
default=False,
help='Record sessions to FILE.[session_number]'),
cfg.BoolOpt('daemon',
default=False,
help='Become a daemon (background process)'),
cfg.BoolOpt('ssl_only',
default=False,
help='Disallow non-encrypted connections'),
cfg.BoolOpt('source_is_ipv6',
default=False,
help='Source is ipv6'),
cfg.StrOpt('cert',
default='self.pem',
help='SSL certificate file'),
cfg.StrOpt('key',
default=None,
help='SSL key file (if separate from cert)'),
cfg.StrOpt('web',
default='.',
help='Run webserver on same port. Serve files from DIR.'),
cfg.StrOpt('novncproxy_host',
default='0.0.0.0',
help='Host on which to listen for incoming requests'),
cfg.IntOpt('novncproxy_port',
default=6080,
help='Port on which to listen for incoming requests'),
]
FLAGS = flags.FLAGS
FLAGS.register_cli_opts(opts)
class NovaWebSocketProxy(wsproxy.WebSocketProxy):
def __init__(self, *args, **kwargs):
wsproxy.WebSocketProxy.__init__(self, *args, **kwargs)
def new_client(self):
"""
Called after a new WebSocket connection has been established.
"""
cookie = Cookie.SimpleCookie()
cookie.load(self.headers.getheader('cookie'))
token = cookie['token'].value
ctxt = context.get_admin_context()
connect_info = rpc.call(ctxt, 'consoleauth',
{'method': 'check_token',
'args': {'token': token}})
if not connect_info:
raise Exception("Invalid Token")
host = connect_info['host']
port = int(connect_info['port'])
# Connect to the target
self.msg("connecting to: %s:%s" % (
host, port))
tsock = self.socket(host, port,
connect=True)
# Handshake as necessary
if connect_info.get('internal_access_path'):
tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
connect_info['internal_access_path'])
while True:
data = tsock.recv(4096, socket.MSG_PEEK)
if data.find("\r\n\r\n") != -1:
if not data.split("\r\n")[0].find("200"):
raise Exception("Invalid Connection Info")
tsock.recv(len(data))
break
if self.verbose and not self.daemon:
print(self.traffic_legend)
# Start proxying
try:
self.do_proxy(tsock)
except:
if tsock:
tsock.shutdown(socket.SHUT_RDWR)
tsock.close()
self.vmsg("%s:%s: Target closed" % (host, port))
raise
if __name__ == '__main__':
if FLAGS.ssl_only and not os.path.exists(FLAGS.cert):
parser.error("SSL only and %s not found" % FLAGS.cert)
# Setup flags
utils.default_flagfile()
FLAGS(sys.argv)
# Create and start the NovaWebSockets proxy
server = NovaWebSocketProxy(listen_host=FLAGS.novncproxy_host,
listen_port=FLAGS.novncproxy_port,
source_is_ipv6=FLAGS.source_is_ipv6,
verbose=FLAGS.verbose,
cert=FLAGS.cert,
key=FLAGS.key,
ssl_only=FLAGS.ssl_only,
daemon=FLAGS.daemon,
record=FLAGS.record,
web=FLAGS.web,
target_host='ignore',
target_port='ignore',
wrap_mode='exit',
wrap_cmd=None)
server.start_server()
...@@ -84,14 +84,15 @@ ...@@ -84,14 +84,15 @@
} }
window.onload = function () { window.onload = function () {
var host, port, password, path; var host, port, password, path, token;
$D('sendCtrlAltDelButton').style.display = "inline"; $D('sendCtrlAltDelButton').style.display = "inline";
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel; $D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
document.title = unescape(WebUtil.getQueryVar('title', 'noVNC')); document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
host = WebUtil.getQueryVar('host', null); token = WebUtil.getQueryVar('token', null);
port = WebUtil.getQueryVar('port', null); host = window.location.hostname;
port = window.location.port;
password = WebUtil.getQueryVar('password', ''); password = WebUtil.getQueryVar('password', '');
path = WebUtil.getQueryVar('path', 'websockify'); path = WebUtil.getQueryVar('path', 'websockify');
if ((!host) || (!port)) { if ((!host) || (!port)) {
...@@ -109,6 +110,12 @@ ...@@ -109,6 +110,12 @@
'view_only': WebUtil.getQueryVar('view_only', false), 'view_only': WebUtil.getQueryVar('view_only', false),
'updateState': updateState, 'updateState': updateState,
'onPasswordRequired': passwordRequired}); 'onPasswordRequired': passwordRequired});
/* If a token variable is passed in, set the parameter in a cookie. This is
used by nova-novncproxy. */
if (token) {
WebUtil.createCookie('token', token, 1)
}
rfb.connect(host, port, password, path); rfb.connect(host, port, password, path);
}; };
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment