Log a warning for unsupported drivers and interfaces

This iterates over all loaded drivers/interfaces at factory
initialization time, and looks at an attribute 'supported'. If supported
is not True, a message will be logged that the driver is unsupported,
deprecated, and may be removed in a future release.

This patch marks all drivers as supported, and subsequent patches will
mark specific drivers as unsupported, based on their testing status.

This also changes the NetworkInterface class to inherit from
BaseInterface (to make this work right). That looks like a programming
error when that interface was created.

Change-Id: I6f9fa4f367bd2e14e5992d2e601bfdcf852ef3a4
Partial-Bug: #1526410
This commit is contained in:
Jim Rollenhagen 2016-09-06 22:10:48 +00:00
parent 047fc52a99
commit 0f07436861
3 changed files with 63 additions and 4 deletions

View File

@ -184,7 +184,8 @@ class BaseDriverFactory(object):
cls._entrypoint_name, cls._entrypoint_name,
_check_func, _check_func,
invoke_on_load=True, invoke_on_load=True,
on_load_failure_callback=_catch_driver_not_found)) on_load_failure_callback=_catch_driver_not_found,
propagate_map_exceptions=True))
# NOTE(deva): if we were unable to load any configured driver, perhaps # NOTE(deva): if we were unable to load any configured driver, perhaps
# because it is not present on the system, raise an error. # because it is not present on the system, raise an error.
@ -197,6 +198,10 @@ class BaseDriverFactory(object):
raise exception.DriverNotFoundInEntrypoint( raise exception.DriverNotFoundInEntrypoint(
driver_name=names, entrypoint=cls._entrypoint_name) driver_name=names, entrypoint=cls._entrypoint_name)
# warn for any untested/unsupported/deprecated drivers or interfaces
cls._extension_manager.map(cls._extension_manager.names(),
_warn_if_unsupported)
LOG.info(_LI("Loaded the following drivers: %s"), LOG.info(_LI("Loaded the following drivers: %s"),
cls._extension_manager.names()) cls._extension_manager.names())
@ -206,6 +211,12 @@ class BaseDriverFactory(object):
return self._extension_manager.names() return self._extension_manager.names()
def _warn_if_unsupported(ext):
if not ext.obj.supported:
LOG.warning(_LW('Driver "%s" is UNSUPPORTED. It has been deprecated '
'and may be removed in a future release.'), ext.name)
class DriverFactory(BaseDriverFactory): class DriverFactory(BaseDriverFactory):
_entrypoint_name = 'ironic.drivers' _entrypoint_name = 'ironic.drivers'
_enabled_driver_list_config_option = 'enabled_drivers' _enabled_driver_list_config_option = 'enabled_drivers'

View File

@ -48,6 +48,13 @@ class BaseDriver(object):
the interfaces are appropriate. the interfaces are appropriate.
""" """
supported = True
"""Indicates if a driver is supported.
This will be set to False for drivers which are untested in first- or
third-party CI, or in the proces of being deprecated.
"""
core_interfaces = [] core_interfaces = []
standard_interfaces = [] standard_interfaces = []
@ -166,6 +173,14 @@ class BareDriver(BaseDriver):
class BaseInterface(object): class BaseInterface(object):
"""A base interface implementing common functions for Driver Interfaces.""" """A base interface implementing common functions for Driver Interfaces."""
supported = True
"""Indicates if an interface is supported.
This will be set to False for interfaces which are untested in first- or
third-party CI, or in the proces of being deprecated.
"""
interface_type = 'base' interface_type = 'base'
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
@ -1021,9 +1036,11 @@ class RAIDInterface(BaseInterface):
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class NetworkInterface(object): class NetworkInterface(BaseInterface):
"""Base class for network interfaces.""" """Base class for network interfaces."""
interface_type = 'network'
def get_properties(self): def get_properties(self):
"""Return the properties of the interface. """Return the properties of the interface.

View File

@ -65,7 +65,7 @@ class DriverLoadTestCase(base.TestCase):
with mock.patch.object(dispatch.NameDispatchExtensionManager, with mock.patch.object(dispatch.NameDispatchExtensionManager,
'__init__', self._fake_init_driver_err): '__init__', self._fake_init_driver_err):
driver_factory.DriverFactory._init_extension_manager() driver_factory.DriverFactory._init_extension_manager()
self.assertEqual(2, mock_em.call_count) self.assertEqual(3, mock_em.call_count)
@mock.patch.object(driver_factory.LOG, 'warning', autospec=True) @mock.patch.object(driver_factory.LOG, 'warning', autospec=True)
def test_driver_duplicated_entry(self, mock_log): def test_driver_duplicated_entry(self, mock_log):
@ -75,6 +75,33 @@ class DriverLoadTestCase(base.TestCase):
['fake'], driver_factory.DriverFactory._extension_manager.names()) ['fake'], driver_factory.DriverFactory._extension_manager.names())
self.assertTrue(mock_log.called) self.assertTrue(mock_log.called)
@mock.patch.object(driver_factory, '_warn_if_unsupported')
def test_driver_init_checks_unsupported(self, mock_warn):
self.config(enabled_drivers=['fake'])
driver_factory.DriverFactory._init_extension_manager()
self.assertEqual(
['fake'], driver_factory.DriverFactory._extension_manager.names())
self.assertTrue(mock_warn.called)
class WarnUnsupportedDriversTestCase(base.TestCase):
@mock.patch.object(driver_factory.LOG, 'warning', autospec=True)
def _test__warn_if_unsupported(self, supported, mock_log):
ext = mock.Mock()
ext.obj = mock.Mock()
ext.obj.supported = supported
driver_factory._warn_if_unsupported(ext)
if supported:
self.assertFalse(mock_log.called)
else:
self.assertTrue(mock_log.called)
def test__warn_if_unsupported_with_supported(self):
self._test__warn_if_unsupported(True)
def test__warn_if_unsupported_with_unsupported(self):
self._test__warn_if_unsupported(False)
class GetDriverTestCase(base.TestCase): class GetDriverTestCase(base.TestCase):
def setUp(self): def setUp(self):
@ -98,7 +125,8 @@ class NetworkInterfaceFactoryTestCase(db_base.DbTestCase):
driver_factory.NetworkInterfaceFactory._extension_manager = None driver_factory.NetworkInterfaceFactory._extension_manager = None
self.config(enabled_drivers=['fake']) self.config(enabled_drivers=['fake'])
def test_build_driver_for_task(self): @mock.patch.object(driver_factory, '_warn_if_unsupported')
def test_build_driver_for_task(self, mock_warn):
# flat and noop network interfaces are enabled in base test case # flat and noop network interfaces are enabled in base test case
factory = driver_factory.NetworkInterfaceFactory factory = driver_factory.NetworkInterfaceFactory
node = obj_utils.create_test_node(self.context, driver='fake', node = obj_utils.create_test_node(self.context, driver='fake',
@ -112,6 +140,9 @@ class NetworkInterfaceFactoryTestCase(db_base.DbTestCase):
factory._entrypoint_name) factory._entrypoint_name)
self.assertEqual(['flat', 'neutron', 'noop'], self.assertEqual(['flat', 'neutron', 'noop'],
sorted(factory._enabled_driver_list)) sorted(factory._enabled_driver_list))
# NOTE(jroll) 4 checks, one for the driver we're building and
# one for each of the 3 network interfaces
self.assertEqual(4, mock_warn.call_count)
def test_build_driver_for_task_default_is_none(self): def test_build_driver_for_task_default_is_none(self):
# flat and noop network interfaces are enabled in base test case # flat and noop network interfaces are enabled in base test case