From d746c2bdc9f64f4db00c36c7f2e6fe24fedd2873 Mon Sep 17 00:00:00 2001 From: Jingjing Ren Date: Wed, 18 Nov 2015 23:39:08 +0000 Subject: [PATCH] Handle glanceclient CommunicationError in horizon When glanceclient throws a CommunicationError, Horizon doesn't show the error message from the exception handling code because the exception type CommunicationError is not recognized. This change registers the exception type and adds a unit test case. Change-Id: I5c6f3df4097a4493b4c88716f30de86e4cde3b4b Closes-Bug: #1517652 --- .../dashboards/project/images/tests.py | 59 +++++++++++++++++++ openstack_dashboard/exceptions.py | 1 + 2 files changed, 60 insertions(+) diff --git a/openstack_dashboard/dashboards/project/images/tests.py b/openstack_dashboard/dashboards/project/images/tests.py index 6827b7ccbf..a1878eafad 100644 --- a/openstack_dashboard/dashboards/project/images/tests.py +++ b/openstack_dashboard/dashboards/project/images/tests.py @@ -22,10 +22,13 @@ from socket import timeout as socket_timeout # noqa from django.core.urlresolvers import reverse from django import http +from glanceclient.common import exceptions as glance_exec + from mox3.mox import IsA # noqa import six from horizon import exceptions +from horizon import messages from openstack_dashboard import api from openstack_dashboard.dashboards.project.images import utils @@ -263,6 +266,62 @@ class ImagesAndSnapshotsUtilsTests(test.TestCase): len(private_images), len(images_cache['images_by_project'][self.tenant.id])) + @test.create_stubs({api.glance: ('image_list_detailed',), + messages: ('error',)}) + def test_list_image_communication_error_public_image_list(self): + public_images = [image for image in self.images.list() + if image.status == 'active' and image.is_public] + private_images = [image for image in self.images.list() + if (image.status == 'active' and + not image.is_public)] + api.glance.image_list_detailed( + IsA(http.HttpRequest), + filters={'is_public': True, 'status': 'active'}) \ + .AndRaise(glance_exec.CommunicationError) + # Make sure the exception is handled with the correct + # error message. If the exception cannot be handled, + # the error message will be different. + messages.error(IsA(http.HttpRequest), + "Unable to retrieve public images.") + api.glance.image_list_detailed( + IsA(http.HttpRequest), + filters={'property-owner_id': self.tenant.id, + 'status': 'active'}) \ + .AndReturn([private_images, False, False]) + api.glance.image_list_detailed( + IsA(http.HttpRequest), + filters={'is_public': True, 'status': 'active'}) \ + .AndReturn([public_images, False, False]) + + self.mox.ReplayAll() + + images_cache = {} + ret = utils.get_available_images(self.request, self.tenant.id, + images_cache) + + expected_images = [image for image in private_images + if image.container_format not in ('ami', 'aki')] + self.assertEqual(len(expected_images), len(ret)) + self.assertNotIn('public_images', images_cache) + self.assertEqual(1, len(images_cache['images_by_project'])) + self.assertEqual( + len(private_images), + len(images_cache['images_by_project'][self.tenant.id])) + + ret = utils.get_available_images(self.request, self.tenant.id, + images_cache) + + expected_images = [image for image in self.images.list() + if image.container_format not in ('ami', 'aki')] + self.assertEqual(len(expected_images), len(ret)) + self.assertEqual( + len(public_images), + len(images_cache['public_images'])) + self.assertEqual(1, len(images_cache['images_by_project'])) + self.assertEqual( + len(private_images), + len(images_cache['images_by_project'][self.tenant.id])) + @test.create_stubs({api.glance: ('image_list_detailed',), exceptions: ('handle',)}) def test_list_image_error_private_image_list(self): diff --git a/openstack_dashboard/exceptions.py b/openstack_dashboard/exceptions.py index a84d09f6a4..0de0b82834 100644 --- a/openstack_dashboard/exceptions.py +++ b/openstack_dashboard/exceptions.py @@ -62,6 +62,7 @@ RECOVERABLE = ( novaclient.ClientException, novaclient.Forbidden, glanceclient.ClientException, + glanceclient.CommunicationError, neutronclient.Forbidden, neutronclient.NeutronClientException, swiftclient.ClientException,