From: Steven Hardy Date: Wed, 4 Jul 2012 14:41:20 +0000 (+0100) Subject: heat API : Convert API to use HeatAPIException subclasses X-Git-Tag: 2014.1~1643 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=9ce1d94553bd6341ac0416d1920be32506d7a94b;p=openstack-build%2Fheat-build.git heat API : Convert API to use HeatAPIException subclasses Covert API to use HeatAPIException subclasses, instead of plain webob exceptions, which cannot be correctly serialized by the wsgi controller, and map engine errors to API exceptions so the raw engine exception is not propogated to the user. ref #125 fixes #150 Change-Id: I164c71e12ed29f40ad67188b645ca7ad2fa1fee8 Signed-off-by: Steven Hardy --- diff --git a/heat/api/v1/stacks.py b/heat/api/v1/stacks.py index 56cb5299..f65c25e1 100644 --- a/heat/api/v1/stacks.py +++ b/heat/api/v1/stacks.py @@ -25,9 +25,7 @@ import sys import re import urlparse import webob -from webob.exc import (HTTPNotFound, - HTTPConflict, - HTTPBadRequest) +from heat.api.v1 import exception from heat.common import wsgi from heat.common import config from heat.common import context @@ -64,6 +62,20 @@ class StackController(object): ''' return {'%sResponse' % action: {'%sResult' % action: response}} + def _remote_error(self, ex): + ''' + Map rpc_common.RemoteError exceptions returned by the engine + to HeatAPIException subclasses which can be used to return + properly formatted AWS error responses + ''' + if ex.exc_type == 'AttributeError': + # Attribute error, bad user data, ex.value should tell us why + return exception.HeatInvalidParameterValueError(detail=ex.value) + else: + # Map everything else to internal server error for now + # FIXME : further investigation into engine errors required + return exception.HeatInternalFailureError(detail=ex.value) + def list(self, req): """ Returns the following information for all stacks: @@ -103,7 +115,7 @@ class StackController(object): 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) res = {'Stacks': []} for s in stack_list['stacks']: @@ -151,16 +163,17 @@ class StackController(object): templ = self._get_template(req) except socket.gaierror: msg = _('Invalid Template URL') - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatInvalidParameterValueError(detail=msg) + if templ is None: msg = _("TemplateBody or TemplateUrl were not given.") - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatMissingParameterError(detail=msg) try: stack = json.loads(templ) except ValueError: msg = _("The Template must be a JSON document.") - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatInvalidParameterValueError(detail=msg) try: res = rpc.call(con, 'engine', @@ -169,7 +182,7 @@ class StackController(object): 'template': stack, 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) return self._format_response('CreateStack', self._stackid_addprefix(res)) @@ -186,10 +199,11 @@ class StackController(object): 'args': {'stack_name': req.params['StackName'], 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) if templ is None: - return webob.exc.HTTPNotFound('stack not found') + msg = _('stack not not found') + return exception.HeatInvalidParameterValueError(detail=msg) return self._format_response('GetTemplate', {'TemplateBody': templ}) @@ -206,16 +220,16 @@ class StackController(object): templ = self._get_template(req) except socket.gaierror: msg = _('Invalid Template URL') - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatInvalidParameterValueError(detail=msg) if templ is None: msg = _("TemplateBody or TemplateUrl were not given.") - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatMissingParameterError(detail=msg) try: stack = json.loads(templ) except ValueError: msg = _("The Template must be a JSON document.") - return webob.exc.HTTPBadRequest(explanation=msg) + return exception.HeatInvalidParameterValueError(detail=msg) logger.info('validate_template') try: @@ -224,7 +238,7 @@ class StackController(object): 'args': {'template': stack, 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) def delete(self, req): """ @@ -240,7 +254,7 @@ class StackController(object): 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) if res is None: return self._format_response('DeleteStack', '') @@ -261,7 +275,7 @@ class StackController(object): 'args': {'stack_name': stack_name, 'params': parms}}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) events = 'Error' not in event_res and event_res['events'] or [] @@ -284,7 +298,7 @@ class StackController(object): 'args': args}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) return self._format_response('DescribeStackResource', {'StackResourceDetail': resource_details}) @@ -309,7 +323,7 @@ class StackController(object): physical_resource_id = req.params.get('PhysicalResourceId') if stack_name and physical_resource_id: msg = 'Use `StackName` or `PhysicalResourceId` but not both' - return webob.exc.HTTPBadRequest(msg) + return exception.HeatInvalidParameterCombinationError(detail=msg) args = { 'stack_name': stack_name, @@ -323,7 +337,7 @@ class StackController(object): 'args': args}) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) return self._format_response('DescribeStackResources', {'StackResources': resources}) @@ -341,7 +355,7 @@ class StackController(object): 'args': {'stack_name': req.params.get('StackName')} }) except rpc_common.RemoteError as ex: - return webob.exc.HTTPBadRequest(str(ex)) + return self._remote_error(ex) return self._format_response('ListStackResources', {'StackResourceSummaries': resources})