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
This commit is contained in:
Chris Yeoh 2013-07-12 11:26:43 +09:30
parent 9e2d4ac460
commit aad95316d4
3 changed files with 63 additions and 4 deletions

View File

@ -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"))

View File

@ -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 = """
<server xmlns="http://docs.openstack.org/compute/api/v2"
name="new-server-test"
imageRef="1"
flavorRef="2"/>"""
self.assertRaises(KeyError, self.deserializer.deserialize,
serial_request)
def test_request_with_alternate_namespace_prefix(self):
serial_request = """
<ns2:server xmlns:ns2="http://docs.openstack.org/compute/api/v2"

View File

@ -27,7 +27,7 @@ python-neutronclient>=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