diff --git a/etc/heat/api-paste.ini b/etc/heat/api-paste.ini index 72e5e579a4..273e94c14f 100644 --- a/etc/heat/api-paste.ini +++ b/etc/heat/api-paste.ini @@ -1,7 +1,7 @@ # heat-api pipeline [pipeline:heat-api] -pipeline = versionnegotiation authtoken context apiv1app +pipeline = faultwrap versionnegotiation authtoken context apiv1app # heat-api pipeline for standalone heat # ie. uses alternative auth backend that authenticates users against keystone @@ -12,7 +12,7 @@ pipeline = versionnegotiation authtoken context apiv1app # flavor = standalone # [pipeline:heat-api-standalone] -pipeline = versionnegotiation authpassword context apiv1app +pipeline = faultwrap versionnegotiation authpassword context apiv1app # heat-api pipeline for custom cloud backends # i.e. in heat-api.conf: @@ -20,7 +20,7 @@ pipeline = versionnegotiation authpassword context apiv1app # flavor = custombackend # [pipeline:heat-api-custombackend] -pipeline = versionnegotiation context custombackendauth apiv1app +pipeline = faultwrap versionnegotiation context custombackendauth apiv1app # heat-api-cfn pipeline [pipeline:heat-api-cfn] @@ -56,6 +56,10 @@ heat.app_factory = heat.api.cloudwatch:API paste.filter_factory = heat.common.wsgi:filter_factory heat.filter_factory = heat.api.openstack:version_negotiation_filter +[filter:faultwrap] +paste.filter_factory = heat.common.wsgi:filter_factory +heat.filter_factory = heat.api.openstack:faultwrap_filter + [filter:cfnversionnegotiation] paste.filter_factory = heat.common.wsgi:filter_factory heat.filter_factory = heat.api.cfn:version_negotiation_filter diff --git a/heat/api/middleware/fault.py b/heat/api/middleware/fault.py new file mode 100644 index 0000000000..370fe49536 --- /dev/null +++ b/heat/api/middleware/fault.py @@ -0,0 +1,108 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Unitedstack Inc. +# +# Author: Jianing YANG (jianingy@unitedstack.com) +# +# 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. + +"""A middleware that turns exceptions into parsable string. Inspired by +Cinder's faultwrapper +""" + +import traceback +import webob + +from heat.openstack.common import log as logging +import heat.openstack.common.rpc.common as rpc_common + +from heat.common import wsgi + +logger = logging.getLogger(__name__) + + +class Fault(object): + + def __init__(self, error): + self.error = error + + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + if req.content_type == 'application/xml': + serializer = wsgi.XMLResponseSerializer() + else: + serializer = wsgi.JSONResponseSerializer() + resp = webob.Response(request=req) + default_webob_exc = webob.exc.HTTPInternalServerError() + resp.status_code = self.error.get('code', default_webob_exc.code) + serializer.default(resp, self.error) + return resp + + +class FaultWrapper(wsgi.Middleware): + """Replace error body with something the client can parse.""" + + error_map = { + 'AttributeError': webob.exc.HTTPBadRequest, + 'ValueError': webob.exc.HTTPBadRequest, + 'StackNotFound': webob.exc.HTTPNotFound, + 'ResourceNotFound': webob.exc.HTTPNotFound, + 'ResourceNotAvailable': webob.exc.HTTPNotFound, + 'PhysicalResourceNotFound': webob.exc.HTTPNotFound, + 'InvalidTenant': webob.exc.HTTPForbidden, + 'StackExists': webob.exc.HTTPConflict, + 'StackValidationFailed': webob.exc.HTTPBadRequest, + 'InvalidTemplateReference': webob.exc.HTTPBadRequest, + 'UnknownUserParameter': webob.exc.HTTPBadRequest, + 'RevertFailed': webob.exc.HTTPInternalServerError, + 'ServerBuildFailed': webob.exc.HTTPInternalServerError, + 'NotSupported': webob.exc.HTTPBadRequest, + 'MissingCredentialError': webob.exc.HTTPBadRequest, + 'UserParameterMissing': webob.exc.HTTPBadRequest, + } + + def _error(self, ex): + + ex_type = ex.__class__.__name__ + + if ex_type.endswith(rpc_common._REMOTE_POSTFIX): + ex_type = ex_type[:-len(rpc_common._REMOTE_POSTFIX)] + + message = str(ex) + if message.find('\n') > -1: + message, trace = message.split('\n', 1) + else: + message = str(ex) + trace = traceback.format_exc() + + webob_exc = self.error_map.get(ex_type, + webob.exc.HTTPInternalServerError) + + error = { + 'code': webob_exc.code, + 'title': webob_exc.title, + 'explanation': webob_exc.explanation, + 'error': { + 'message': message, + 'type': ex_type, + 'traceback': trace, + } + } + + return error + + def process_request(self, req): + try: + return req.get_response(self.application) + except Exception as exc: + return req.get_response(Fault(self._error(exc))) diff --git a/heat/api/openstack/__init__.py b/heat/api/openstack/__init__.py index ff263f7c77..dfb897f34d 100644 --- a/heat/api/openstack/__init__.py +++ b/heat/api/openstack/__init__.py @@ -14,9 +14,14 @@ # under the License. from heat.api.middleware.version_negotiation import VersionNegotiationFilter +from heat.api.middleware.fault import FaultWrapper from heat.api.openstack import versions def version_negotiation_filter(app, conf, **local_conf): return VersionNegotiationFilter(versions.Controller, app, conf, **local_conf) + + +def faultwrap_filter(app, conf, **local_conf): + return FaultWrapper(app) diff --git a/heat/api/openstack/v1/util.py b/heat/api/openstack/v1/util.py index a344154fd6..d87e6adf57 100644 --- a/heat/api/openstack/v1/util.py +++ b/heat/api/openstack/v1/util.py @@ -67,31 +67,10 @@ def make_link(req, identity, relationship='self'): def remote_error(ex): - """ - Map rpc_common.RemoteError exceptions returned by the engine - to webob exceptions which can be used to return - properly formatted error responses. + """The RemoteError mapping work has been moved to heat.api.middleware.fault + which handles error formating now. This function will be deprecated + in the future, so please raise exceptions directly. """ - error_map = { - 'AttributeError': exc.HTTPBadRequest, - 'ValueError': exc.HTTPBadRequest, - 'StackNotFound': exc.HTTPNotFound, - 'ResourceNotFound': exc.HTTPNotFound, - 'ResourceNotAvailable': exc.HTTPNotFound, - 'PhysicalResourceNotFound': exc.HTTPNotFound, - 'InvalidTenant': exc.HTTPForbidden, - 'StackExists': exc.HTTPConflict, - 'StackValidationFailed': exc.HTTPBadRequest, - 'InvalidTemplateReference': exc.HTTPBadRequest, - 'UnknownUserParameter': exc.HTTPBadRequest, - 'RevertFailed': exc.HTTPInternalServerError, - 'ServerBuildFailed': exc.HTTPInternalServerError, - 'NotSupported': exc.HTTPBadRequest, - 'MissingCredentialError': exc.HTTPBadRequest, - 'UserParameterMissing': exc.HTTPBadRequest, - } - - Exc = error_map.get(ex.exc_type, exc.HTTPInternalServerError) - - raise Exc(str(ex)) + # TODO(jianingy): add a deprecated warning here to inform others. + raise ex diff --git a/heat/common/config.py b/heat/common/config.py index d32025a656..8113ec1289 100644 --- a/heat/common/config.py +++ b/heat/common/config.py @@ -116,6 +116,14 @@ cfg.CONF.register_opts(rpc_opts) cfg.CONF.register_group(paste_deploy_group) cfg.CONF.register_opts(paste_deploy_opts, group=paste_deploy_group) +# TODO(jianingy): I'll set allowed_rpc_exception_modules here for now. +# after figure out why rpc_set_default was not called, +# I'll move these settings into rpc_set_default() +allowed_rpc_exception_modules = cfg.CONF.allowed_rpc_exception_modules +allowed_rpc_exception_modules.append('heat.common.exception') +cfg.CONF.set_default(name='allowed_rpc_exception_modules', + default=allowed_rpc_exception_modules) + def rpc_set_default(): rpc.set_defaults(control_exchange='heat') diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index 10b1b0c919..ce38c4eb3c 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -19,9 +19,11 @@ import webob.exc from heat.common import identifier from heat.openstack.common import rpc -import heat.openstack.common.rpc.common as rpc_common + +from heat.common import exception as heat_exc from heat.common.wsgi import Request from heat.common import urlfetch +from heat.openstack.common.rpc import common as rpc_common from heat.rpc import api as rpc_api from heat.tests.common import HeatTestCase @@ -32,6 +34,33 @@ import heat.api.openstack.v1.events as events import heat.api.openstack.v1.actions as actions from heat.tests.utils import dummy_context +import heat.api.middleware.fault as fault + + +def request_with_middleware(middleware, func, req, *args, **kwargs): + + @webob.dec.wsgify + def _app(req): + return func(req, *args, **kwargs) + + resp = middleware(_app).process_request(req) + return resp + + +def remote_error(ex_type, message=''): + """convert rpc original exception to the one with _Remote suffix.""" + + # NOTE(jianingy): this function helps simulate the real world exceptions + + module = ex_type().__class__.__module__ + str_override = lambda self: "%s\n" % message + new_ex_type = type(ex_type.__name__ + rpc_common._REMOTE_POSTFIX, + (ex_type,), + {'__str__': str_override, '__unicode__': str_override}) + + new_ex_type.__module__ = '%s%s' % (module, rpc_common._REMOTE_POSTFIX) + return new_ex_type() + class InstantiationDataTest(HeatTestCase): @@ -369,12 +398,15 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'list_stacks', 'args': {}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("AttributeError")) + None).AndRaise(remote_error(AttributeError)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller.index, - req, tenant_id=self.tenant) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.index, + req, tenant_id=self.tenant) + + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'AttributeError') self.m.VerifyAll() def test_index_rmt_interr(self): @@ -386,12 +418,15 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'list_stacks', 'args': {}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("Exception")) + None).AndRaise(remote_error(Exception)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPInternalServerError, - self.controller.index, - req, tenant_id=self.tenant) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.index, + req, tenant_id=self.tenant) + + self.assertEqual(resp.json['code'], 500) + self.assertEqual(resp.json['error']['type'], 'Exception') self.m.VerifyAll() def test_create(self): @@ -488,7 +523,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("AttributeError")) + None).AndRaise(remote_error(AttributeError)) rpc.call(req.context, self.topic, {'namespace': None, 'method': 'create_stack', @@ -498,7 +533,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("UnknownUserParameter")) + None).AndRaise(remote_error(heat_exc.UnknownUserParameter)) rpc.call(req.context, self.topic, {'namespace': None, 'method': 'create_stack', @@ -508,20 +543,28 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("UserParameterMissing")) - + None).AndRaise(remote_error(heat_exc.UserParameterMissing)) self.m.ReplayAll() + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, body=body) - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller.create, - req, tenant_id=self.tenant, body=body) - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller.create, - req, tenant_id=self.tenant, body=body) - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller.create, - req, tenant_id=self.tenant, body=body) + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'AttributeError') + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, body=body) + + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'UnknownUserParameter') + + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, body=body) + + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'UserParameterMissing') self.m.VerifyAll() def test_create_err_existing(self): @@ -546,12 +589,15 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackExists")) + None).AndRaise(remote_error(heat_exc.StackExists)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPConflict, - self.controller.create, - req, tenant_id=self.tenant, body=body) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, body=body) + + self.assertEqual(resp.json['code'], 409) + self.assertEqual(resp.json['error']['type'], 'StackExists') self.m.VerifyAll() def test_create_err_engine(self): @@ -576,14 +622,15 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError( - 'StackValidationFailed', - 'Something went wrong')) + None).AndRaise(remote_error(heat_exc.StackValidationFailed)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPBadRequest, - self.controller.create, - req, tenant_id=self.tenant, body=body) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, body=body) + + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'StackValidationFailed') self.m.VerifyAll() def test_lookup(self): @@ -637,11 +684,16 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'identify_stack', 'args': {'stack_name': stack_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, self.controller.lookup, - req, tenant_id=self.tenant, stack_name=stack_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.lookup, + req, tenant_id=self.tenant, + stack_name=stack_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_lookup_resource(self): @@ -681,12 +733,17 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'identify_stack', 'args': {'stack_name': stack_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, self.controller.lookup, - req, tenant_id=self.tenant, stack_name=stack_name, - path='resources') + resp = request_with_middleware(fault.FaultWrapper, + self.controller.lookup, + req, tenant_id=self.tenant, + stack_name=stack_name, + path='resources') + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_show(self): @@ -769,14 +826,17 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'show_stack', 'args': {'stack_identity': dict(identity)}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, tenant_id=identity.tenant, - stack_name=identity.stack_name, - stack_id=identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_show_invalidtenant(self): @@ -790,14 +850,17 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'show_stack', 'args': {'stack_identity': dict(identity)}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("InvalidTenant")) + None).AndRaise(remote_error(heat_exc.InvalidTenant)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPForbidden, - self.controller.show, - req, tenant_id=identity.tenant, - stack_name=identity.stack_name, - stack_id=identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id) + + self.assertEqual(resp.json['code'], 403) + self.assertEqual(resp.json['error']['type'], 'InvalidTenant') self.m.VerifyAll() def test_get_template(self): @@ -832,15 +895,18 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'get_template', 'args': {'stack_identity': dict(identity)}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.template, - req, tenant_id=identity.tenant, - stack_name=identity.stack_name, - stack_id=identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.template, + req, tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_update(self): @@ -902,15 +968,18 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.update, - req, tenant_id=identity.tenant, - stack_name=identity.stack_name, - stack_id=identity.stack_id, - body=body) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.update, + req, tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id, + body=body) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_delete(self): @@ -959,14 +1028,17 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'delete_stack', 'args': {'stack_identity': dict(identity)}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.delete, - req, tenant_id=identity.tenant, - stack_name=identity.stack_name, - stack_id=identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.delete, + req, tenant_id=identity.tenant, + stack_name=identity.stack_name, + stack_id=identity.stack_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_validate_template(self): @@ -1056,12 +1128,14 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'list_resource_types', 'args': {}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("ValueError")) + None).AndRaise(remote_error(heat_exc.ServerError)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPInternalServerError, - self.controller.list_resource_types, - req, tenant_id=self.tenant) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.list_resource_types, + req, tenant_id=self.tenant) + self.assertEqual(resp.json['code'], 500) + self.assertEqual(resp.json['error']['type'], 'ServerError') self.m.VerifyAll() @@ -1163,14 +1237,17 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'method': 'list_stack_resources', 'args': {'stack_identity': stack_identity}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.index, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.index, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_show(self): @@ -1248,15 +1325,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': stack_identity, 'resource_name': res_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_show_nonexist_resource(self): @@ -1275,15 +1355,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': stack_identity, 'resource_name': res_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("ResourceNotFound")) + None).AndRaise(remote_error(heat_exc.ResourceNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'ResourceNotFound') self.m.VerifyAll() def test_show_uncreated_resource(self): @@ -1302,15 +1385,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': stack_identity, 'resource_name': res_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("ResourceNotAvailable")) + None).AndRaise(remote_error(heat_exc.ResourceNotAvailable)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'ResourceNotAvailable') self.m.VerifyAll() def test_metadata_show(self): @@ -1373,15 +1459,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': stack_identity, 'resource_name': res_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.metadata, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.metadata, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_metadata_show_nonexist_resource(self): @@ -1400,15 +1489,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': stack_identity, 'resource_name': res_name}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("ResourceNotFound")) + None).AndRaise(remote_error(heat_exc.ResourceNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.metadata, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.metadata, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'ResourceNotFound') self.m.VerifyAll() @@ -1577,14 +1669,17 @@ class EventControllerTest(ControllerTest, HeatTestCase): 'method': 'list_events', 'args': {'stack_identity': stack_identity}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.index, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.index, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() def test_index_resource_nonexist(self): @@ -1818,15 +1913,19 @@ class EventControllerTest(ControllerTest, HeatTestCase): 'method': 'list_events', 'args': {'stack_identity': stack_identity}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("StackNotFound")) + None).AndRaise(remote_error(heat_exc.StackNotFound)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - resource_name=res_name, event_id=event_id) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.show, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + resource_name=res_name, + event_id=event_id) + + self.assertEqual(resp.json['code'], 404) + self.assertEqual(resp.json['error']['type'], 'StackNotFound') self.m.VerifyAll() @@ -2233,15 +2332,18 @@ class ActionControllerTest(ControllerTest, HeatTestCase): 'method': 'stack_suspend', 'args': {'stack_identity': stack_identity}, 'version': self.api_version}, - None).AndRaise(rpc_common.RemoteError("AttributeError")) + None).AndRaise(remote_error(AttributeError)) self.m.ReplayAll() - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.action, - req, tenant_id=self.tenant, - stack_name=stack_identity.stack_name, - stack_id=stack_identity.stack_id, - body=body) + resp = request_with_middleware(fault.FaultWrapper, + self.controller.action, + req, tenant_id=self.tenant, + stack_name=stack_identity.stack_name, + stack_id=stack_identity.stack_id, + body=body) + self.assertEqual(resp.json['code'], 400) + self.assertEqual(resp.json['error']['type'], 'AttributeError') self.m.VerifyAll() def test_action_badaction_ise(self):