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.