Fail conductor startup if invalid defaults exist

This causes the conductor to fail to start up if a default interface
implementation cannot be found for any dynamic driver. This avoids
problems later where building a task object to operate on a node
could fail for the same reason.

This also removes a RAID interface test that turned out to be an
invalid test, but we couldn't tell it was invalid until we had
changed the start up behavior of the conductor.

Note that this release note doesn't actually note a change between
releases, but rather is mostly for my use when I come back to combine
many of the release notes for this feature later.

Change-Id: I39d3c30a6beda2e496ff85119281fdf4de191560
Partial-Bug: #1524745
This commit is contained in:
Jim Rollenhagen 2017-01-31 17:29:10 +00:00
parent 0071c7e1ec
commit 6206c47720
4 changed files with 47 additions and 16 deletions

View File

@ -171,7 +171,8 @@ class BaseConductorManager(object):
self._register_and_validate_hardware_interfaces(hardware_types)
except (exception.DriverLoadError, exception.DriverNotFound,
exception.ConductorHardwareInterfacesAlreadyRegistered,
exception.InterfaceNotFoundInEntrypoint) as e:
exception.InterfaceNotFoundInEntrypoint,
exception.NoValidDefaultForInterface) as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Failed to register hardware types. %s'), e)
self.del_host()
@ -263,6 +264,8 @@ class BaseConductorManager(object):
hardware type object.
:raises: ConductorHardwareInterfacesAlreadyRegistered
:raises: InterfaceNotFoundInEntrypoint
:raises: NoValidDefaultForInterface if the default value cannot be
calculated and is not provided in the configuration
"""
# first unregister, in case we have cruft laying around
self.conductor.unregister_all_hardware_interfaces()
@ -272,6 +275,9 @@ class BaseConductorManager(object):
for interface_type, interface_names in interface_map.items():
default_interface = driver_factory.default_interface(
ht, interface_type)
if default_interface is None:
raise exception.NoValidDefaultForInterface(
interface_type=interface_type, node=None, driver=ht)
self.conductor.register_hardware_interfaces(ht_name,
interface_type,
interface_names,

View File

@ -338,6 +338,31 @@ class RegisterInterfacesTestCase(mgr_utils.ServiceSetUpMixin,
# we're iterating over dicts, don't worry about order
reg_mock.assert_has_calls(expected_calls)
def test__register_and_validate_no_valid_default(self,
esi_mock,
default_mock,
reg_mock,
unreg_mock):
# these must be same order as esi_mock side effect
hardware_types = collections.OrderedDict((
('fake-hardware', fake_hardware.FakeHardware()),
))
esi_mock.side_effect = [
collections.OrderedDict((
('management', ['fake', 'noop']),
('deploy', ['agent', 'iscsi']),
)),
]
default_mock.return_value = None
self.assertRaises(
exception.NoValidDefaultForInterface,
self.service._register_and_validate_hardware_interfaces,
hardware_types)
unreg_mock.assert_called_once_with(mock.ANY)
self.assertFalse(reg_mock.called)
class StartConsolesTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):

View File

@ -637,7 +637,6 @@ class VendorPassthruTestCase(mgr_utils.ServiceSetUpMixin,
self._test_vendor_passthru_async('fake', None)
def test_vendor_passthru_async_hw_type(self):
self.config(enabled_vendor_interfaces=['fake'])
self._test_vendor_passthru_async('fake-hardware', 'fake')
@mock.patch.object(task_manager.TaskManager, 'upgrade_lock')
@ -3845,12 +3844,10 @@ class RaidHardwareTypeTestCases(RaidTestCases):
raid_interface = 'fake'
def test_get_raid_logical_disk_properties_iface_not_supported(self):
self.config(enabled_raid_interfaces=[])
self._start_service()
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.get_raid_logical_disk_properties,
self.context, self.driver_name)
self.assertEqual(exception.UnsupportedDriverExtension, exc.exc_info[0])
# NOTE(jroll) we don't run this test as get_logical_disk_properties
# is supported on all RAID implementations, and we cannot have a
# null interface for a hardware type
pass
def test_set_target_raid_config_iface_not_supported(self):
# NOTE(jroll): it's impossible for a dynamic driver to have a null
@ -4624,7 +4621,8 @@ class ManagerCheckDeployTimeoutsTestCase(mgr_utils.CommonMixIn,
@mgr_utils.mock_record_keepalive
class ManagerTestProperties(tests_db_base.DbTestCase):
class ManagerTestProperties(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def setUp(self):
super(ManagerTestProperties, self).setUp()
@ -4633,7 +4631,7 @@ class ManagerTestProperties(tests_db_base.DbTestCase):
def _check_driver_properties(self, driver, expected):
mgr_utils.mock_the_extension_manager(driver=driver)
self.driver = driver_factory.get_driver(driver)
self.service.init_host()
self._start_service()
properties = self.service.get_driver_properties(self.context, driver)
self.assertEqual(sorted(expected), sorted(properties.keys()))
@ -4753,16 +4751,13 @@ class ManagerTestProperties(tests_db_base.DbTestCase):
@mgr_utils.mock_record_keepalive
class ManagerTestHardwareTypeProperties(tests_db_base.DbTestCase):
def setUp(self):
super(ManagerTestHardwareTypeProperties, self).setUp()
self.service = manager.ConductorManager('test-host', 'test-topic')
class ManagerTestHardwareTypeProperties(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def _check_hardware_type_properties(self, hardware_type, expected):
self.config(enabled_hardware_types=[hardware_type])
self.hardware_type = driver_factory.get_hardware_type(hardware_type)
self.service.init_host()
self._start_service()
properties = self.service.get_driver_properties(self.context,
hardware_type)
self.assertEqual(sorted(expected), sorted(properties.keys()))

View File

@ -0,0 +1,5 @@
---
upgrade:
- The conductor will now fail to start up if invalid configuration is
provided, such that a default interface implementation for any enabled
hardware type cannot be found.