2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
4
# Copyright (c) 2012 Openstack, LLC.
7
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8
# not use this file except in compliance with the License. You may obtain
9
# a copy of the License at
11
# http://www.apache.org/licenses/LICENSE-2.0
13
# Unless required by applicable law or agreed to in writing, software
14
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
# License for the specific language governing permissions and limitations
20
Websocket proxy that is compatible with Openstack Nova.
21
Leverages websockify.py by Joel Martin
31
from nova import context
32
from nova import flags
33
from nova.openstack.common import cfg
34
from nova.openstack.common import log as logging
36
from nova import utils
42
help='Record sessions to FILE.[session_number]'),
45
help='Become a daemon (background process)'),
46
cfg.BoolOpt('ssl_only',
48
help='Disallow non-encrypted connections'),
49
cfg.BoolOpt('source_is_ipv6',
51
help='Source is ipv6'),
54
help='SSL certificate file'),
57
help='SSL key file (if separate from cert)'),
59
default='/usr/share/novnc',
60
help='Run webserver on same port. Serve files from DIR.'),
61
cfg.StrOpt('novncproxy_host',
63
help='Host on which to listen for incoming requests'),
64
cfg.IntOpt('novncproxy_port',
66
help='Port on which to listen for incoming requests'),
69
FLAGS.register_cli_opts(opts)
70
LOG = logging.getLogger(__name__)
73
class NovaWebSocketProxy(websockify.WebSocketProxy):
74
def __init__(self, *args, **kwargs):
75
websockify.WebSocketProxy.__init__(self, unix_target=None,
76
ssl_target=None, *args, **kwargs)
80
Called after a new WebSocket connection has been established.
82
cookie = Cookie.SimpleCookie()
83
cookie.load(self.headers.getheader('cookie'))
84
token = cookie['token'].value
85
ctxt = context.get_admin_context()
86
connect_info = rpc.call(ctxt, 'consoleauth',
87
{'method': 'check_token',
88
'args': {'token': token}})
91
LOG.audit("Invalid Token: %s", token)
92
raise Exception("Invalid Token")
94
host = connect_info['host']
95
port = int(connect_info['port'])
97
# Connect to the target
98
self.msg("connecting to: %s:%s" % (host, port))
99
LOG.audit("connecting to: %s:%s" % (host, port))
100
tsock = self.socket(host, port, connect=True)
102
# Handshake as necessary
103
if connect_info.get('internal_access_path'):
104
tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
105
connect_info['internal_access_path'])
107
data = tsock.recv(4096, socket.MSG_PEEK)
108
if data.find("\r\n\r\n") != -1:
109
if not data.split("\r\n")[0].find("200"):
110
LOG.audit("Invalid Connection Info %s", token)
111
raise Exception("Invalid Connection Info")
112
tsock.recv(len(data))
115
if self.verbose and not self.daemon:
116
print(self.traffic_legend)
123
tsock.shutdown(socket.SHUT_RDWR)
125
self.vmsg("%s:%s: Target closed" % (host, port))
126
LOG.audit("%s:%s: Target closed" % (host, port))
130
if __name__ == '__main__':
131
if FLAGS.ssl_only and not os.path.exists(FLAGS.cert):
132
parser.error("SSL only and %s not found" % FLAGS.cert)
135
flags.parse_args(sys.argv)
137
# Check to see if novnc html/js/css files are present
138
if not os.path.exists(FLAGS.web):
139
print "Can not find novnc html/js/css files at %s." % FLAGS.web
142
# Create and start the NovaWebSockets proxy
143
server = NovaWebSocketProxy(listen_host=FLAGS.novncproxy_host,
144
listen_port=FLAGS.novncproxy_port,
145
source_is_ipv6=FLAGS.source_is_ipv6,
146
verbose=FLAGS.verbose,
149
ssl_only=FLAGS.ssl_only,
153
target_host='ignore',
154
target_port='ignore',
157
server.start_server()