summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-02-20 08:54:20 +0000
committerGerrit Code Review <review@openstack.org>2012-02-20 08:54:20 +0000
commitcf75c2d45cf1ddb73564bb1f0193bcc8d3c85044 (patch)
tree9218b15d066e34d646907f9214f42196766b43e6
parent757d8aa6f5e412aae08c2b1fb2d0c6f174d2f29c (diff)
parent942762d48afc81f1f71652b0861953e32c78b124 (diff)
downloadnova-cf75c2d45cf1ddb73564bb1f0193bcc8d3c85044.tar.gz
nova-cf75c2d45cf1ddb73564bb1f0193bcc8d3c85044.tar.xz
nova-cf75c2d45cf1ddb73564bb1f0193bcc8d3c85044.zip
Merge "Add additional information to servers output."
-rw-r--r--etc/nova/policy.json1
-rw-r--r--nova/api/openstack/compute/contrib/extended_server_attributes.py129
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_extended_server_attributes.py95
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py1
-rw-r--r--nova/tests/policy.json1
5 files changed, 227 insertions, 0 deletions
diff --git a/etc/nova/policy.json b/etc/nova/policy.json
index ce183b889..ac2a76064 100644
--- a/etc/nova/policy.json
+++ b/etc/nova/policy.json
@@ -31,6 +31,7 @@
"compute_extension:createserverext": [],
"compute_extension:deferred_delete": [],
"compute_extension:disk_config": [],
+ "compute_extension:extended_server_attributes": [["rule:admin_api"]],
"compute_extension:extended_status": [["rule:admin_api"]],
"compute_extension:flavorextradata": [],
"compute_extension:flavorextraspecs": [],
diff --git a/nova/api/openstack/compute/contrib/extended_server_attributes.py b/nova/api/openstack/compute/contrib/extended_server_attributes.py
new file mode 100644
index 000000000..102477db3
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/extended_server_attributes.py
@@ -0,0 +1,129 @@
+# Copyright 2012 Openstack, LLC.
+#
+# 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.
+
+"""The Extended Server Attributes API extension."""
+
+from webob import exc
+
+from nova.api.openstack import extensions
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+from nova import compute
+from nova import exception
+from nova import flags
+from nova import log as logging
+
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger("nova.api.openstack.compute.contrib."
+ "extended_server_attributes")
+authorize = extensions.soft_extension_authorizer('compute',
+ 'extended_server_attributes')
+
+
+class ExtendedServerAttributesController(wsgi.Controller):
+ def __init__(self, *args, **kwargs):
+ super(ExtendedServerAttributesController, self).__init__(*args,
+ **kwargs)
+ self.compute_api = compute.API()
+
+ def _get_instances(self, context, instance_uuids):
+ filters = {'uuid': instance_uuids}
+ instances = self.compute_api.get_all(context, filters)
+ return dict((instance['uuid'], instance) for instance in instances)
+
+ def _extend_server(self, server, instance):
+ for attr in ['host', 'name']:
+ if attr == 'name':
+ key = "%s:instance_%s" % (Extended_server_attributes.alias,
+ attr)
+ else:
+ key = "%s:%s" % (Extended_server_attributes.alias, attr)
+ server[key] = instance[attr]
+
+ @wsgi.extends
+ def show(self, req, resp_obj, id):
+ context = req.environ['nova.context']
+ if authorize(context):
+ # Attach our slave template to the response object
+ resp_obj.attach(xml=ExtendedServerAttributesTemplate())
+
+ try:
+ instance = self.compute_api.get(context, id)
+ except exception.NotFound:
+ explanation = _("Server not found.")
+ raise exc.HTTPNotFound(explanation=explanation)
+
+ self._extend_server(resp_obj.obj['server'], instance)
+
+ @wsgi.extends
+ def detail(self, req, resp_obj):
+ context = req.environ['nova.context']
+ if authorize(context):
+ # Attach our slave template to the response object
+ resp_obj.attach(xml=ExtendedServerAttributesTemplate())
+
+ servers = list(resp_obj.obj['servers'])
+ instance_uuids = [server['id'] for server in servers]
+ instances = self._get_instances(context, instance_uuids)
+
+ for server_object in servers:
+ try:
+ instance_data = instances[server_object['id']]
+ except KeyError:
+ # Ignore missing instance data
+ continue
+
+ self._extend_server(server_object, instance_data)
+
+
+class Extended_server_attributes(extensions.ExtensionDescriptor):
+ """Extended Server Attributes support."""
+
+ name = "ExtendedServerAttributes"
+ alias = "OS-EXT-SRV-ATTR"
+ namespace = "http://docs.openstack.org/compute/ext/" \
+ "extended_status/api/v1.1"
+ updated = "2011-11-03T00:00:00+00:00"
+
+ def get_controller_extensions(self):
+ controller = ExtendedServerAttributesController()
+ extension = extensions.ControllerExtension(self, 'servers', controller)
+ return [extension]
+
+
+def make_server(elem):
+ elem.set('{%s}instance_name' % Extended_server_attributes.namespace,
+ '%s:instance_name' % Extended_server_attributes.alias)
+ elem.set('{%s}host' % Extended_server_attributes.namespace,
+ '%s:host' % Extended_server_attributes.alias)
+
+
+class ExtendedServerAttributeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('server', selector='server')
+ make_server(root)
+ return xmlutil.SlaveTemplate(root, 1, nsmap={
+ Extended_server_attributes.alias: \
+ Extended_server_attributes.namespace})
+
+
+class ExtendedServerAttributesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('servers')
+ elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
+ make_server(elem)
+ return xmlutil.SlaveTemplate(root, 1, nsmap={
+ Extended_server_attributes.alias: \
+ Extended_server_attributes.namespace})
diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_server_attributes.py b/nova/tests/api/openstack/compute/contrib/test_extended_server_attributes.py
new file mode 100644
index 000000000..9944fc0e8
--- /dev/null
+++ b/nova/tests/api/openstack/compute/contrib/test_extended_server_attributes.py
@@ -0,0 +1,95 @@
+# Copyright 2011 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 json
+
+import webob
+
+from nova import compute
+from nova import exception
+from nova import flags
+from nova import test
+from nova.tests.api.openstack import fakes
+
+
+FLAGS = flags.FLAGS
+
+
+UUID1 = '00000000-0000-0000-0000-000000000001'
+UUID2 = '00000000-0000-0000-0000-000000000002'
+UUID3 = '00000000-0000-0000-0000-000000000003'
+
+
+def fake_compute_get(*args, **kwargs):
+ return fakes.stub_instance(1, uuid=UUID3, host="host-fake")
+
+
+def fake_compute_get_all(*args, **kwargs):
+ return [
+ fakes.stub_instance(1, uuid=UUID1, host="host-1"),
+ fakes.stub_instance(2, uuid=UUID2, host="host-2")
+ ]
+
+
+class ExtendedServerAttributesTest(test.TestCase):
+
+ def setUp(self):
+ super(ExtendedServerAttributesTest, self).setUp()
+ fakes.stub_out_nw_api(self.stubs)
+ self.stubs.Set(compute.api.API, 'get', fake_compute_get)
+ self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all)
+
+ def _make_request(self, url):
+ req = webob.Request.blank(url)
+ req.headers['Accept'] = 'application/json'
+ res = req.get_response(fakes.wsgi_app())
+ return res
+
+ def assertServerAttributes(self, server, host, instance_name):
+ self.assertEqual(server.get('OS-EXT-SRV-ATTR:host'), host)
+ self.assertEqual(server.get('OS-EXT-SRV-ATTR:instance_name'),
+ instance_name)
+
+ def test_show(self):
+ url = '/v2/fake/servers/%s' % UUID3
+ res = self._make_request(url)
+ body = json.loads(res.body)
+
+ self.assertEqual(res.status_int, 200)
+ self.assertServerAttributes(body['server'],
+ host='host-fake',
+ instance_name='instance-1')
+
+ def test_detail(self):
+ url = '/v2/fake/servers/detail'
+ res = self._make_request(url)
+ body = json.loads(res.body)
+
+ self.assertEqual(res.status_int, 200)
+ for i, server in enumerate(body['servers']):
+ self.assertServerAttributes(server,
+ host='host-%s' % (i + 1),
+ instance_name='instance-%s' % (i + 1))
+
+ def test_no_instance_passthrough_404(self):
+
+ def fake_compute_get(*args, **kwargs):
+ raise exception.InstanceNotFound()
+
+ self.stubs.Set(compute.api.API, 'get', fake_compute_get)
+ url = '/v2/fake/servers/70f6db34-de8d-4fbd-aafb-4065bdfa6115'
+ res = self._make_request(url)
+
+ self.assertEqual(res.status_int, 404)
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index 1a281590f..5140472c6 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -161,6 +161,7 @@ class ExtensionControllerTest(ExtensionTestCase):
"DeferredDelete",
"DiskConfig",
"ExtendedStatus",
+ "ExtendedServerAttributes",
"FlavorExtraSpecs",
"FlavorExtraData",
"FlavorManage",
diff --git a/nova/tests/policy.json b/nova/tests/policy.json
index 4a6bf872a..c231bff60 100644
--- a/nova/tests/policy.json
+++ b/nova/tests/policy.json
@@ -88,6 +88,7 @@
"compute_extension:createserverext": [],
"compute_extension:deferred_delete": [],
"compute_extension:disk_config": [],
+ "compute_extension:extended_server_attributes": [],
"compute_extension:extended_status": [],
"compute_extension:flavorextradata": [],
"compute_extension:flavorextraspecs": [],