Fix error that failed to get image for booting server
Glance image list API supports pagination, but `_get_service_image` uses novaclient.glance.list() that only return images in one page. When the image needed by share server is not returned in the first page, the exception occurs. This patch uses `find_image` method to get the image. Since latest novaclient has no proxy to lookup image, so only novaclient.glance. Change-Id: I57b15b7ebb29c545c9780a90734988565fa1f6b7 Closes-Bug: #1844046
This commit is contained in:
parent
02b2903fc7
commit
a7aa847097
@ -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)
|
||||
|
@ -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."""
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user