diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-07-13 23:32:51 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-07-13 23:32:51 +0000 |
| commit | 58c92d66e7220574038cedd3079d64649ced2106 (patch) | |
| tree | de6e7ba63faf9681e7d4c611c29422b27d6ab374 | |
| parent | f4a778f31f647b065b945311920148366d4ead53 (diff) | |
| parent | e9d21589d39355ffc126e360cc2ba7311e014edb (diff) | |
| download | nova-58c92d66e7220574038cedd3079d64649ced2106.tar.gz nova-58c92d66e7220574038cedd3079d64649ced2106.tar.xz nova-58c92d66e7220574038cedd3079d64649ced2106.zip | |
Merge "Expose over-quota exceptions via native API."
| -rw-r--r-- | nova/api/openstack/__init__.py | 30 | ||||
| -rw-r--r-- | nova/exception.py | 2 | ||||
| -rw-r--r-- | nova/tests/api/openstack/compute/test_api.py | 24 |
3 files changed, 47 insertions, 9 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index afeed0399..3372d9b5e 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -25,6 +25,7 @@ import webob.dec import webob.exc from nova.api.openstack import wsgi +from nova import exception from nova.openstack.common import log as logging from nova import wsgi as base_wsgi @@ -35,20 +36,31 @@ LOG = logging.getLogger(__name__) class FaultWrapper(base_wsgi.Middleware): """Calls down the middleware stack, making exceptions into faults.""" + def _error(self, inner, req, safe=False): + LOG.exception(_("Caught error: %s"), unicode(inner)) + msg_dict = dict(url=req.url, status=500) + LOG.info(_("%(url)s returned with HTTP %(status)d") % msg_dict) + outer = webob.exc.HTTPInternalServerError() + # NOTE(johannes): We leave the explanation empty here on + # purpose. It could possibly have sensitive information + # that should not be returned back to the user. See + # bugs 868360 and 874472 + # NOTE(eglynn): However, it would be over-conservative and + # inconsistent with the EC2 API to hide every exception, + # including those that are safe to expose, see bug 1021373 + if safe: + outer.explanation = '%s: %s' % (inner.__class__.__name__, + unicode(inner)) + return wsgi.Fault(outer) + @webob.dec.wsgify(RequestClass=wsgi.Request) def __call__(self, req): try: return req.get_response(self.application) + except exception.NovaException as ex: + return self._error(ex, req, ex.safe) except Exception as ex: - LOG.exception(_("Caught error: %s"), unicode(ex)) - msg_dict = dict(url=req.url, status=500) - LOG.info(_("%(url)s returned with HTTP %(status)d") % msg_dict) - exc = webob.exc.HTTPInternalServerError() - # NOTE(johannes): We leave the explanation empty here on - # purpose. It could possibly have sensitive information - # that should not be returned back to the user. See - # bugs 868360 and 874472 - return wsgi.Fault(exc) + return self._error(ex, req) class APIMapper(routes.Mapper): diff --git a/nova/exception.py b/nova/exception.py index 8d0a20922..ac4f44abf 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -129,6 +129,7 @@ class NovaException(Exception): """ message = _("An unknown exception occurred.") + safe = False def __init__(self, message=None, **kwargs): self.kwargs = kwargs @@ -994,6 +995,7 @@ class WillNotSchedule(NovaException): class QuotaError(NovaException): message = _("Quota exceeded") + ": code=%(code)s" + safe = True class TooManyInstances(QuotaError): diff --git a/nova/tests/api/openstack/compute/test_api.py b/nova/tests/api/openstack/compute/test_api.py index 434befdb9..a1dd01be3 100644 --- a/nova/tests/api/openstack/compute/test_api.py +++ b/nova/tests/api/openstack/compute/test_api.py @@ -23,6 +23,7 @@ import webob.exc from nova.api import openstack as openstack_api from nova.api.openstack import wsgi import nova.context +from nova import exception from nova.openstack.common import jsonutils from nova import test from nova.tests.api.openstack import fakes @@ -120,6 +121,29 @@ class APITest(test.TestCase): self.assertTrue('<computeFault' in resp.body, resp.body) self.assertEqual(resp.status_int, 500, resp.body) + def _do_test_exception_safety_reflected_in_faults(self, expose): + class ExceptionWithSafety(exception.NovaException): + safe = expose + + @webob.dec.wsgify + def fail(req): + raise ExceptionWithSafety('some explanation') + + api = self._wsgi_app(fail) + resp = webob.Request.blank('/').get_response(api) + self.assertTrue('{"computeFault' in resp.body, resp.body) + expected = ('ExceptionWithSafety: some explanation' if expose else + 'The server has either erred or is incapable ' + 'of performing the requested operation.') + self.assertTrue(expected in resp.body, resp.body) + self.assertEqual(resp.status_int, 500, resp.body) + + def test_safe_exceptions_are_described_in_faults(self): + self._do_test_exception_safety_reflected_in_faults(True) + + def test_unsafe_exceptions_are_not_described_in_faults(self): + self._do_test_exception_safety_reflected_in_faults(False) + def test_request_id_in_response(self): req = webob.Request.blank('/') req.method = 'GET' |
