diff --git a/manila/compute/nova.py b/manila/compute/nova.py index d418a2fb1a..5da9a75149 100644 --- a/manila/compute/nova.py +++ b/manila/compute/nova.py @@ -268,6 +268,18 @@ class API(base.Base): # New novaclient without 'images' API proxy return client.glance.list() + def image_get(self, context, name): + client = novaclient(context) + try: + # New novaclient without 'images' API proxy + return client.glance.find_image(name) + except nova_exception.NotFound: + raise exception.ServiceInstanceException( + _("Image with name '%s' was not found.") % name) + except nova_exception.NoUniqueMatch: + raise exception.ServiceInstanceException( + _("Found more than one image by name '%s'.") % name) + def add_security_group_to_server(self, context, server, security_group): return novaclient(context).servers.add_security_group(server, security_group) diff --git a/manila/share/drivers/service_instance.py b/manila/share/drivers/service_instance.py index a6ca9fdc81..d0ab5585a2 100644 --- a/manila/share/drivers/service_instance.py +++ b/manila/share/drivers/service_instance.py @@ -519,19 +519,12 @@ class ServiceInstanceManager(object): def _get_service_image(self, context): """Returns ID of service image for service vm creating.""" service_image_name = self.get_config_option("service_image_name") - images = [image.id for image in self.compute_api.image_list(context) - if image.name == service_image_name - and image.status == 'active'] - if len(images) == 1: - return images[0] - elif not images: + image = self.compute_api.image_get(context, service_image_name) + if image.status != 'active': raise exception.ServiceInstanceException( - _("Image with name '%s' was not found or is not in " - "'active' state.") % service_image_name) - else: - raise exception.ServiceInstanceException( - _("Found more than one image by name '%s'.") % + _("Image with name '%s' is not in 'active' state.") % service_image_name) + return image def _create_service_instance(self, context, instance_name, network_info): """Creates service vm and sets up networking for it.""" diff --git a/manila/tests/compute/test_nova.py b/manila/tests/compute/test_nova.py index abf961f7e5..147c640af1 100644 --- a/manila/tests/compute/test_nova.py +++ b/manila/tests/compute/test_nova.py @@ -222,6 +222,48 @@ class NovaApiTestCase(test.TestCase): self.assertEqual(image_list1, result) + def test_image_get_novaclient_has_no_proxy(self): + image = 'fake-image' + + class FakeGlanceClient(object): + def find_image(self, name): + return image + + self.novaclient.glance = FakeGlanceClient() + result = self.api.image_get(self.ctx, 'fake-image') + + self.assertEqual(image, result) + + def test_image_get_novaclient_not_found(self): + image = 'fake-image' + + class FakeGlanceClient(object): + def find_image(self, image): + return image + + self.novaclient.glance = FakeGlanceClient() + + self.mock_object(self.novaclient.glance, 'find_image', + mock.Mock(return_value=image, + side_effect=nova_exception.NotFound(404))) + self.assertRaises(exception.ServiceInstanceException, + self.api.image_get, self.ctx, image) + + def test_image_get_novaclient_multi_match(self): + image = 'fake-image' + + class FakeGlanceClient(object): + def find_image(self, image): + return image + + self.novaclient.glance = FakeGlanceClient() + + self.mock_object(self.novaclient.glance, 'find_image', + mock.Mock(return_value=image, + side_effect=nova_exception.NoUniqueMatch)) + self.assertRaises(exception.ServiceInstanceException, + self.api.image_get, self.ctx, image) + def test_server_create(self): result = self.api.server_create(self.ctx, 'server_name', 'fake_image', 'fake_flavor', None, None, None) diff --git a/manila/tests/fake_compute.py b/manila/tests/fake_compute.py index cb537828bd..039abdac83 100644 --- a/manila/tests/fake_compute.py +++ b/manila/tests/fake_compute.py @@ -101,6 +101,9 @@ class API(object): def image_list(self, *args, **kwargs): pass + def image_get(self, *args, **kwargs): + pass + def security_group_create(self, *args, **kwargs): pass diff --git a/manila/tests/share/drivers/test_service_instance.py b/manila/tests/share/drivers/test_service_instance.py index 412dc8bac3..2da0780741 100644 --- a/manila/tests/share/drivers/test_service_instance.py +++ b/manila/tests/share/drivers/test_service_instance.py @@ -732,46 +732,21 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.assertEqual((None, None), result) def test_get_service_image(self): - fake_image1 = fake_compute.FakeImage( + fake_image = fake_compute.FakeImage( name=self._manager.get_config_option('service_image_name'), status='active') - fake_image2 = fake_compute.FakeImage( - name='service_image_name', - status='error') - fake_image3 = fake_compute.FakeImage( - name='another-image', - status='active') - self.mock_object(self._manager.compute_api, 'image_list', - mock.Mock(return_value=[fake_image1, - fake_image2, - fake_image3])) + self.mock_object(self._manager.compute_api, 'image_get', + mock.Mock(return_value=fake_image)) result = self._manager._get_service_image(self._manager.admin_context) - self.assertEqual(fake_image1.id, result) - - def test_get_service_image_not_found(self): - self.mock_object(self._manager.compute_api, 'image_list', - mock.Mock(return_value=[])) - self.assertRaises( - exception.ServiceInstanceException, - self._manager._get_service_image, self._manager.admin_context) + self.assertEqual(fake_image, result) + def test_get_service_image_not_active(self): fake_error_image = fake_compute.FakeImage( name='service_image_name', status='error') - self.mock_object(self._manager.compute_api, 'image_list', - mock.Mock(return_value=[fake_error_image])) - self.assertRaises( - exception.ServiceInstanceException, - self._manager._get_service_image, self._manager.admin_context) - - def test_get_service_image_ambiguous(self): - fake_image = fake_compute.FakeImage( - name=fake_get_config_option('service_image_name'), - status='active') - fake_images = [fake_image, fake_image] - self.mock_object(self._manager.compute_api, 'image_list', - mock.Mock(return_value=fake_images)) + self.mock_object(self._manager.compute_api, 'image_get', + mock.Mock(return_value=fake_error_image)) self.assertRaises( exception.ServiceInstanceException, self._manager._get_service_image, self._manager.admin_context) diff --git a/releasenotes/notes/bug_1844046-fix-image-not-found-629415d50cd6042a.yaml b/releasenotes/notes/bug_1844046-fix-image-not-found-629415d50cd6042a.yaml new file mode 100644 index 0000000000..228db8bf58 --- /dev/null +++ b/releasenotes/notes/bug_1844046-fix-image-not-found-629415d50cd6042a.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + The Generic driver has been fixed to invoke compute image + retrieval by ID rather than list all images and implement a filter. + This prevents failures in case there are a lot of images available + and the image service returns a paginated response.