diff --git a/nova/api/openstack/placement/handlers/allocation.py b/nova/api/openstack/placement/handlers/allocation.py index 545957c29e29..b8b8e7aead26 100644 --- a/nova/api/openstack/placement/handlers/allocation.py +++ b/nova/api/openstack/placement/handlers/allocation.py @@ -20,6 +20,7 @@ from oslo_utils import encodeutils import webob from nova.api.openstack.placement import util +from nova.api.openstack.placement import wsgi_wrapper from nova import exception from nova.i18n import _, _LE from nova import objects @@ -157,7 +158,7 @@ def _serialize_allocations_for_resource_provider(allocations, resource_provider=resource_provider) -@webob.dec.wsgify +@wsgi_wrapper.PlacementWsgify @util.check_accept('application/json') def list_for_consumer(req): """List allocations associated with a consumer.""" @@ -179,7 +180,7 @@ def list_for_consumer(req): return req.response -@webob.dec.wsgify +@wsgi_wrapper.PlacementWsgify @util.check_accept('application/json') def list_for_resource_provider(req): """List allocations associated with a resource provider.""" @@ -199,8 +200,7 @@ def list_for_resource_provider(req): except exception.NotFound as exc: raise webob.exc.HTTPNotFound( _("Resource provider '%(rp_uuid)s' not found: %(error)s") % - {'rp_uuid': uuid, 'error': exc}, - json_formatter=util.json_error_formatter) + {'rp_uuid': uuid, 'error': exc}) allocations = objects.AllocationList.get_all_by_resource_provider_uuid( context, uuid) @@ -215,7 +215,7 @@ def list_for_resource_provider(req): return req.response -@webob.dec.wsgify +@wsgi_wrapper.PlacementWsgify @util.require_content('application/json') def set_allocations(req): context = req.environ['placement.context'] @@ -236,8 +236,7 @@ def set_allocations(req): raise webob.exc.HTTPBadRequest( _("Allocation for resource provider '%(rp_uuid)s' " "that does not exist.") % - {'rp_uuid': resource_provider_uuid}, - json_formatter=util.json_error_formatter) + {'rp_uuid': resource_provider_uuid}) resources = allocation['resources'] for resource_class in resources: @@ -264,21 +263,19 @@ def set_allocations(req): except exception.InvalidInventory as exc: LOG.exception(_LE("Bad inventory")) raise webob.exc.HTTPConflict( - _('Unable to allocate inventory: %(error)s') % {'error': exc}, - json_formatter=util.json_error_formatter) + _('Unable to allocate inventory: %(error)s') % {'error': exc}) except exception.ConcurrentUpdateDetected as exc: LOG.exception(_LE("Concurrent Update")) raise webob.exc.HTTPConflict( _('Inventory changed while attempting to allocate: %(error)s') % - {'error': exc}, - json_formatter=util.json_error_formatter) + {'error': exc}) req.response.status = 204 req.response.content_type = None return req.response -@webob.dec.wsgify +@wsgi_wrapper.PlacementWsgify def delete_allocations(req): context = req.environ['placement.context'] consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid') @@ -295,13 +292,11 @@ def delete_allocations(req): raise webob.exc.HTPPNotFound( _("Allocation for consumer with id %(id)s not found." "error: %(error)s") % - {'id': consumer_uuid, 'error': exc}, - json_formatter=util.json_error_formatter) + {'id': consumer_uuid, 'error': exc}) else: raise webob.exc.HTTPNotFound( _("No allocations for consumer '%(consumer_uuid)s'") % - {'consumer_uuid': consumer_uuid}, - json_formatter=util.json_error_formatter) + {'consumer_uuid': consumer_uuid}) LOG.debug("Successfully deleted allocations %s", allocations) req.response.status = 204 diff --git a/nova/api/openstack/placement/wsgi_wrapper.py b/nova/api/openstack/placement/wsgi_wrapper.py new file mode 100644 index 000000000000..4aa8b789ba5f --- /dev/null +++ b/nova/api/openstack/placement/wsgi_wrapper.py @@ -0,0 +1,33 @@ +# 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. +"""Extend functionality from webob.dec.wsgify for Placement API.""" + +import webob + +from oslo_log import log as logging +from webob.dec import wsgify + +from nova.api.openstack.placement import util + +LOG = logging.getLogger(__name__) + + +class PlacementWsgify(wsgify): + + def call_func(self, req, *args, **kwargs): + """Add json_error_formatter to any webob HTTPExceptions.""" + try: + super(PlacementWsgify, self).call_func(req, *args, **kwargs) + except webob.exc.HTTPException as exc: + LOG.debug("Placement API returning an error response: %s", exc) + exc.json_formatter = util.json_error_formatter + raise diff --git a/nova/tests/functional/api/openstack/placement/gabbits/allocations.yaml b/nova/tests/functional/api/openstack/placement/gabbits/allocations.yaml index 86b6e7072118..61c060805774 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/allocations.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/allocations.yaml @@ -17,6 +17,8 @@ tests: - name: get allocations no consumer is 404 GET: /allocations status: 404 + response_json_paths: + $.errors[0].title: Not Found - name: get allocations is empty dict GET: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958 @@ -32,6 +34,8 @@ tests: - resources: DISK_GB: 10 status: 400 + response_json_paths: + $.errors[0].title: Bad Request - name: create the resource provider POST: /resource_providers @@ -47,6 +51,8 @@ tests: request_headers: content-type: application/json status: 400 + response_json_paths: + $.errors[0].title: Bad Request - name: put an allocation violate schema PUT: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958 @@ -59,6 +65,8 @@ tests: resources: cow: 10 status: 400 + response_json_paths: + $.errors[0].title: Bad Request - name: put an allocation no inventory PUT: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958 @@ -71,6 +79,8 @@ tests: resources: DISK_GB: 10 status: 409 + response_json_paths: + $.errors[0].title: Conflict - name: post some inventory POST: /resource_providers/$ENVIRON['RP_UUID']/inventories @@ -145,6 +155,8 @@ tests: status: 400 response_strings: - No such resource class COWS + response_json_paths: + $.errors[0].title: Bad Request - name: delete allocation DELETE: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958 @@ -155,10 +167,14 @@ tests: status: 404 response_strings: - No allocations for consumer '599ffd2d-526a-4b2e-8683-f13ad25f9958' + response_json_paths: + $.errors[0].title: Not Found - name: delete allocation of unknown consumer id DELETE: /allocations/da78521f-bf7e-4e6e-9901-3f79bd94d55d status: 404 + response_json_paths: + $.errors[0].title: Not Found - name: redo an allocation PUT: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958 @@ -217,6 +233,8 @@ tests: - name: confirm 404 for allocations of bad resource provider GET: /resource_providers/cb8a3007-b93a-471f-9e1f-4d58355678bd/allocations status: 404 + response_json_paths: + $.errors[0].title: Not Found - name: check allocations by consumer id GET: /allocations/833f0885-f78c-4788-bb2b-3607b0656be7 @@ -358,3 +376,5 @@ tests: status: 400 response_strings: - Allocation for resource provider 'be8b9cba-e7db-4a12-a386-99b4242167fe' that does not exist + response_json_paths: + $.errors[0].title: Bad Request