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:
parent
fe1557d60d
commit
c5ab33614b
|
@ -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
|
||||||
|
|
|
@ -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)))
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue