Fix CFN API error responses

A remote exception (included in conf.allowed_rpc_exception_modules)
is now restored to a subclass of its original type (with the
exception of non heap types which will always be restored to its
original type). Catching rpc_common.RemoteError is not enough
anymore.

Fixes bug #1214831

Change-Id: Iae3ce0c9d0d3f6565fab25ec899f83f19d46e81b
This commit is contained in:
Liang Chen 2013-08-28 22:55:42 +08:00
parent b43018834e
commit 03638aad74
4 changed files with 49 additions and 47 deletions

View File

@ -19,6 +19,7 @@
import webob.exc
from heat.common import wsgi
import heat.openstack.common.rpc.common as rpc_common
class HeatAPIException(webob.exc.HTTPError):
@ -270,12 +271,17 @@ def map_remote_error(ex):
denied_errors = ('Forbidden', 'NotAuthorized')
already_exists_errors = ('StackExists')
if ex.exc_type in inval_param_errors:
return HeatInvalidParameterValueError(detail=ex.value)
elif ex.exc_type in denied_errors:
return HeatAccessDeniedError(detail=ex.value)
elif ex.exc_type in already_exists_errors:
return AlreadyExistsError(detail=ex.value)
ex_type = ex.__class__.__name__
if ex_type.endswith(rpc_common._REMOTE_POSTFIX):
ex_type = ex_type[:-len(rpc_common._REMOTE_POSTFIX)]
if ex_type in inval_param_errors:
return HeatInvalidParameterValueError(detail=str(ex.message))
elif ex_type in denied_errors:
return HeatAccessDeniedError(detail=str(ex.message))
elif ex_type in already_exists_errors:
return AlreadyExistsError(detail=str(ex.message))
else:
# Map everything else to internal server error for now
return HeatInternalFailureError(detail=ex.value)
return HeatInternalFailureError(detail=str(ex.message))

View File

@ -17,7 +17,6 @@ from heat.common import wsgi
from heat.rpc import client as rpc_client
from heat.common import identifier
from heat.api.aws import exception
import heat.openstack.common.rpc.common as rpc_common
class SignalController(object):
@ -34,7 +33,7 @@ class SignalController(object):
stack_identity=dict(identity.stack()),
resource_name=identity.resource_name,
metadata=body)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
return {'resource': identity.resource_name, 'metadata': md}
@ -48,7 +47,7 @@ class SignalController(object):
stack_identity=dict(identity.stack()),
resource_name=identity.resource_name,
details=body)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)

View File

@ -31,8 +31,6 @@ from heat.common import identifier
from heat.common import urlfetch
from heat.common import policy
import heat.openstack.common.rpc.common as rpc_common
from heat.openstack.common import log as logging
from heat.openstack.common.gettextutils import _
@ -146,7 +144,7 @@ class StackController(object):
con = req.context
try:
stack_list = self.engine_rpcapi.list_stacks(con)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
res = {'StackSummaries': [format_stack_summary(s) for s in stack_list]}
@ -237,7 +235,7 @@ class StackController(object):
stack_list = self.engine_rpcapi.show_stack(con, identity)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
res = {'Stacks': [format_stack(s) for s in stack_list]}
@ -353,7 +351,7 @@ class StackController(object):
args['stack_identity'] = self._get_identity(con, stack_name)
result = engine_action[action](con, **args)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
try:
@ -376,7 +374,7 @@ class StackController(object):
try:
identity = self._get_identity(con, req.params['StackName'])
templ = self.engine_rpcapi.get_template(con, identity)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
if templ is None:
@ -445,7 +443,7 @@ class StackController(object):
res['Parameters'] = [format_validate_parameter(k, v)
for k, v in res['Parameters'].items()]
return api_utils.format_response('ValidateTemplate', res)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
def delete(self, req):
@ -460,7 +458,7 @@ class StackController(object):
identity = self._get_identity(con, req.params['StackName'])
res = self.engine_rpcapi.delete_stack(con, identity, cast=False)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
if res is None:
@ -505,7 +503,7 @@ class StackController(object):
try:
identity = stack_name and self._get_identity(con, stack_name)
events = self.engine_rpcapi.list_events(con, identity)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
result = [format_stack_event(e) for e in events]
@ -557,7 +555,7 @@ class StackController(object):
stack_identity=identity,
resource_name=req.params.get('LogicalResourceId'))
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
result = format_resource_detail(resource_details)
@ -623,7 +621,7 @@ class StackController(object):
stack_identity=identity,
resource_name=req.params.get('LogicalResourceId'))
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
result = [format_stack_resource(r) for r in resources]
@ -663,7 +661,7 @@ class StackController(object):
resources = self.engine_rpcapi.list_stack_resources(
con,
stack_identity=identity)
except rpc_common.RemoteError as ex:
except Exception as ex:
return exception.map_remote_error(ex)
summaries = [format_resource_summary(r) for r in resources]

View File

@ -17,10 +17,10 @@ import os
from oslo.config import cfg
from heat.common import exception as heat_exception
from heat.common import identifier
from heat.common import policy
from heat.openstack.common import rpc
import heat.openstack.common.rpc.common as rpc_common
from heat.common.wsgi import Request
from heat.rpc import api as rpc_api
from heat.api.aws import exception
@ -152,7 +152,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'list_stacks',
'args': {},
'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("AttributeError"))
None).AndRaise(AttributeError())
self.m.ReplayAll()
@ -174,7 +174,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'list_stacks',
'args': {},
'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("Exception"))
None).AndRaise(Exception())
self.m.ReplayAll()
@ -372,7 +372,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'show_stack',
'args': {'stack_identity': identity},
'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("InvalidTenant"))
None).AndRaise(heat_exception.InvalidTenant())
self.m.ReplayAll()
@ -400,7 +400,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'show_stack',
'args': {'stack_identity': identity},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("AttributeError"))
).AndRaise(AttributeError())
self.m.ReplayAll()
@ -422,7 +422,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -743,7 +743,7 @@ class CfnStackControllerTest(HeatTestCase):
'files': {},
'args': engine_args},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("AttributeError"))
).AndRaise(AttributeError())
rpc.call(dummy_req.context, self.topic,
{'namespace': None,
'method': 'create_stack',
@ -753,7 +753,7 @@ class CfnStackControllerTest(HeatTestCase):
'files': {},
'args': engine_args},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("UnknownUserParameter"))
).AndRaise(heat_exception.UnknownUserParameter())
rpc.call(dummy_req.context, self.topic,
{'namespace': None,
'method': 'create_stack',
@ -763,7 +763,7 @@ class CfnStackControllerTest(HeatTestCase):
'files': {},
'args': engine_args},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("UserParameterMissing"))
).AndRaise(heat_exception.UserParameterMissing())
self.m.ReplayAll()
@ -811,7 +811,7 @@ class CfnStackControllerTest(HeatTestCase):
'files': {},
'args': engine_args},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackExists"))
).AndRaise(heat_exception.StackExists())
self.m.ReplayAll()
@ -847,9 +847,8 @@ class CfnStackControllerTest(HeatTestCase):
'files': {},
'args': engine_args},
'version': self.api_version}, None).AndRaise(
rpc_common.RemoteError(
'StackValidationFailed',
'Something went wrong'))
heat_exception.StackValidationFailed(
message='Something went wrong'))
self.m.ReplayAll()
@ -926,7 +925,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -993,7 +992,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'get_template',
'args': {'stack_identity': identity},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("AttributeError"))
).AndRaise(AttributeError())
self.m.ReplayAll()
@ -1016,7 +1015,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -1161,7 +1160,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'delete_stack',
'args': {'stack_identity': identity},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("AttributeError"))
).AndRaise(AttributeError())
self.m.ReplayAll()
@ -1184,7 +1183,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -1273,7 +1272,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'list_events',
'args': {'stack_identity': identity},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("Exception"))
).AndRaise(Exception())
self.m.ReplayAll()
@ -1295,7 +1294,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -1390,7 +1389,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound"))
None).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -1424,7 +1423,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'describe_stack_resource',
'args': args,
'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("ResourceNotFound"))
None).AndRaise(heat_exception.ResourceNotFound())
self.m.ReplayAll()
@ -1517,7 +1516,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()
@ -1614,7 +1613,7 @@ class CfnStackControllerTest(HeatTestCase):
'aaaaaaaa-9f88-404d-cccc-ffffffffffff'},
'version': self.api_version},
None).AndRaise(
rpc_common.RemoteError("PhysicalResourceNotFound"))
heat_exception.PhysicalResourceNotFound())
self.m.ReplayAll()
@ -1709,7 +1708,7 @@ class CfnStackControllerTest(HeatTestCase):
'method': 'identify_stack',
'args': {'stack_name': stack_name},
'version': self.api_version}, None
).AndRaise(rpc_common.RemoteError("StackNotFound"))
).AndRaise(heat_exception.StackNotFound())
self.m.ReplayAll()