Support glance's new location API

This makes us use the new method if available, and if not, fall back
to the old method.

Change-Id: If52ac05a02b69476bd2cfa74a7ee800c3f6eeb20
This commit is contained in:
Dan Smith 2023-08-10 07:10:15 -07:00
parent 33f859cab7
commit eab0de2900
3 changed files with 45 additions and 11 deletions

View File

@ -563,11 +563,19 @@ class GlanceImageServiceV2(object):
def _add_location(self, context, image_id, location):
# 'show_multiple_locations' must be enabled in glance api conf file.
try:
return self._client.call(
context, 2, 'add_location', args=(image_id, location, {}))
except glanceclient.exc.HTTPBadRequest:
_reraise_translated_exception()
try_methods = ('add_image_location', 'add_location')
exc = None
for method in try_methods:
try:
return self._client.call(
context, 2, method, args=(image_id, location, {}))
except glanceclient.exc.HTTPNotImplemented as e:
exc = e
LOG.debug('Glance method %s not available', method)
except glanceclient.exc.HTTPBadRequest as e:
exc = e
_reraise_translated_exception()
raise exc
def _add_image_member(self, context, image_id, member_id):
"""Grant access to another project that does not own the image
@ -666,7 +674,7 @@ class GlanceImageServiceV2(object):
# Sending image location in a separate request.
if location:
image = self._add_location(context, image_id, location)
self._add_location(context, image_id, location)
# Add image membership in a separate request.
if sharing_member_id:
@ -715,7 +723,7 @@ class GlanceImageServiceV2(object):
# Sending image location in a separate request.
if location:
image = self._add_location(context, image_id, location)
self._add_location(context, image_id, location)
# If we have some data we have to send it in separate request and
# update the image then.

View File

@ -1745,7 +1745,8 @@ class TestCreate(test.NoDBTestCase):
@mock.patch('nova.image.glance._translate_from_glance')
@mock.patch('nova.image.glance._translate_to_glance')
def test_create_success_v2_with_location(
self, trans_to_mock, trans_from_mock):
self, trans_to_mock, trans_from_mock, old_api=False,
new_api=True):
translated = {
'id': mock.sentinel.id,
'name': mock.sentinel.name,
@ -1755,15 +1756,40 @@ class TestCreate(test.NoDBTestCase):
trans_from_mock.return_value = mock.sentinel.trans_from
image_mock = {}
client = mock.MagicMock()
client.call.return_value = translated
if old_api:
client.call.side_effect = [translated,
glanceclient.exc.HTTPNotImplemented,
None]
elif not new_api:
# If neither API is available we expect back whatever glanceclient
# raised to us
client.call.side_effect = test.TestingException
else:
client.call.side_effect = [translated, None]
ctx = mock.sentinel.ctx
service = glance.GlanceImageServiceV2(client)
if not new_api and not old_api:
self.assertRaises(test.TestingException,
service.create, ctx, image_mock)
return
image_meta = service.create(ctx, image_mock)
trans_to_mock.assert_called_once_with(image_mock)
self.assertEqual(2, client.call.call_count)
calls = [c[0][2] for c in client.call.call_args_list]
if old_api:
expected = ['create', 'add_image_location', 'add_location']
else:
expected = ['create', 'add_image_location']
self.assertEqual(expected, calls)
trans_from_mock.assert_called_once_with(translated)
self.assertEqual(mock.sentinel.trans_from, image_meta)
def test_create_success_v2_with_location_old_api(self):
self.test_create_success_v2_with_location(old_api=True)
def test_create_success_v2_with_location_no_api(self):
self.test_create_success_v2_with_location(old_api=False,
new_api=False)
@mock.patch('nova.image.glance._translate_from_glance')
@mock.patch('nova.image.glance._translate_to_glance')
def test_create_success_v2_with_sharing(

View File

@ -24,7 +24,7 @@ jsonschema>=4.0.0 # MIT
python-cinderclient>=4.0.1 # Apache-2.0
keystoneauth1>=3.16.0 # Apache-2.0
python-neutronclient>=7.1.0 # Apache-2.0
python-glanceclient>=2.8.0 # Apache-2.0
python-glanceclient>=4.7.0 # Apache-2.0
requests>=2.25.1 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
websockify>=0.9.0 # LGPLv3