Merge "redfish: handle missing Bios attribute"
This commit is contained in:
commit
3f2c04079d
@ -1307,10 +1307,13 @@ class ConductorManager(base_manager.BaseConductorManager):
|
|||||||
|
|
||||||
# Do caching of bios settings if supported by driver,
|
# Do caching of bios settings if supported by driver,
|
||||||
# this will be called for both manual and automated cleaning.
|
# this will be called for both manual and automated cleaning.
|
||||||
# TODO(zshi) remove this check when classic drivers are removed
|
|
||||||
try:
|
try:
|
||||||
task.driver.bios.cache_bios_settings(task)
|
task.driver.bios.cache_bios_settings(task)
|
||||||
except Exception as e:
|
except exception.UnsupportedDriverExtension:
|
||||||
|
LOG.warning('BIOS settings are not supported for node %s, '
|
||||||
|
'skipping', task.node.uuid)
|
||||||
|
# TODO(zshi) remove this check when classic drivers are removed
|
||||||
|
except Exception:
|
||||||
msg = (_('Caching of bios settings failed on node %(node)s. '
|
msg = (_('Caching of bios settings failed on node %(node)s. '
|
||||||
'Continuing with node cleaning.')
|
'Continuing with node cleaning.')
|
||||||
% {'node': node.uuid})
|
% {'node': node.uuid})
|
||||||
|
@ -50,11 +50,20 @@ class RedfishBIOS(base.BIOSInterface):
|
|||||||
:param task: a TaskManager instance containing the node to act on.
|
:param task: a TaskManager instance containing the node to act on.
|
||||||
:raises: RedfishConnectionError when it fails to connect to Redfish
|
:raises: RedfishConnectionError when it fails to connect to Redfish
|
||||||
:raises: RedfishError on an error from the Sushy library
|
:raises: RedfishError on an error from the Sushy library
|
||||||
|
:raises: UnsupportedDriverExtension if the system does not support BIOS
|
||||||
|
settings
|
||||||
"""
|
"""
|
||||||
|
|
||||||
node_id = task.node.id
|
node_id = task.node.id
|
||||||
system = redfish_utils.get_system(task.node)
|
system = redfish_utils.get_system(task.node)
|
||||||
attributes = system.bios.attributes
|
try:
|
||||||
|
attributes = system.bios.attributes
|
||||||
|
except sushy.exceptions.MissingAttributeError:
|
||||||
|
error_msg = _('Cannot fetch BIOS attributes for node %s, '
|
||||||
|
'BIOS settings are not supported.') % task.node.uuid
|
||||||
|
LOG.error(error_msg)
|
||||||
|
raise exception.UnsupportedDriverExtension(error_msg)
|
||||||
|
|
||||||
settings = []
|
settings = []
|
||||||
# Convert Redfish BIOS attributes to Ironic BIOS settings
|
# Convert Redfish BIOS attributes to Ironic BIOS settings
|
||||||
if attributes:
|
if attributes:
|
||||||
@ -88,11 +97,10 @@ class RedfishBIOS(base.BIOSInterface):
|
|||||||
:raises: RedfishError on an error from the Sushy library
|
:raises: RedfishError on an error from the Sushy library
|
||||||
"""
|
"""
|
||||||
system = redfish_utils.get_system(task.node)
|
system = redfish_utils.get_system(task.node)
|
||||||
bios = system.bios
|
|
||||||
LOG.debug('Factory reset BIOS settings for node %(node_uuid)s',
|
LOG.debug('Factory reset BIOS settings for node %(node_uuid)s',
|
||||||
{'node_uuid': task.node.uuid})
|
{'node_uuid': task.node.uuid})
|
||||||
try:
|
try:
|
||||||
bios.reset_bios()
|
system.bios.reset_bios()
|
||||||
except sushy.exceptions.SushyError as e:
|
except sushy.exceptions.SushyError as e:
|
||||||
error_msg = (_('Redfish BIOS factory reset failed for node '
|
error_msg = (_('Redfish BIOS factory reset failed for node '
|
||||||
'%(node)s. Error: %(error)s') %
|
'%(node)s. Error: %(error)s') %
|
||||||
@ -122,7 +130,15 @@ class RedfishBIOS(base.BIOSInterface):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
system = redfish_utils.get_system(task.node)
|
system = redfish_utils.get_system(task.node)
|
||||||
bios = system.bios
|
try:
|
||||||
|
bios = system.bios
|
||||||
|
except sushy.exceptions.MissingAttributeError:
|
||||||
|
error_msg = (_('Redfish BIOS factory reset failed for node '
|
||||||
|
'%s, because BIOS settings are not supported.') %
|
||||||
|
task.node.uuid)
|
||||||
|
LOG.error(error_msg)
|
||||||
|
raise exception.RedfishError(error=error_msg)
|
||||||
|
|
||||||
# Convert Ironic BIOS settings to Redfish BIOS attributes
|
# Convert Ironic BIOS settings to Redfish BIOS attributes
|
||||||
attributes = {s['name']: s['value'] for s in settings}
|
attributes = {s['name']: s['value'] for s in settings}
|
||||||
|
|
||||||
|
@ -3513,8 +3513,11 @@ class DoNodeCleanTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|||||||
def _test__do_node_clean_cache_bios(self, mock_bios, mock_validate,
|
def _test__do_node_clean_cache_bios(self, mock_bios, mock_validate,
|
||||||
mock_prep, mock_next_step, mock_steps,
|
mock_prep, mock_next_step, mock_steps,
|
||||||
mock_log, clean_steps=None,
|
mock_log, clean_steps=None,
|
||||||
|
enable_unsupported=False,
|
||||||
enable_exception=False):
|
enable_exception=False):
|
||||||
if enable_exception:
|
if enable_unsupported:
|
||||||
|
mock_bios.side_effect = exception.UnsupportedDriverExtension('')
|
||||||
|
elif enable_exception:
|
||||||
mock_bios.side_effect = exception.IronicException('test')
|
mock_bios.side_effect = exception.IronicException('test')
|
||||||
mock_prep.return_value = states.NOSTATE
|
mock_prep.return_value = states.NOSTATE
|
||||||
tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
|
tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
|
||||||
@ -3553,6 +3556,13 @@ class DoNodeCleanTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|||||||
def test__do_node_clean_automated_cache_bios_exception(self):
|
def test__do_node_clean_automated_cache_bios_exception(self):
|
||||||
self._test__do_node_clean_cache_bios(enable_exception=True)
|
self._test__do_node_clean_cache_bios(enable_exception=True)
|
||||||
|
|
||||||
|
def test__do_node_clean_manual_cache_bios_unsupported(self):
|
||||||
|
self._test__do_node_clean_cache_bios(clean_steps=[self.deploy_raid],
|
||||||
|
enable_unsupported=True)
|
||||||
|
|
||||||
|
def test__do_node_clean_automated_cache_bios_unsupported(self):
|
||||||
|
self._test__do_node_clean_cache_bios(enable_unsupported=True)
|
||||||
|
|
||||||
@mock.patch('ironic.drivers.modules.fake.FakePower.validate',
|
@mock.patch('ironic.drivers.modules.fake.FakePower.validate',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
def test__do_node_clean_automated_disabled(self, mock_validate):
|
def test__do_node_clean_automated_disabled(self, mock_validate):
|
||||||
|
@ -31,8 +31,13 @@ sushy = importutils.try_import('sushy')
|
|||||||
INFO_DICT = db_utils.get_test_redfish_info()
|
INFO_DICT = db_utils.get_test_redfish_info()
|
||||||
|
|
||||||
|
|
||||||
class MockedSushyError(Exception):
|
class NoBiosSystem(object):
|
||||||
pass
|
identity = '/redfish/v1/Systems/1234'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bios(self):
|
||||||
|
raise sushy.exceptions.MissingAttributeError(attribute='Bios',
|
||||||
|
resource=self)
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('eventlet.greenthread.sleep', lambda _t: None)
|
@mock.patch('eventlet.greenthread.sleep', lambda _t: None)
|
||||||
@ -95,6 +100,31 @@ class RedfishBiosTestCase(db_base.DbTestCase):
|
|||||||
mock_setting_list.save.assert_not_called()
|
mock_setting_list.save.assert_not_called()
|
||||||
mock_setting_list.delete.assert_not_called()
|
mock_setting_list.delete.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
@mock.patch.object(objects, 'BIOSSettingList', autospec=True)
|
||||||
|
def test_cache_bios_settings_no_bios(self, mock_setting_list,
|
||||||
|
mock_get_system):
|
||||||
|
create_list = []
|
||||||
|
update_list = []
|
||||||
|
delete_list = []
|
||||||
|
nochange_list = [{'name': 'EmbeddedSata', 'value': 'Raid'},
|
||||||
|
{'name': 'NicBoot1', 'value': 'NetworkBoot'}]
|
||||||
|
mock_setting_list.sync_node_setting.return_value = (
|
||||||
|
create_list, update_list, delete_list, nochange_list
|
||||||
|
)
|
||||||
|
mock_get_system.return_value = NoBiosSystem()
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
self.assertRaisesRegex(exception.UnsupportedDriverExtension,
|
||||||
|
'BIOS settings are not supported',
|
||||||
|
task.driver.bios.cache_bios_settings, task)
|
||||||
|
mock_get_system.assert_called_once_with(task.node)
|
||||||
|
mock_setting_list.sync_node_setting.assert_not_called()
|
||||||
|
mock_setting_list.create.assert_not_called()
|
||||||
|
mock_setting_list.save.assert_not_called()
|
||||||
|
mock_setting_list.delete.assert_not_called()
|
||||||
|
|
||||||
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
@mock.patch.object(objects, 'BIOSSettingList', autospec=True)
|
@mock.patch.object(objects, 'BIOSSettingList', autospec=True)
|
||||||
def test_cache_bios_settings(self, mock_setting_list, mock_get_system):
|
def test_cache_bios_settings(self, mock_setting_list, mock_get_system):
|
||||||
@ -139,14 +169,21 @@ class RedfishBiosTestCase(db_base.DbTestCase):
|
|||||||
bios = mock_get_system(task.node).bios
|
bios = mock_get_system(task.node).bios
|
||||||
bios.reset_bios.assert_called_once()
|
bios.reset_bios.assert_called_once()
|
||||||
|
|
||||||
@mock.patch('ironic.drivers.modules.redfish.bios.sushy')
|
|
||||||
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
def test_factory_reset_fail(self, mock_get_system, mock_sushy):
|
def test_factory_reset_fail(self, mock_get_system):
|
||||||
mock_sushy.exceptions.SushyError = MockedSushyError
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid,
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
shared=False) as task:
|
shared=False) as task:
|
||||||
bios = mock_get_system(task.node).bios
|
bios = mock_get_system(task.node).bios
|
||||||
bios.reset_bios.side_effect = MockedSushyError
|
bios.reset_bios.side_effect = sushy.exceptions.SushyError
|
||||||
|
self.assertRaisesRegex(
|
||||||
|
exception.RedfishError, 'BIOS factory reset failed',
|
||||||
|
task.driver.bios.factory_reset, task)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_factory_reset_not_supported(self, mock_get_system):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
mock_get_system.return_value = NoBiosSystem()
|
||||||
self.assertRaisesRegex(
|
self.assertRaisesRegex(
|
||||||
exception.RedfishError, 'BIOS factory reset failed',
|
exception.RedfishError, 'BIOS factory reset failed',
|
||||||
task.driver.bios.factory_reset, task)
|
task.driver.bios.factory_reset, task)
|
||||||
@ -183,6 +220,19 @@ class RedfishBiosTestCase(db_base.DbTestCase):
|
|||||||
task.driver.bios._clear_reboot_requested\
|
task.driver.bios._clear_reboot_requested\
|
||||||
.assert_called_once_with(task)
|
.assert_called_once_with(task)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_apply_configuration_not_supported(self, mock_get_system):
|
||||||
|
settings = [{'name': 'ProcTurboMode', 'value': 'Disabled'},
|
||||||
|
{'name': 'NicBoot1', 'value': 'NetworkBoot'}]
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
mock_get_system.return_value = NoBiosSystem()
|
||||||
|
self.assertRaisesRegex(exception.RedfishError,
|
||||||
|
'BIOS settings are not supported',
|
||||||
|
task.driver.bios.apply_configuration,
|
||||||
|
task, settings)
|
||||||
|
mock_get_system.assert_called_once_with(task.node)
|
||||||
|
|
||||||
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
def test_check_bios_attrs(self, mock_get_system):
|
def test_check_bios_attrs(self, mock_get_system):
|
||||||
settings = [{'name': 'ProcTurboMode', 'value': 'Disabled'},
|
settings = [{'name': 'ProcTurboMode', 'value': 'Disabled'},
|
||||||
@ -200,16 +250,14 @@ class RedfishBiosTestCase(db_base.DbTestCase):
|
|||||||
task.driver.bios._check_bios_attrs \
|
task.driver.bios._check_bios_attrs \
|
||||||
.assert_called_once_with(task, attributes, requested_attrs)
|
.assert_called_once_with(task, attributes, requested_attrs)
|
||||||
|
|
||||||
@mock.patch('ironic.drivers.modules.redfish.bios.sushy')
|
|
||||||
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
def test_apply_configuration_fail(self, mock_get_system, mock_sushy):
|
def test_apply_configuration_fail(self, mock_get_system):
|
||||||
settings = [{'name': 'ProcTurboMode', 'value': 'Disabled'},
|
settings = [{'name': 'ProcTurboMode', 'value': 'Disabled'},
|
||||||
{'name': 'NicBoot1', 'value': 'NetworkBoot'}]
|
{'name': 'NicBoot1', 'value': 'NetworkBoot'}]
|
||||||
mock_sushy.exceptions.SushyError = MockedSushyError
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid,
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
shared=False) as task:
|
shared=False) as task:
|
||||||
bios = mock_get_system(task.node).bios
|
bios = mock_get_system(task.node).bios
|
||||||
bios.set_attributes.side_effect = MockedSushyError
|
bios.set_attributes.side_effect = sushy.exceptions.SushyError
|
||||||
self.assertRaisesRegex(
|
self.assertRaisesRegex(
|
||||||
exception.RedfishError, 'BIOS apply configuration failed',
|
exception.RedfishError, 'BIOS apply configuration failed',
|
||||||
task.driver.bios.apply_configuration, task, settings)
|
task.driver.bios.apply_configuration, task, settings)
|
||||||
|
@ -237,9 +237,11 @@ if not sushy:
|
|||||||
sushy.exceptions.SushyError = (
|
sushy.exceptions.SushyError = (
|
||||||
type('SushyError', (MockKwargsException,), {}))
|
type('SushyError', (MockKwargsException,), {}))
|
||||||
sushy.exceptions.ConnectionError = (
|
sushy.exceptions.ConnectionError = (
|
||||||
type('ConnectionError', (MockKwargsException,), {}))
|
type('ConnectionError', (sushy.exceptions.SushyError,), {}))
|
||||||
sushy.exceptions.ResourceNotFoundError = (
|
sushy.exceptions.ResourceNotFoundError = (
|
||||||
type('ResourceNotFoundError', (MockKwargsException,), {}))
|
type('ResourceNotFoundError', (sushy.exceptions.SushyError,), {}))
|
||||||
|
sushy.exceptions.MissingAttributeError = (
|
||||||
|
type('MissingAttributeError', (sushy.exceptions.SushyError,), {}))
|
||||||
sushy.auth = mock.MagicMock(spec_set=mock_specs.SUSHY_AUTH_SPEC)
|
sushy.auth = mock.MagicMock(spec_set=mock_specs.SUSHY_AUTH_SPEC)
|
||||||
sys.modules['sushy.auth'] = sushy.auth
|
sys.modules['sushy.auth'] = sushy.auth
|
||||||
|
|
||||||
|
5
releasenotes/notes/cleaning-bios-d74a4947d2525b80.yaml
Normal file
5
releasenotes/notes/cleaning-bios-d74a4947d2525b80.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes traceback on cleaning of nodes with the ``redfish`` hardware type
|
||||||
|
if their BMC does not support BIOS settings.
|
Loading…
x
Reference in New Issue
Block a user