diff options
| author | Michael Gundlach <michael.gundlach@rackspace.com> | 2010-10-19 19:37:42 -0400 |
|---|---|---|
| committer | Michael Gundlach <michael.gundlach@rackspace.com> | 2010-10-19 19:37:42 -0400 |
| commit | 86a8a5a2091dc0a36ccbe05f46609c82b1060291 (patch) | |
| tree | 559f050766e02d57850bba2baefdaf89e55d43d6 | |
| parent | 9947da22ab939f122e49857e3fd555542dae5248 (diff) | |
| download | nova-86a8a5a2091dc0a36ccbe05f46609c82b1060291.tar.gz nova-86a8a5a2091dc0a36ccbe05f46609c82b1060291.tar.xz nova-86a8a5a2091dc0a36ccbe05f46609c82b1060291.zip | |
Fixes https://bugs.launchpad.net/nova/+bug/663551 by catching exceptions at the top level of the API and turning them into Faults.
| -rw-r--r-- | nova/api/openstack/__init__.py | 11 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_api.py | 65 |
2 files changed, 76 insertions, 0 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 5706dbc09..24e1dd090 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -23,6 +23,7 @@ WSGI middleware for OpenStack API controllers. import json import time +import logging import routes import webob.dec import webob.exc @@ -53,6 +54,16 @@ class API(wsgi.Middleware): app = AuthMiddleware(RateLimitingMiddleware(APIRouter())) super(API, self).__init__(app) + @webob.dec.wsgify + def __call__(self, req): + try: + return req.get_response(self.application) + except Exception as ex: + logging.warn("Caught error: %s" % str(ex)) + exc = webob.exc.HTTPInternalServerError(explanation=str(ex)) + return faults.Fault(exc) + + class AuthMiddleware(wsgi.Middleware): """Authorize the openstack API request or return an HTTP Forbidden.""" diff --git a/nova/tests/api/openstack/test_api.py b/nova/tests/api/openstack/test_api.py new file mode 100644 index 000000000..171818806 --- /dev/null +++ b/nova/tests/api/openstack/test_api.py @@ -0,0 +1,65 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# 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. + +import unittest +import webob.exc +import webob.dec + +import nova.api.openstack +from nova.api.openstack import API +from nova.api.openstack import faults +from webob import Request + +class APITest(unittest.TestCase): + + def test_exceptions_are_converted_to_faults(self): + @webob.dec.wsgify + def succeed(req): + return 'Succeeded' + @webob.dec.wsgify + def raise_webob_exc(req): + raise webob.exc.HTTPNotFound(explanation='Raised a webob.exc') + @webob.dec.wsgify + def fail(req): + raise Exception("Threw an exception") + @webob.dec.wsgify + def raise_api_fault(req): + exc = webob.exc.HTTPNotFound(explanation='Raised a webob.exc') + return faults.Fault(exc) + api = API() + + api.application = succeed + resp = Request.blank('/').get_response(api) + self.assertFalse('cloudServersFault' in resp.body, resp.body) + self.assertEqual(resp.status_int, 200, resp.body) + + api.application = raise_webob_exc + resp = Request.blank('/').get_response(api) + self.assertFalse('cloudServersFault' in resp.body, resp.body) + self.assertEqual(resp.status_int, 404, resp.body) + + api.application = raise_api_fault + resp = Request.blank('/').get_response(api) + self.assertTrue('itemNotFound' in resp.body, resp.body) + self.assertEqual(resp.status_int, 404, resp.body) + + api.application = fail + resp = Request.blank('/').get_response(api) + self.assertTrue('cloudServersFault' in resp.body, resp.body) + self.assertEqual(resp.status_int, 500, resp.body) + + |
