From aad95316d4c3e72e4f84a8506a32c21b72d20835 Mon Sep 17 00:00:00 2001 From: Chris Yeoh Date: Fri, 12 Jul 2013 11:26:43 +0930 Subject: [PATCH] Allow exceptions to propagate through stevedore map Allow exceptions to propagate up through the stevedore map function used by the V3 API servers core extension. This allows for functionality such as extension specific parsing of client supplied data formerly required to be handled by the core API to be handled by the extension itself instead. This functionality requires stevedore 0.10 or later Partially implements blueprint nova-v3-api Change-Id: Ib848147225707f1c7eda27b1ba796022161ba20f --- .../openstack/compute/plugins/v3/servers.py | 6 +- .../compute/plugins/v3/test_servers.py | 59 ++++++++++++++++++- requirements.txt | 2 +- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/nova/api/openstack/compute/plugins/v3/servers.py b/nova/api/openstack/compute/plugins/v3/servers.py index b7ec0a5cba8a..d4ef13525153 100644 --- a/nova/api/openstack/compute/plugins/v3/servers.py +++ b/nova/api/openstack/compute/plugins/v3/servers.py @@ -509,7 +509,8 @@ class ServersController(wsgi.Controller): namespace=self.EXTENSION_CREATE_NAMESPACE, check_func=_create_check_load_extension('server_create'), invoke_on_load=True, - invoke_kwds={"extension_info": self.extension_info}) + invoke_kwds={"extension_info": self.extension_info}, + propagate_map_exceptions=True) if not list(self.create_extension_manager): LOG.debug(_("Did not find any server create extensions")) @@ -521,7 +522,8 @@ class ServersController(wsgi.Controller): check_func=_create_check_load_extension( 'server_xml_extract_server_deserialize'), invoke_on_load=True, - invoke_kwds={"extension_info": self.extension_info}) + invoke_kwds={"extension_info": self.extension_info}, + propagate_map_exceptions=True) if not list(self.create_xml_deserialize_manager): LOG.debug(_("Did not find any server create xml deserializer" " extensions")) diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py index c13996a1c8b0..d2c9cbef21cd 100644 --- a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py +++ b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py @@ -30,7 +30,9 @@ import webob from nova.api.openstack import compute from nova.api.openstack.compute import plugins +from nova.api.openstack.compute.plugins.v3 import availability_zone from nova.api.openstack.compute.plugins.v3 import ips +from nova.api.openstack.compute.plugins.v3 import keypairs from nova.api.openstack.compute.plugins.v3 import servers from nova.api.openstack.compute import views from nova.api.openstack import xmlutil @@ -2836,6 +2838,42 @@ class ServersControllerCreateTest(test.TestCase): self._check_admin_pass_len(server) self.assertEqual(FAKE_UUID, server['id']) + def test_create_instance_extension_create_exception(self): + def fake_keypair_server_create(self, server_dict, + create_kwargs): + raise KeyError + + self.stubs.Set(keypairs.Keypairs, 'server_create', + fake_keypair_server_create) + # proper local hrefs must start with 'http://localhost/v3/' + image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' + image_href = 'http://localhost/v3/images/%s' % image_uuid + flavor_ref = 'http://localhost/123/flavors/3' + body = { + 'server': { + 'name': 'server_test', + 'imageRef': image_href, + 'flavorRef': flavor_ref, + 'metadata': { + 'hello': 'world', + 'open': 'stack', + }, + 'personality': [ + { + "path": "/etc/banner.txt", + "contents": "MQ==", + }, + + ], + }, + } + + req = fakes.HTTPRequestV3.blank('/servers') + req.method = 'POST' + req.body = jsonutils.dumps(body) + req.headers["content-type"] = "application/json" + self.assertRaises(KeyError, self.controller.create, req, body) + def test_create_instance_pass_disabled(self): self.flags(enable_instance_password=False) # proper local hrefs must start with 'http://localhost/v3/' @@ -3246,7 +3284,9 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase): def setUp(self): super(TestServerCreateRequestXMLDeserializer, self).setUp() - self.deserializer = servers.CreateDeserializer(None) + ext_info = plugins.LoadedExtensionInfo() + servers_controller = servers.ServersController(extension_info=ext_info) + self.deserializer = servers.CreateDeserializer(servers_controller) def test_minimal_request(self): serial_request = """ @@ -3264,6 +3304,23 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase): } self.assertEquals(request['body'], expected) + def test_xml_create_exception(self): + def fake_availablity_extract_xml_deserialize(self, + server_node, + server_dict): + raise KeyError + + self.stubs.Set(availability_zone.AvailabilityZone, + 'server_xml_extract_server_deserialize', + fake_availablity_extract_xml_deserialize) + serial_request = """ +""" + self.assertRaises(KeyError, self.deserializer.deserialize, + serial_request) + def test_request_with_alternate_namespace_prefix(self): serial_request = """ =2.2.3,<3.0.0 python-glanceclient>=0.9.0 python-keystoneclient>=0.2.0 six -stevedore>=0.9 +stevedore>=0.10 websockify<0.4 pyparsing>=1.5.7,<2.0 # order-dependent python-quantumclient req, bug 1191866