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 <shardy@redhat.com>
This commit is contained in:
Steven Hardy 2012-07-04 15:41:20 +01:00
parent 9de825c5d2
commit 9ce1d94553
1 changed files with 34 additions and 20 deletions

View File

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