summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-06-21 19:36:25 +0000
committerGerrit Code Review <review@openstack.org>2012-06-21 19:36:25 +0000
commit6a16ebd2ac1259c7dbde3be8db5679f24070ed5c (patch)
tree618bbe6a4e5e35ee449a3a7d0fa3778e29fedb32
parent1ecf8311f817cf1c5b3b6f0efe7c022da1950187 (diff)
parent13871ad4f39361531dff1abd7f9257369862cccc (diff)
downloadnova-6a16ebd2ac1259c7dbde3be8db5679f24070ed5c.tar.gz
nova-6a16ebd2ac1259c7dbde3be8db5679f24070ed5c.tar.xz
nova-6a16ebd2ac1259c7dbde3be8db5679f24070ed5c.zip
Merge "Propose nova-novncproxy back into nove core."
-rwxr-xr-xbin/nova-novncproxy157
1 files changed, 157 insertions, 0 deletions
diff --git a/bin/nova-novncproxy b/bin/nova-novncproxy
new file mode 100755
index 000000000..228db0d2f
--- /dev/null
+++ b/bin/nova-novncproxy
@@ -0,0 +1,157 @@
+#!/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.
+
+'''
+Websocket proxy that is compatible with Openstack Nova.
+Leverages websockify.py by Joel Martin
+'''
+
+import Cookie
+import os
+import socket
+import sys
+
+import websockify
+
+from nova import context
+from nova import flags
+from nova import log as logging
+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='/usr/share/novnc',
+ 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)
+LOG = logging.getLogger(__name__)
+
+
+class NovaWebSocketProxy(websockify.WebSocketProxy):
+ def __init__(self, *args, **kwargs):
+ websockify.WebSocketProxy.__init__(self, unix_target=None,
+ ssl_target=None, *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:
+ LOG.audit("Invalid Token: %s", token)
+ 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))
+ LOG.audit("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"):
+ LOG.audit("Invalid Connection Info %s", token)
+ 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 Exception:
+ if tsock:
+ tsock.shutdown(socket.SHUT_RDWR)
+ tsock.close()
+ self.vmsg("%s:%s: Target closed" % (host, port))
+ LOG.audit("%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
+ flags.parse_args(sys.argv)
+
+ # Check to see if novnc html/js/css files are present
+ if not os.path.exists(FLAGS.web):
+ print "Can not find novnc html/js/css files at %s." % FLAGS.web
+ sys.exit(-1)
+
+ # 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()