wsgi.Resource exception handling to not log errors

In order to not log some exceptions as errors, the
wsgi.Resource.__call__() was modified.
Instead of check if an exception is a HTTPBadRequest or a HTTPNotFound,
now all the exceptions that are not childs of HTTPError are raised
directly, without logging, translation or disguise.
If the exception is a child of HeatException, then the exception is
tranlated but not logged as an error. When this exception reaches the
Fault Wrapper Middleware it is logged as debug.
Some unused, or only use in test, exceptions were removed.

Change-Id: I105eeb74a55dcabc79cd3926dd88da0e19d1e1f1
Closes-Bug: #1231133
This commit is contained in:
Pablo Andres Fuente 2013-12-13 16:51:47 -03:00
parent e8c745487d
commit 7cca4576f0
5 changed files with 51 additions and 24 deletions

View File

@ -166,19 +166,10 @@ class AuthorizationRedirect(HeatException):
msg_fmt = _("Redirecting to %(uri)s for authorization.")
class ClientConfigurationError(HeatException):
msg_fmt = _("There was an error configuring the client.")
class RequestUriTooLong(HeatException):
msg_fmt = _("The URI was too long.")
class ServerError(HeatException):
msg_fmt = _("The request returned 500 Internal Server Error"
"\n\nThe response body:\n%(body)s")
class MaxRedirectsExceeded(HeatException):
msg_fmt = _("Maximum redirects (%(redirects)s) was exceeded.")
@ -187,10 +178,6 @@ class InvalidRedirect(HeatException):
msg_fmt = _("Received invalid HTTP redirect.")
class NoServiceEndpoint(HeatException):
msg_fmt = _("Response from Keystone does not contain a Heat endpoint.")
class RegionAmbiguity(HeatException):
msg_fmt = _("Multiple 'image' service matches for region %(region)s. This "
"generally means that a region is required and you have not "

View File

@ -670,17 +670,18 @@ class Resource(object):
# won't make it into the pipeline app that serializes errors
raise exception.HTTPExceptionDisguise(http_exc)
except webob.exc.HTTPException as err:
if isinstance(err, (webob.exc.HTTPOk, webob.exc.HTTPRedirection)):
if not isinstance(err, webob.exc.HTTPError):
# Some HTTPException are actually not errors, they are
# responses ready to be sent back to the users, so we don't
# error log, disguise or translate those
raise
logging.error(_("Returning %(code)s to user: %(explanation)s"),
{'code': err.code, 'explanation': err.explanation})
if isinstance(err, webob.exc.HTTPServerError):
logging.error(
_("Returning %(code)s to user: %(explanation)s"),
{'code': err.code, 'explanation': err.explanation})
http_exc = translate_exception(err, request.best_match_language())
raise exception.HTTPExceptionDisguise(http_exc)
except exception.HeatException as err:
log_exception(err, sys.exc_info())
raise translate_exception(err, request.best_match_language())
except Exception as err:
log_exception(err, sys.exc_info())

View File

@ -1284,7 +1284,7 @@ class StackControllerTest(ControllerTest, HeatTestCase):
def test_list_resource_types_error(self):
req = self._get('/resource_types')
error = heat_exc.ServerError(body='')
error = heat_exc.ResourceTypeNotFound(type_name='')
self.m.StubOutWithMock(rpc, 'call')
rpc.call(req.context, self.topic,
{'namespace': None,
@ -1297,8 +1297,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
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.assertEqual(resp.json['code'], 404)
self.assertEqual(resp.json['error']['type'], 'ResourceTypeNotFound')
self.m.VerifyAll()
def test_resource_schema(self):

View File

@ -39,12 +39,12 @@ class FaultMiddlewareTest(HeatTestCase):
def test_openstack_exception_without_kwargs(self):
wrapper = fault.FaultWrapper(None)
msg = wrapper._error(heat_exc.NoServiceEndpoint())
msg = wrapper._error(heat_exc.StackResourceLimitExceeded())
expected = {'code': 500,
'error': {'message': 'Response from Keystone does '
'not contain a Heat endpoint.',
'error': {'message': 'Maximum resources '
'per stack exceeded.',
'traceback': None,
'type': 'NoServiceEndpoint'},
'type': 'StackResourceLimitExceeded'},
'explanation': 'The server has either erred or is '
'incapable of performing the requested '
'operation.',

View File

@ -20,12 +20,15 @@ import datetime
import json
from oslo.config import cfg
import stubout
import testscenarios
import webob
from heat.common import exception
from heat.common import wsgi
from heat.tests.common import HeatTestCase
load_tests = testscenarios.load_tests_apply_scenarios
class RequestTest(HeatTestCase):
@ -226,6 +229,42 @@ class ResourceTest(HeatTestCase):
self.m.VerifyAll()
class ResourceExceptionHandlingTest(HeatTestCase):
scenarios = [
('client_exceptions', dict(
exception=exception.StackResourceLimitExceeded,
exception_catch=exception.StackResourceLimitExceeded)),
('webob_bad_request', dict(
exception=webob.exc.HTTPBadRequest,
exception_catch=exception.HTTPExceptionDisguise)),
('webob_not_found', dict(
exception=webob.exc.HTTPNotFound,
exception_catch=exception.HTTPExceptionDisguise)),
]
def setUp(self):
super(ResourceExceptionHandlingTest, self).setUp()
def test_resource_client_exceptions_dont_log_error(self):
class Controller(object):
def __init__(self, excpetion_to_raise):
self.excpetion_to_raise = excpetion_to_raise
def raise_exception(self, req, body):
raise self.excpetion_to_raise()
actions = {'action': 'raise_exception', 'body': 'data'}
env = {'wsgiorg.routing_args': [None, actions]}
request = wsgi.Request.blank('/tests/123', environ=env)
request.body = '{"foo" : "value"}'
resource = wsgi.Resource(Controller(self.exception),
wsgi.JSONRequestDeserializer(),
None)
e = self.assertRaises(self.exception_catch, resource, request)
e = e.exc if hasattr(e, 'exc') else e
self.assertNotIn(str(e), self.logger.output)
class JSONResponseSerializerTest(HeatTestCase):
def test_to_json(self):