make heat-api return a parsable error

add a wsgi middleware (faultwrap) that catches exceptions
and transform those exceptions into a parsable format
according to 'Content-Type' of the request.

Fixes bug 1158598
Implements blueprint exception-formatting

Change-Id: Iacdb8cc119b250ff1e39c99b7a7f66fd4c35e7d9
This commit is contained in:
Jianing YANG 2013-07-11 23:17:52 +08:00 committed by Steve Baker
parent fe1557d60d
commit c5ab33614b
6 changed files with 369 additions and 163 deletions

View File

@ -1,7 +1,7 @@
# heat-api pipeline # heat-api pipeline
[pipeline:heat-api] [pipeline:heat-api]
pipeline = versionnegotiation authtoken context apiv1app pipeline = faultwrap versionnegotiation authtoken context apiv1app
# heat-api pipeline for standalone heat # heat-api pipeline for standalone heat
# ie. uses alternative auth backend that authenticates users against keystone # ie. uses alternative auth backend that authenticates users against keystone
@ -12,7 +12,7 @@ pipeline = versionnegotiation authtoken context apiv1app
# flavor = standalone # flavor = standalone
# #
[pipeline:heat-api-standalone] [pipeline:heat-api-standalone]
pipeline = versionnegotiation authpassword context apiv1app pipeline = faultwrap versionnegotiation authpassword context apiv1app
# heat-api pipeline for custom cloud backends # heat-api pipeline for custom cloud backends
# i.e. in heat-api.conf: # i.e. in heat-api.conf:
@ -20,7 +20,7 @@ pipeline = versionnegotiation authpassword context apiv1app
# flavor = custombackend # flavor = custombackend
# #
[pipeline:heat-api-custombackend] [pipeline:heat-api-custombackend]
pipeline = versionnegotiation context custombackendauth apiv1app pipeline = faultwrap versionnegotiation context custombackendauth apiv1app
# heat-api-cfn pipeline # heat-api-cfn pipeline
[pipeline:heat-api-cfn] [pipeline:heat-api-cfn]
@ -56,6 +56,10 @@ heat.app_factory = heat.api.cloudwatch:API
paste.filter_factory = heat.common.wsgi:filter_factory paste.filter_factory = heat.common.wsgi:filter_factory
heat.filter_factory = heat.api.openstack:version_negotiation_filter 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] [filter:cfnversionnegotiation]
paste.filter_factory = heat.common.wsgi:filter_factory paste.filter_factory = heat.common.wsgi:filter_factory
heat.filter_factory = heat.api.cfn:version_negotiation_filter heat.filter_factory = heat.api.cfn:version_negotiation_filter

View File

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

View File

@ -14,9 +14,14 @@
# under the License. # under the License.
from heat.api.middleware.version_negotiation import VersionNegotiationFilter from heat.api.middleware.version_negotiation import VersionNegotiationFilter
from heat.api.middleware.fault import FaultWrapper
from heat.api.openstack import versions from heat.api.openstack import versions
def version_negotiation_filter(app, conf, **local_conf): def version_negotiation_filter(app, conf, **local_conf):
return VersionNegotiationFilter(versions.Controller, app, return VersionNegotiationFilter(versions.Controller, app,
conf, **local_conf) conf, **local_conf)
def faultwrap_filter(app, conf, **local_conf):
return FaultWrapper(app)

View File

@ -67,31 +67,10 @@ def make_link(req, identity, relationship='self'):
def remote_error(ex): def remote_error(ex):
""" """The RemoteError mapping work has been moved to heat.api.middleware.fault
Map rpc_common.RemoteError exceptions returned by the engine which handles error formating now. This function will be deprecated
to webob exceptions which can be used to return in the future, so please raise exceptions directly.
properly formatted error responses.
""" """
error_map = { # TODO(jianingy): add a deprecated warning here to inform others.
'AttributeError': exc.HTTPBadRequest, raise ex
'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))

View File

@ -116,6 +116,14 @@ cfg.CONF.register_opts(rpc_opts)
cfg.CONF.register_group(paste_deploy_group) cfg.CONF.register_group(paste_deploy_group)
cfg.CONF.register_opts(paste_deploy_opts, 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(): def rpc_set_default():
rpc.set_defaults(control_exchange='heat') rpc.set_defaults(control_exchange='heat')

View File

@ -19,9 +19,11 @@ import webob.exc
from heat.common import identifier from heat.common import identifier
from heat.openstack.common import rpc 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.wsgi import Request
from heat.common import urlfetch 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.rpc import api as rpc_api
from heat.tests.common import HeatTestCase 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 import heat.api.openstack.v1.actions as actions
from heat.tests.utils import dummy_context 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<Traceback>" % 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): class InstantiationDataTest(HeatTestCase):
@ -369,12 +398,15 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'list_stacks', 'method': 'list_stacks',
'args': {}, 'args': {},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("AttributeError")) None).AndRaise(remote_error(AttributeError))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPBadRequest, resp = request_with_middleware(fault.FaultWrapper,
self.controller.index, self.controller.index,
req, tenant_id=self.tenant) req, tenant_id=self.tenant)
self.assertEqual(resp.json['code'], 400)
self.assertEqual(resp.json['error']['type'], 'AttributeError')
self.m.VerifyAll() self.m.VerifyAll()
def test_index_rmt_interr(self): def test_index_rmt_interr(self):
@ -386,12 +418,15 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'list_stacks', 'method': 'list_stacks',
'args': {}, 'args': {},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("Exception")) None).AndRaise(remote_error(Exception))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPInternalServerError, resp = request_with_middleware(fault.FaultWrapper,
self.controller.index, self.controller.index,
req, tenant_id=self.tenant) req, tenant_id=self.tenant)
self.assertEqual(resp.json['code'], 500)
self.assertEqual(resp.json['error']['type'], 'Exception')
self.m.VerifyAll() self.m.VerifyAll()
def test_create(self): def test_create(self):
@ -488,7 +523,7 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("AttributeError")) None).AndRaise(remote_error(AttributeError))
rpc.call(req.context, self.topic, rpc.call(req.context, self.topic,
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
@ -498,7 +533,7 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("UnknownUserParameter")) None).AndRaise(remote_error(heat_exc.UnknownUserParameter))
rpc.call(req.context, self.topic, rpc.call(req.context, self.topic,
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
@ -508,20 +543,28 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("UserParameterMissing")) None).AndRaise(remote_error(heat_exc.UserParameterMissing))
self.m.ReplayAll() 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.assertEqual(resp.json['code'], 400)
self.controller.create, self.assertEqual(resp.json['error']['type'], 'AttributeError')
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)
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() self.m.VerifyAll()
def test_create_err_existing(self): def test_create_err_existing(self):
@ -546,12 +589,15 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackExists")) None).AndRaise(remote_error(heat_exc.StackExists))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPConflict, resp = request_with_middleware(fault.FaultWrapper,
self.controller.create, self.controller.create,
req, tenant_id=self.tenant, body=body) req, tenant_id=self.tenant, body=body)
self.assertEqual(resp.json['code'], 409)
self.assertEqual(resp.json['error']['type'], 'StackExists')
self.m.VerifyAll() self.m.VerifyAll()
def test_create_err_engine(self): def test_create_err_engine(self):
@ -576,14 +622,15 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError( None).AndRaise(remote_error(heat_exc.StackValidationFailed))
'StackValidationFailed',
'Something went wrong'))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPBadRequest, resp = request_with_middleware(fault.FaultWrapper,
self.controller.create, self.controller.create,
req, tenant_id=self.tenant, body=body) req, tenant_id=self.tenant, body=body)
self.assertEqual(resp.json['code'], 400)
self.assertEqual(resp.json['error']['type'], 'StackValidationFailed')
self.m.VerifyAll() self.m.VerifyAll()
def test_lookup(self): def test_lookup(self):
@ -637,11 +684,16 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'identify_stack', 'method': 'identify_stack',
'args': {'stack_name': stack_name}, 'args': {'stack_name': stack_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, self.controller.lookup, resp = request_with_middleware(fault.FaultWrapper,
req, tenant_id=self.tenant, stack_name=stack_name) 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() self.m.VerifyAll()
def test_lookup_resource(self): def test_lookup_resource(self):
@ -681,12 +733,17 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'identify_stack', 'method': 'identify_stack',
'args': {'stack_name': stack_name}, 'args': {'stack_name': stack_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, self.controller.lookup, resp = request_with_middleware(fault.FaultWrapper,
req, tenant_id=self.tenant, stack_name=stack_name, self.controller.lookup,
path='resources') 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() self.m.VerifyAll()
def test_show(self): def test_show(self):
@ -769,14 +826,17 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'show_stack', 'method': 'show_stack',
'args': {'stack_identity': dict(identity)}, 'args': {'stack_identity': dict(identity)},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=identity.tenant, req, tenant_id=identity.tenant,
stack_name=identity.stack_name, stack_name=identity.stack_name,
stack_id=identity.stack_id) stack_id=identity.stack_id)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_show_invalidtenant(self): def test_show_invalidtenant(self):
@ -790,14 +850,17 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'show_stack', 'method': 'show_stack',
'args': {'stack_identity': dict(identity)}, 'args': {'stack_identity': dict(identity)},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("InvalidTenant")) None).AndRaise(remote_error(heat_exc.InvalidTenant))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPForbidden, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=identity.tenant, req, tenant_id=identity.tenant,
stack_name=identity.stack_name, stack_name=identity.stack_name,
stack_id=identity.stack_id) stack_id=identity.stack_id)
self.assertEqual(resp.json['code'], 403)
self.assertEqual(resp.json['error']['type'], 'InvalidTenant')
self.m.VerifyAll() self.m.VerifyAll()
def test_get_template(self): def test_get_template(self):
@ -832,15 +895,18 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'get_template', 'method': 'get_template',
'args': {'stack_identity': dict(identity)}, 'args': {'stack_identity': dict(identity)},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.template, self.controller.template,
req, tenant_id=identity.tenant, req, tenant_id=identity.tenant,
stack_name=identity.stack_name, stack_name=identity.stack_name,
stack_id=identity.stack_id) stack_id=identity.stack_id)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_update(self): def test_update(self):
@ -902,15 +968,18 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'files': {}, 'files': {},
'args': {'timeout_mins': 30}}, 'args': {'timeout_mins': 30}},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.update, self.controller.update,
req, tenant_id=identity.tenant, req, tenant_id=identity.tenant,
stack_name=identity.stack_name, stack_name=identity.stack_name,
stack_id=identity.stack_id, stack_id=identity.stack_id,
body=body) body=body)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_delete(self): def test_delete(self):
@ -959,14 +1028,17 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'delete_stack', 'method': 'delete_stack',
'args': {'stack_identity': dict(identity)}, 'args': {'stack_identity': dict(identity)},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.delete, self.controller.delete,
req, tenant_id=identity.tenant, req, tenant_id=identity.tenant,
stack_name=identity.stack_name, stack_name=identity.stack_name,
stack_id=identity.stack_id) stack_id=identity.stack_id)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_validate_template(self): def test_validate_template(self):
@ -1056,12 +1128,14 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'list_resource_types', 'method': 'list_resource_types',
'args': {}, 'args': {},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("ValueError")) None).AndRaise(remote_error(heat_exc.ServerError))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPInternalServerError, resp = request_with_middleware(fault.FaultWrapper,
self.controller.list_resource_types, self.controller.list_resource_types,
req, tenant_id=self.tenant) req, tenant_id=self.tenant)
self.assertEqual(resp.json['code'], 500)
self.assertEqual(resp.json['error']['type'], 'ServerError')
self.m.VerifyAll() self.m.VerifyAll()
@ -1163,14 +1237,17 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'method': 'list_stack_resources', 'method': 'list_stack_resources',
'args': {'stack_identity': stack_identity}, 'args': {'stack_identity': stack_identity},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.index, self.controller.index,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id) stack_id=stack_identity.stack_id)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_show(self): def test_show(self):
@ -1248,15 +1325,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'args': {'stack_identity': stack_identity, 'args': {'stack_identity': stack_identity,
'resource_name': res_name}, 'resource_name': res_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name) resource_name=res_name)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_show_nonexist_resource(self): def test_show_nonexist_resource(self):
@ -1275,15 +1355,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'args': {'stack_identity': stack_identity, 'args': {'stack_identity': stack_identity,
'resource_name': res_name}, 'resource_name': res_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("ResourceNotFound")) None).AndRaise(remote_error(heat_exc.ResourceNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name) resource_name=res_name)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'ResourceNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_show_uncreated_resource(self): def test_show_uncreated_resource(self):
@ -1302,15 +1385,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'args': {'stack_identity': stack_identity, 'args': {'stack_identity': stack_identity,
'resource_name': res_name}, 'resource_name': res_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("ResourceNotAvailable")) None).AndRaise(remote_error(heat_exc.ResourceNotAvailable))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name) resource_name=res_name)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'ResourceNotAvailable')
self.m.VerifyAll() self.m.VerifyAll()
def test_metadata_show(self): def test_metadata_show(self):
@ -1373,15 +1459,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'args': {'stack_identity': stack_identity, 'args': {'stack_identity': stack_identity,
'resource_name': res_name}, 'resource_name': res_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.metadata, self.controller.metadata,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name) resource_name=res_name)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_metadata_show_nonexist_resource(self): def test_metadata_show_nonexist_resource(self):
@ -1400,15 +1489,18 @@ class ResourceControllerTest(ControllerTest, HeatTestCase):
'args': {'stack_identity': stack_identity, 'args': {'stack_identity': stack_identity,
'resource_name': res_name}, 'resource_name': res_name},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("ResourceNotFound")) None).AndRaise(remote_error(heat_exc.ResourceNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.metadata, self.controller.metadata,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name) resource_name=res_name)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'ResourceNotFound')
self.m.VerifyAll() self.m.VerifyAll()
@ -1577,14 +1669,17 @@ class EventControllerTest(ControllerTest, HeatTestCase):
'method': 'list_events', 'method': 'list_events',
'args': {'stack_identity': stack_identity}, 'args': {'stack_identity': stack_identity},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.index, self.controller.index,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id) stack_id=stack_identity.stack_id)
self.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'StackNotFound')
self.m.VerifyAll() self.m.VerifyAll()
def test_index_resource_nonexist(self): def test_index_resource_nonexist(self):
@ -1818,15 +1913,19 @@ class EventControllerTest(ControllerTest, HeatTestCase):
'method': 'list_events', 'method': 'list_events',
'args': {'stack_identity': stack_identity}, 'args': {'stack_identity': stack_identity},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("StackNotFound")) None).AndRaise(remote_error(heat_exc.StackNotFound))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPNotFound, resp = request_with_middleware(fault.FaultWrapper,
self.controller.show, self.controller.show,
req, tenant_id=self.tenant, req, tenant_id=self.tenant,
stack_name=stack_identity.stack_name, stack_name=stack_identity.stack_name,
stack_id=stack_identity.stack_id, stack_id=stack_identity.stack_id,
resource_name=res_name, event_id=event_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() self.m.VerifyAll()
@ -2233,15 +2332,18 @@ class ActionControllerTest(ControllerTest, HeatTestCase):
'method': 'stack_suspend', 'method': 'stack_suspend',
'args': {'stack_identity': stack_identity}, 'args': {'stack_identity': stack_identity},
'version': self.api_version}, 'version': self.api_version},
None).AndRaise(rpc_common.RemoteError("AttributeError")) None).AndRaise(remote_error(AttributeError))
self.m.ReplayAll() self.m.ReplayAll()
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.action, resp = request_with_middleware(fault.FaultWrapper,
req, tenant_id=self.tenant, self.controller.action,
stack_name=stack_identity.stack_name, req, tenant_id=self.tenant,
stack_id=stack_identity.stack_id, stack_name=stack_identity.stack_name,
body=body) stack_id=stack_identity.stack_id,
body=body)
self.assertEqual(resp.json['code'], 400)
self.assertEqual(resp.json['error']['type'], 'AttributeError')
self.m.VerifyAll() self.m.VerifyAll()
def test_action_badaction_ise(self): def test_action_badaction_ise(self):