Placement api: set custom json_error_formatter in allocations

Any time placement API (v1.0) code wants to raise a webob.exc of some kind it
needs to add a json_formatter attribute to the call. This is easy to forget.

This change adds wrapper for webob.dec.wsgify which will set default custom
json error formatter. Resource based actions from placement need to use this
wrapper as decorater instead of webob.dec.wsgify.

In this change, decorator updated for allocations related actions.
Change in other resource handlers can be addressed in subsequent patches.

Change-Id: I3b81c5bd00a013f1659b9e6e80c71b373d965862
Partial-Bug: #1635182
This commit is contained in:
Pushkar Umaranikar 2017-02-06 16:28:08 +00:00 committed by John Garbutt
parent 1129a9ff47
commit 8cef55c53c
3 changed files with 64 additions and 16 deletions

View File

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

View File

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

View File

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