incorporate feedback from termie

This commit is contained in:
Anthony Young 2011-03-24 15:55:29 -07:00
parent 71bd388a6c
commit b01742ddb5
9 changed files with 36 additions and 197 deletions

View File

@ -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()

View File

@ -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"""

View File

@ -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)

View File

@ -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')

View File

@ -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>

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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()