incorporate feedback from termie
This commit is contained in:
parent
71bd388a6c
commit
b01742ddb5
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# pylint: disable-msg=C0103
|
|
||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
# Copyright 2010 United States Government as represented by the
|
||||||
@ -50,7 +49,7 @@ flags.DEFINE_boolean('vnc_debug', False,
|
|||||||
'Enable debugging features, like token bypassing')
|
'Enable debugging features, like token bypassing')
|
||||||
flags.DEFINE_integer('vnc_proxy_port', 6080,
|
flags.DEFINE_integer('vnc_proxy_port', 6080,
|
||||||
'Port that the VNC proxy should bind to')
|
'Port that the VNC proxy should bind to')
|
||||||
flags.DEFINE_string('vnc_proxy_iface', '0.0.0.0',
|
flags.DEFINE_string('vnc_proxy_host', '0.0.0.0',
|
||||||
'Address that the VNC proxy should bind to')
|
'Address that the VNC proxy should bind to')
|
||||||
flags.DEFINE_integer('vnc_token_ttl', 300,
|
flags.DEFINE_integer('vnc_token_ttl', 300,
|
||||||
'How many seconds before deleting tokens')
|
'How many seconds before deleting tokens')
|
||||||
@ -90,5 +89,5 @@ if __name__ == "__main__":
|
|||||||
with_auth = auth.NovaAuthMiddleware(with_logging)
|
with_auth = auth.NovaAuthMiddleware(with_logging)
|
||||||
|
|
||||||
server = wsgi.Server()
|
server = wsgi.Server()
|
||||||
server.start(with_auth, FLAGS.vnc_proxy_port, host=FLAGS.vnc_proxy_iface)
|
server.start(with_auth, FLAGS.vnc_proxy_port, host=FLAGS.vnc_proxy_host)
|
||||||
server.wait()
|
server.wait()
|
||||||
|
@ -477,21 +477,22 @@ class API(base.Base):
|
|||||||
output['token'])}
|
output['token'])}
|
||||||
|
|
||||||
def get_vnc_console(self, context, instance_id):
|
def get_vnc_console(self, context, instance_id):
|
||||||
"""Get a url to an AJAX Console"""
|
"""Get a url to a VNC Console."""
|
||||||
instance = self.get(context, instance_id)
|
instance = self.get(context, instance_id)
|
||||||
output = self._call_compute_message('get_vnc_console',
|
output = self._call_compute_message('get_vnc_console',
|
||||||
context,
|
context,
|
||||||
instance_id)
|
instance_id)
|
||||||
rpc.cast(context, '%s' % FLAGS.vnc_console_proxy_topic,
|
rpc.cast(context, '%s' % FLAGS.vnc_console_proxy_topic,
|
||||||
{'method': 'authorize_vnc_console',
|
{'method': 'authorize_vnc_console',
|
||||||
'args': {'token': output['token'], 'host': output['host'],
|
'args': {'token': output['token'],
|
||||||
|
'host': output['host'],
|
||||||
'port': output['port']}})
|
'port': output['port']}})
|
||||||
|
|
||||||
time.sleep(1)
|
return {'url': '%s/vnc_auto.html?token=%s&host=%s&port=%s' % (
|
||||||
|
FLAGS.vnc_console_proxy_url,
|
||||||
return {'url': '%s/vnc_auto.html?token=%s&host=%s&port=%s' %
|
output['token'],
|
||||||
(FLAGS.vnc_console_proxy_url,
|
'hostignore',
|
||||||
output['token'], 'hostignore', 'portignore')}
|
'portignore')}
|
||||||
|
|
||||||
def get_console_output(self, context, instance_id):
|
def get_console_output(self, context, instance_id):
|
||||||
"""Get console output for an an instance"""
|
"""Get console output for an an instance"""
|
||||||
|
@ -559,7 +559,7 @@ class ComputeManager(manager.Manager):
|
|||||||
|
|
||||||
@exception.wrap_exception
|
@exception.wrap_exception
|
||||||
def get_vnc_console(self, context, instance_id):
|
def get_vnc_console(self, context, instance_id):
|
||||||
"""Return connection information for an vnc console"""
|
"""Return connection information for an vnc console."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
LOG.debug(_("instance %s: getting vnc console"), instance_id)
|
LOG.debug(_("instance %s: getting vnc console"), instance_id)
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
@ -287,8 +287,8 @@ DEFINE_string('vnc_console_proxy_url',
|
|||||||
'http://127.0.0.1:6080',
|
'http://127.0.0.1:6080',
|
||||||
'location of vnc console proxy, \
|
'location of vnc console proxy, \
|
||||||
in the form "http://127.0.0.1:6080"')
|
in the form "http://127.0.0.1:6080"')
|
||||||
DEFINE_string('vnc_compute_host_iface', '0.0.0.0',
|
DEFINE_string('vnc_server_host', '0.0.0.0',
|
||||||
'the compute host interface on which vnc server should listen')
|
'the host interface on which vnc server should listen')
|
||||||
DEFINE_bool('vnc_enabled', True,
|
DEFINE_bool('vnc_enabled', True,
|
||||||
'enable vnc related features')
|
'enable vnc related features')
|
||||||
DEFINE_bool('verbose', False, 'show debug output')
|
DEFINE_bool('verbose', False, 'show debug output')
|
||||||
|
@ -101,8 +101,8 @@
|
|||||||
<target port='0'/>
|
<target port='0'/>
|
||||||
</serial>
|
</serial>
|
||||||
|
|
||||||
#if $getVar('vnc_compute_host_iface', False)
|
#if $getVar('vnc_server_host', False)
|
||||||
<graphics type='vnc' port='-1' autoport='yes' keymap='en-us' listen='${vnc_compute_host_iface}'/>
|
<graphics type='vnc' port='-1' autoport='yes' keymap='en-us' listen='${vnc_server_host}'/>
|
||||||
#end if
|
#end if
|
||||||
</devices>
|
</devices>
|
||||||
</domain>
|
</domain>
|
||||||
|
@ -516,6 +516,7 @@ class LibvirtConnection(object):
|
|||||||
def get_vnc_port_for_instance(instance_name):
|
def get_vnc_port_for_instance(instance_name):
|
||||||
virt_dom = self._conn.lookupByName(instance_name)
|
virt_dom = self._conn.lookupByName(instance_name)
|
||||||
xml = virt_dom.XMLDesc(0)
|
xml = virt_dom.XMLDesc(0)
|
||||||
|
# TODO: use etree instead of minidom
|
||||||
dom = minidom.parseString(xml)
|
dom = minidom.parseString(xml)
|
||||||
|
|
||||||
for graphic in dom.getElementsByTagName('graphics'):
|
for graphic in dom.getElementsByTagName('graphics'):
|
||||||
@ -735,7 +736,7 @@ class LibvirtConnection(object):
|
|||||||
'driver_type': driver_type}
|
'driver_type': driver_type}
|
||||||
|
|
||||||
if FLAGS.vnc_enabled:
|
if FLAGS.vnc_enabled:
|
||||||
xml_info['vnc_compute_host_iface'] = FLAGS.vnc_compute_host_iface
|
xml_info['vnc_server_host'] = FLAGS.vnc_server_host
|
||||||
if ra_server:
|
if ra_server:
|
||||||
xml_info['ra_server'] = ra_server + "/128"
|
xml_info['ra_server'] = ra_server + "/128"
|
||||||
if not rescue:
|
if not rescue:
|
||||||
|
@ -18,11 +18,12 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
"""Auth Components for VNC Console"""
|
"""Auth Components for VNC Console."""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import urlparse
|
import urlparse
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from webob import Request
|
from webob import Request
|
||||||
|
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@ -32,12 +33,13 @@ from nova import utils
|
|||||||
from nova import wsgi
|
from nova import wsgi
|
||||||
from nova import vnc
|
from nova import vnc
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.vnc-proxy')
|
LOG = logging.getLogger('nova.vnc-proxy')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class NovaAuthMiddleware(object):
|
class NovaAuthMiddleware(object):
|
||||||
"""Implementation of Middleware to Handle Nova Auth"""
|
"""Implementation of Middleware to Handle Nova Auth."""
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
@ -67,8 +69,7 @@ class NovaAuthMiddleware(object):
|
|||||||
middleware = self
|
middleware = self
|
||||||
middleware.tokens = {}
|
middleware.tokens = {}
|
||||||
|
|
||||||
class Callback:
|
def callback(self, data, message):
|
||||||
def __call__(self, data, message):
|
|
||||||
if data['method'] == 'authorize_vnc_console':
|
if data['method'] == 'authorize_vnc_console':
|
||||||
token = data['args']['token']
|
token = data['args']['token']
|
||||||
LOG.audit(_("Received Token: %s)"), token)
|
LOG.audit(_("Received Token: %s)"), token)
|
||||||
@ -90,7 +91,7 @@ class NovaAuthMiddleware(object):
|
|||||||
consumer = rpc.TopicConsumer(
|
consumer = rpc.TopicConsumer(
|
||||||
connection=conn,
|
connection=conn,
|
||||||
topic=FLAGS.vnc_console_proxy_topic)
|
topic=FLAGS.vnc_console_proxy_topic)
|
||||||
consumer.register_callback(Callback())
|
consumer.register_callback(callback)
|
||||||
|
|
||||||
utils.LoopingCall(consumer.fetch, auto_ack=True,
|
utils.LoopingCall(consumer.fetch, auto_ack=True,
|
||||||
enable_callbacks=True).start(0.1)
|
enable_callbacks=True).start(0.1)
|
||||||
@ -103,7 +104,6 @@ class LoggingMiddleware(object):
|
|||||||
|
|
||||||
@webob.dec.wsgify
|
@webob.dec.wsgify
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
|
|
||||||
if req.path == vnc.proxy.WS_ENDPOINT:
|
if req.path == vnc.proxy.WS_ENDPOINT:
|
||||||
LOG.info(_("Received Websocket Request: %s"), req.url)
|
LOG.info(_("Received Websocket Request: %s"), req.url)
|
||||||
else:
|
else:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# pylint: disable-msg=C0103
|
|
||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
# Copyright 2010 United States Government as represented by the
|
||||||
@ -20,11 +19,13 @@
|
|||||||
|
|
||||||
"""Eventlet WSGI Services to proxy VNC. No nova deps."""
|
"""Eventlet WSGI Services to proxy VNC. No nova deps."""
|
||||||
|
|
||||||
from base64 import b64encode, b64decode
|
import base64
|
||||||
|
import os
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import wsgi
|
from eventlet import wsgi
|
||||||
from eventlet import websocket
|
from eventlet import websocket
|
||||||
import os
|
|
||||||
from webob import Request
|
from webob import Request
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ WS_ENDPOINT = '/data'
|
|||||||
|
|
||||||
|
|
||||||
class WebsocketVNCProxy(object):
|
class WebsocketVNCProxy(object):
|
||||||
"""Class to proxy from websocket to vnc server"""
|
"""Class to proxy from websocket to vnc server."""
|
||||||
|
|
||||||
def __init__(self, wwwroot):
|
def __init__(self, wwwroot):
|
||||||
self.wwwroot = wwwroot
|
self.wwwroot = wwwroot
|
||||||
@ -58,7 +59,7 @@ class WebsocketVNCProxy(object):
|
|||||||
d = source.recv(32384)
|
d = source.recv(32384)
|
||||||
if d == '':
|
if d == '':
|
||||||
break
|
break
|
||||||
d = b64encode(d)
|
d = base64.b64encode(d)
|
||||||
dest.send(d)
|
dest.send(d)
|
||||||
except:
|
except:
|
||||||
source.close()
|
source.close()
|
||||||
@ -70,7 +71,7 @@ class WebsocketVNCProxy(object):
|
|||||||
d = source.wait()
|
d = source.wait()
|
||||||
if d is None:
|
if d is None:
|
||||||
break
|
break
|
||||||
d = b64decode(d)
|
d = base64.b64decode(d)
|
||||||
dest.sendall(d)
|
dest.sendall(d)
|
||||||
except:
|
except:
|
||||||
source.close()
|
source.close()
|
||||||
@ -118,7 +119,7 @@ class WebsocketVNCProxy(object):
|
|||||||
|
|
||||||
|
|
||||||
class DebugMiddleware(object):
|
class DebugMiddleware(object):
|
||||||
"""Debug middleware. Skip auth, get vnc port and host from query string"""
|
"""Debug middleware. Skip auth, get vnc connect info from query string."""
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
@ -1,163 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# pylint: disable-msg=C0103
|
|
||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Euca add-on to use vnc console"""
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
|
||||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
|
||||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
|
||||||
os.pardir,
|
|
||||||
os.pardir))
|
|
||||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
|
||||||
sys.path.insert(0, possible_topdir)
|
|
||||||
|
|
||||||
import boto
|
|
||||||
import nova
|
|
||||||
from boto.ec2.connection import EC2Connection
|
|
||||||
from euca2ools import Euca2ool, InstanceValidationError, Util, ConnectionFailed
|
|
||||||
|
|
||||||
usage_string = """
|
|
||||||
Retrieves a url to an vnc console terminal
|
|
||||||
|
|
||||||
euca-get-vnc-console [-h, --help] [--version] [--debug] instance_id
|
|
||||||
|
|
||||||
REQUIRED PARAMETERS
|
|
||||||
|
|
||||||
instance_id: unique identifier for the instance show the console output for.
|
|
||||||
|
|
||||||
OPTIONAL PARAMETERS
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# This class extends boto to add VNCConsole functionality
|
|
||||||
class NovaEC2Connection(EC2Connection):
|
|
||||||
|
|
||||||
def get_vnc_console(self, instance_id):
|
|
||||||
"""
|
|
||||||
Retrieves a console connection for the specified instance.
|
|
||||||
|
|
||||||
:type instance_id: string
|
|
||||||
:param instance_id: The instance ID of a running instance on the cloud.
|
|
||||||
|
|
||||||
:rtype: :class:`VNCConsole`
|
|
||||||
"""
|
|
||||||
|
|
||||||
class VNCConsole:
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
self.parent = parent
|
|
||||||
self.instance_id = None
|
|
||||||
self.url = None
|
|
||||||
|
|
||||||
def startElement(self, name, attrs, connection):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def endElement(self, name, value, connection):
|
|
||||||
if name == 'instanceId':
|
|
||||||
self.instance_id = value
|
|
||||||
elif name == 'url':
|
|
||||||
self.url = value
|
|
||||||
else:
|
|
||||||
setattr(self, name, value)
|
|
||||||
|
|
||||||
params = {}
|
|
||||||
return self.get_object('GetVNCConsole',
|
|
||||||
{'InstanceId': instance_id}, VNCConsole)
|
|
||||||
|
|
||||||
|
|
||||||
def override_connect_ec2(aws_access_key_id=None,
|
|
||||||
aws_secret_access_key=None, **kwargs):
|
|
||||||
return NovaEC2Connection(aws_access_key_id,
|
|
||||||
aws_secret_access_key, **kwargs)
|
|
||||||
|
|
||||||
# override boto's connect_ec2 method, so that we can use NovaEC2Connection
|
|
||||||
boto.connect_ec2 = override_connect_ec2
|
|
||||||
|
|
||||||
|
|
||||||
def usage(status=1):
|
|
||||||
print usage_string
|
|
||||||
Util().usage()
|
|
||||||
sys.exit(status)
|
|
||||||
|
|
||||||
|
|
||||||
def version():
|
|
||||||
print Util().version()
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
def display_console_output(console_output):
|
|
||||||
print console_output.instance_id
|
|
||||||
print console_output.timestamp
|
|
||||||
print console_output.output
|
|
||||||
|
|
||||||
|
|
||||||
def display_vnc_console_output(console_output):
|
|
||||||
print console_output.url
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
euca = Euca2ool()
|
|
||||||
except Exception, e:
|
|
||||||
print e
|
|
||||||
usage()
|
|
||||||
|
|
||||||
instance_id = None
|
|
||||||
|
|
||||||
for name, value in euca.opts:
|
|
||||||
if name in ('-h', '--help'):
|
|
||||||
usage(0)
|
|
||||||
elif name == '--version':
|
|
||||||
version()
|
|
||||||
elif name == '--debug':
|
|
||||||
debug = True
|
|
||||||
|
|
||||||
for arg in euca.args:
|
|
||||||
instance_id = arg
|
|
||||||
break
|
|
||||||
|
|
||||||
if instance_id:
|
|
||||||
try:
|
|
||||||
euca.validate_instance_id(instance_id)
|
|
||||||
except InstanceValidationError:
|
|
||||||
print 'Invalid instance id'
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
euca_conn = euca.make_connection()
|
|
||||||
except ConnectionFailed, e:
|
|
||||||
print e.message
|
|
||||||
sys.exit(1)
|
|
||||||
try:
|
|
||||||
console_output = euca_conn.get_vnc_console(instance_id)
|
|
||||||
except Exception, ex:
|
|
||||||
euca.display_error_and_exit('%s' % ex)
|
|
||||||
|
|
||||||
display_vnc_console_output(console_output)
|
|
||||||
else:
|
|
||||||
print 'instance_id must be specified'
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Loading…
Reference in New Issue
Block a user