summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@tonbuntu>2010-11-01 16:25:56 -0700
committerroot <root@tonbuntu>2010-11-01 16:25:56 -0700
commita3077cbb859a9237f9516ed0f073fe00839277c4 (patch)
treea011d0fea8c123287797c8f4dbf92c05fac37a6a
parent7bf0f86e5863f4943900a78f9797810b80d171e5 (diff)
basics to get proxied ajaxterm working with virsh
-rwxr-xr-xbin/nova-ajax-proxy31
-rw-r--r--nova/api/ec2/cloud.py50
-rw-r--r--nova/boto_extensions.py40
-rw-r--r--nova/utils.py3
-rw-r--r--nova/virt/libvirt.qemu.xml.template9
-rwxr-xr-xtools/euca_additions/euca-get-ajax-console83
6 files changed, 192 insertions, 24 deletions
diff --git a/bin/nova-ajax-proxy b/bin/nova-ajax-proxy
new file mode 100755
index 000000000..1a0c896ee
--- /dev/null
+++ b/bin/nova-ajax-proxy
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+from twisted.internet import reactor
+from twisted.web import http
+from twisted.web.proxy import Proxy, ProxyRequest
+import urlparse, exceptions
+
+class AjaxProxyRequest(ProxyRequest):
+ def process(self):
+ if 'referer' in self.received_headers:
+ auth_uri = self.received_headers['referer']
+ else:
+ auth_uri = self.uri
+
+ try:
+ auth_params = urlparse.parse_qs(urlparse.urlparse(auth_uri).query)
+ parsed_uri = urlparse.urlparse(self.uri)
+
+ self.uri = "http://%s:%s%s?%s"% (auth_params['host'][0], auth_params['port'][0], parsed_uri.path, parsed_uri.query)
+
+ ProxyRequest.process(self)
+ except (exceptions.KeyError):
+ pass
+
+class AjaxProxy(Proxy):
+ requestFactory = AjaxProxyRequest
+
+factory = http.HTTPFactory()
+factory.protocol = AjaxProxy
+
+reactor.listenTCP(8000, factory)
+reactor.run()
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 @@
<type>hvm</type>
<kernel>%(basepath)s/kernel</kernel>
<initrd>%(basepath)s/ramdisk</initrd>
+<!--
+ <cmdline>root=/dev/vda1 console=tty0 console=ttyS0,115200</cmdline>
+-->
<cmdline>root=/dev/vda1 console=ttyS0</cmdline>
</os>
<features>
@@ -25,9 +28,15 @@
<parameter name="DHCPSERVER" value="%(dhcp_server)s" />
</filterref>
</interface>
+ <serial type='pty'>
+ <source path='/dev/pts/2'/>
+ <target port='0'/>
+ </serial>
+<!--
<serial type="file">
<source path='%(basepath)s/console.log'/>
<target port='1'/>
</serial>
+-->
</devices>
</domain>
diff --git a/tools/euca_additions/euca-get-ajax-console b/tools/euca_additions/euca-get-ajax-console
new file mode 100755
index 000000000..14891c1c6
--- /dev/null
+++ b/tools/euca_additions/euca-get-ajax-console
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+
+import getopt, sys, os
+from euca2ools import Euca2ool, InstanceValidationError, Util, ConnectionFailed
+
+usage_string = """
+Retrieves a url to an ajax console terminal
+
+euca-get-ajax-console [-h, --help] [--version] [--debug] instance_id
+
+REQUIRED PARAMETERS
+
+instance_id unique identifier for the instance show the console output for.
+
+OPTIONAL PARAMETERS
+
+"""
+
+from nova.boto_extensions import *
+
+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_ajax_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_ajax_console(instance_id)
+ except Exception, ex:
+ euca.display_error_and_exit('%s' % ex)
+
+ display_ajax_console_output(console_output)
+ else:
+ print 'instance_id must be specified'
+ usage()
+if __name__ == "__main__":
+ main()
+