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
This commit is contained in:
Dan Smith 2020-05-04 09:25:47 -07:00 committed by Jiri Suchomel
parent 6bc1352744
commit 2fbe8e02d5
4 changed files with 25 additions and 92 deletions

View File

@ -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

View File

@ -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:

View File

@ -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(

View File

@ -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.