Merge "Adds clean step 'restore_irmc_bios_config' to iRMC drivers"
This commit is contained in:
commit
cdd13b405c
@ -1992,6 +1992,10 @@
|
||||
# SNMP polling interval in seconds (integer value)
|
||||
#snmp_polling_interval = 10
|
||||
|
||||
# Priority for restore_irmc_bios_config clean step. (integer
|
||||
# value)
|
||||
#clean_priority_restore_irmc_bios_config = 0
|
||||
|
||||
|
||||
[ironic_lib]
|
||||
|
||||
|
@ -69,6 +69,9 @@ opts = [
|
||||
cfg.IntOpt('snmp_polling_interval',
|
||||
default=10,
|
||||
help='SNMP polling interval in seconds'),
|
||||
cfg.IntOpt('clean_priority_restore_irmc_bios_config',
|
||||
default=0,
|
||||
help=_('Priority for restore_irmc_bios_config clean step.')),
|
||||
]
|
||||
|
||||
|
||||
|
@ -91,7 +91,10 @@ class IRMCHardware(generic.GenericHardware):
|
||||
@property
|
||||
def supported_boot_interfaces(self):
|
||||
"""List of supported boot interfaces."""
|
||||
return [boot.IRMCVirtualMediaBoot, pxe.PXEBoot]
|
||||
# NOTE: Support for pxe boot is deprecated, and will be
|
||||
# removed from the list in the future.
|
||||
return [boot.IRMCVirtualMediaBoot, boot.IRMCPXEBoot,
|
||||
pxe.PXEBoot]
|
||||
|
||||
@property
|
||||
def supported_console_interfaces(self):
|
||||
|
@ -36,6 +36,8 @@ from ironic.conf import CONF
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.irmc import common as irmc_common
|
||||
from ironic.drivers.modules.irmc import management as irmc_management
|
||||
from ironic.drivers.modules import pxe
|
||||
|
||||
|
||||
scci = importutils.try_import('scciclient.irmc.scci')
|
||||
@ -587,6 +589,11 @@ class IRMCVirtualMediaBoot(base.BootInterface):
|
||||
task.node.provision_state != states.CLEANING):
|
||||
return
|
||||
|
||||
# NOTE(tiendc): Before deploying, we need to backup BIOS config
|
||||
# as the data will be used later when cleaning.
|
||||
if task.node.provision_state == states.DEPLOYING:
|
||||
irmc_management.backup_bios_config(task)
|
||||
|
||||
deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task)
|
||||
ramdisk_params['BOOTIF'] = deploy_nic_mac
|
||||
|
||||
@ -654,3 +661,34 @@ class IRMCVirtualMediaBoot(base.BootInterface):
|
||||
task, node.driver_internal_info['irmc_boot_iso'])
|
||||
manager_utils.node_set_boot_device(task, boot_devices.CDROM,
|
||||
persistent=True)
|
||||
|
||||
|
||||
class IRMCPXEBoot(pxe.PXEBoot):
|
||||
"""iRMC PXE boot."""
|
||||
|
||||
@METRICS.timer('IRMCPXEBoot.prepare_ramdisk')
|
||||
def prepare_ramdisk(self, task, ramdisk_params):
|
||||
"""Prepares the boot of Ironic ramdisk using PXE.
|
||||
|
||||
This method prepares the boot of the deploy kernel/ramdisk after
|
||||
reading relevant information from the node's driver_info and
|
||||
instance_info.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:param ramdisk_params: the parameters to be passed to the ramdisk.
|
||||
pxe driver passes these parameters as kernel command-line
|
||||
arguments.
|
||||
:returns: None
|
||||
:raises: MissingParameterValue, if some information is missing in
|
||||
node's driver_info or instance_info.
|
||||
:raises: InvalidParameterValue, if some information provided is
|
||||
invalid.
|
||||
:raises: IronicException, if some power or set boot device
|
||||
operation failed on the node.
|
||||
"""
|
||||
# NOTE(tiendc): Before deploying, we need to backup BIOS config
|
||||
# as the data will be used later when cleaning.
|
||||
if task.node.provision_state == states.DEPLOYING:
|
||||
irmc_management.backup_bios_config(task)
|
||||
|
||||
super(IRMCPXEBoot, self).prepare_ramdisk(task, ramdisk_params)
|
||||
|
@ -14,6 +14,7 @@
|
||||
"""
|
||||
iRMC Management Driver
|
||||
"""
|
||||
|
||||
from ironic_lib import metrics_utils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
@ -21,14 +22,19 @@ from oslo_utils import importutils
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic import conf
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules.irmc import common as irmc_common
|
||||
from ironic.drivers import utils as driver_utils
|
||||
|
||||
scci = importutils.try_import('scciclient.irmc.scci')
|
||||
irmc = importutils.try_import('scciclient.irmc')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = conf.CONF
|
||||
|
||||
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||
|
||||
@ -61,12 +67,12 @@ def _get_sensors_data(task):
|
||||
|
||||
try:
|
||||
report = irmc_common.get_irmc_report(task.node)
|
||||
sensor = scci.get_sensor_data(report)
|
||||
sensor = irmc.scci.get_sensor_data(report)
|
||||
|
||||
except (exception.InvalidParameterValue,
|
||||
exception.MissingParameterValue,
|
||||
scci.SCCIInvalidInputError,
|
||||
scci.SCCIClientError) as e:
|
||||
irmc.scci.SCCIInvalidInputError,
|
||||
irmc.scci.SCCIClientError) as e:
|
||||
LOG.error("SCCI get sensor data failed for node %(node_id)s "
|
||||
"with the following error: %(error)s",
|
||||
{'node_id': task.node.uuid, 'error': e})
|
||||
@ -106,6 +112,96 @@ def _get_sensors_data(task):
|
||||
return sensors_data
|
||||
|
||||
|
||||
def backup_bios_config(task):
|
||||
"""Backup BIOS config from a node.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:raises: IRMCOperationError on failure.
|
||||
"""
|
||||
node_uuid = task.node.uuid
|
||||
|
||||
# Skip this operation if the clean step 'restore' is disabled
|
||||
if CONF.irmc.clean_priority_restore_irmc_bios_config == 0:
|
||||
LOG.debug('Skipped the operation backup_BIOS_config for node %s '
|
||||
'as the clean step restore_BIOS_config is disabled.',
|
||||
node_uuid)
|
||||
return
|
||||
|
||||
irmc_info = irmc_common.parse_driver_info(task.node)
|
||||
|
||||
try:
|
||||
# Backup bios config
|
||||
result = irmc.elcm.backup_bios_config(irmc_info)
|
||||
except irmc.scci.SCCIError as e:
|
||||
LOG.error('Failed to backup BIOS config for node %(node)s. '
|
||||
'Error: %(error)s', {'node': node_uuid, 'error': e})
|
||||
raise exception.IRMCOperationError(operation='backup BIOS config',
|
||||
error=e)
|
||||
|
||||
# Save bios config into the driver_internal_info
|
||||
internal_info = task.node.driver_internal_info
|
||||
internal_info['irmc_bios_config'] = result['bios_config']
|
||||
task.node.driver_internal_info = internal_info
|
||||
task.node.save()
|
||||
|
||||
LOG.info('BIOS config is backed up successfully for node %s',
|
||||
node_uuid)
|
||||
|
||||
# NOTE(tiendc): When the backup operation done, server is automatically
|
||||
# shutdown. However, this function is called right before the method
|
||||
# task.driver.deploy() that will trigger a reboot. So, we don't need
|
||||
# to power on the server at this point.
|
||||
|
||||
|
||||
def _restore_bios_config(task):
|
||||
"""Restore BIOS config to a node.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:raises: IRMCOperationError if the operation fails.
|
||||
"""
|
||||
node_uuid = task.node.uuid
|
||||
|
||||
# Get bios config stored in the node object
|
||||
bios_config = task.node.driver_internal_info.get('irmc_bios_config')
|
||||
if not bios_config:
|
||||
LOG.info('Skipped operation "restore BIOS config" on node %s '
|
||||
'as the backup data not found.', node_uuid)
|
||||
return
|
||||
|
||||
def _remove_bios_config(task):
|
||||
"""Remove backup bios config from the node."""
|
||||
internal_info = task.node.driver_internal_info
|
||||
internal_info.pop('irmc_bios_config', None)
|
||||
task.node.driver_internal_info = internal_info
|
||||
task.node.save()
|
||||
|
||||
irmc_info = irmc_common.parse_driver_info(task.node)
|
||||
|
||||
try:
|
||||
# Restore bios config
|
||||
irmc.elcm.restore_bios_config(irmc_info, bios_config)
|
||||
except irmc.scci.SCCIError as e:
|
||||
# If the input bios config is not correct or corrupted, then
|
||||
# we should remove it from the node object.
|
||||
if isinstance(e, irmc.scci.SCCIInvalidInputError):
|
||||
_remove_bios_config(task)
|
||||
|
||||
LOG.error('Failed to restore BIOS config on node %(node)s. '
|
||||
'Error: %(error)s', {'node': node_uuid, 'error': e})
|
||||
raise exception.IRMCOperationError(operation='restore BIOS config',
|
||||
error=e)
|
||||
|
||||
# Remove the backup data after restoring
|
||||
_remove_bios_config(task)
|
||||
|
||||
LOG.info('BIOS config is restored successfully on node %s',
|
||||
node_uuid)
|
||||
|
||||
# Change power state to ON as server is automatically
|
||||
# shutdown after the operation.
|
||||
manager_utils.node_power_action(task, states.POWER_ON)
|
||||
|
||||
|
||||
class IRMCManagement(ipmitool.IPMIManagement):
|
||||
|
||||
def get_properties(self):
|
||||
@ -249,9 +345,25 @@ class IRMCManagement(ipmitool.IPMIManagement):
|
||||
node = task.node
|
||||
irmc_client = irmc_common.get_irmc_client(node)
|
||||
try:
|
||||
irmc_client(scci.POWER_RAISE_NMI)
|
||||
except scci.SCCIClientError as err:
|
||||
irmc_client(irmc.scci.POWER_RAISE_NMI)
|
||||
except irmc.scci.SCCIClientError as err:
|
||||
LOG.error('iRMC Inject NMI failed for node %(node)s: %(err)s.',
|
||||
{'node': node.uuid, 'err': err})
|
||||
raise exception.IRMCOperationError(
|
||||
operation=scci.POWER_RAISE_NMI, error=err)
|
||||
operation=irmc.scci.POWER_RAISE_NMI, error=err)
|
||||
|
||||
@METRICS.timer('IRMCManagement.restore_irmc_bios_config')
|
||||
@base.clean_step(
|
||||
priority=CONF.irmc.clean_priority_restore_irmc_bios_config)
|
||||
def restore_irmc_bios_config(self, task):
|
||||
"""Restore BIOS config for a node.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:raises: NodeCleaningFailure, on failure to execute step.
|
||||
:returns: None.
|
||||
"""
|
||||
try:
|
||||
_restore_bios_config(task)
|
||||
except exception.IRMCOperationError as e:
|
||||
raise exception.NodeCleaningFailure(node=task.node.uuid,
|
||||
reason=e)
|
||||
|
@ -34,6 +34,7 @@ from ironic.drivers.modules.ilo import power as ilo_power
|
||||
from ironic.drivers.modules.ilo import vendor as ilo_vendor
|
||||
from ironic.drivers.modules import inspector
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules.irmc import boot as irmc_boot
|
||||
from ironic.drivers.modules.irmc import inspect as irmc_inspect
|
||||
from ironic.drivers.modules.irmc import management as irmc_management
|
||||
from ironic.drivers.modules.irmc import power as irmc_power
|
||||
@ -142,7 +143,7 @@ class PXEAndIRMCDriver(base.BaseDriver):
|
||||
reason=_("Unable to import python-scciclient library"))
|
||||
self.power = irmc_power.IRMCPower()
|
||||
self.console = ipmitool.IPMIShellinaboxConsole()
|
||||
self.boot = pxe.PXEBoot()
|
||||
self.boot = irmc_boot.IRMCPXEBoot()
|
||||
self.deploy = iscsi_deploy.ISCSIDeploy()
|
||||
self.management = irmc_management.IRMCManagement()
|
||||
self.inspect = irmc_inspect.IRMCInspect()
|
||||
|
@ -36,12 +36,13 @@ from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.irmc import boot as irmc_boot
|
||||
from ironic.drivers.modules.irmc import common as irmc_common
|
||||
from ironic.drivers.modules.irmc import management as irmc_management
|
||||
from ironic.drivers.modules import pxe
|
||||
from ironic.tests.unit.conductor import mgr_utils
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
from ironic.tests.unit.db import utils as db_utils
|
||||
from ironic.tests.unit.objects import utils as obj_utils
|
||||
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
@ -896,13 +897,16 @@ class IRMCVirtualMediaBootTestCase(db_base.DbTestCase):
|
||||
validate_prop_mock.assert_called_once_with(
|
||||
task.context, d_info, ['kernel', 'ramdisk'])
|
||||
|
||||
@mock.patch.object(irmc_management, 'backup_bios_config', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(irmc_boot, '_setup_deploy_iso',
|
||||
spec_set=True, autospec=True)
|
||||
@mock.patch.object(deploy_utils, 'get_single_nic_with_vif_port_id',
|
||||
spec_set=True, autospec=True)
|
||||
def _test_prepare_ramdisk(self,
|
||||
get_single_nic_with_vif_port_id_mock,
|
||||
_setup_deploy_iso_mock):
|
||||
_setup_deploy_iso_mock,
|
||||
mock_backup_bios):
|
||||
instance_info = self.node.instance_info
|
||||
instance_info['irmc_boot_iso'] = 'glance://abcdef'
|
||||
instance_info['image_source'] = '6b2f0c0c-79e8-4db6-842e-43c9764204af'
|
||||
@ -922,6 +926,9 @@ class IRMCVirtualMediaBootTestCase(db_base.DbTestCase):
|
||||
task, expected_ramdisk_opts)
|
||||
self.assertEqual('glance://abcdef',
|
||||
self.node.instance_info['irmc_boot_iso'])
|
||||
provision_state = task.node.provision_state
|
||||
self.assertEqual(1 if provision_state == states.DEPLOYING else 0,
|
||||
mock_backup_bios.call_count)
|
||||
|
||||
def test_prepare_ramdisk_glance_image_deploying(self):
|
||||
self.node.provision_state = states.DEPLOYING
|
||||
@ -1051,3 +1058,42 @@ class IRMCVirtualMediaBootTestCase(db_base.DbTestCase):
|
||||
cfg.CONF.set_override('remote_image_share_type', 'nfs', 'irmc')
|
||||
self.assertRaises(ValueError, cfg.CONF.set_override,
|
||||
'remote_image_share_type', 'fake', 'irmc')
|
||||
|
||||
|
||||
class IRMCPXEBootTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(IRMCPXEBootTestCase, self).setUp()
|
||||
mgr_utils.mock_the_extension_manager(driver="pxe_irmc")
|
||||
self.node = obj_utils.create_test_node(
|
||||
self.context, driver='pxe_irmc', driver_info=INFO_DICT)
|
||||
|
||||
@mock.patch.object(irmc_management, 'backup_bios_config', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk', spec_set=True,
|
||||
autospec=True)
|
||||
def test_prepare_ramdisk_with_backup_bios(self, mock_parent_prepare,
|
||||
mock_backup_bios):
|
||||
self.node.provision_state = states.DEPLOYING
|
||||
self.node.save()
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.boot.prepare_ramdisk(task, {})
|
||||
mock_backup_bios.assert_called_once_with(task)
|
||||
mock_parent_prepare.assert_called_once_with(
|
||||
task.driver.boot, task, {})
|
||||
|
||||
@mock.patch.object(irmc_management, 'backup_bios_config', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk', spec_set=True,
|
||||
autospec=True)
|
||||
def test_prepare_ramdisk_without_backup_bios(self, mock_parent_prepare,
|
||||
mock_backup_bios):
|
||||
self.node.provision_state = states.CLEANING
|
||||
self.node.save()
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.boot.prepare_ramdisk(task, {})
|
||||
self.assertFalse(mock_backup_bios.called)
|
||||
mock_parent_prepare.assert_called_once_with(
|
||||
task.driver.boot, task, {})
|
||||
|
@ -24,10 +24,13 @@ import mock
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import driver_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules.irmc import common as irmc_common
|
||||
from ironic.drivers.modules.irmc import management as irmc_management
|
||||
from ironic.drivers.modules.irmc import power as irmc_power
|
||||
from ironic.drivers import utils as driver_utils
|
||||
from ironic.tests.unit.conductor import mgr_utils
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
@ -39,6 +42,116 @@ from ironic.tests.unit.objects import utils as obj_utils
|
||||
INFO_DICT = db_utils.get_test_irmc_info()
|
||||
|
||||
|
||||
@mock.patch.object(irmc_management.irmc, 'elcm',
|
||||
spec_set=mock_specs.SCCICLIENT_IRMC_ELCM_SPEC)
|
||||
@mock.patch.object(manager_utils, 'node_power_action',
|
||||
specset=True, autospec=True)
|
||||
@mock.patch.object(irmc_power.IRMCPower, 'get_power_state',
|
||||
return_value=states.POWER_ON,
|
||||
specset=True, autospec=True)
|
||||
class IRMCManagementFunctionsTestCase(db_base.DbTestCase):
|
||||
def setUp(self):
|
||||
super(IRMCManagementFunctionsTestCase, self).setUp()
|
||||
driver_info = INFO_DICT
|
||||
|
||||
mgr_utils.mock_the_extension_manager(driver="fake_irmc")
|
||||
self.driver = driver_factory.get_driver("fake_irmc")
|
||||
self.node = obj_utils.create_test_node(self.context,
|
||||
driver='fake_irmc',
|
||||
driver_info=driver_info)
|
||||
self.info = irmc_common.parse_driver_info(self.node)
|
||||
|
||||
irmc_management.irmc.scci.SCCIError = Exception
|
||||
irmc_management.irmc.scci.SCCIInvalidInputError = ValueError
|
||||
|
||||
def test_backup_bios_config(self, mock_get_power, mock_power_action,
|
||||
mock_elcm):
|
||||
self.config(clean_priority_restore_irmc_bios_config=10, group='irmc')
|
||||
bios_config = {'Server': {'System': {'BiosConfig': {'key1': 'val1'}}}}
|
||||
mock_elcm.backup_bios_config.return_value = {
|
||||
'bios_config': bios_config}
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
irmc_management.backup_bios_config(task)
|
||||
|
||||
self.assertEqual(bios_config, task.node.driver_internal_info[
|
||||
'irmc_bios_config'])
|
||||
self.assertEqual(1, mock_elcm.backup_bios_config.call_count)
|
||||
|
||||
def test_backup_bios_config_skipped(self, mock_get_power,
|
||||
mock_power_action, mock_elcm):
|
||||
self.config(clean_priority_restore_irmc_bios_config=0, group='irmc')
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
irmc_management.backup_bios_config(task)
|
||||
|
||||
self.assertNotIn('irmc_bios_config',
|
||||
task.node.driver_internal_info)
|
||||
self.assertFalse(mock_elcm.backup_bios_config.called)
|
||||
|
||||
def test_backup_bios_config_failed(self, mock_get_power,
|
||||
mock_power_action, mock_elcm):
|
||||
self.config(clean_priority_restore_irmc_bios_config=10, group='irmc')
|
||||
mock_elcm.backup_bios_config.side_effect = Exception
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.IRMCOperationError,
|
||||
irmc_management.backup_bios_config,
|
||||
task)
|
||||
self.assertNotIn('irmc_bios_config',
|
||||
task.node.driver_internal_info)
|
||||
self.assertEqual(1, mock_elcm.backup_bios_config.call_count)
|
||||
|
||||
def test__restore_bios_config(self, mock_get_power, mock_power_action,
|
||||
mock_elcm):
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
# Set bios data for the node info
|
||||
task.node.driver_internal_info['irmc_bios_config'] = 'data'
|
||||
irmc_management._restore_bios_config(task)
|
||||
|
||||
self.assertEqual(1, mock_elcm.restore_bios_config.call_count)
|
||||
|
||||
def test__restore_bios_config_failed(self, mock_get_power,
|
||||
mock_power_action,
|
||||
mock_elcm):
|
||||
mock_elcm.restore_bios_config.side_effect = Exception
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
# Set bios data for the node info
|
||||
task.node.driver_internal_info['irmc_bios_config'] = 'data'
|
||||
|
||||
self.assertRaises(exception.IRMCOperationError,
|
||||
irmc_management._restore_bios_config,
|
||||
task)
|
||||
# Backed up BIOS config is still in the node object
|
||||
self.assertEqual('data', task.node.driver_internal_info[
|
||||
'irmc_bios_config'])
|
||||
self.assertTrue(mock_elcm.restore_bios_config.called)
|
||||
|
||||
def test__restore_bios_config_corrupted(self, mock_get_power,
|
||||
mock_power_action,
|
||||
mock_elcm):
|
||||
mock_elcm.restore_bios_config.side_effect = \
|
||||
irmc_management.irmc.scci.SCCIInvalidInputError
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
# Set bios data for the node info
|
||||
task.node.driver_internal_info['irmc_bios_config'] = 'data'
|
||||
|
||||
self.assertRaises(exception.IRMCOperationError,
|
||||
irmc_management._restore_bios_config,
|
||||
task)
|
||||
# Backed up BIOS config is removed from the node object
|
||||
self.assertNotIn('irmc_bios_config',
|
||||
task.node.driver_internal_info)
|
||||
self.assertTrue(mock_elcm.restore_bios_config.called)
|
||||
|
||||
|
||||
class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
def setUp(self):
|
||||
super(IRMCManagementTestCase, self).setUp()
|
||||
@ -259,7 +372,7 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
task,
|
||||
"unknown")
|
||||
|
||||
@mock.patch.object(irmc_management, 'scci',
|
||||
@mock.patch.object(irmc_management.irmc, 'scci',
|
||||
spec_set=mock_specs.SCCICLIENT_IRMC_SCCI_SPEC)
|
||||
@mock.patch.object(irmc_common, 'get_irmc_report', spec_set=True,
|
||||
autospec=True)
|
||||
@ -307,7 +420,7 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
}
|
||||
self.assertEqual(expected, sensor_dict)
|
||||
|
||||
@mock.patch.object(irmc_management, 'scci',
|
||||
@mock.patch.object(irmc_management.irmc, 'scci',
|
||||
spec_set=mock_specs.SCCICLIENT_IRMC_SCCI_SPEC)
|
||||
@mock.patch.object(irmc_common, 'get_irmc_report', spec_set=True,
|
||||
autospec=True)
|
||||
@ -350,8 +463,8 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
|
||||
get_irmc_report_mock.side_effect = exception.InvalidParameterValue(
|
||||
"Fake Error")
|
||||
irmc_management.scci.SCCIInvalidInputError = Exception
|
||||
irmc_management.scci.SCCIClientError = Exception
|
||||
irmc_management.irmc.scci.SCCIInvalidInputError = Exception
|
||||
irmc_management.irmc.scci.SCCIClientError = Exception
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.node.driver_info['irmc_sensor_method'] = 'scci'
|
||||
@ -373,7 +486,7 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
self.driver.management.inject_nmi(task)
|
||||
|
||||
irmc_client.assert_called_once_with(
|
||||
irmc_management.scci.POWER_RAISE_NMI)
|
||||
irmc_management.irmc.scci.POWER_RAISE_NMI)
|
||||
self.assertFalse(mock_log.called)
|
||||
|
||||
@mock.patch.object(irmc_management.LOG, 'error', spec_set=True,
|
||||
@ -384,7 +497,7 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
mock_log):
|
||||
irmc_client = mock_get_irmc_client.return_value
|
||||
irmc_client.side_effect = Exception()
|
||||
irmc_management.scci.SCCIClientError = Exception
|
||||
irmc_management.irmc.scci.SCCIClientError = Exception
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
self.assertRaises(exception.IRMCOperationError,
|
||||
@ -392,5 +505,14 @@ class IRMCManagementTestCase(db_base.DbTestCase):
|
||||
task)
|
||||
|
||||
irmc_client.assert_called_once_with(
|
||||
irmc_management.scci.POWER_RAISE_NMI)
|
||||
irmc_management.irmc.scci.POWER_RAISE_NMI)
|
||||
self.assertTrue(mock_log.called)
|
||||
|
||||
@mock.patch.object(irmc_management, '_restore_bios_config',
|
||||
spec_set=True, autospec=True)
|
||||
def test_management_interface_restore_irmc_bios_config(self,
|
||||
mock_restore_bios):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
result = task.driver.management.restore_irmc_bios_config(task)
|
||||
self.assertIsNone(result)
|
||||
mock_restore_bios.assert_called_once_with(task)
|
||||
|
@ -29,6 +29,7 @@ from ironic.drivers.modules.ilo import management as ilo_management
|
||||
from ironic.drivers.modules.ilo import power as ilo_power
|
||||
from ironic.drivers.modules.ilo import vendor as ilo_vendor
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules.irmc import boot as irmc_boot
|
||||
from ironic.drivers.modules.irmc import management as irmc_management
|
||||
from ironic.drivers.modules.irmc import power as irmc_power
|
||||
from ironic.drivers.modules import iscsi_deploy
|
||||
@ -107,7 +108,7 @@ class PXEDriversTestCase(testtools.TestCase):
|
||||
|
||||
self.assertIsInstance(driver.power, irmc_power.IRMCPower)
|
||||
self.assertIsInstance(driver.console, ipmitool.IPMIShellinaboxConsole)
|
||||
self.assertIsInstance(driver.boot, pxe_module.PXEBoot)
|
||||
self.assertIsInstance(driver.boot, irmc_boot.IRMCPXEBoot)
|
||||
self.assertIsInstance(driver.deploy, iscsi_deploy.ISCSIDeploy)
|
||||
self.assertIsInstance(driver.management,
|
||||
irmc_management.IRMCManagement)
|
||||
|
@ -91,6 +91,7 @@ SCCICLIENT_IRMC_SCCI_SPEC = (
|
||||
'UNMOUNT_CD',
|
||||
'MOUNT_FD',
|
||||
'UNMOUNT_FD',
|
||||
'SCCIError',
|
||||
'SCCIClientError',
|
||||
'SCCIInvalidInputError',
|
||||
'get_share_type',
|
||||
@ -101,6 +102,10 @@ SCCICLIENT_IRMC_SCCI_SPEC = (
|
||||
'get_virtual_fd_set_params_cmd',
|
||||
'get_essential_properties',
|
||||
)
|
||||
SCCICLIENT_IRMC_ELCM_SPEC = (
|
||||
'backup_bios_config',
|
||||
'restore_bios_config',
|
||||
)
|
||||
|
||||
ONEVIEWCLIENT_SPEC = (
|
||||
'client',
|
||||
|
@ -164,6 +164,8 @@ if not scciclient:
|
||||
UNMOUNT_CD=mock.sentinel.UNMOUNT_CD,
|
||||
MOUNT_FD=mock.sentinel.MOUNT_FD,
|
||||
UNMOUNT_FD=mock.sentinel.UNMOUNT_FD)
|
||||
sys.modules['scciclient.irmc.elcm'] = mock.MagicMock(
|
||||
spec_set=mock_specs.SCCICLIENT_IRMC_ELCM_SPEC)
|
||||
|
||||
|
||||
# if anything has loaded the iRMC driver yet, reload it now that the
|
||||
|
@ -0,0 +1,16 @@
|
||||
---
|
||||
features:
|
||||
- Adds new boot interface named ``irmc-pxe``.
|
||||
- Adds clean step ``restore_irmc_bios_config`` to restore BIOS config
|
||||
for a node during automatic cleaning.
|
||||
upgrade:
|
||||
- Adds new configuration option
|
||||
``[irmc]clean_priority_restore_irmc_bios_config``, which
|
||||
enables setting priority for the clean step. Default value for
|
||||
this option is 0, which means the clean step is disabled.
|
||||
deprecations:
|
||||
- Deprecates the boot interface ``pxe`` from using with hardware type
|
||||
``irmc``. It is recommended for operator to switch to use the boot
|
||||
iterface ``irmc-pxe`` as soon as possible. Using the interface
|
||||
``pxe`` with ``irmc`` drivers will cause the reset bios feature
|
||||
not to work even the priority option is set to enable.
|
@ -86,6 +86,7 @@ ironic.hardware.interfaces.boot =
|
||||
fake = ironic.drivers.modules.fake:FakeBoot
|
||||
ilo-pxe = ironic.drivers.modules.ilo.boot:IloPXEBoot
|
||||
ilo-virtual-media = ironic.drivers.modules.ilo.boot:IloVirtualMediaBoot
|
||||
irmc-pxe = ironic.drivers.modules.irmc.boot:IRMCPXEBoot
|
||||
irmc-virtual-media = ironic.drivers.modules.irmc.boot:IRMCVirtualMediaBoot
|
||||
pxe = ironic.drivers.modules.pxe:PXEBoot
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user