From 2fbe8e02d5ed82da84543488bf2e8ee9df6594b5 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 4 May 2020 09:25:47 -0700 Subject: [PATCH] Remove deprecated nova.image.download hook In Queens we deprecated the nova.image.download hook, which provided a mechanism to inject custom code into the download path of our glance module. This can now be removed. The one known potential user of this is was a direct-rbd download proposal, which needs further modification of the base glance client in order to work. Thus, this removes the hook point, but not the config option to allow specifying location schemes that should be considered direct by the glance module. This provides a path forward to integrate the direct-rbd code as a proper feature to our glance module, which will mean un-deprecating that config option, but also providing a stable list of potential options for it. Change-Id: I7463af2ba9b74a73ffbb0a6b5fa12dff3fa5cac6 --- nova/image/download/__init__.py | 54 ------------------- nova/image/glance.py | 34 +++--------- nova/tests/unit/image/test_glance.py | 24 ++++----- ...-image-download-hook-27b39dca2497446a.yaml | 5 ++ 4 files changed, 25 insertions(+), 92 deletions(-) delete mode 100644 nova/image/download/__init__.py create mode 100644 releasenotes/notes/remove-image-download-hook-27b39dca2497446a.yaml diff --git a/nova/image/download/__init__.py b/nova/image/download/__init__.py deleted file mode 100644 index f464e2c02c66..000000000000 --- a/nova/image/download/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2013 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -import stevedore.driver -import stevedore.extension - -LOG = logging.getLogger(__name__) - - -def load_transfer_modules(): - - module_dictionary = {} - - ex = stevedore.extension.ExtensionManager('nova.image.download.modules') - for module_name in ex.names(): - mgr = stevedore.driver.DriverManager( - namespace='nova.image.download.modules', - name=module_name, - invoke_on_load=False) - - schemes_list = mgr.driver.get_schemes() - for scheme in schemes_list: - if scheme in module_dictionary: - LOG.error('%(scheme)s is registered as a module twice. ' - '%(module_name)s is not being used.', - {'scheme': scheme, - 'module_name': module_name}) - else: - module_dictionary[scheme] = mgr.driver - - if module_dictionary: - LOG.warning('The nova.image.download.modules extension point is ' - 'deprecated for removal starting in the 17.0.0 Queens ' - 'release and may be removed as early as the 18.0.0 Rocky ' - 'release. It is not maintained and there is no indication ' - 'of its use in production clouds. If you are using this ' - 'extension point, please make the nova development team ' - 'aware by contacting us in the #openstack-nova freenode ' - 'IRC channel or on the openstack-discuss mailing list.') - - return module_dictionary diff --git a/nova/image/glance.py b/nova/image/glance.py index 91a3c77b01c7..961b5055e387 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -43,7 +43,6 @@ import six.moves.urllib.parse as urlparse import nova.conf from nova import exception -import nova.image.download as image_xfers from nova import objects from nova.objects import fields from nova import profiler @@ -217,24 +216,10 @@ class GlanceImageServiceV2(object): def __init__(self, client=None): self._client = client or GlanceClientWrapper() - # NOTE(jbresnah) build the table of download handlers at the beginning - # so that operators can catch errors at load time rather than whenever - # a user attempts to use a module. Note this cannot be done in glance - # space when this python module is loaded because the download module - # may require configuration options to be parsed. + # NOTE(danms): This used to be built from a list of external modules + # that were loaded at runtime. Preserve this list for implementations + # to be added here. self._download_handlers = {} - download_modules = image_xfers.load_transfer_modules() - - for scheme, mod in download_modules.items(): - if scheme not in CONF.glance.allowed_direct_url_schemes: - continue - - try: - self._download_handlers[scheme] = mod.get_download_handler() - except Exception as ex: - LOG.error('When loading the module %(module_str)s the ' - 'following error occurred: %(ex)s', - {'module_str': str(mod), 'ex': ex}) def show(self, context, image_id, include_locations=False, show_deleted=True): @@ -273,15 +258,12 @@ class GlanceImageServiceV2(object): return image - def _get_transfer_module(self, scheme): + def _get_transfer_method(self, scheme): + """Returns a transfer method for scheme, or None.""" try: return self._download_handlers[scheme] except KeyError: return None - except Exception: - LOG.error("Failed to instantiate the download handler " - "for %(scheme)s", {'scheme': scheme}) - return def detail(self, context, **kwargs): """Calls out to Glance for a list of detailed image information.""" @@ -323,10 +305,10 @@ class GlanceImageServiceV2(object): loc_url = entry['url'] loc_meta = entry['metadata'] o = urlparse.urlparse(loc_url) - xfer_mod = self._get_transfer_module(o.scheme) - if xfer_mod: + xfer_method = self._get_transfer_method(o.scheme) + if xfer_method: try: - xfer_mod.download(context, o, dst_path, loc_meta) + xfer_method(context, o, dst_path, loc_meta) LOG.info("Successfully transferred using %s", o.scheme) return except Exception: diff --git a/nova/tests/unit/image/test_glance.py b/nova/tests/unit/image/test_glance.py index 59f5710d4929..795cf875210c 100644 --- a/nova/tests/unit/image/test_glance.py +++ b/nova/tests/unit/image/test_glance.py @@ -686,7 +686,7 @@ class TestDownloadNoDirectUri(test.NoDBTestCase): with testtools.ExpectedException(exception.ImageUnacceptable): service.download(ctx, mock.sentinel.image_id) - @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_module') + @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_method') @mock.patch('nova.image.glance.GlanceImageServiceV2.show') def test_download_direct_file_uri_v2(self, show_mock, get_tran_mock): self.flags(allowed_direct_url_schemes=['file'], group='glance') @@ -712,11 +712,11 @@ class TestDownloadNoDirectUri(test.NoDBTestCase): mock.sentinel.image_id, include_locations=True) get_tran_mock.assert_called_once_with('file') - tran_mod.download.assert_called_once_with(ctx, mock.ANY, - mock.sentinel.dst_path, - mock.sentinel.loc_meta) + tran_mod.assert_called_once_with(ctx, mock.ANY, + mock.sentinel.dst_path, + mock.sentinel.loc_meta) - @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_module') + @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_method') @mock.patch('nova.image.glance.GlanceImageServiceV2.show') @mock.patch('nova.image.glance.GlanceImageServiceV2._safe_fsync') def test_download_direct_exception_fallback_v2( @@ -733,9 +733,9 @@ class TestDownloadNoDirectUri(test.NoDBTestCase): } ] } - tran_mod = mock.MagicMock() - tran_mod.download.side_effect = Exception - get_tran_mock.return_value = tran_mod + tran_method = mock.MagicMock() + tran_method.side_effect = Exception + get_tran_mock.return_value = tran_method client = mock.MagicMock() client.call.return_value = fake_glance_response([1, 2, 3]) ctx = mock.sentinel.ctx @@ -752,9 +752,9 @@ class TestDownloadNoDirectUri(test.NoDBTestCase): mock.sentinel.image_id, include_locations=True) get_tran_mock.assert_called_once_with('file') - tran_mod.download.assert_called_once_with(ctx, mock.ANY, - mock.sentinel.dst_path, - mock.sentinel.loc_meta) + tran_method.assert_called_once_with(ctx, mock.ANY, + mock.sentinel.dst_path, + mock.sentinel.loc_meta) client.call.assert_called_once_with( ctx, 2, 'data', args=(mock.sentinel.image_id,)) fsync_mock.assert_called_once_with(writer) @@ -771,7 +771,7 @@ class TestDownloadNoDirectUri(test.NoDBTestCase): ] ) - @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_module') + @mock.patch('nova.image.glance.GlanceImageServiceV2._get_transfer_method') @mock.patch('nova.image.glance.GlanceImageServiceV2.show') @mock.patch('nova.image.glance.GlanceImageServiceV2._safe_fsync') def test_download_direct_no_mod_fallback( diff --git a/releasenotes/notes/remove-image-download-hook-27b39dca2497446a.yaml b/releasenotes/notes/remove-image-download-hook-27b39dca2497446a.yaml new file mode 100644 index 000000000000..a7153dc58057 --- /dev/null +++ b/releasenotes/notes/remove-image-download-hook-27b39dca2497446a.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + The ``nova.image.download`` entry point hook has been removed, per the deprecation + announcement in the 17.0.0 (Queens) release.