diff options
| author | Andy Smith <code@term.ie> | 2010-12-10 11:46:29 -0800 |
|---|---|---|
| committer | Andy Smith <code@term.ie> | 2010-12-10 11:46:29 -0800 |
| commit | e3aae367c2d449bfc25216865f37182953b535f4 (patch) | |
| tree | c7bacce0d21577041edcfa5a394d46f4f32d52ab /nova | |
| parent | 4d06429290a373ae3a42b1f9b58d7253d269e048 (diff) | |
| parent | 1a759c3722610d720dd8dabf816db146c1063937 (diff) | |
merge-a-tat-tat upstream to this branch
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/api/ec2/cloud.py | 1 | ||||
| -rw-r--r-- | nova/api/openstack/__init__.py | 8 | ||||
| -rw-r--r-- | nova/compute/api.py | 17 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_adminapi.py | 61 | ||||
| -rw-r--r-- | nova/virt/xenapi/vm_utils.py | 48 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 12 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 4 |
7 files changed, 144 insertions, 7 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4eef5e1ef..05f8c3d0b 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -753,7 +753,6 @@ class CloudController(object): ramdisk_id=kwargs.get('ramdisk_id'), display_name=kwargs.get('display_name'), description=kwargs.get('display_description'), - user_data=kwargs.get('user_data', ''), key_name=kwargs.get('key_name'), security_group=kwargs.get('security_group'), generate_hostname=internal_id_to_ec2_id) diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 4ca108c4e..c9efe5222 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -48,6 +48,10 @@ flags.DEFINE_string('nova_api_auth', 'nova.api.openstack.auth.BasicApiAuthManager', 'The auth mechanism to use for the OpenStack API implemenation') +flags.DEFINE_bool('allow_admin_api', + False, + 'When True, this API service will accept admin operations.') + class API(wsgi.Middleware): """WSGI entry point for all OpenStack API requests.""" @@ -183,6 +187,10 @@ class APIRouter(wsgi.Router): mapper.resource("sharedipgroup", "sharedipgroups", controller=sharedipgroups.Controller()) + if FLAGS.allow_admin_api: + logging.debug("Including admin operations in API.") + # TODO: Place routes for admin operations here. + super(APIRouter, self).__init__(mapper) diff --git a/nova/compute/api.py b/nova/compute/api.py index cb23dae55..8e0efa4cc 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -55,9 +55,8 @@ class ComputeAPI(base.Base): def create_instances(self, context, instance_type, image_id, min_count=1, max_count=1, kernel_id=None, ramdisk_id=None, - display_name='', description='', user_data='', - key_name=None, key_data=None, - security_group='default', + display_name='', description='', key_name=None, + key_data=None, security_group='default', generate_hostname=generate_default_hostname): """Create the number of instances requested if quote and other arguments check out ok.""" @@ -158,8 +157,8 @@ class ComputeAPI(base.Base): {"method": "setup_fixed_ip", "args": {"address": address}}) - logging.debug("Casting to scheduler for %s/%s's instance %s" % - (context.project_id, context.user_id, instance_id)) + logging.debug("Casting to scheduler for %s/%s's instance %s", + context.project_id, context.user_id, instance_id) rpc.cast(context, FLAGS.scheduler_topic, {"method": "run_instance", @@ -169,6 +168,12 @@ class ComputeAPI(base.Base): return instances def ensure_default_security_group(self, context): + """ Create security group for the security context if it + does not already exist + + :param context: the security context + + """ try: db.security_group_get_by_name(context, context.project_id, 'default') @@ -177,7 +182,7 @@ class ComputeAPI(base.Base): 'description': 'default', 'user_id': context.user_id, 'project_id': context.project_id} - group = db.security_group_create(context, values) + db.security_group_create(context, values) def update_instance(self, context, instance_id, **kwargs): """Updates the instance in the datastore. diff --git a/nova/tests/api/openstack/test_adminapi.py b/nova/tests/api/openstack/test_adminapi.py new file mode 100644 index 000000000..1b2e1654d --- /dev/null +++ b/nova/tests/api/openstack/test_adminapi.py @@ -0,0 +1,61 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# 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. + +import unittest + +import stubout +import webob + +import nova.api +from nova import flags +from nova.tests.api.openstack import fakes + +FLAGS = flags.FLAGS + + +class AdminAPITest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.auth_data = {} + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fakes.stub_out_auth(self.stubs) + self.allow_admin = FLAGS.allow_admin_api + + def tearDown(self): + self.stubs.UnsetAll() + FLAGS.allow_admin_api = self.allow_admin + + def test_admin_enabled(self): + FLAGS.allow_admin_api = True + # We should still be able to access public operations. + req = webob.Request.blank('/v1.0/flavors') + res = req.get_response(nova.api.API('os')) + self.assertEqual(res.status_int, 200) + # TODO: Confirm admin operations are available. + + def test_admin_disabled(self): + FLAGS.allow_admin_api = False + # We should still be able to access public operations. + req = webob.Request.blank('/v1.0/flavors') + res = req.get_response(nova.api.API('os')) + self.assertEqual(res.status_int, 200) + # TODO: Confirm admin operations are unavailable. + +if __name__ == '__main__': + unittest.main() diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index b72b8e13d..dde138404 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -20,6 +20,8 @@ their attributes like VDIs, VIFs, as well as their lookup functions. """ import logging +import urllib +from xml.dom import minidom from nova import utils from nova.auth.manager import AuthManager @@ -44,6 +46,15 @@ class VMHelper(): The class that wraps the helper methods together. """ def __init__(self): + return + + @classmethod + def late_import(cls): + """ + Load the XenAPI module in for helper class, if required. + This is to avoid to install the XenAPI library when other + hypervisors are used + """ global XenAPI if XenAPI is None: XenAPI = __import__('XenAPI') @@ -208,3 +219,40 @@ class VMHelper(): 'mem': long(record['memory_dynamic_max']) >> 10, 'num_cpu': record['VCPUs_max'], 'cpu_time': 0} + + @classmethod + def compile_diagnostics(cls, session, record): + """Compile VM diagnostics data""" + try: + host = session.get_xenapi_host() + host_ip = session.get_xenapi().host.get_record(host)["address"] + metrics = session.get_xenapi().VM_guest_metrics.get_record( + record["guest_metrics"]) + diags = { + "Kernel": metrics["os_version"]["uname"], + "Distro": metrics["os_version"]["name"]} + xml = get_rrd(host_ip, record["uuid"]) + if xml: + rrd = minidom.parseString(xml) + for i, node in enumerate(rrd.firstChild.childNodes): + # We don't want all of the extra garbage + if i >= 3 and i <= 11: + ref = node.childNodes + # Name and Value + diags[ref[0].firstChild.data] = ref[6].firstChild.data + return diags + except XenAPI.Failure as e: + return {"Unable to retrieve diagnostics": e} + + +def get_rrd(host, uuid): + """Return the VM RRD XML as a string""" + try: + xml = urllib.urlopen("http://%s:%s@%s/vm_rrd?uuid=%s" % ( + FLAGS.xenapi_connection_username, + FLAGS.xenapi_connection_password, + host, + uuid)) + return xml.read() + except IOError: + return None diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 0223e512a..13871b479 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -22,6 +22,7 @@ import logging from nova import db from nova import context + from nova.auth.manager import AuthManager from nova.virt.xenapi.network_utils import NetworkHelper from nova.virt.xenapi.vm_utils import VMHelper @@ -38,6 +39,8 @@ class VMOps(object): if XenAPI is None: XenAPI = __import__('XenAPI') self._session = session + # Load XenAPI module in the helper class + VMHelper.late_import() def list_instances(self): """ List VM instances """ @@ -123,6 +126,15 @@ class VMOps(object): rec = self._session.get_xenapi().VM.get_record(vm) return VMHelper.compile_info(rec) + @defer.inlineCallbacks + def get_diagnostics(self, instance_id): + """Return data about VM diagnostics""" + vm = yield VMHelper.lookup(self._session, instance_id) + if vm is None: + raise Exception("instance not present %s" % instance_id) + rec = yield self._session.get_xenapi().VM.get_record(vm) + defer.returnValue(VMHelper.compile_diagnostics(self._session, rec)) + def get_console_output(self, instance): """ Return snapshot of console """ # TODO: implement this to fix pylint! diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 96d211cc0..df8e42d34 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -124,6 +124,10 @@ class XenAPIConnection(object): """ Return data about VM instance """ return self._vmops.get_info(instance_id) + def get_diagnostics(self, instance_id): + """Return data about VM diagnostics""" + return self._vmops.get_diagnostics(instance_id) + def get_console_output(self, instance): """ Return snapshot of console """ return self._vmops.get_console_output(instance) |
