Add support for glance new location APIs

This patch adds the call for ``add_image_location`` API
which triggers the new location API workflow in glance
that addresses OSSN-0065. It is more secure and robust
compared to the old location workflow.
This call will be made when glance is using cinder as
a backend and we want to perform an optimized
``upload volume to image`` operation.

Signed-off-by: Rajat Dhasmana <rajatdhasmana@gmail.com>
Change-Id: Ib70219a9d085257c90a75ddcfcb935b4659fd28d
This commit is contained in:
Rajat Dhasmana
2024-02-20 14:37:25 +05:30
parent f54c9a23cd
commit a39fa8fb28
2 changed files with 47 additions and 5 deletions

View File

@@ -377,11 +377,26 @@ class GlanceImageService(object):
Returns a dict containing image metadata on success.
"""
client = GlanceClientWrapper()
# The ``add_image_location`` API was added to address
# OSSN-0065, however to keep backward compatibility,
# we need to try with the old ``add_location`` call
# if we are using an older version of glance.
# TODO: Remove the ``add_location`` API call when 2024.1
# trasitions to unmaintained. (``add_image_location``
# was added in 2024.2).
try_methods = ('add_image_location', 'add_location')
for method in try_methods:
try:
return client.call(context, 'add_location',
return client.call(context, method,
image_id, url, metadata)
except glanceclient.exc.HTTPNotImplemented:
LOG.debug('Glance method %s not available', method)
except Exception:
_reraise_translated_image_exception(image_id)
# If both method return HTTPNotImplemented exception
raise exception.ProgrammingError(
reason='unwarranted assumption about available glanceclient '
'methods.')
def download(self,
context: context.RequestContext,

View File

@@ -773,6 +773,33 @@ class TestGlanceImageService(test.TestCase):
self.assertEqual(self.NOW_DATETIME, image_meta['created_at'])
self.assertEqual(self.NOW_DATETIME, image_meta['updated_at'])
@mock.patch.object(glance.GlanceClientWrapper, 'call')
def test_add_location(self, mock_call):
image_id = mock.sentinel.image_id
service = glance.GlanceImageService(client=mock_call)
url = 'cinder://fake-store/c984be2b-8789-4b9e-bf71-19164f537e63'
metadata = {'store': 'fake-store'}
service.add_location(self.context, image_id, url, metadata)
mock_call.assert_called_once_with(
self.context, 'add_image_location', image_id, url, metadata)
@mock.patch.object(glance.GlanceClientWrapper, 'call')
def test_add_location_old(self, mock_call):
mock_call.side_effect = [glanceclient.exc.HTTPNotImplemented, None]
image_id = mock.sentinel.image_id
service = glance.GlanceImageService(client=mock_call)
url = 'cinder://fake-store/c984be2b-8789-4b9e-bf71-19164f537e63'
metadata = {'store': 'fake-store'}
service.add_location(self.context, image_id, url, metadata)
calls = [
mock.call.call(
self.context, 'add_image_location', image_id, url, metadata),
mock.call.call(
self.context, 'add_location', image_id, url, metadata)]
mock_call.assert_has_calls(calls)
def test_download_with_retries(self):
tries = [0]