When the glance client throws an Exception at Horizon, catch it and determine if it is an HTTP exception. If it is, recast it as a glance_client.ClientConnectionError so that Horizon can deal with it in a better manner. Fixes 951200

Change-Id: I7cbfa74d340d25d523ab8fb18138f5cf7d33a9d9
This commit is contained in:
John Postlethwait 2012-03-11 18:37:18 -07:00
parent bf217e8381
commit 7b526b6a7e
2 changed files with 64 additions and 0 deletions

View File

@ -20,10 +20,14 @@
from __future__ import absolute_import
import functools
import logging
import urlparse
from django.utils.decorators import available_attrs
from glance import client as glance_client
from glance.common import exception as glance_exception
from horizon.api.base import APIDictWrapper, url_for
@ -31,6 +35,27 @@ from horizon.api.base import APIDictWrapper, url_for
LOG = logging.getLogger(__name__)
def catch_glance_exception(func):
"""
The glance client sometimes throws ``Exception`` classed exceptions for
HTTP communication issues. Catch those, and rethrow them as
``glance_client.ClientConnectionErrors`` so that we can do something
useful with them.
"""
# TODO(johnp): Remove this once Bug 952618 is fixed in the glance client.
@functools.wraps(func, assigned=available_attrs(func))
def inner_func(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as exc:
exc_message = str(exc)
if('Unknown error occurred' in exc_message or
'Internal Server error' in exc_message):
raise glance_exception.ClientConnectionError(exc_message)
raise
return inner_func
class Image(APIDictWrapper):
"""
Wrapper around glance image dictionary to make it object-like and provide
@ -58,6 +83,7 @@ class ImageProperties(APIDictWrapper):
'project_id', 'ramdisk_id', 'image_type']
@catch_glance_exception
def glanceclient(request):
o = urlparse.urlparse(url_for(request, 'image'))
LOG.debug('glanceclient connection created for host "%s:%d"' %
@ -67,14 +93,17 @@ def glanceclient(request):
auth_tok=request.user.token)
@catch_glance_exception
def image_create(request, image_meta, image_file):
return Image(glanceclient(request).add_image(image_meta, image_file))
@catch_glance_exception
def image_delete(request, image_id):
return glanceclient(request).delete_image(image_id)
@catch_glance_exception
def image_get(request, image_id):
"""
Returns the actual image file from Glance for image with
@ -83,6 +112,7 @@ def image_get(request, image_id):
return glanceclient(request).get_image(image_id)[1]
@catch_glance_exception
def image_get_meta(request, image_id):
"""
Returns an Image object populated with metadata for image
@ -91,16 +121,19 @@ def image_get_meta(request, image_id):
return Image(glanceclient(request).get_image_meta(image_id))
@catch_glance_exception
def image_list_detailed(request):
return [Image(i) for i in glanceclient(request).get_images_detailed()]
@catch_glance_exception
def image_update(request, image_id, image_meta=None):
image_meta = image_meta and image_meta or {}
return Image(glanceclient(request).update_image(image_id,
image_meta=image_meta))
@catch_glance_exception
def snapshot_list_detailed(request):
filters = {}
filters['property-image_type'] = 'snapshot'

View File

@ -18,6 +18,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.common import exception as glance_exception
from horizon import api
from horizon import test
@ -56,6 +58,35 @@ class GlanceApiTests(test.APITestCase):
self.assertIsInstance(image, api.glance.Image)
self.assertIn(image._apidict, images)
def test_glance_exception_wrapping_for_internal_server_errors(self):
"""
Verify that generic "Exception" classed exceptions from the glance
client's HTTP Internal Service Errors get converted to
ClientConnectionError's.
"""
# TODO(johnp): Remove once Bug 952618 is fixed in the glance client.
glanceclient = self.stub_glanceclient()
glanceclient.get_images_detailed().AndRaise(
Exception("Internal Server error: "))
self.mox.ReplayAll()
with self.assertRaises(glance_exception.ClientConnectionError):
api.image_list_detailed(self.request)
def test_glance_exception_wrapping_for_generic_http_errors(self):
"""
Verify that generic "Exception" classed exceptions from the glance
client's HTTP errors get converted to ClientConnectionError's.
"""
# TODO(johnp): Remove once Bug 952618 is fixed in the glance client.
glanceclient = self.stub_glanceclient()
glanceclient.get_images_detailed().AndRaise(
Exception("Unknown error occurred! 503 Service Unavailable"))
self.mox.ReplayAll()
with self.assertRaises(glance_exception.ClientConnectionError):
api.image_list_detailed(self.request)
class ImageWrapperTests(test.TestCase):
""" Tests for wrapper classes since they have extra logic attached. """