From 4ee5ef25dcaa9d4235e97972acdbbcbf5067d88c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Sep 2010 19:28:10 -0700 Subject: add in support for ajaxterm console access --- nova/adminclient.py | 22 ++++++++++++++++++++++ nova/endpoint/admin.py | 29 +++++++++++++++++++++++++++++ nova/utils.py | 4 ++++ 3 files changed, 55 insertions(+) (limited to 'nova') diff --git a/nova/adminclient.py b/nova/adminclient.py index 0ca32b1e5..9670b7186 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -24,6 +24,19 @@ import base64 import boto from boto.ec2.regioninfo import RegionInfo +class ConsoleInfo(object): + def __init__(self, connection=None, endpoint=None): + self.connection = connection + self.endpoint = endpoint + + def startElement(self, name, attrs, connection): + return None + + def endElement(self, name, value, connection): + if name == 'url': + self.url = str(value) + if name == 'kind': + self.url = str(value) class UserInfo(object): """ @@ -349,3 +362,12 @@ class NovaAdminClient(object): def get_hosts(self): return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)]) + def create_console(self, instance_id, kind='ajax'): + """ + Create a console + """ + console = self.apiconn.get_object('CreateConsole', {'Kind': kind, 'InstanceId': instance_id}, ConsoleInfo) + + if console.url != None: + return console + diff --git a/nova/endpoint/admin.py b/nova/endpoint/admin.py index 3d91c66dc..686e462b5 100644 --- a/nova/endpoint/admin.py +++ b/nova/endpoint/admin.py @@ -21,10 +21,14 @@ Admin API controller, exposed through http via the api worker. """ import base64 +import uuid +import subprocess +import random from nova import db from nova import exception from nova.auth import manager +from utils import novadir def user_dict(user, base64_file=None): @@ -211,3 +215,28 @@ class AdminController(object): def describe_host(self, _context, name, **_kwargs): """Returns status info for single node.""" return host_dict(db.host_get(name)) + + @admin_only + def create_console(self, _context, kind, instance_id, **_kwargs): + """Create a Console""" + #instance = db.instance_get(_context, instance_id) + host = '127.0.0.1' + + def get_port(): + for i in range(0,100): # don't loop forever + port = int(random.uniform(10000, 12000)) + cmd = "netcat 0.0.0.0 " + str(port) + " -w 2 < /dev/null" + # this Popen will exit with 0 only if the port is in use, + # so a nonzero return value implies it is unused + port_is_unused = subprocess.Popen(cmd, shell=True).wait() + if port_is_unused: + return port + raise 'Unable to find an open port' + + port = str(get_port()) + token = str(uuid.uuid4()) + cmd = novadir() + "tools/ajaxterm//ajaxterm.py --command 'ssh root@" + host + "' -t " \ + + token + " -p " + port + port_is_unused = subprocess.Popen(cmd, shell=True) + return {'url': 'http://tonbuntu:' + port + '/?token=' + token } + diff --git a/nova/utils.py b/nova/utils.py index 536d722bb..ed703a9db 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -92,6 +92,10 @@ def abspath(s): return os.path.join(os.path.dirname(__file__), s) +def novadir(s): + return os.path.abspath(nova.__file__).split('nova/__init__.pyc')[0] + + def default_flagfile(filename='nova.conf'): for arg in sys.argv: if arg.find('flagfile') != -1: -- cgit From 4f7bbaa83216dfdb298f460c771806ef1071113b Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Sep 2010 20:36:13 -0700 Subject: add in a few comments --- nova/endpoint/admin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/endpoint/admin.py b/nova/endpoint/admin.py index 686e462b5..8d184f10e 100644 --- a/nova/endpoint/admin.py +++ b/nova/endpoint/admin.py @@ -220,10 +220,9 @@ class AdminController(object): def create_console(self, _context, kind, instance_id, **_kwargs): """Create a Console""" #instance = db.instance_get(_context, instance_id) - host = '127.0.0.1' def get_port(): - for i in range(0,100): # don't loop forever + for i in xrange(0,100): # don't loop forever port = int(random.uniform(10000, 12000)) cmd = "netcat 0.0.0.0 " + str(port) + " -w 2 < /dev/null" # this Popen will exit with 0 only if the port is in use, @@ -235,8 +234,10 @@ class AdminController(object): port = str(get_port()) token = str(uuid.uuid4()) + + host = '127.0.0.1' #TODO add actual host cmd = novadir() + "tools/ajaxterm//ajaxterm.py --command 'ssh root@" + host + "' -t " \ + token + " -p " + port - port_is_unused = subprocess.Popen(cmd, shell=True) - return {'url': 'http://tonbuntu:' + port + '/?token=' + token } + port_is_unused = subprocess.Popen(cmd, shell=True) #TODO error check + return {'url': 'http://tonbuntu:' + port + '/?token=' + token } #TODO - s/tonbuntu/api_server_public_ip -- cgit From 5d0f6ac00633f622d238b49af1a0d7c566057ec5 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sun, 24 Oct 2010 17:54:52 -0700 Subject: move create_console to cloud.py from admin.py --- nova/api/ec2/admin.py | 30 ------------------------------ nova/api/ec2/cloud.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 30 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index 4281ad055..24ce5ee7c 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -21,15 +21,10 @@ Admin API controller, exposed through http via the api worker. """ import base64 -import uuid -import subprocess -import random from nova import db from nova import exception from nova.auth import manager -from utils import novadir - def user_dict(user, base64_file=None): """Convert the user object to a result dict""" @@ -187,28 +182,3 @@ class AdminController(object): """Returns status info for single node.""" return host_dict(db.host_get(name)) - @admin_only - def create_console(self, _context, kind, instance_id, **_kwargs): - """Create a Console""" - #instance = db.instance_get(_context, instance_id) - - def get_port(): - for i in xrange(0,100): # don't loop forever - port = int(random.uniform(10000, 12000)) - cmd = "netcat 0.0.0.0 " + str(port) + " -w 2 < /dev/null" - # this Popen will exit with 0 only if the port is in use, - # so a nonzero return value implies it is unused - port_is_unused = subprocess.Popen(cmd, shell=True).wait() - if port_is_unused: - return port - raise 'Unable to find an open port' - - port = str(get_port()) - token = str(uuid.uuid4()) - - host = '127.0.0.1' #TODO add actual host - cmd = novadir() + "tools/ajaxterm//ajaxterm.py --command 'ssh root@" + host + "' -t " \ - + token + " -p " + port - port_is_unused = subprocess.Popen(cmd, shell=True) #TODO error check - return {'url': 'http://tonbuntu:' + port + '/?token=' + token } #TODO - s/tonbuntu/api_server_public_ip - diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 784697b01..be537a290 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -26,7 +26,10 @@ import base64 import datetime import logging import os +import random +import subprocess import time +import uuid from nova import context import IPy @@ -436,6 +439,31 @@ class CloudController(object): db.security_group_destroy(context, security_group.id) return True + def create_console(self, context, kind, instance_id, **_kwargs): + """Create a Console""" + + instance_ref = db.instance_get(context, instance_id) + + def get_port(): + for i in xrange(0,100): # don't loop forever + port = random.randint(10000, 12000) + cmd = "netcat 0.0.0.0 %s -w 2 < /dev/null" % (port,) + # this Popen will exit with 0 only if the port is in use, + # so a nonzero return value implies it is unused + port_is_unused = subprocess.Popen(cmd, shell=True).wait() + if port_is_unused: + return port + raise 'Unable to find an open port' + + port = get_port() + token = str(uuid.uuid4()) + + host = instance_ref['host'] + cmd = "%s/tools/ajaxterm/ajaxterm.py --command 'ssh %s' -t %s -p %s" \ + % (utils.novadir(), host, token, port) + port_is_unused = subprocess.Popen(cmd, shell=True) #TODO error check + return {'url': 'http://%s:%s/?token=%s' % (FLAGS.cc_dmz, port, token)} + def get_console_output(self, context, instance_id, **kwargs): # instance_id is passed in as a list of instances ec2_id = instance_id[0] -- cgit From 7bf0f86e5863f4943900a78f9797810b80d171e5 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sun, 24 Oct 2010 17:56:09 -0700 Subject: whitespace --- nova/api/ec2/admin.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova') diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index 24ce5ee7c..23942af6e 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -26,6 +26,7 @@ from nova import db from nova import exception from nova.auth import manager + def user_dict(user, base64_file=None): """Convert the user object to a result dict""" if user: -- cgit From a3077cbb859a9237f9516ed0f073fe00839277c4 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 1 Nov 2010 16:25:56 -0700 Subject: basics to get proxied ajaxterm working with virsh --- nova/api/ec2/cloud.py | 50 ++++++++++++++++++++----------------- nova/boto_extensions.py | 40 +++++++++++++++++++++++++++++ nova/utils.py | 3 ++- nova/virt/libvirt.qemu.xml.template | 9 +++++++ 4 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 nova/boto_extensions.py (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index be537a290..469331a66 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -439,10 +439,27 @@ class CloudController(object): db.security_group_destroy(context, security_group.id) return True - def create_console(self, context, kind, instance_id, **_kwargs): - """Create a Console""" + def get_console_output(self, context, instance_id, **kwargs): + # instance_id is passed in as a list of instances + ec2_id = instance_id[0] + internal_id = ec2_id_to_internal_id(ec2_id) + instance_ref = db.instance_get_by_internal_id(context, internal_id) + output = rpc.call(context, + '%s.%s' % (FLAGS.compute_topic, + instance_ref['host']), + {"method": "get_console_output", + "args": {"instance_id": instance_ref['id']}}) + + now = datetime.datetime.utcnow() + return {"InstanceId": ec2_id, + "Timestamp": now, + "output": base64.b64encode(output)} + def get_ajax_console(self, context, instance_id, **kwargs): + """Create an AJAX Console""" - instance_ref = db.instance_get(context, instance_id) + ec2_id = instance_id[0] + internal_id = ec2_id_to_internal_id(ec2_id) + instance_ref = db.instance_get_by_internal_id(context, internal_id) def get_port(): for i in xrange(0,100): # don't loop forever @@ -450,7 +467,7 @@ class CloudController(object): cmd = "netcat 0.0.0.0 %s -w 2 < /dev/null" % (port,) # this Popen will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused - port_is_unused = subprocess.Popen(cmd, shell=True).wait() + port_is_unused = (subprocess.Popen(cmd, shell=True).wait() != 0) if port_is_unused: return port raise 'Unable to find an open port' @@ -459,26 +476,11 @@ class CloudController(object): token = str(uuid.uuid4()) host = instance_ref['host'] - cmd = "%s/tools/ajaxterm/ajaxterm.py --command 'ssh %s' -t %s -p %s" \ - % (utils.novadir(), host, token, port) + cmd = "%s/tools/ajaxterm/ajaxterm.py --command 'virsh console instance-%d' -t %s -p %s" \ + % (utils.novadir(), internal_id, token, port) port_is_unused = subprocess.Popen(cmd, shell=True) #TODO error check - return {'url': 'http://%s:%s/?token=%s' % (FLAGS.cc_dmz, port, token)} - - def get_console_output(self, context, instance_id, **kwargs): - # instance_id is passed in as a list of instances - ec2_id = instance_id[0] - internal_id = ec2_id_to_internal_id(ec2_id) - instance_ref = db.instance_get_by_internal_id(context, internal_id) - output = rpc.call(context, - '%s.%s' % (FLAGS.compute_topic, - instance_ref['host']), - {"method": "get_console_output", - "args": {"instance_id": instance_ref['id']}}) - - now = datetime.datetime.utcnow() - return {"InstanceId": ec2_id, - "Timestamp": now, - "output": base64.b64encode(output)} + dmz = 'tonbuntu' #TODO put correct value for dmz + return {'url': 'http://%s:%s/?token=%s&host=%s&port=%s' % (dmz, 8000, token, host, port)} def describe_volumes(self, context, **kwargs): if context.user.is_admin(): @@ -896,6 +898,8 @@ class CloudController(object): (context.project.name, context.user.name, inst_id)) return self._format_run_instances(context, reservation_id) + def run_instances2(self, context, **kwargs): + return self.run_instances(context, kwargs) def terminate_instances(self, context, instance_id, **kwargs): """Terminate each instance in instance_id, which is a list of ec2 ids. diff --git a/nova/boto_extensions.py b/nova/boto_extensions.py new file mode 100644 index 000000000..6d55b8012 --- /dev/null +++ b/nova/boto_extensions.py @@ -0,0 +1,40 @@ +import base64 +import boto +from boto.ec2.connection import EC2Connection + +class AjaxConsole: + 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) + +class NovaEC2Connection(EC2Connection): + def get_ajax_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:`AjaxConsole` + """ + params = {} + self.build_list_params(params, [instance_id], 'InstanceId') + return self.get_object('GetAjaxConsole', params, AjaxConsole) + pass + +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) + +boto.connect_ec2 = override_connect_ec2 diff --git a/nova/utils.py b/nova/utils.py index ca9a667cf..be61767c7 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -100,7 +100,8 @@ def abspath(s): return os.path.join(os.path.dirname(__file__), s) -def novadir(s): +def novadir(): + import nova return os.path.abspath(nova.__file__).split('nova/__init__.pyc')[0] diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index 2538b1ade..d5a249665 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -4,6 +4,9 @@ hvm %(basepath)s/kernel %(basepath)s/ramdisk + root=/dev/vda1 console=ttyS0 @@ -25,9 +28,15 @@ + + + + + -- cgit From 08963a0df7a6d1c90ba12ce60cbf15c93b0b70e6 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 21 Dec 2010 14:44:53 -0800 Subject: prototype works with kvm. now moving call from api to compute --- nova/api/ec2/cloud.py | 37 ++++++++++++++++++++++++++++++------- nova/compute/instance_types.py | 2 +- nova/compute/manager.py | 9 +++++++++ nova/virt/libvirt.qemu.xml.template | 22 +++++++++++++--------- 4 files changed, 53 insertions(+), 17 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 469331a66..09fdd32da 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -27,6 +27,7 @@ import datetime import logging import os import random +import re import subprocess import time import uuid @@ -44,10 +45,13 @@ from nova import utils from nova.compute.instance_types import INSTANCE_TYPES from nova.api import cloud from nova.api.ec2 import images +from nova.virt import libvirt_conn +from xml.dom import minidom FLAGS = flags.FLAGS flags.DECLARE('storage_availability_zone', 'nova.volume.manager') +flags.DEFINE_string("console_dmz", "tonbuntu:8000", "location of console proxy") InvalidInputException = exception.InvalidInputException @@ -454,6 +458,7 @@ class CloudController(object): return {"InstanceId": ec2_id, "Timestamp": now, "output": base64.b64encode(output)} + def get_ajax_console(self, context, instance_id, **kwargs): """Create an AJAX Console""" @@ -461,7 +466,7 @@ class CloudController(object): internal_id = ec2_id_to_internal_id(ec2_id) instance_ref = db.instance_get_by_internal_id(context, internal_id) - def get_port(): + def get_open_port(): for i in xrange(0,100): # don't loop forever port = random.randint(10000, 12000) cmd = "netcat 0.0.0.0 %s -w 2 < /dev/null" % (port,) @@ -472,15 +477,33 @@ class CloudController(object): return port raise 'Unable to find an open port' - port = get_port() + def get_pty_for_instance(instance_id): + stdout, stderr = utils.execute('virsh dumpxml instance-%d' % int(instance_id)) + dom = minidom.parseString(stdout) + serials = dom.getElementsByTagName('serial') + for serial in serials: + if serial.getAttribute('type') == 'pty': + source = serial.getElementsByTagName('source')[0] + return source.getAttribute('path') + + port = get_open_port() token = str(uuid.uuid4()) host = instance_ref['host'] - cmd = "%s/tools/ajaxterm/ajaxterm.py --command 'virsh console instance-%d' -t %s -p %s" \ - % (utils.novadir(), internal_id, token, port) - port_is_unused = subprocess.Popen(cmd, shell=True) #TODO error check - dmz = 'tonbuntu' #TODO put correct value for dmz - return {'url': 'http://%s:%s/?token=%s&host=%s&port=%s' % (dmz, 8000, token, host, port)} + + if FLAGS.libvirt_type == 'uml': + pass #FIXME + elif FLAGS.libvirt_type == 'xen': + pass #FIXME + else: + ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(internal_id) + + cmd = "%s/tools/ajaxterm/ajaxterm.py --command '%s' -t %s -p %s" \ + % (utils.novadir(), ajaxterm_cmd, token, port) + + subprocess.Popen(cmd, shell=True) + FLAGS.console_dmz = 'tonbuntu:8000' + return {'url': 'http://%s/?token=%s&host=%s&port=%s' % (FLAGS.console_dmz, token, host, port)} def describe_volumes(self, context, **kwargs): if context.user.is_admin(): diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 67ee8f8a8..bca9839d0 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -22,7 +22,7 @@ The built-in instance properties. """ INSTANCE_TYPES = { - 'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1), + 'm1.tiny': dict(memory_mb=128, vcpus=1, local_gb=0, flavorid=1), 'm1.small': dict(memory_mb=2048, vcpus=1, local_gb=20, flavorid=2), 'm1.medium': dict(memory_mb=4096, vcpus=2, local_gb=40, flavorid=3), 'm1.large': dict(memory_mb=8192, vcpus=4, local_gb=80, flavorid=4), diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 523bb8893..0897eee45 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -154,6 +154,15 @@ class ComputeManager(manager.Manager): return self.driver.get_console_output(instance_ref) + @exception.wrap_exception + def get_ajax_console(self, context, instance_id): + """Send the console output for an instance.""" + context = context.elevated() + logging.debug("instance %s: getting ajax console", instance_id) + instance_ref = self.db.instance_get(context, instance_id) + + return self.driver.get_console_output(instance_ref) + @defer.inlineCallbacks @exception.wrap_exception def attach_volume(self, context, instance_id, volume_id, mountpoint): diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index d5a249665..1f0c8a3ff 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -4,9 +4,6 @@ hvm %(basepath)s/kernel %(basepath)s/ramdisk - root=/dev/vda1 console=ttyS0 @@ -28,15 +25,22 @@ - - - - - ---> + + + + + + + + + + + -- cgit From a84e2b9131e4c8b212c9de0b9ad4931f7743ff75 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 21 Dec 2010 18:20:55 -0800 Subject: move prototype code from api into compute worker --- nova/api/ec2/cloud.py | 49 ++++++----------------------------------------- nova/compute/manager.py | 2 +- nova/virt/libvirt_conn.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 45 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 09fdd32da..4c9d882f1 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -26,11 +26,8 @@ import base64 import datetime import logging import os -import random import re -import subprocess import time -import uuid from nova import context import IPy @@ -45,13 +42,10 @@ from nova import utils from nova.compute.instance_types import INSTANCE_TYPES from nova.api import cloud from nova.api.ec2 import images -from nova.virt import libvirt_conn -from xml.dom import minidom FLAGS = flags.FLAGS flags.DECLARE('storage_availability_zone', 'nova.volume.manager') -flags.DEFINE_string("console_dmz", "tonbuntu:8000", "location of console proxy") InvalidInputException = exception.InvalidInputException @@ -466,44 +460,13 @@ class CloudController(object): internal_id = ec2_id_to_internal_id(ec2_id) instance_ref = db.instance_get_by_internal_id(context, internal_id) - def get_open_port(): - for i in xrange(0,100): # don't loop forever - port = random.randint(10000, 12000) - cmd = "netcat 0.0.0.0 %s -w 2 < /dev/null" % (port,) - # this Popen will exit with 0 only if the port is in use, - # so a nonzero return value implies it is unused - port_is_unused = (subprocess.Popen(cmd, shell=True).wait() != 0) - if port_is_unused: - return port - raise 'Unable to find an open port' - - def get_pty_for_instance(instance_id): - stdout, stderr = utils.execute('virsh dumpxml instance-%d' % int(instance_id)) - dom = minidom.parseString(stdout) - serials = dom.getElementsByTagName('serial') - for serial in serials: - if serial.getAttribute('type') == 'pty': - source = serial.getElementsByTagName('source')[0] - return source.getAttribute('path') - - port = get_open_port() - token = str(uuid.uuid4()) - - host = instance_ref['host'] - - if FLAGS.libvirt_type == 'uml': - pass #FIXME - elif FLAGS.libvirt_type == 'xen': - pass #FIXME - else: - ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(internal_id) - - cmd = "%s/tools/ajaxterm/ajaxterm.py --command '%s' -t %s -p %s" \ - % (utils.novadir(), ajaxterm_cmd, token, port) + output = rpc.call(context, + '%s.%s' % (FLAGS.compute_topic, + instance_ref['host']), + {"method": "get_ajax_console", + "args": {"instance_id": instance_ref['id']}}) - subprocess.Popen(cmd, shell=True) - FLAGS.console_dmz = 'tonbuntu:8000' - return {'url': 'http://%s/?token=%s&host=%s&port=%s' % (FLAGS.console_dmz, token, host, port)} + return {"url": output } def describe_volumes(self, context, **kwargs): if context.user.is_admin(): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0897eee45..1fc71d1e5 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -161,7 +161,7 @@ class ComputeManager(manager.Manager): logging.debug("instance %s: getting ajax console", instance_id) instance_ref = self.db.instance_get(context, instance_id) - return self.driver.get_console_output(instance_ref) + return self.driver.get_ajax_console(instance_ref) @defer.inlineCallbacks @exception.wrap_exception diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 509ed97a0..f2110e4e8 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -42,6 +42,10 @@ from nova.compute import disk from nova.compute import instance_types from nova.compute import power_state from nova.virt import images +import subprocess +import random +import uuid +from xml.dom import minidom libvirt = None libxml2 = None @@ -71,7 +75,9 @@ flags.DEFINE_string('libvirt_uri', flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') - +flags.DEFINE_string('console_dmz', + 'tonbuntu:8000', + 'location of console proxy') def get_connection(read_only): # These are loaded late so that there's no need to install these @@ -310,6 +316,47 @@ class LibvirtConnection(object): d.addCallback(self._dump_file) return d + @exception.wrap_exception + def get_ajax_console(self, instance): + def get_open_port(): + for i in xrange(0,100): # don't loop forever + port = random.randint(10000, 12000) + cmd = 'netcat 0.0.0.0 %s -w 2 < /dev/null' % (port,) + # this Popen will exit with 0 only if the port is in use, + # so a nonzero return value implies it is unused + port_is_unused = (subprocess.Popen(cmd, shell=True).wait() != 0) + if port_is_unused: + return port + raise 'Unable to find an open port' + + def get_pty_for_instance(instance_name): + stdout, stderr = utils.execute('virsh dumpxml %s' % instance_name) + dom = minidom.parseString(stdout) + serials = dom.getElementsByTagName('serial') + for serial in serials: + if serial.getAttribute('type') == 'pty': + source = serial.getElementsByTagName('source')[0] + return source.getAttribute('path') + + port = get_open_port() + token = str(uuid.uuid4()) + + host = instance['host'] + + if FLAGS.libvirt_type == 'uml': + pass #FIXME + elif FLAGS.libvirt_type == 'xen': + pass #FIXME + else: + ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(instance['name']) + + cmd = '%s/tools/ajaxterm/ajaxterm.py --command "%s" -t %s -p %s' \ + % (utils.novadir(), ajaxterm_cmd, token, port) + + subprocess.Popen(cmd, shell=True) + return 'http://%s/?token=%s&host=%s&port=%s' \ + % (FLAGS.console_dmz, token, host, port) + @defer.inlineCallbacks def _create_image(self, inst, libvirt_xml): # syntactic nicety -- cgit From 28645bec4a6d084f6dc6fa51184061844826cb12 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 21 Dec 2010 23:15:00 -0800 Subject: a few more fixes after merge with trunk --- nova/virt/libvirt_conn.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'nova') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d39e3cc5b..b186a7c45 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -42,6 +42,7 @@ import shutil import random import subprocess import uuid +from xml.dom import minidom from eventlet import event @@ -86,6 +87,9 @@ flags.DEFINE_string('libvirt_uri', flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') +flags.DEFINE_string('console_dmz', + 'tonbuntu:8000', + 'location of console proxy') def get_connection(read_only): @@ -389,13 +393,13 @@ class LibvirtConnection(object): def get_open_port(): for i in xrange(0,100): # don't loop forever port = random.randint(10000, 12000) - cmd = 'netcat 0.0.0.0 %s -w 2 < /dev/null' % (port,) - # this Popen will exit with 0 only if the port is in use, + # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused - port_is_unused = (subprocess.Popen(cmd, shell=True).wait() != 0) - if port_is_unused: + cmd = 'netcat 0.0.0.0 %s -w 1 < /dev/null || echo free' % (port) + stdout, stderr = utils.execute(cmd) + if stdout.strip() == 'free': return port - raise 'Unable to find an open port' + raise Exception('Unable to find an open port') def get_pty_for_instance(instance_name): stdout, stderr = utils.execute('virsh dumpxml %s' % instance_name) -- cgit From f98bb2b2dee4a0ff67a6548646a852686092c53f Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 22 Dec 2010 02:19:38 -0800 Subject: connecting ajax proxy to rabbit to allow token based security --- nova/api/ec2/cloud.py | 4 ++++ nova/flags.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 2ca95c70a..e4ef552b0 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -464,6 +464,10 @@ class CloudController(object): {"method": "get_ajax_console", "args": {"instance_id": instance_ref['id']}}) + rpc.cast(context, '%s' % FLAGS.ajax_proxy_topic, + {"method": "authorize", + "args": {"token": "token", "host": "host", "port":8000}}) + return {"url": output } def describe_volumes(self, context, volume_id=None, **kwargs): diff --git a/nova/flags.py b/nova/flags.py index 8fa0beb7a..53ae9be4f 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -217,7 +217,8 @@ DEFINE_string('scheduler_topic', 'scheduler', 'the topic scheduler nodes listen on') DEFINE_string('volume_topic', 'volume', 'the topic volume nodes listen on') DEFINE_string('network_topic', 'network', 'the topic network nodes listen on') - +DEFINE_string('ajax_proxy_topic', 'ajax_proxy', + 'the topic ajax proxy nodes listen on') DEFINE_bool('verbose', False, 'show debug output') DEFINE_boolean('fake_rabbit', False, 'use a fake rabbit') DEFINE_bool('fake_network', False, -- cgit From 19f389b3dcc89f0115dc6fc1a6ca606338ad866a Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 22 Dec 2010 12:36:37 -0800 Subject: working connection security --- nova/api/ec2/cloud.py | 21 ++++++++++++++------- nova/flags.py | 5 ++++- nova/virt/libvirt_conn.py | 8 +++----- 3 files changed, 21 insertions(+), 13 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index e4ef552b0..b3aa83398 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -452,7 +452,11 @@ class CloudController(object): "output": base64.b64encode(output)} def get_ajax_console(self, context, instance_id, **kwargs): - """Create an AJAX Console""" + """Get an AJAX Console + + In order for this to work properly, a ttyS0 must be configured + in the instance + """ ec2_id = instance_id[0] internal_id = ec2_id_to_internal_id(ec2_id) @@ -461,14 +465,17 @@ class CloudController(object): output = rpc.call(context, '%s.%s' % (FLAGS.compute_topic, instance_ref['host']), - {"method": "get_ajax_console", - "args": {"instance_id": instance_ref['id']}}) + {'method': 'get_ajax_console', + 'args': {'instance_id': instance_ref['id']}}) - rpc.cast(context, '%s' % FLAGS.ajax_proxy_topic, - {"method": "authorize", - "args": {"token": "token", "host": "host", "port":8000}}) + # TODO: make this a call + rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, + {'method': 'authorize_ajax_console', + 'args': {'token': output['token'], 'host': output['host'], + 'port':output['port']}}) - return {"url": output } + return {'url': '%s?token=%s' % (FLAGS.ajax_console_proxy_url, + output['token'])} def describe_volumes(self, context, volume_id=None, **kwargs): if context.user.is_admin(): diff --git a/nova/flags.py b/nova/flags.py index 53ae9be4f..c6e56fcc7 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -217,8 +217,11 @@ DEFINE_string('scheduler_topic', 'scheduler', 'the topic scheduler nodes listen on') DEFINE_string('volume_topic', 'volume', 'the topic volume nodes listen on') DEFINE_string('network_topic', 'network', 'the topic network nodes listen on') -DEFINE_string('ajax_proxy_topic', 'ajax_proxy', +DEFINE_string('ajax_console_proxy_topic', 'ajax_proxy', 'the topic ajax proxy nodes listen on') +DEFINE_string('ajax_console_proxy_url', + 'http://tonbuntu:8000', + 'location of ajax console proxy, in the form "http://tonbuntu:8000"') DEFINE_bool('verbose', False, 'show debug output') DEFINE_boolean('fake_rabbit', False, 'use a fake rabbit') DEFINE_bool('fake_network', False, diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index b186a7c45..800312c98 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -87,9 +87,6 @@ flags.DEFINE_string('libvirt_uri', flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') -flags.DEFINE_string('console_dmz', - 'tonbuntu:8000', - 'location of console proxy') def get_connection(read_only): @@ -426,8 +423,9 @@ class LibvirtConnection(object): % (utils.novadir(), ajaxterm_cmd, token, port) subprocess.Popen(cmd, shell=True) - return 'http://%s/?token=%s&host=%s&port=%s' \ - % (FLAGS.console_dmz, token, host, port) + return {'token': token, 'host': host, 'port': port} + #return 'http://%s/?token=%s&host=%s&port=%s' \ + # % (FLAGS.console_dmz, token, host, port) def _create_image(self, inst, libvirt_xml, prefix='', disk_images=None): # syntactic nicety -- cgit From aa8a6a01bdf8a2f0f732e993a1732993f7328eff Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 22 Dec 2010 13:00:20 -0800 Subject: add in support of openstack api --- nova/api/ec2/cloud.py | 23 +---------------------- nova/api/openstack/servers.py | 9 +++++++++ nova/compute/api.py | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 22 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b3aa83398..11853c8db 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -452,30 +452,9 @@ class CloudController(object): "output": base64.b64encode(output)} def get_ajax_console(self, context, instance_id, **kwargs): - """Get an AJAX Console - - In order for this to work properly, a ttyS0 must be configured - in the instance - """ - ec2_id = instance_id[0] internal_id = ec2_id_to_internal_id(ec2_id) - instance_ref = db.instance_get_by_internal_id(context, internal_id) - - output = rpc.call(context, - '%s.%s' % (FLAGS.compute_topic, - instance_ref['host']), - {'method': 'get_ajax_console', - 'args': {'instance_id': instance_ref['id']}}) - - # TODO: make this a call - rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, - {'method': 'authorize_ajax_console', - 'args': {'token': output['token'], 'host': output['host'], - 'port':output['port']}}) - - return {'url': '%s?token=%s' % (FLAGS.ajax_console_proxy_url, - output['token'])} + return self.compute_api.get_ajax_console(context, internal_id) def describe_volumes(self, context, volume_id=None, **kwargs): if context.user.is_admin(): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 5c3322f7c..45db89cbf 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -195,3 +195,12 @@ class Controller(wsgi.Controller): logging.error("Compute.api::unpause %s", readable) return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() + + def get_ajax_console(self, req, id): + """ Returns a url to and ajaxterm instance console. """ + try: + self.compute_api.get_ajax_console(req.environ['nova.context'], + int(id)) + except exception.NotFound: + return faults.Fault(exc.HTTPNotFound()) + return exc.HTTPAccepted() diff --git a/nova/compute/api.py b/nova/compute/api.py index c740814da..1acf320ae 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -316,6 +316,30 @@ class ComputeAPI(base.Base): {"method": "unrescue_instance", "args": {"instance_id": instance['id']}}) + def get_ajax_console(self, context, instance_id): + """Get an AJAX Console + + In order for this to work properly, a ttyS0 must be configured + in the instance + """ + + instance_ref = db.instance_get_by_internal_id(context, instance_id) + + output = rpc.call(context, + '%s.%s' % (FLAGS.compute_topic, + instance_ref['host']), + {'method': 'get_ajax_console', + 'args': {'instance_id': instance_ref['id']}}) + + # TODO: make this a call + rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, + {'method': 'authorize_ajax_console', + 'args': {'token': output['token'], 'host': output['host'], + 'port':output['port']}}) + + return {'url': '%s?token=%s' % (FLAGS.ajax_console_proxy_url, + output['token'])} + def _get_network_topic(self, context): """Retrieves the network host for a project""" network_ref = self.network_manager.get_network(context) -- cgit From 0093342106cc270859df0511dbefad8ec8fc2320 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 22 Dec 2010 13:31:33 -0800 Subject: use libvirt python bindings instead of system call --- nova/virt/libvirt_conn.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'nova') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 800312c98..658efa8d1 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -392,17 +392,18 @@ class LibvirtConnection(object): port = random.randint(10000, 12000) # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused - cmd = 'netcat 0.0.0.0 %s -w 1 < /dev/null || echo free' % (port) + cmd = 'netcat 0.0.0.0 %s -w 1 Date: Wed, 22 Dec 2010 18:52:43 -0800 Subject: minor notes, commit before rewriting proxy with eventlet --- nova/compute/api.py | 1 - nova/virt/libvirt_conn.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/compute/api.py b/nova/compute/api.py index 1acf320ae..3e9b58db5 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -331,7 +331,6 @@ class ComputeAPI(base.Base): {'method': 'get_ajax_console', 'args': {'instance_id': instance_ref['id']}}) - # TODO: make this a call rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, {'method': 'authorize_ajax_console', 'args': {'token': output['token'], 'host': output['host'], diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 658efa8d1..55754ea48 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -389,7 +389,7 @@ class LibvirtConnection(object): def get_ajax_console(self, instance): def get_open_port(): for i in xrange(0,100): # don't loop forever - port = random.randint(10000, 12000) + port = random.randint(10000, 12000) #TODO - make flag # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused cmd = 'netcat 0.0.0.0 %s -w 1 Date: Wed, 22 Dec 2010 23:41:07 -0800 Subject: rewrite proxy to not use twisted --- nova/flags.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index c6e56fcc7..c4404a120 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -222,6 +222,9 @@ DEFINE_string('ajax_console_proxy_topic', 'ajax_proxy', DEFINE_string('ajax_console_proxy_url', 'http://tonbuntu:8000', 'location of ajax console proxy, in the form "http://tonbuntu:8000"') +DEFINE_string('ajax_console_proxy_port', + 8000, + 'port that ajax_console_proxy binds') DEFINE_bool('verbose', False, 'show debug output') DEFINE_boolean('fake_rabbit', False, 'use a fake rabbit') DEFINE_bool('fake_network', False, -- cgit From 151ffc57a3dd5217981dbaa1754384290d7d73ec Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Thu, 23 Dec 2010 00:23:08 -0800 Subject: move port range for ajaxterm to flag --- nova/virt/libvirt_conn.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 55754ea48..1049eaefa 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -87,6 +87,9 @@ flags.DEFINE_string('libvirt_uri', flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') +flags.DEFINE_string('ajaxterm_portrange', + '10000-12000', + 'Range of ports that ajaxterm should randomly try to bind') def get_connection(read_only): @@ -388,8 +391,9 @@ class LibvirtConnection(object): @exception.wrap_exception def get_ajax_console(self, instance): def get_open_port(): + start_port, end_port = FLAGS.ajaxterm_portrange.split("-") for i in xrange(0,100): # don't loop forever - port = random.randint(10000, 12000) #TODO - make flag + port = random.randint(int(start_port), int(end_port)) # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused cmd = 'netcat 0.0.0.0 %s -w 1 Date: Thu, 23 Dec 2010 00:58:15 -0800 Subject: removing xen/uml specific switches. If they need special treatment, we can add it --- nova/virt/libvirt_conn.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d855770b7..3c0efd18f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -427,12 +427,7 @@ class LibvirtConnection(object): host = instance['host'] - if FLAGS.libvirt_type == 'uml': - pass #FIXME - elif FLAGS.libvirt_type == 'xen': - pass #FIXME - else: - ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(instance['name']) + ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(instance['name']) cmd = '%s/tools/ajaxterm/ajaxterm.py --command "%s" -t %s -p %s' \ % (utils.novadir(), ajaxterm_cmd, token, port) -- cgit From 43dfae5926bafa1575aee9624651cfcb8f170bb3 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Thu, 23 Dec 2010 01:22:54 -0800 Subject: some pep8 fixes --- nova/flags.py | 2 +- nova/virt/libvirt_conn.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index 2d5aec840..406f159e6 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -220,7 +220,7 @@ DEFINE_string('scheduler_topic', 'scheduler', 'the topic scheduler nodes listen on') DEFINE_string('volume_topic', 'volume', 'the topic volume nodes listen on') DEFINE_string('network_topic', 'network', 'the topic network nodes listen on') -DEFINE_string('ajax_console_proxy_topic', 'ajax_proxy', +DEFINE_string('ajax_console_proxy_topic', 'ajax_proxy', 'the topic ajax proxy nodes listen on') DEFINE_string('ajax_console_proxy_url', 'http://tonbuntu:8000', diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 3c0efd18f..40a430d86 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -402,7 +402,7 @@ class LibvirtConnection(object): def get_ajax_console(self, instance): def get_open_port(): start_port, end_port = FLAGS.ajaxterm_portrange.split("-") - for i in xrange(0,100): # don't loop forever + for i in xrange(0,100): # don't loop forever port = random.randint(int(start_port), int(end_port)) # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused -- cgit From 35638077a186f9315ac6e30cdbe096730a540ed8 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 28 Dec 2010 17:42:33 -0800 Subject: add in unit tests --- nova/tests/cloud_unittest.py | 13 +++++++++++++ nova/tests/compute_unittest.py | 10 ++++++++++ nova/virt/fake.py | 2 ++ 3 files changed, 25 insertions(+) (limited to 'nova') diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py index 70d2c44da..8e3391226 100644 --- a/nova/tests/cloud_unittest.py +++ b/nova/tests/cloud_unittest.py @@ -150,6 +150,19 @@ class CloudTestCase(test.TestCase): greenthread.sleep(0.3) rv = yield self.cloud.terminate_instances(self.context, [instance_id]) + def test_ajax_console(self): + kwargs = {'image_id': image_id } + rv = yield self.cloud.run_instances(self.context, **kwargs) + instance_id = rv['instancesSet'][0]['instanceId'] + output = yield self.cloud.get_console_output(context=self.context, + instance_id=[instance_id]) + self.assertEquals(b64decode(output['output']), + 'http://fakeajaxconsole.com/?token=FAKETOKEN') + # TODO(soren): We need this until we can stop polling in the rpc code + # for unit tests. + greenthread.sleep(0.3) + rv = yield self.cloud.terminate_instances(self.context, [instance_id]) + def test_key_generation(self): result = self._create_key('test') private_key = result['private_key'] diff --git a/nova/tests/compute_unittest.py b/nova/tests/compute_unittest.py index 348bb3351..529847972 100644 --- a/nova/tests/compute_unittest.py +++ b/nova/tests/compute_unittest.py @@ -153,6 +153,16 @@ class ComputeTestCase(test.TestCase): self.assert_(console) self.compute.terminate_instance(self.context, instance_id) + def test_ajax_console(self): + """Make sure we can get console output from instance""" + instance_id = self._create_instance() + self.compute.run_instance(self.context, instance_id) + + console = self.compute.get_ajax_console(self.context, + instance_id) + self.assert_(console) + self.compute.terminate_instance(self.context, instance_id) + def test_run_instance_existing(self): """Ensure failure when running an instance that already exists""" instance_id = self._create_instance() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 238acf798..b97dbd511 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -260,6 +260,8 @@ class FakeConnection(object): def get_console_output(self, instance): return 'FAKE CONSOLE OUTPUT' + def get_ajax_console(self, instance): + return 'http://fakeajaxconsole.com/?token=FAKETOKEN' class FakeInstance(object): -- cgit From 13dfb66624ca082bd5e83969213c657d2d2d1dff Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 29 Dec 2010 16:11:02 -0800 Subject: pep8 fix, and add in flags that don't refernece my laptop --- nova/flags.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index 406f159e6..6f2747fc9 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -223,11 +223,11 @@ DEFINE_string('network_topic', 'network', 'the topic network nodes listen on') DEFINE_string('ajax_console_proxy_topic', 'ajax_proxy', 'the topic ajax proxy nodes listen on') DEFINE_string('ajax_console_proxy_url', - 'http://tonbuntu:8000', - 'location of ajax console proxy, in the form "http://tonbuntu:8000"') + 'http://127.0.0.1:8000', + 'location of ajax console proxy, \ + in the form "http://127.0.0.1:8000"') DEFINE_string('ajax_console_proxy_port', - 8000, - 'port that ajax_console_proxy binds') + 8000, 'port that ajax_console_proxy binds') DEFINE_bool('verbose', False, 'show debug output') DEFINE_boolean('fake_rabbit', False, 'use a fake rabbit') DEFINE_bool('fake_network', False, -- cgit From 8df8dd5cedb8bd84053fa489df8b9cf34ee68895 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 3 Jan 2011 08:56:36 -0800 Subject: add stubs for xen driver --- nova/virt/xenapi/vmops.py | 5 +++++ nova/virt/xenapi_conn.py | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 76f31635a..146b9e6df 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -281,3 +281,8 @@ class VMOps(object): """Return snapshot of console""" # TODO: implement this to fix pylint! return 'FAKE CONSOLE OUTPUT of instance' + + def get_ajax_console(self, instance): + """Return link to instance's ajax console""" + # TODO: implement this! + return 'http://fakeajaxconsole/fake_url' diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index f17c8f39d..e1ad04b15 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -175,6 +175,10 @@ class XenAPIConnection(object): """Return snapshot of console""" return self._vmops.get_console_output(instance) + def get_ajax_console(self, instance): + """Return link to instance's ajax console""" + return self._vmops.get_ajax_console(instance) + def attach_volume(self, instance_name, device_path, mountpoint): """Attach volume storage to VM instance""" return self._volumeops.attach_volume(instance_name, -- cgit From ee2d8a5bcdaf938b7047131d7809d1b6b3120b59 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 3 Jan 2011 22:51:19 -0800 Subject: some fixes per vish's feedback --- nova/compute/instance_types.py | 2 +- nova/compute/manager.py | 2 +- nova/virt/libvirt_conn.py | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 02defbf2f..196d6a8df 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -26,7 +26,7 @@ from nova import exception FLAGS = flags.FLAGS INSTANCE_TYPES = { - 'm1.tiny': dict(memory_mb=128, vcpus=1, local_gb=0, flavorid=1), + 'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1), 'm1.small': dict(memory_mb=2048, vcpus=1, local_gb=20, flavorid=2), 'm1.medium': dict(memory_mb=4096, vcpus=2, local_gb=40, flavorid=3), 'm1.large': dict(memory_mb=8192, vcpus=4, local_gb=80, flavorid=4), diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 882b000ef..e485a0415 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -372,7 +372,7 @@ class ComputeManager(manager.Manager): def get_ajax_console(self, context, instance_id): """Send the console output for an instance.""" context = context.elevated() - logging.debug("instance %s: getting ajax console", instance_id) + logging.debug(_("instance %s: getting ajax console"), instance_id) instance_ref = self.db.instance_get(context, instance_id) return self.driver.get_ajax_console(instance_ref) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 6471e8c0c..a36af16e2 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -438,7 +438,7 @@ class LibvirtConnection(object): stdout, stderr = utils.execute(cmd) if stdout.strip() == 'free': return port - raise Exception('Unable to find an open port') + raise Exception(_('Unable to find an open port')) def get_pty_for_instance(instance_name): virt_dom = self._conn.lookupByName(instance_name) @@ -452,7 +452,6 @@ class LibvirtConnection(object): port = get_open_port() token = str(uuid.uuid4()) - host = instance['host'] ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(instance['name']) @@ -462,8 +461,6 @@ class LibvirtConnection(object): subprocess.Popen(cmd, shell=True) return {'token': token, 'host': host, 'port': port} - #return 'http://%s/?token=%s&host=%s&port=%s' \ - # % (FLAGS.console_dmz, token, host, port) def _create_image(self, inst, libvirt_xml, prefix='', disk_images=None): # syntactic nicety -- cgit From 7c01430020ceabec765f388b70685808064cda3f Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 4 Jan 2011 16:22:47 -0800 Subject: some more cleanup --- nova/adminclient.py | 24 ------------------------ nova/api/ec2/admin.py | 1 - nova/api/ec2/cloud.py | 2 -- nova/virt/libvirt.xml.template | 2 +- 4 files changed, 1 insertion(+), 28 deletions(-) (limited to 'nova') diff --git a/nova/adminclient.py b/nova/adminclient.py index c4e72b930..eabfce804 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -26,20 +26,6 @@ import httplib from nova import flags from boto.ec2.regioninfo import RegionInfo -class ConsoleInfo(object): - def __init__(self, connection=None, endpoint=None): - self.connection = connection - self.endpoint = endpoint - - def startElement(self, name, attrs, connection): - return None - - def endElement(self, name, value, connection): - if name == 'url': - self.url = str(value) - if name == 'kind': - self.url = str(value) - FLAGS = flags.FLAGS DEFAULT_CLC_URL = 'http://127.0.0.1:8773' @@ -389,13 +375,3 @@ class NovaAdminClient(object): def get_hosts(self): return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)]) - - def create_console(self, instance_id, kind='ajax'): - """ - Create a console - """ - console = self.apiconn.get_object('CreateConsole', {'Kind': kind, 'InstanceId': instance_id}, ConsoleInfo) - - if console.url != None: - return console - diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index e876724b1..fac01369e 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -183,4 +183,3 @@ class AdminController(object): def describe_host(self, _context, name, **_kwargs): """Returns status info for single node.""" return host_dict(db.host_get(name)) - diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 20413e319..a59131ab5 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -774,8 +774,6 @@ class CloudController(object): return self._format_run_instances(context, instances[0]['reservation_id']) - def run_instances2(self, context, **kwargs): - return self.run_instances(context, kwargs) def terminate_instances(self, context, instance_id, **kwargs): """Terminate each instance in instance_id, which is a list of ec2 ids. instance_id is a kwarg so its name cannot be modified.""" diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template index 3317c9eca..2eb7d9488 100644 --- a/nova/virt/libvirt.xml.template +++ b/nova/virt/libvirt.xml.template @@ -72,7 +72,7 @@ - + -- cgit From 9b99e385967c4ba21d94d82aa62115fc11634118 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 5 Jan 2011 14:57:31 -0800 Subject: socat will need to be added to our nova sudoers --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index a36af16e2..d83c57741 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -454,7 +454,7 @@ class LibvirtConnection(object): token = str(uuid.uuid4()) host = instance['host'] - ajaxterm_cmd = 'socat - %s' % get_pty_for_instance(instance['name']) + ajaxterm_cmd = 'sudo socat - %s' % get_pty_for_instance(instance['name']) cmd = '%s/tools/ajaxterm/ajaxterm.py --command "%s" -t %s -p %s' \ % (utils.novadir(), ajaxterm_cmd, token, port) -- cgit From 4edfa8ea26f8e820674e8bebbe34b6ed5885a69b Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 10 Jan 2011 13:44:45 -0800 Subject: consolidate boto_extensions.py and euca-get-ajax-console, fix bugs from previous trunk merge --- nova/api/ec2/cloud.py | 2 +- nova/boto_extensions.py | 40 ---------------------------------------- nova/compute/api.py | 6 +++--- 3 files changed, 4 insertions(+), 44 deletions(-) delete mode 100644 nova/boto_extensions.py (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 17b9a14fb..b426710bc 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -500,7 +500,7 @@ class CloudController(object): def get_ajax_console(self, context, instance_id, **kwargs): ec2_id = instance_id[0] - internal_id = ec2_id_to_internal_id(ec2_id) + internal_id = ec2_id_to_id(ec2_id) return self.compute_api.get_ajax_console(context, internal_id) def describe_volumes(self, context, volume_id=None, **kwargs): diff --git a/nova/boto_extensions.py b/nova/boto_extensions.py deleted file mode 100644 index 6d55b8012..000000000 --- a/nova/boto_extensions.py +++ /dev/null @@ -1,40 +0,0 @@ -import base64 -import boto -from boto.ec2.connection import EC2Connection - -class AjaxConsole: - 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) - -class NovaEC2Connection(EC2Connection): - def get_ajax_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:`AjaxConsole` - """ - params = {} - self.build_list_params(params, [instance_id], 'InstanceId') - return self.get_object('GetAjaxConsole', params, AjaxConsole) - pass - -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) - -boto.connect_ec2 = override_connect_ec2 diff --git a/nova/compute/api.py b/nova/compute/api.py index adf4dbe43..4d25bd705 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -416,13 +416,13 @@ class API(base.Base): def get_ajax_console(self, context, instance_id): """Get a url to an AJAX Console""" - instance_ref = db.instance_get_by_internal_id(context, instance_id) + instance = self.get(context, instance_id) output = rpc.call(context, '%s.%s' % (FLAGS.compute_topic, - instance_ref['host']), + instance['host']), {'method': 'get_ajax_console', - 'args': {'instance_id': instance_ref['id']}}) + 'args': {'instance_id': instance['id']}}) rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, {'method': 'authorize_ajax_console', -- cgit From eb48bdce5ad131245977dff50030f5561b8809c1 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 11 Jan 2011 14:33:20 -0800 Subject: bah - pep8 errors --- nova/compute/api.py | 4 ++-- nova/tests/test_cloud.py | 2 +- nova/virt/fake.py | 1 + nova/virt/libvirt_conn.py | 7 ++++--- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/compute/api.py b/nova/compute/api.py index 4d25bd705..632ce0efb 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -426,8 +426,8 @@ class API(base.Base): rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic, {'method': 'authorize_ajax_console', - 'args': {'token': output['token'], 'host': output['host'], - 'port':output['port']}}) + 'args': {'token': output['token'], 'host': output['host'], + 'port': output['port']}}) return {'url': '%s?token=%s' % (FLAGS.ajax_console_proxy_url, output['token'])} diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 76a620406..8e43eec00 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -168,7 +168,7 @@ class CloudTestCase(test.TestCase): rv = self.cloud.terminate_instances(self.context, [instance_id]) def test_ajax_console(self): - kwargs = {'image_id': image_id } + kwargs = {'image_id': image_id} rv = yield self.cloud.run_instances(self.context, **kwargs) instance_id = rv['instancesSet'][0]['instanceId'] output = yield self.cloud.get_console_output(context=self.context, diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 925c32e4d..8abe08e41 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -292,6 +292,7 @@ class FakeConnection(object): def get_ajax_console(self, instance): return 'http://fakeajaxconsole.com/?token=FAKETOKEN' + class FakeInstance(object): def __init__(self): diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index dc31d8357..4a907c88f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -445,7 +445,7 @@ class LibvirtConnection(object): def get_ajax_console(self, instance): def get_open_port(): start_port, end_port = FLAGS.ajaxterm_portrange.split("-") - for i in xrange(0,100): # don't loop forever + for i in xrange(0, 100): # don't loop forever port = random.randint(int(start_port), int(end_port)) # netcat will exit with 0 only if the port is in use, # so a nonzero return value implies it is unused @@ -469,10 +469,11 @@ class LibvirtConnection(object): token = str(uuid.uuid4()) host = instance['host'] - ajaxterm_cmd = 'sudo socat - %s' % get_pty_for_instance(instance['name']) + ajaxterm_cmd = 'sudo socat - %s' \ + % get_pty_for_instance(instance['name']) cmd = '%s/tools/ajaxterm/ajaxterm.py --command "%s" -t %s -p %s' \ - % (utils.novadir(), ajaxterm_cmd, token, port) + % (utils.novadir(), ajaxterm_cmd, token, port) subprocess.Popen(cmd, shell=True) return {'token': token, 'host': host, 'port': port} -- cgit