From 335f6b4fd1b1c8c83887eeb1c00eef60a68d39c6 Mon Sep 17 00:00:00 2001 From: vmud213 Date: Thu, 13 Sep 2018 15:30:53 +0530 Subject: [PATCH] Make iLO BIOS interface clean steps asynchronous Make iLO BIOS interface clean steps asynchronous to ensure the BIOS settings on the node are consistent with the settings stored in the database. Node goes through the power cycle after the settings are applied. Once the node reboots, ironic gets the current settings from the node, caches the settings in the database, checks for any errors from the status message and marks the clean step as failed or success accordingly. Change-Id: I00deaa2f2b68d2a34f8592ea20c36349a87d6c23 Story: #2004066 Task: #27074 --- ironic/drivers/modules/ilo/bios.py | 140 ++++-- .../unit/drivers/modules/ilo/test_bios.py | 468 +++++++++++++----- ...ync-bios-clean-steps-15e49545ba818997.yaml | 8 + 3 files changed, 468 insertions(+), 148 deletions(-) create mode 100644 releasenotes/notes/ilo-async-bios-clean-steps-15e49545ba818997.yaml diff --git a/ironic/drivers/modules/ilo/bios.py b/ironic/drivers/modules/ilo/bios.py index 3d6359914e..74ccb503d5 100644 --- a/ironic/drivers/modules/ilo/bios.py +++ b/ironic/drivers/modules/ilo/bios.py @@ -21,12 +21,14 @@ from oslo_utils import importutils from ironic.common import exception from ironic.common.i18n import _ +from ironic.common import states +from ironic.conductor import utils as manager_utils from ironic.drivers import base +from ironic.drivers.modules import deploy_utils from ironic.drivers.modules.ilo import common as ilo_common from ironic import objects LOG = logging.getLogger(__name__) - METRICS = metrics_utils.get_metrics_logger(__name__) ilo_error = importutils.try_import('proliantutils.exception') @@ -51,6 +53,100 @@ class IloBIOS(base.BIOSInterface): """ ilo_common.parse_driver_info(task.node) + def _execute_pre_boot_bios_step(self, task, step, data=None): + """Perform operations required prior to the reboot. + + Depending on the clean step, it executes the operations required + and moves the node to CLEANWAIT state prior to reboot. + :param task: a task from TaskManager. + :param step: name of the clean step to be performed + :param data: if the clean step is apply_configuration it holds + the settings data. + :raises: NodeCleaningFailure if it fails any conditions expected + """ + node = task.node + + if step not in ('apply_configuration', 'factory_reset'): + errmsg = _('Could not find the step %(step)s for the ' + 'node %(node)s.') + raise exception.NodeCleaningFailure( + errmsg % {'step': step, 'node': node.uuid}) + + try: + ilo_object = ilo_common.get_ilo_object(node) + ilo_object.set_bios_settings(data) if step == ( + 'apply_configuration') else ilo_object.reset_bios_to_default() + except (exception.MissingParameterValue, + exception.InvalidParameterValue, + ilo_error.IloError, + ilo_error.IloCommandNotSupportedError) as ir_exception: + errmsg = _('Clean step %(step)s failed ' + 'on the node %(node)s with error: %(err)s') + raise exception.NodeCleaningFailure( + errmsg % {'step': step, 'node': node.uuid, + 'err': ir_exception}) + + deploy_opts = deploy_utils.build_agent_options(node) + task.driver.boot.prepare_ramdisk(task, deploy_opts) + manager_utils.node_power_action(task, states.REBOOT) + + driver_internal_info = node.driver_internal_info + driver_internal_info['cleaning_reboot'] = True + driver_internal_info['skip_current_clean_step'] = False + + if step == 'apply_configuration': + driver_internal_info['apply_bios'] = True + else: + driver_internal_info['reset_bios'] = True + + node.driver_internal_info = driver_internal_info + node.save() + return states.CLEANWAIT + + def _execute_post_boot_bios_step(self, task, step): + """Perform operations required after the reboot. + + Caches BIOS settings in the database and clear the flags assocated + with the clean step post reboot. + :param task: a task from TaskManager. + :param step: name of the clean step to be performed + :raises: NodeCleaningFailure if it fails any conditions expected + """ + node = task.node + + driver_internal_info = node.driver_internal_info + driver_internal_info.pop('apply_bios', None) + driver_internal_info.pop('reset_bios', None) + task.node.driver_internal_info = driver_internal_info + task.node.save() + + if step not in ('apply_configuration', 'factory_reset'): + errmsg = _('Could not find the step %(step)s for the ' + 'node %(node)s.') + raise exception.NodeCleaningFailure( + errmsg % {'step': step, 'node': node.uuid}) + + try: + ilo_object = ilo_common.get_ilo_object(node) + status = ilo_object.get_bios_settings_result() + except (exception.MissingParameterValue, + exception.InvalidParameterValue, + ilo_error.IloError, + ilo_error.IloCommandNotSupportedError) as ir_exception: + + errmsg = _('Clean step %(step)s failed ' + 'on the node %(node)s with error: %(err)s') + raise exception.NodeCleaningFailure( + errmsg % {'step': step, 'node': node.uuid, + 'err': ir_exception}) + + if status.get('status') == 'failed': + errmsg = _('Clean step %(step)s failed ' + 'on the node %(node)s with error: %(err)s') + raise exception.NodeCleaningFailure( + errmsg % {'step': step, 'node': node.uuid, + 'err': status.get('results')}) + @METRICS.timer('IloBIOS.apply_configuration') @base.clean_step(priority=0, abortable=False, argsinfo={ 'settings': { @@ -67,24 +163,17 @@ class IloBIOS(base.BIOSInterface): the node fails. """ + node = task.node + driver_internal_info = node.driver_internal_info data = {} for setting in settings: data.update({setting['name']: setting['value']}) - - node = task.node - - errmsg = _("Clean step \"apply_configuration\" failed " - "on node %(node)s with error: %(err)s") - - try: - ilo_object = ilo_common.get_ilo_object(node) - ilo_object.set_bios_settings(data) - except (exception.MissingParameterValue, - exception.InvalidParameterValue, - ilo_error.IloError, - ilo_error.IloCommandNotSupportedError) as ir_exception: - raise exception.NodeCleaningFailure( - errmsg % {'node': node.uuid, 'err': ir_exception}) + if not driver_internal_info.get('apply_bios'): + return self._execute_pre_boot_bios_step( + task, 'apply_configuration', data) + else: + return self._execute_post_boot_bios_step( + task, 'apply_configuration') @METRICS.timer('IloBIOS.factory_reset') @base.clean_step(priority=0, abortable=False) @@ -97,19 +186,12 @@ class IloBIOS(base.BIOSInterface): """ node = task.node + driver_internal_info = node.driver_internal_info - errmsg = _("Clean step \"factory_reset\" failed " - "on node %(node)s with error: %(err)s") - - try: - ilo_object = ilo_common.get_ilo_object(node) - ilo_object.reset_bios_to_default() - except (exception.MissingParameterValue, - exception.InvalidParameterValue, - ilo_error.IloError, - ilo_error.IloCommandNotSupportedError) as ir_exception: - raise exception.NodeCleaningFailure( - errmsg % {'node': node.uuid, 'err': ir_exception}) + if not driver_internal_info.get('reset_bios'): + return self._execute_pre_boot_bios_step(task, 'factory_reset') + else: + return self._execute_post_boot_bios_step(task, 'factory_reset') @METRICS.timer('IloBIOS.cache_bios_settings') def cache_bios_settings(self, task): @@ -127,7 +209,7 @@ class IloBIOS(base.BIOSInterface): "on node %(node)s with error: %(err)s") try: ilo_object = ilo_common.get_ilo_object(node) - bios_settings = ilo_object.get_pending_bios_settings() + bios_settings = ilo_object.get_current_bios_settings() except (exception.MissingParameterValue, exception.InvalidParameterValue, diff --git a/ironic/tests/unit/drivers/modules/ilo/test_bios.py b/ironic/tests/unit/drivers/modules/ilo/test_bios.py index e285d879c6..0d0c12b665 100644 --- a/ironic/tests/unit/drivers/modules/ilo/test_bios.py +++ b/ironic/tests/unit/drivers/modules/ilo/test_bios.py @@ -21,6 +21,10 @@ from oslo_utils import importutils from ironic.common import exception from ironic.conductor import task_manager +from ironic.conductor import utils as manager_utils +from ironic.drivers.modules import deploy_utils +from ironic.drivers.modules.ilo import bios as ilo_bios +from ironic.drivers.modules.ilo import boot as ilo_boot from ironic.drivers.modules.ilo import common as ilo_common from ironic import objects from ironic.tests.unit.db import utils as db_utils @@ -48,145 +52,356 @@ class IloBiosTestCase(test_common.BaseIloTest): task.driver.bios.validate(task) mock_drvinfo.assert_called_once_with(task.node) - @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, - autospec=True) - def _test_ilo_error(self, error_type, - test_methods_not_called, method_details, ilo_mock): - error_dict = { - "missing_parameter": exception.MissingParameterValue, - "invalid_parameter": exception.InvalidParameterValue - } - - exc = error_dict.get(error_type)('error') - ilo_mock.side_effect = exc + def _test_ilo_error(self, exc_cls, + test_methods_not_called, + test_methods_called, + method_details, exception_mock): + exception_mock.side_effect = exc_cls('error') method = method_details.get("name") args = method_details.get("args") self.assertRaises(exception.NodeCleaningFailure, method, *args) for test_method in test_methods_not_called: - eval("ilo_mock.return_value.%s.assert_not_called()" % ( - test_method)) + test_method.assert_not_called() + for called_method in test_methods_called: + called_method["name"].assert_called_once_with( + *called_method["args"]) + @mock.patch.object(ilo_bios.IloBIOS, '_execute_post_boot_bios_step', + autospec=True) + @mock.patch.object(ilo_bios.IloBIOS, '_execute_pre_boot_bios_step', + autospec=True) + def test_apply_configuration_pre_boot(self, exe_pre_boot_mock, + exe_post_boot_mock): + settings = [ + { + "name": "SET_A", "value": "VAL_A", + }, + { + "name": "SET_B", "value": "VAL_B", + }, + { + "name": "SET_C", "value": "VAL_C", + }, + { + "name": "SET_D", "value": "VAL_D", + } + ] + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_internal_info = task.node.driver_internal_info + driver_internal_info.pop('apply_bios', None) + task.node.driver_internal_info = driver_internal_info + task.node.save() + actual_settings = {'SET_A': 'VAL_A', 'SET_B': 'VAL_B', + 'SET_C': 'VAL_C', 'SET_D': 'VAL_D'} + task.driver.bios.apply_configuration(task, settings) + + exe_pre_boot_mock.assert_called_once_with( + task.driver.bios, task, 'apply_configuration', actual_settings) + self.assertFalse(exe_post_boot_mock.called) + + @mock.patch.object(ilo_bios.IloBIOS, '_execute_post_boot_bios_step', + autospec=True) + @mock.patch.object(ilo_bios.IloBIOS, '_execute_pre_boot_bios_step', + autospec=True) + def test_apply_configuration_post_boot(self, exe_pre_boot_mock, + exe_post_boot_mock): + settings = [ + { + "name": "SET_A", "value": "VAL_A", + }, + { + "name": "SET_B", "value": "VAL_B", + }, + { + "name": "SET_C", "value": "VAL_C", + }, + { + "name": "SET_D", "value": "VAL_D", + } + ] + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_internal_info = task.node.driver_internal_info + driver_internal_info['apply_bios'] = True + task.node.driver_internal_info = driver_internal_info + task.node.save() + task.driver.bios.apply_configuration(task, settings) + + exe_post_boot_mock.assert_called_once_with( + task.driver.bios, task, 'apply_configuration') + self.assertFalse(exe_pre_boot_mock.called) + + @mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk', + spec_set=True, autospec=True) + @mock.patch.object(manager_utils, 'node_power_action', spec_set=True, + autospec=True) + @mock.patch.object(deploy_utils, 'build_agent_options', spec_set=True, + autospec=True) @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, autospec=True) - def test_apply_configuration(self, get_ilo_object_mock): + def test__execute_pre_boot_bios_step_apply_configuration( + self, get_ilo_object_mock, build_agent_mock, + node_power_mock, prepare_mock): + with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: ilo_object_mock = get_ilo_object_mock.return_value - data = [ - { - "name": "SET_A", "value": "VAL_A", - }, - { - "name": "SET_B", "value": "VAL_B", - }, - { - "name": "SET_C", "value": "VAL_C", - }, - { - "name": "SET_D", "value": "VAL_D", - } - ] - task.driver.bios.apply_configuration(task, data) - expected = { + data = { "SET_A": "VAL_A", "SET_B": "VAL_B", "SET_C": "VAL_C", "SET_D": "VAL_D" } - ilo_object_mock.set_bios_settings.assert_called_once_with(expected) - - def test_apply_configuration_missing_parameter(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=True) as task: - mdobj = { - "name": task.driver.bios.apply_configuration, - "args": (task, []) - } - self._test_ilo_error("missing_parameter", ["set_bios_settings"], - mdobj) - - def test_apply_configuration_invalid_parameter(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=True) as task: - mdobj = { - "name": task.driver.bios.apply_configuration, - "args": (task, []) - } - self._test_ilo_error("invalid_parameter", ["set_bios_settings"], - mdobj) + step = 'apply_configuration' + task.driver.bios._execute_pre_boot_bios_step(task, step, data) + driver_info = task.node.driver_internal_info + self.assertTrue( + all(x in driver_info for x in ( + 'apply_bios', 'cleaning_reboot', + 'skip_current_clean_step'))) + ilo_object_mock.set_bios_settings.assert_called_once_with(data) + self.assertFalse(ilo_object_mock.reset_bios_to_default.called) + build_agent_mock.assert_called_once_with(task.node) + self.assertTrue(prepare_mock.called) + self.assertTrue(node_power_mock.called) + @mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk', + spec_set=True, autospec=True) + @mock.patch.object(manager_utils, 'node_power_action', spec_set=True, + autospec=True) + @mock.patch.object(deploy_utils, 'build_agent_options', spec_set=True, + autospec=True) @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, autospec=True) - def test_apply_configuration_with_ilo_error(self, get_ilo_object_mock): + def test__execute_pre_boot_bios_step_factory_reset( + self, get_ilo_object_mock, build_agent_mock, + node_power_mock, prepare_mock): + with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: ilo_object_mock = get_ilo_object_mock.return_value - data = [ - { - "name": "SET_A", "value": "VAL_A", - }, - { - "name": "SET_B", "value": "VAL_B", - }, - ] - exc = ilo_error.IloError('error') - ilo_object_mock.set_bios_settings.side_effect = exc - self.assertRaises(exception.NodeCleaningFailure, - task.driver.bios.apply_configuration, - task, data) - - @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, - autospec=True) - def test_factory_reset(self, get_ilo_object_mock): - with task_manager.acquire(self.context, self.node.uuid, - shared=True) as task: - ilo_object_mock = get_ilo_object_mock.return_value - task.driver.bios.factory_reset(task) + data = { + "SET_A": "VAL_A", + "SET_B": "VAL_B", + "SET_C": "VAL_C", + "SET_D": "VAL_D" + } + step = 'factory_reset' + task.driver.bios._execute_pre_boot_bios_step(task, step, data) + driver_info = task.node.driver_internal_info + self.assertTrue( + all(x in driver_info for x in ( + 'reset_bios', 'cleaning_reboot', + 'skip_current_clean_step'))) ilo_object_mock.reset_bios_to_default.assert_called_once_with() - - def test_factory_reset_missing_parameter(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=True) as task: - mdobj = { - "name": task.driver.bios.factory_reset, - "args": (task,) - } - self._test_ilo_error("missing_parameter", - ["reset_bios_to_default"], mdobj) - - def test_factory_reset_invalid_parameter(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=True) as task: - mdobj = { - "name": task.driver.bios.factory_reset, - "args": (task,) - } - self._test_ilo_error("invalid_parameter", - ["reset_bios_to_default"], mdobj) + self.assertFalse(ilo_object_mock.set_bios_settings.called) + build_agent_mock.assert_called_once_with(task.node) + self.assertTrue(prepare_mock.called) + self.assertTrue(node_power_mock.called) @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, autospec=True) - def test_factory_reset_with_ilo_error(self, get_ilo_object_mock): + def test__execute_pre_boot_bios_step_invalid( + self, get_ilo_object_mock): + with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: - ilo_object_mock = get_ilo_object_mock.return_value - exc = ilo_error.IloError('error') - ilo_object_mock.reset_bios_to_default.side_effect = exc + data = { + "SET_A": "VAL_A", + "SET_B": "VAL_B", + "SET_C": "VAL_C", + "SET_D": "VAL_D" + } + step = 'invalid_step' self.assertRaises(exception.NodeCleaningFailure, - task.driver.bios.factory_reset, task) + task.driver.bios._execute_pre_boot_bios_step, + task, step, data) @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, autospec=True) - def test_factory_reset_with_unknown_error(self, get_ilo_object_mock): + def test__execute_pre_boot_bios_step_iloobj_failed( + self, get_ilo_object_mock): + with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: - ilo_object_mock = get_ilo_object_mock.return_value - exc = ilo_error.IloCommandNotSupportedError('error') - ilo_object_mock.reset_bios_to_default.side_effect = exc + data = { + "SET_A": "VAL_A", + "SET_B": "VAL_B", + "SET_C": "VAL_C", + "SET_D": "VAL_D" + } + get_ilo_object_mock.side_effect = exception.MissingParameterValue( + 'err') + step = 'apply_configuration' self.assertRaises(exception.NodeCleaningFailure, - task.driver.bios.factory_reset, task) + task.driver.bios._execute_pre_boot_bios_step, + task, step, data) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_pre_boot_bios_step_set_bios_failed( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + data = { + "SET_A": "VAL_A", + "SET_B": "VAL_B", + "SET_C": "VAL_C", + "SET_D": "VAL_D" + } + ilo_object_mock = get_ilo_object_mock.return_value + ilo_object_mock.set_bios_settings.side_effect = ilo_error.IloError( + 'err') + step = 'apply_configuration' + self.assertRaises(exception.NodeCleaningFailure, + task.driver.bios._execute_pre_boot_bios_step, + task, step, data) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_pre_boot_bios_step_reset_bios_failed( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + data = { + "SET_A": "VAL_A", + "SET_B": "VAL_B", + "SET_C": "VAL_C", + "SET_D": "VAL_D" + } + ilo_object_mock = get_ilo_object_mock.return_value + ilo_object_mock.reset_bios_to_default.side_effect = ( + ilo_error.IloError('err')) + step = 'factory_reset' + self.assertRaises(exception.NodeCleaningFailure, + task.driver.bios._execute_pre_boot_bios_step, + task, step, data) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_step_apply_configuration( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'apply_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + ilo_object_mock = get_ilo_object_mock.return_value + step = 'apply_configuration' + task.driver.bios._execute_post_boot_bios_step(task, step) + driver_info = task.node.driver_internal_info + self.assertTrue('apply_bios' not in driver_info) + ilo_object_mock.get_bios_settings_result.assert_called_once_with() + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_step_factory_reset( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'reset_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + ilo_object_mock = get_ilo_object_mock.return_value + step = 'factory_reset' + task.driver.bios._execute_post_boot_bios_step(task, step) + driver_info = task.node.driver_internal_info + self.assertTrue('reset_bios' not in driver_info) + ilo_object_mock.get_bios_settings_result.assert_called_once_with() + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_step_invalid( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'apply_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + step = 'invalid_step' + self.assertRaises(exception.NodeCleaningFailure, + task.driver.bios._execute_post_boot_bios_step, + task, step) + self.assertTrue( + 'apply_bios' not in task.node.driver_internal_info) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_step_iloobj_failed( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'apply_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + get_ilo_object_mock.side_effect = exception.MissingParameterValue( + 'err') + step = 'apply_configuration' + self.assertRaises(exception.NodeCleaningFailure, + task.driver.bios._execute_post_boot_bios_step, + task, step) + self.assertTrue( + 'apply_bios' not in task.node.driver_internal_info) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_get_settings_error( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'apply_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + ilo_object_mock = get_ilo_object_mock.return_value + + step = 'apply_configuration' + mdobj = { + "name": task.driver.bios._execute_post_boot_bios_step, + "args": (task, step,) + } + + self._test_ilo_error(ilo_error.IloCommandNotSupportedError, + [], + [], mdobj, + ilo_object_mock.get_bios_settings_result) + self.assertTrue( + 'apply_bios' not in task.node.driver_internal_info) + + @mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, + autospec=True) + def test__execute_post_boot_bios_get_settings_failed( + self, get_ilo_object_mock): + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + driver_info = task.node.driver_internal_info + driver_info.update({'reset_bios': True}) + task.node.driver_internal_info = driver_info + task.node.save() + ilo_object_mock = get_ilo_object_mock.return_value + ilo_object_mock.get_bios_settings_result.return_value = ( + {'status': 'failed', 'message': 'Some data'}) + step = 'factory_reset' + self.assertRaises(exception.NodeCleaningFailure, + task.driver.bios._execute_post_boot_bios_step, + task, step) + self.assertTrue( + 'reset_bios' not in task.node.driver_internal_info) @mock.patch.object(objects.BIOSSettingList, 'create') @mock.patch.object(objects.BIOSSettingList, 'save') @@ -205,7 +420,7 @@ class IloBiosTestCase(test_common.BaseIloTest): "SET_D": True } - ilo_object_mock.get_pending_bios_settings.return_value = settings + ilo_object_mock.get_current_bios_settings.return_value = settings expected_bios_settings = [ {"name": "SET_A", "value": True}, {"name": "SET_B", "value": True}, @@ -230,7 +445,7 @@ class IloBiosTestCase(test_common.BaseIloTest): ) sync_node_mock.return_value = all_settings task.driver.bios.cache_bios_settings(task) - ilo_object_mock.get_pending_bios_settings.assert_called_once_with() + ilo_object_mock.get_current_bios_settings.assert_called_once_with() actual_arg = sorted(sync_node_mock.call_args[0][2], key=lambda x: x.get("name")) expected_arg = sorted(expected_bios_settings, @@ -244,25 +459,29 @@ class IloBiosTestCase(test_common.BaseIloTest): delete_mock.assert_called_once_with( self.context, task.node.id, del_names) - def test_cache_bios_settings_missing_parameter(self): + @mock.patch.object(ilo_common, 'get_ilo_object', autospec=True) + def test_cache_bios_settings_missing_parameter(self, get_ilo_object_mock): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: mdobj = { "name": task.driver.bios.cache_bios_settings, "args": (task,) } - self._test_ilo_error("missing_parameter", - ["get_pending_bios_settings"], mdobj) + self._test_ilo_error(exception.MissingParameterValue, + [], + [], mdobj, get_ilo_object_mock) - def test_cache_bios_settings_invalid_parameter(self): + @mock.patch.object(ilo_common, 'get_ilo_object', autospec=True) + def test_cache_bios_settings_invalid_parameter(self, get_ilo_object_mock): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: mdobj = { "name": task.driver.bios.cache_bios_settings, "args": (task,) } - self._test_ilo_error("invalid_parameter", - ["get_pending_bios_settings"], mdobj) + self._test_ilo_error(exception.InvalidParameterValue, + [], + [], mdobj, get_ilo_object_mock) @mock.patch.object(ilo_common, 'get_ilo_object', autospec=True) def test_cache_bios_settings_with_ilo_error(self, get_ilo_object_mock): @@ -270,10 +489,15 @@ class IloBiosTestCase(test_common.BaseIloTest): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: ilo_object_mock = get_ilo_object_mock.return_value - exc = ilo_error.IloError('error') - ilo_object_mock.get_pending_bios_settings.side_effect = exc - self.assertRaises(exception.NodeCleaningFailure, - task.driver.bios.cache_bios_settings, task) + mdobj = { + "name": task.driver.bios.cache_bios_settings, + "args": (task,) + } + self._test_ilo_error(ilo_error.IloError, + [], + [], + mdobj, + ilo_object_mock.get_current_bios_settings) @mock.patch.object(ilo_common, 'get_ilo_object', autospec=True) def test_cache_bios_settings_with_unknown_error(self, get_ilo_object_mock): @@ -281,7 +505,13 @@ class IloBiosTestCase(test_common.BaseIloTest): with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: ilo_object_mock = get_ilo_object_mock.return_value - exc = ilo_error.IloCommandNotSupportedError('error') - ilo_object_mock.get_pending_bios_settings.side_effect = exc - self.assertRaises(exception.NodeCleaningFailure, - task.driver.bios.cache_bios_settings, task) + + mdobj = { + "name": task.driver.bios.cache_bios_settings, + "args": (task,) + } + self._test_ilo_error(ilo_error.IloCommandNotSupportedError, + [], + [], + mdobj, + ilo_object_mock.get_current_bios_settings) diff --git a/releasenotes/notes/ilo-async-bios-clean-steps-15e49545ba818997.yaml b/releasenotes/notes/ilo-async-bios-clean-steps-15e49545ba818997.yaml new file mode 100644 index 0000000000..91819d1705 --- /dev/null +++ b/releasenotes/notes/ilo-async-bios-clean-steps-15e49545ba818997.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Makes all ``ilo`` driver BIOS interface clean steps as asynchronous. This is + required to ensure the settings on the baremetal node are consistent with + the settings stored in the database irrespective of the node clean step + status. Refer bug `2004066 + `_ for details.