DRAC: Upgraded RAID delete_config cleaning step

This upgrades Delete_configuration by cleaning step by
replacing delete_virtual_disk with reset_raid_config
which is not only responsible for removing Virtual Disks
but also removes Global and Dedicated Hot-Spares.
It also removes any foreign drives.

Change-Id: Id9461015f7352a3cc6278d0eaf2970764cafedb9
Story: 2005884
Task: 33732
This commit is contained in:
Rachit7194 2019-06-11 12:23:20 -04:00
parent 7d204b6568
commit 4724d55e96
5 changed files with 363 additions and 72 deletions

View File

@ -35,6 +35,7 @@ from ironic.drivers.modules.drac import common as drac_common
from ironic.drivers.modules.drac import job as drac_job
drac_exceptions = importutils.try_import('dracclient.exceptions')
drac_constants = importutils.try_import('dracclient.constants')
LOG = logging.getLogger(__name__)
@ -134,6 +135,34 @@ def list_physical_disks(node):
raise exception.DracOperationError(error=exc)
def _is_raid_controller(node, raid_controller_fqdd, raid_controllers=None):
"""Find out if object's fqdd is for a raid controller or not
:param node: an ironic node object
:param raid_controller_fqdd: The object's fqdd we are testing to see
if it is a raid controller or not.
:param raid_controllers: A list of RAIDControllers used to check for
the presence of BOSS cards. If None, the
iDRAC will be queried for the list of
controllers.
:returns: boolean, True if the device is a RAID controller,
False if not.
"""
client = drac_common.get_drac_client(node)
try:
return client.is_raid_controller(raid_controller_fqdd,
raid_controllers)
except drac_exceptions.BaseClientException as exc:
LOG.error('Unable to determine if controller %(raid_controller_fqdd)s '
'on node %(node_uuid)s is a RAID controller. '
'Reason: %(error)s. ',
{'raid_controller_fqdd': raid_controller_fqdd,
'node_uuid': node.uuid, 'error': exc})
raise exception.DracOperationError(error=exc)
def create_virtual_disk(node, raid_controller, physical_disks, raid_level,
size_mb, disk_name=None, span_length=None,
span_depth=None):
@ -202,6 +231,69 @@ def delete_virtual_disk(node, virtual_disk):
raise exception.DracOperationError(error=exc)
def _reset_raid_config(node, raid_controller):
"""Delete all virtual disk and unassign all hotspares physical disk
:param node: an ironic node object.
:param raid_controller: id of the RAID controller.
:returns: a dictionary containing
- The is_commit_required needed key with a
boolean value indicating whether a config job must be created
for the values to be applied.
- The is_reboot_required key with a RebootRequired enumerated
value indicating whether the server must be rebooted to
reset configuration.
:raises: DracOperationError on an error from python-dracclient.
"""
try:
drac_job.validate_job_queue(node)
client = drac_common.get_drac_client(node)
return client.reset_raid_config(raid_controller)
except drac_exceptions.BaseClientException as exc:
LOG.error('DRAC driver failed to delete all virtual disk '
'and unassign all hotspares '
'on %(raid_controller_fqdd)s '
'for node %(node_uuid)s. '
'Reason: %(error)s.',
{'raid_controller_fqdd': raid_controller,
'node_uuid': node.uuid,
'error': exc})
raise exception.DracOperationError(error=exc)
def clear_foreign_config(node, raid_controller):
"""Free up the foreign drives.
:param node: an ironic node object.
:param raid_controller: id of the RAID controller.
:returns: a dictionary containing
- The is_commit_required needed key with a
boolean value indicating whether a config job must be created
for the values to be applied.
- The is_reboot_required key with a RebootRequired enumerated
value indicating whether the server must be rebooted to
clear foreign configuration.
:raises: DracOperationError on an error from python-dracclient.
"""
try:
drac_job.validate_job_queue(node)
client = drac_common.get_drac_client(node)
return client.clear_foreign_config(raid_controller)
except drac_exceptions.BaseClientException as exc:
LOG.error('DRAC driver failed to free foreign driver '
'on %(raid_controller_fqdd)s '
'for node %(node_uuid)s. '
'Reason: %(error)s.',
{'raid_controller_fqdd': raid_controller,
'node_uuid': node.uuid,
'error': exc})
raise exception.DracOperationError(error=exc)
def commit_config(node, raid_controller, reboot=False, realtime=False):
"""Apply all pending changes on a RAID controller.
@ -635,19 +727,41 @@ def _filter_logical_disks(logical_disks, include_root_volume,
return filtered_disks
def _commit_to_controllers(node, controllers):
"""Commit changes to RAID controllers on the node."""
def _commit_to_controllers(node, controllers, substep="completed"):
"""Commit changes to RAID controllers on the node.
:param node: an ironic node object
:param controllers: a list of dictionary containing
- The raid_controller key with raid controller
fqdd value indicating on which raid configuration
job needs to be perform.
- The is_commit_required needed key with a
boolean value indicating whether a config job must
be created.
- The is_reboot_required key with a RebootRequired
enumerated value indicating whether the server must
be rebooted only if raid controller does not support
realtime.
:param substep: contain sub cleaning step which executes any raid
configuration job if set after cleaning step.
(default to completed)
:returns: states.CLEANWAIT if deletion is in progress asynchronously
or None if it is completed.
"""
if not controllers:
LOG.debug('No changes on any of the controllers on node %s',
node.uuid)
return
driver_internal_info = node.driver_internal_info
driver_internal_info['raid_config_substep'] = substep
driver_internal_info['raid_config_parameters'] = []
if 'raid_config_job_ids' not in driver_internal_info:
driver_internal_info['raid_config_job_ids'] = []
all_realtime = True
optional = drac_constants.RebootRequired.optional
for controller in controllers:
raid_controller = controller['raid_controller']
@ -656,7 +770,8 @@ def _commit_to_controllers(node, controllers):
# controller without real time support. In that case the reboot
# is triggered when the configuration is committed to the last
# controller.
realtime = controller['is_reboot_required'] == 'optional'
realtime = controller['is_reboot_required'] == optional
all_realtime = all_realtime and realtime
if controller == controllers[-1]:
job_id = commit_config(node, raid_controller=raid_controller,
@ -675,6 +790,11 @@ def _commit_to_controllers(node, controllers):
driver_internal_info['raid_config_job_ids'].append(job_id)
if raid_controller not in driver_internal_info[
'raid_config_parameters']:
driver_internal_info['raid_config_parameters'].append(
raid_controller)
node.driver_internal_info = driver_internal_info
node.save()
@ -728,7 +848,7 @@ class DracRAID(base.RAIDInterface):
logical_disks = node.target_raid_config['logical_disks']
for disk in logical_disks:
if (disk['size_gb'] == 'MAX' and 'physical_disks' not in disk):
if disk['size_gb'] == 'MAX' and 'physical_disks' not in disk:
raise exception.InvalidParameterValue(
_("create_configuration called with invalid "
"target_raid_configuration for node %(node_id)s. "
@ -782,15 +902,18 @@ class DracRAID(base.RAIDInterface):
node = task.node
controllers = list()
for disk in list_virtual_disks(node):
controller = dict()
controller_cap = delete_virtual_disk(node, disk.id)
controller['raid_controller'] = disk.controller
controller['is_reboot_required'] = controller_cap[
'is_reboot_required']
controllers.append(controller)
drac_raid_controllers = list_raid_controllers(node)
for cntrl in drac_raid_controllers:
if _is_raid_controller(node, cntrl.id, drac_raid_controllers):
controller = dict()
controller_cap = _reset_raid_config(node, cntrl.id)
controller["raid_controller"] = cntrl.id
controller["is_reboot_required"] = controller_cap[
"is_reboot_required"]
controllers.append(controller)
return _commit_to_controllers(node, controllers)
return _commit_to_controllers(node, controllers,
substep="delete_foreign_config")
@METRICS.timer('DracRAID.get_logical_disks')
def get_logical_disks(self, task):
@ -864,7 +987,7 @@ class DracRAID(base.RAIDInterface):
for config_job_id in raid_config_job_ids:
config_job = drac_job.get_job(node, job_id=config_job_id)
if config_job.status == 'Completed':
if config_job is None or config_job.status == 'Completed':
finished_job_ids.append(config_job_id)
elif config_job.status == 'Failed':
finished_job_ids.append(config_job_id)
@ -876,13 +999,58 @@ class DracRAID(base.RAIDInterface):
task.upgrade_lock()
self._delete_cached_config_job_id(node, finished_job_ids)
if not node.driver_internal_info['raid_config_job_ids']:
if not node.driver_internal_info.get('raid_config_job_failure',
False):
self._resume_cleaning(task)
if not node.driver_internal_info.get('raid_config_job_failure',
False):
if 'raid_config_substep' in node.driver_internal_info:
if node.driver_internal_info['raid_config_substep'] == \
'delete_foreign_config':
self._execute_cleaning_foreign_drives(task, node)
elif node.driver_internal_info['raid_config_substep'] == \
'completed':
self._complete_raid_cleaning_substep(task, node)
else:
self._clear_raid_config_job_failure(node)
self._set_clean_failed(task, config_job)
self._complete_raid_cleaning_substep(task, node)
else:
self._clear_raid_substep(node)
self._clear_raid_config_job_failure(node)
self._set_clean_failed(task, config_job)
def _execute_cleaning_foreign_drives(self, task, node):
controllers = list()
jobs_required = False
for controller_id in node.driver_internal_info[
'raid_config_parameters']:
controller_cap = clear_foreign_config(
node, controller_id)
controller = {'raid_controller': controller_id,
'is_reboot_required':
controller_cap[
'is_reboot_required']}
controllers.append(controller)
jobs_required = jobs_required or controller_cap[
'is_commit_required']
if not jobs_required:
LOG.info(
"No foreign drives detected, so "
"resume cleaning")
self._complete_raid_cleaning_substep(task, node)
else:
_commit_to_controllers(
node,
controllers,
substep='completed')
def _complete_raid_cleaning_substep(self, task, node):
self._clear_raid_substep(node)
self._resume_cleaning(task)
def _clear_raid_substep(self, node):
driver_internal_info = node.driver_internal_info
driver_internal_info.pop('raid_config_substep', None)
driver_internal_info.pop('raid_config_parameters', None)
node.driver_internal_info = driver_internal_info
node.save()
def _set_raid_config_job_failure(self, node):
driver_internal_info = node.driver_internal_info

View File

@ -15,12 +15,14 @@
Test class for DRAC RAID interface
"""
from dracclient import constants
from dracclient import exceptions as drac_exceptions
import mock
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as conductor_utils
from ironic.drivers.modules.drac import common as drac_common
from ironic.drivers.modules.drac import job as drac_job
from ironic.drivers.modules.drac import raid as drac_raid
@ -222,6 +224,62 @@ class DracManageVirtualDisksTestCase(test_utils.BaseDracTest):
exception.DracOperationError, drac_raid.delete_virtual_disk,
self.node, 'disk1')
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
def test__reset_raid_config(self, mock_validate_job_queue,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
drac_raid._reset_raid_config(
self.node, 'controller')
mock_validate_job_queue.assert_called_once_with(self.node)
mock_client.reset_raid_config.assert_called_once_with(
'controller')
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
def test__reset_raid_config_fail(self, mock_validate_job_queue,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
exc = drac_exceptions.BaseClientException('boom')
mock_client.reset_raid_config.side_effect = exc
self.assertRaises(
exception.DracOperationError, drac_raid._reset_raid_config,
self.node, 'RAID.Integrated.1-1')
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
def test_clear_foreign_config(self, mock_validate_job_queue,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
drac_raid.clear_foreign_config(
self.node, 'RAID.Integrated.1-1')
mock_validate_job_queue.assert_called_once_with(self.node)
mock_client.clear_foreign_config.assert_called_once_with(
'RAID.Integrated.1-1')
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
def test_clear_foreign_config_fail(self, mock_validate_job_queue,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
exc = drac_exceptions.BaseClientException('boom')
mock_client.clear_foreign_config.side_effect = exc
self.assertRaises(
exception.DracOperationError, drac_raid.clear_foreign_config,
self.node, 'RAID.Integrated.1-1')
def test_commit_config(self, mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
@ -620,7 +678,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_list_physical_disks.return_value = physical_disks
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -657,7 +715,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
physical_disks = self._generate_physical_disks()
mock_list_physical_disks.return_value = physical_disks
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -699,10 +757,9 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
physical_disks = self._generate_physical_disks()
mock_list_physical_disks.return_value = physical_disks
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -758,7 +815,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -802,15 +859,14 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_list_physical_disks.return_value = physical_disks
mock_commit_config.side_effect = ['42', '12', '13']
mock_client.create_virtual_disk.side_effect = [{
'is_reboot_required': 'True',
'is_reboot_required': constants.RebootRequired.true,
'is_commit_required': True
}, {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}, {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}]
@ -878,7 +934,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.side_effect = ['42', '12', '13']
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}
@ -940,9 +996,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
physical_disks = self._generate_physical_disks()
mock_list_physical_disks.return_value = physical_disks
mock_commit_config.side_effect = ['42', '12']
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}
@ -1007,7 +1062,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.side_effect = ['42', '12', '13']
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}
@ -1100,7 +1155,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.side_effect = ['42', '12']
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}
@ -1158,7 +1213,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -1177,7 +1232,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
autospec=True)
def test_create_configuration_with_max_size_and_share_physical_disks(
self, mock_commit_config, mock_validate_job_queue,
mock_list_physical_disks, mock_get_drac_client):
mock_list_physical_disks,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
@ -1199,7 +1255,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True
}
@ -1268,7 +1324,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_client.create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -1309,7 +1365,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -1352,7 +1408,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
mock_commit_config.return_value = '42'
mock_create_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -1364,38 +1420,35 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'list_virtual_disks', autospec=True)
@mock.patch.object(drac_raid, 'list_raid_controllers', autospec=True)
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'commit_config', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'delete_virtual_disk', spec_set=True,
@mock.patch.object(drac_raid, '_reset_raid_config', spec_set=True,
autospec=True)
def test_delete_configuration(self, mock_delete_virtual_disk,
def test_delete_configuration(self, mock__reset_raid_config,
mock_commit_config,
mock_validate_job_queue,
mock_list_virtual_disks,
mock_list_raid_controllers,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
virtual_disk_dict = {
'id': 'Disk.Virtual.0:RAID.Integrated.1-1',
'name': 'disk 0',
'description': 'Virtual Disk 0 on Integrated RAID Controller 1',
'controller': 'RAID.Integrated.1-1',
'raid_level': '1',
'size_mb': 571776,
'status': 'ok',
'raid_status': 'online',
'span_depth': 1,
'span_length': 2,
'pending_operations': None,
'physical_disks': []}
mock_list_virtual_disks.return_value = [
test_utils.make_virtual_disk(virtual_disk_dict)]
raid_controller_dict = {
'id': 'RAID.Integrated.1-1',
'description': 'Integrated RAID Controller 1',
'manufacturer': 'DELL',
'model': 'PERC H710 Mini',
'primary_status': 'ok',
'firmware_version': '21.3.0-0009',
'bus': '1',
'supports_realtime': True}
mock_list_raid_controllers.return_value = [
test_utils.make_raid_controller(raid_controller_dict)]
mock_commit_config.return_value = '42'
mock_delete_virtual_disk.return_value = {
'is_reboot_required': 'optional',
mock__reset_raid_config.return_value = {
'is_reboot_required': constants.RebootRequired.optional,
'is_commit_required': True}
with task_manager.acquire(self.context, self.node.uuid,
@ -1413,30 +1466,24 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'list_virtual_disks', autospec=True)
@mock.patch.object(drac_raid, 'list_raid_controllers', autospec=True)
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'commit_config', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'delete_virtual_disk', spec_set=True,
autospec=True)
def test_delete_configuration_no_change(self, mock_delete_virtual_disk,
mock_commit_config,
def test_delete_configuration_no_change(self, mock_commit_config,
mock_validate_job_queue,
mock_list_virtual_disks,
mock_list_raid_controllers,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
mock_list_virtual_disks.return_value = []
mock_delete_virtual_disk.return_value = {
'is_reboot_required': 'optional',
'is_commit_required': True}
mock_list_raid_controllers.return_value = []
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
return_value = task.driver.raid.delete_configuration(task)
self.assertEqual(0, mock_client.delete_virtual_disk.call_count)
self.assertEqual(0, mock_client._reset_raid_config.call_count)
self.assertEqual(0, mock_commit_config.call_count)
self.assertIsNone(return_value)
@ -1473,3 +1520,61 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
self.assertEqual({'logical_disks': [expected_logical_disk]},
props)
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
autospec=True)
@mock.patch.object(conductor_utils, '_notify_conductor_resume_operation',
autospec=True)
@mock.patch.object(drac_raid, 'clear_foreign_config', spec_set=True,
autospec=True)
@mock.patch.object(drac_raid, 'list_virtual_disks', autospec=True)
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
def test__execute_cleaning_foreign_drives(self,
mock_validate_job_queue,
mock_list_virtual_disks,
mock_clear_foreign_config,
mock_resume,
mock_get_drac_client):
mock_client = mock.Mock()
mock_get_drac_client.return_value = mock_client
virtual_disk_dict = {
'id': 'Disk.Virtual.0:RAID.Integrated.1-1',
'name': 'disk 0',
'description': 'Virtual Disk 0 on Integrated RAID Controller 1',
'controller': 'RAID.Integrated.1-1',
'raid_level': '1',
'size_mb': 571776,
'status': 'ok',
'raid_status': 'online',
'span_depth': 1,
'span_length': 2,
'pending_operations': None,
'physical_disks': []}
mock_list_virtual_disks.return_value = [
test_utils.make_virtual_disk(virtual_disk_dict)]
raid_config_params = ['RAID.Integrated.1-1']
raid_config_substep = ['completed']
driver_internal_info = self.node.driver_internal_info
driver_internal_info['raid_config_parameters'] = raid_config_params
driver_internal_info['raid_config_substep'] = raid_config_substep
self.node.driver_internal_info = driver_internal_info
self.node.save()
mock_clear_foreign_config.return_value = {
'is_reboot_required': constants.RebootRequired.false,
'is_commit_required': False
}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
return_value = task.driver.raid._execute_cleaning_foreign_drives(
task, self.node)
mock_resume.assert_called_once_with(
task, 'cleaning', 'continue_node_clean')
self.assertIsNone(return_value)
self.assertNotIn('raid_config_parameters',
self.node.driver_internal_info)
self.assertNotIn('raid_config_substep',
self.node.driver_internal_info)

View File

@ -30,7 +30,14 @@ DRACCLIENT_CLIENT_MOD_SPEC = (
DRACCLIENT_CONSTANTS_MOD_SPEC = (
'POWER_OFF',
'POWER_ON',
'REBOOT'
'REBOOT',
'RebootRequired'
)
DRACCLIENT_CONSTANTS_REBOOT_REQUIRED_MOD_SPEC = (
'true',
'optional',
'false'
)
# ironic_inspector

View File

@ -90,6 +90,12 @@ if not dracclient:
POWER_OFF=mock.sentinel.POWER_OFF,
POWER_ON=mock.sentinel.POWER_ON,
REBOOT=mock.sentinel.REBOOT)
dracclient.constants.RebootRequired = mock.MagicMock(
spec_set=mock_specs.DRACCLIENT_CONSTANTS_REBOOT_REQUIRED_MOD_SPEC,
true=mock.sentinel.true,
optional=mock.sentinel.optional,
false=mock.sentinel.false)
sys.modules['dracclient'] = dracclient
sys.modules['dracclient.client'] = dracclient.client
sys.modules['dracclient.constants'] = dracclient.constants

View File

@ -0,0 +1,5 @@
---
features:
- |
Foreign drives and global and dedicated hot spares will be freed
up during the RAID ``delete_configuration`` cleaning step.