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
This commit is contained in:
parent
680e5b5687
commit
335f6b4fd1
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
<https://storyboard.openstack.org/#!/story/2004066>`_ for details.
|
Loading…
Reference in New Issue
Block a user