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:
parent
7d204b6568
commit
4724d55e96
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Foreign drives and global and dedicated hot spares will be freed
|
||||
up during the RAID ``delete_configuration`` cleaning step.
|
Loading…
Reference in New Issue
Block a user