Add iDRAC RAID deploy steps
This change adds two new deploy steps to the idrac RAID interface - apply_configuration and delete_configuration. These use the existing RAID support in the idrac driver used for clean steps. In order to make this work, the lifecycle controller job validation has been modified to allow specification of a name prefix for jobs to check. This is because configuring the node for PXE boot can result in creation of a BIOS config job, which previously caused the validation to fail. The RAID interface now only checks for existing jobs on the same RAID controller, and so ignores the BIOS config job. The disk space calculation has been modified to allow for virtual disks that are pending deletion, as this is necessary to make the numbers work when deleting existing virtual disks and creating new ones from the same set of physical disks. We also use the new deployment_polling flag in driver_internal_info to signal that the RAID interface polls for completion of the deploy step. Co-Authored-By: Shivanand Tendulker <stendulker@gmail.com> Change-Id: I5803131fbdebce6f7896655a61a8fbdd4c1cd4a1 Story: 2003817 Task: 30004
This commit is contained in:
parent
3e51982252
commit
45b03d03b7
@ -27,20 +27,26 @@ drac_exceptions = importutils.try_import('dracclient.exceptions')
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def validate_job_queue(node):
|
||||
def validate_job_queue(node, name_prefix=None):
|
||||
"""Validates the job queue on the node.
|
||||
|
||||
It raises an exception if an unfinished configuration job exists.
|
||||
|
||||
:param node: an ironic node object.
|
||||
:param name_prefix: A name prefix for jobs to validate.
|
||||
:raises: DracOperationError on an error from python-dracclient.
|
||||
"""
|
||||
|
||||
unfinished_jobs = list_unfinished_jobs(node)
|
||||
if unfinished_jobs:
|
||||
msg = _('Unfinished config jobs found: %(jobs)r. Make sure they are '
|
||||
'completed before retrying.') % {'jobs': unfinished_jobs}
|
||||
raise exception.DracOperationError(error=msg)
|
||||
if name_prefix is not None:
|
||||
# Filter out jobs that don't match the name prefix.
|
||||
unfinished_jobs = [job for job in unfinished_jobs
|
||||
if job.name.startswith(name_prefix)]
|
||||
if not unfinished_jobs:
|
||||
return
|
||||
msg = _('Unfinished config jobs found: %(jobs)r. Make sure they are '
|
||||
'completed before retrying.') % {'jobs': unfinished_jobs}
|
||||
raise exception.DracOperationError(error=msg)
|
||||
|
||||
|
||||
def get_job(node, job_id):
|
||||
|
@ -26,11 +26,11 @@ from oslo_utils import units
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import raid as raid_common
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.conf import CONF
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.drac import common as drac_common
|
||||
from ironic.drivers.modules.drac import job as drac_job
|
||||
|
||||
@ -163,6 +163,18 @@ def _is_raid_controller(node, raid_controller_fqdd, raid_controllers=None):
|
||||
raise exception.DracOperationError(error=exc)
|
||||
|
||||
|
||||
def _validate_job_queue(node, raid_controller=None):
|
||||
"""Validate that there are no pending jobs for this controller.
|
||||
|
||||
:param node: an ironic node object.
|
||||
:param raid_controller: id of the RAID controller.
|
||||
"""
|
||||
kwargs = {}
|
||||
if raid_controller:
|
||||
kwargs["name_prefix"] = "Config:RAID:%s" % raid_controller
|
||||
drac_job.validate_job_queue(node, **kwargs)
|
||||
|
||||
|
||||
def create_virtual_disk(node, raid_controller, physical_disks, raid_level,
|
||||
size_mb, disk_name=None, span_length=None,
|
||||
span_depth=None):
|
||||
@ -185,7 +197,9 @@ def create_virtual_disk(node, raid_controller, physical_disks, raid_level,
|
||||
values to be applied.
|
||||
:raises: DracOperationError on an error from python-dracclient.
|
||||
"""
|
||||
drac_job.validate_job_queue(node)
|
||||
# This causes config to fail, because the boot mode is set via a config
|
||||
# job.
|
||||
_validate_job_queue(node, raid_controller)
|
||||
|
||||
client = drac_common.get_drac_client(node)
|
||||
|
||||
@ -215,7 +229,8 @@ def delete_virtual_disk(node, virtual_disk):
|
||||
values to be applied.
|
||||
:raises: DracOperationError on an error from python-dracclient.
|
||||
"""
|
||||
drac_job.validate_job_queue(node)
|
||||
# NOTE(mgoddard): Cannot specify raid_controller as we don't know it.
|
||||
_validate_job_queue(node)
|
||||
|
||||
client = drac_common.get_drac_client(node)
|
||||
|
||||
@ -247,7 +262,7 @@ def _reset_raid_config(node, raid_controller):
|
||||
"""
|
||||
try:
|
||||
|
||||
drac_job.validate_job_queue(node)
|
||||
_validate_job_queue(node, raid_controller)
|
||||
|
||||
client = drac_common.get_drac_client(node)
|
||||
return client.reset_raid_config(raid_controller)
|
||||
@ -279,7 +294,7 @@ def clear_foreign_config(node, raid_controller):
|
||||
"""
|
||||
try:
|
||||
|
||||
drac_job.validate_job_queue(node)
|
||||
_validate_job_queue(node, raid_controller)
|
||||
|
||||
client = drac_common.get_drac_client(node)
|
||||
return client.clear_foreign_config(raid_controller)
|
||||
@ -480,13 +495,18 @@ def _volume_usage_per_disk_mb(logical_disk, physical_disks, spans_count=1,
|
||||
return int(stripes_per_disk * stripe_size_kb / units.Ki)
|
||||
|
||||
|
||||
def _find_configuration(logical_disks, physical_disks):
|
||||
def _find_configuration(logical_disks, physical_disks, pending_delete):
|
||||
"""Find RAID configuration.
|
||||
|
||||
This method transforms the RAID configuration defined in Ironic to a format
|
||||
that is required by dracclient. This includes matching the physical disks
|
||||
to RAID volumes when it's not pre-defined, or in general calculating
|
||||
missing properties.
|
||||
|
||||
:param logical_disks: list of logical disk definitions.
|
||||
:param physical_disks: list of physical disk definitions.
|
||||
:param pending_delete: Whether there is a pending deletion of virtual
|
||||
disks that should be accounted for.
|
||||
"""
|
||||
|
||||
# shared physical disks of RAID volumes size_gb='MAX' should be
|
||||
@ -508,7 +528,7 @@ def _find_configuration(logical_disks, physical_disks):
|
||||
free_space_mb = {}
|
||||
for disk in physical_disks:
|
||||
# calculate free disk space
|
||||
free_space_mb[disk] = disk.free_size_mb
|
||||
free_space_mb[disk] = _get_disk_free_size_mb(disk, pending_delete)
|
||||
|
||||
disk_type = (disk.controller, disk.media_type, disk.interface_type,
|
||||
disk.size_mb)
|
||||
@ -550,7 +570,8 @@ def _find_configuration(logical_disks, physical_disks):
|
||||
if volumes_without_disks:
|
||||
result, free_space_mb = (
|
||||
_assign_disks_to_volume(volumes_without_disks,
|
||||
physical_disks_by_type, free_space_mb))
|
||||
physical_disks_by_type, free_space_mb,
|
||||
pending_delete))
|
||||
if not result:
|
||||
# try again using the reserved physical disks in addition
|
||||
for disk_type, disks in physical_disks_by_type.items():
|
||||
@ -560,7 +581,8 @@ def _find_configuration(logical_disks, physical_disks):
|
||||
result, free_space_mb = (
|
||||
_assign_disks_to_volume(volumes_without_disks,
|
||||
physical_disks_by_type,
|
||||
free_space_mb))
|
||||
free_space_mb,
|
||||
pending_delete))
|
||||
if not result:
|
||||
error_msg = _('failed to find matching physical disks for all '
|
||||
'logical disks')
|
||||
@ -636,7 +658,7 @@ def _calculate_volume_props(logical_disk, physical_disks, free_space_mb):
|
||||
|
||||
|
||||
def _assign_disks_to_volume(logical_disks, physical_disks_by_type,
|
||||
free_space_mb):
|
||||
free_space_mb, pending_delete):
|
||||
logical_disk = logical_disks.pop(0)
|
||||
raid_level = logical_disk['raid_level']
|
||||
|
||||
@ -664,8 +686,12 @@ def _assign_disks_to_volume(logical_disks, physical_disks_by_type,
|
||||
# filter out disks already in use if sharing is disabled
|
||||
if ('share_physical_disks' not in logical_disk
|
||||
or not logical_disk['share_physical_disks']):
|
||||
initial_free_size_mb = {
|
||||
disk: _get_disk_free_size_mb(disk, pending_delete)
|
||||
for disk in disks
|
||||
}
|
||||
disks = [disk for disk in disks
|
||||
if disk.free_size_mb == free_space_mb[disk]]
|
||||
if initial_free_size_mb[disk] == free_space_mb[disk]]
|
||||
|
||||
max_spans = _calculate_spans(raid_level, len(disks))
|
||||
min_spans = min([2, max_spans])
|
||||
@ -701,7 +727,8 @@ def _assign_disks_to_volume(logical_disks, physical_disks_by_type,
|
||||
result, candidate_free_space_mb = (
|
||||
_assign_disks_to_volume(logical_disks,
|
||||
physical_disks_by_type,
|
||||
candidate_free_space_mb))
|
||||
candidate_free_space_mb,
|
||||
pending_delete))
|
||||
if result:
|
||||
logical_disks.append(candidate_volume)
|
||||
return (True, candidate_free_space_mb)
|
||||
@ -742,11 +769,12 @@ def _commit_to_controllers(node, controllers, substep="completed"):
|
||||
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.
|
||||
:param substep: contain sub cleaning or deploy step which executes any raid
|
||||
configuration job if set after cleaning or deploy step.
|
||||
(default to completed)
|
||||
:returns: states.CLEANWAIT if deletion is in progress asynchronously
|
||||
or None if it is completed.
|
||||
:returns: states.CLEANWAIT (cleaning) or states.DEPLOYWAIT (deployment) if
|
||||
configuration 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',
|
||||
@ -796,9 +824,28 @@ def _commit_to_controllers(node, controllers, substep="completed"):
|
||||
raid_controller)
|
||||
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
|
||||
return states.CLEANWAIT
|
||||
# Signal whether the node has been rebooted, that we do not need to execute
|
||||
# the step again, and that this completion of this step is triggered
|
||||
# through async polling.
|
||||
# NOTE(mgoddard): set_async_step_flags calls node.save().
|
||||
deploy_utils.set_async_step_flags(
|
||||
node,
|
||||
reboot=not all_realtime,
|
||||
skip_current_step=True,
|
||||
polling=True)
|
||||
|
||||
return deploy_utils.get_async_step_return_state(node)
|
||||
|
||||
|
||||
def _get_disk_free_size_mb(disk, pending_delete):
|
||||
"""Return the size of free space on the disk in MB.
|
||||
|
||||
:param disk: a PhysicalDisk object.
|
||||
:param pending_delete: Whether there is a pending deletion of all virtual
|
||||
disks.
|
||||
"""
|
||||
return disk.size_mb if pending_delete else disk.free_size_mb
|
||||
|
||||
|
||||
class DracWSManRAID(base.RAIDInterface):
|
||||
@ -807,6 +854,16 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
"""Return the properties of the interface."""
|
||||
return drac_common.COMMON_PROPERTIES
|
||||
|
||||
@base.deploy_step(priority=0,
|
||||
argsinfo=base.RAID_APPLY_CONFIGURATION_ARGSINFO)
|
||||
def apply_configuration(self, task, raid_config, create_root_volume=True,
|
||||
create_nonroot_volumes=False,
|
||||
delete_existing=True):
|
||||
return super(DracRAID, self).apply_configuration(
|
||||
task, raid_config, create_root_volume=create_root_volume,
|
||||
create_nonroot_volumes=create_nonroot_volumes,
|
||||
delete_existing=delete_existing)
|
||||
|
||||
@METRICS.timer('DracRAID.create_configuration')
|
||||
@base.clean_step(priority=0, abortable=False, argsinfo={
|
||||
'create_root_volume': {
|
||||
@ -822,11 +879,20 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
'Defaults to `True`.'
|
||||
),
|
||||
'required': False
|
||||
},
|
||||
"delete_existing": {
|
||||
"description": (
|
||||
"Setting this to 'True' indicates to delete existing RAID "
|
||||
"configuration prior to creating the new configuration. "
|
||||
"Default value is 'False'."
|
||||
),
|
||||
"required": False,
|
||||
}
|
||||
})
|
||||
def create_configuration(self, task,
|
||||
create_root_volume=True,
|
||||
create_nonroot_volumes=True):
|
||||
create_nonroot_volumes=True,
|
||||
delete_existing=False):
|
||||
"""Create the RAID configuration.
|
||||
|
||||
This method creates the RAID configuration on the given node.
|
||||
@ -838,8 +904,12 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
:param create_nonroot_volumes: If True, non-root volumes are
|
||||
created. If False, no non-root volumes are created. Default
|
||||
is True.
|
||||
:returns: states.CLEANWAIT if creation is in progress asynchronously
|
||||
or None if it is completed.
|
||||
:param delete_existing: Setting this to True indicates to delete RAID
|
||||
configuration prior to creating the new configuration. Default is
|
||||
False.
|
||||
:returns: states.CLEANWAIT (cleaning) or states.DEPLOYWAIT (deployment)
|
||||
if creation is in progress asynchronously or None if it is
|
||||
completed.
|
||||
:raises: MissingParameterValue, if node.target_raid_config is missing
|
||||
or empty.
|
||||
:raises: DracOperationError on an error from python-dracclient.
|
||||
@ -864,13 +934,18 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
|
||||
del disk['size_gb']
|
||||
|
||||
if delete_existing:
|
||||
controllers = self._delete_configuration_no_commit(task)
|
||||
else:
|
||||
controllers = list()
|
||||
|
||||
physical_disks = list_physical_disks(node)
|
||||
logical_disks = _find_configuration(logical_disks, physical_disks)
|
||||
logical_disks = _find_configuration(logical_disks, physical_disks,
|
||||
pending_delete=delete_existing)
|
||||
|
||||
logical_disks_to_create = _filter_logical_disks(
|
||||
logical_disks, create_root_volume, create_nonroot_volumes)
|
||||
|
||||
controllers = list()
|
||||
for logical_disk in logical_disks_to_create:
|
||||
controller = dict()
|
||||
controller_cap = create_virtual_disk(
|
||||
@ -892,28 +967,19 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
|
||||
@METRICS.timer('DracRAID.delete_configuration')
|
||||
@base.clean_step(priority=0)
|
||||
@base.deploy_step(priority=0)
|
||||
def delete_configuration(self, task):
|
||||
"""Delete the RAID configuration.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:returns: states.CLEANWAIT if deletion is in progress asynchronously
|
||||
or None if it is completed.
|
||||
:returns: states.CLEANWAIT (cleaning) or states.DEPLOYWAIT (deployment)
|
||||
if deletion is in progress asynchronously or None if it is
|
||||
completed.
|
||||
:raises: DracOperationError on an error from python-dracclient.
|
||||
"""
|
||||
node = task.node
|
||||
|
||||
controllers = list()
|
||||
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,
|
||||
controllers = self._delete_configuration_no_commit(task)
|
||||
return _commit_to_controllers(task.node, controllers,
|
||||
substep="delete_foreign_config")
|
||||
|
||||
@METRICS.timer('DracRAID.get_logical_disks')
|
||||
@ -1005,18 +1071,18 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
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)
|
||||
self._execute_foreign_drives(task, node)
|
||||
elif node.driver_internal_info['raid_config_substep'] == \
|
||||
'completed':
|
||||
self._complete_raid_cleaning_substep(task, node)
|
||||
self._complete_raid_substep(task, node)
|
||||
else:
|
||||
self._complete_raid_cleaning_substep(task, node)
|
||||
self._complete_raid_substep(task, node)
|
||||
else:
|
||||
self._clear_raid_substep(node)
|
||||
self._clear_raid_config_job_failure(node)
|
||||
self._set_clean_failed(task, config_job)
|
||||
self._set_failed(task, config_job)
|
||||
|
||||
def _execute_cleaning_foreign_drives(self, task, node):
|
||||
def _execute_foreign_drives(self, task, node):
|
||||
controllers = list()
|
||||
jobs_required = False
|
||||
for controller_id in node.driver_internal_info[
|
||||
@ -1034,17 +1100,17 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
if not jobs_required:
|
||||
LOG.info(
|
||||
"No foreign drives detected, so "
|
||||
"resume cleaning")
|
||||
self._complete_raid_cleaning_substep(task, node)
|
||||
"resume %s", "cleaning" if node.clean_step else "deployment")
|
||||
self._complete_raid_substep(task, node)
|
||||
else:
|
||||
_commit_to_controllers(
|
||||
node,
|
||||
controllers,
|
||||
substep='completed')
|
||||
|
||||
def _complete_raid_cleaning_substep(self, task, node):
|
||||
def _complete_raid_substep(self, task, node):
|
||||
self._clear_raid_substep(node)
|
||||
self._resume_cleaning(task)
|
||||
self._resume(task)
|
||||
|
||||
def _clear_raid_substep(self, node):
|
||||
driver_internal_info = node.driver_internal_info
|
||||
@ -1076,7 +1142,7 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
|
||||
def _set_clean_failed(self, task, config_job):
|
||||
def _set_failed(self, task, config_job):
|
||||
LOG.error("RAID configuration job failed for node %(node)s. "
|
||||
"Failed config job: %(config_job_id)s. "
|
||||
"Message: '%(message)s'.",
|
||||
@ -1085,14 +1151,33 @@ class DracWSManRAID(base.RAIDInterface):
|
||||
task.node.last_error = config_job.message
|
||||
task.process_event('fail')
|
||||
|
||||
def _resume_cleaning(self, task):
|
||||
def _resume(self, task):
|
||||
raid_common.update_raid_info(
|
||||
task.node, self.get_logical_disks(task))
|
||||
driver_internal_info = task.node.driver_internal_info
|
||||
driver_internal_info['cleaning_reboot'] = True
|
||||
task.node.driver_internal_info = driver_internal_info
|
||||
task.node.save()
|
||||
manager_utils.notify_conductor_resume_clean(task)
|
||||
if task.node.clean_step:
|
||||
manager_utils.notify_conductor_resume_clean(task)
|
||||
else:
|
||||
manager_utils.notify_conductor_resume_deploy(task)
|
||||
|
||||
def _delete_configuration_no_commit(self, task):
|
||||
"""Delete existing RAID configuration without committing the change.
|
||||
|
||||
:param task: A TaskManager instance.
|
||||
:returns: A set of names of RAID controllers which need RAID changes to
|
||||
be committed.
|
||||
"""
|
||||
node = task.node
|
||||
controllers = list()
|
||||
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 controllers
|
||||
|
||||
|
||||
class DracRAID(DracWSManRAID):
|
||||
|
@ -111,6 +111,25 @@ class DracJobTestCase(test_utils.BaseDracTest):
|
||||
self.assertRaises(exception.DracOperationError,
|
||||
drac_job.validate_job_queue, self.node)
|
||||
|
||||
def test_validate_job_queue_name_prefix(self, mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_jobs.return_value = [self.job]
|
||||
|
||||
drac_job.validate_job_queue(self.node, name_prefix='Fake')
|
||||
|
||||
mock_client.list_jobs.assert_called_once_with(only_unfinished=True)
|
||||
|
||||
def test_validate_job_queue_name_prefix_invalid(self,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
mock_client.list_jobs.return_value = [self.job]
|
||||
|
||||
self.assertRaises(exception.DracOperationError,
|
||||
drac_job.validate_job_queue, self.node,
|
||||
name_prefix='ConfigBIOS')
|
||||
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
|
@ -139,9 +139,8 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid.DracRAID, 'get_logical_disks',
|
||||
spec_set=True, autospec=True)
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_completed_job(
|
||||
self, mock_notify_conductor_resume_clean,
|
||||
def _test__check_node_raid_jobs_with_completed_job(
|
||||
self, mock_notify_conductor_resume,
|
||||
mock_get_logical_disks, mock_get_drac_client):
|
||||
expected_logical_disk = {'size_gb': 558,
|
||||
'raid_level': '1',
|
||||
@ -171,14 +170,29 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
self.node.driver_internal_info['raid_config_job_ids'])
|
||||
self.assertEqual([expected_logical_disk],
|
||||
self.node.raid_config['logical_disks'])
|
||||
mock_notify_conductor_resume_clean.assert_called_once_with(task)
|
||||
mock_notify_conductor_resume.assert_called_once_with(task)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_completed_job_in_clean(
|
||||
self, mock_notify_conductor_resume):
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
self._test__check_node_raid_jobs_with_completed_job(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_deploy')
|
||||
def test__check_node_raid_jobs_with_completed_job_in_deploy(
|
||||
self, mock_notify_conductor_resume):
|
||||
self._test__check_node_raid_jobs_with_completed_job(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
def test__check_node_raid_jobs_with_failed_job(self, mock_get_drac_client):
|
||||
# mock node.driver_internal_info
|
||||
# mock node.driver_internal_info and node.clean_step
|
||||
driver_internal_info = {'raid_config_job_ids': ['42']}
|
||||
self.node.driver_internal_info = driver_internal_info
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
# mock task
|
||||
task = mock.Mock(node=self.node, context=self.context)
|
||||
@ -207,9 +221,8 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid.DracRAID, 'get_logical_disks',
|
||||
spec_set=True, autospec=True)
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_completed_job_already_failed(
|
||||
self, mock_notify_conductor_resume_clean,
|
||||
def _test__check_node_raid_jobs_with_completed_job_already_failed(
|
||||
self, mock_notify_conductor_resume,
|
||||
mock_get_logical_disks, mock_get_drac_client):
|
||||
expected_logical_disk = {'size_gb': 558,
|
||||
'raid_level': '1',
|
||||
@ -242,14 +255,28 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
self.node.driver_internal_info)
|
||||
self.assertNotIn('logical_disks', self.node.raid_config)
|
||||
task.process_event.assert_called_once_with('fail')
|
||||
self.assertFalse(mock_notify_conductor_resume.called)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_completed_job_already_failed_in_clean(
|
||||
self, mock_notify_conductor_resume):
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
self._test__check_node_raid_jobs_with_completed_job_already_failed(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_deploy')
|
||||
def test__check_node_raid_jobs_with_completed_job_already_failed_in_deploy(
|
||||
self, mock_notify_conductor_resume):
|
||||
self._test__check_node_raid_jobs_with_completed_job_already_failed(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid.DracRAID, 'get_logical_disks',
|
||||
spec_set=True, autospec=True)
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_completed(
|
||||
self, mock_notify_conductor_resume_clean,
|
||||
def _test__check_node_raid_jobs_with_multiple_jobs_completed(
|
||||
self, mock_notify_conductor_resume,
|
||||
mock_get_logical_disks, mock_get_drac_client):
|
||||
expected_logical_disk = {'size_gb': 558,
|
||||
'raid_level': '1',
|
||||
@ -282,15 +309,28 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
self.node.driver_internal_info)
|
||||
self.assertEqual([expected_logical_disk],
|
||||
self.node.raid_config['logical_disks'])
|
||||
mock_notify_conductor_resume_clean.assert_called_once_with(task)
|
||||
mock_notify_conductor_resume.assert_called_once_with(task)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_completed_in_clean(
|
||||
self, mock_notify_conductor_resume):
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
self._test__check_node_raid_jobs_with_multiple_jobs_completed(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_deploy')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_completed_in_deploy(
|
||||
self, mock_notify_conductor_resume):
|
||||
self._test__check_node_raid_jobs_with_multiple_jobs_completed(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid.DracRAID, 'get_logical_disks',
|
||||
spec_set=True, autospec=True)
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_failed(
|
||||
self, mock_notify_conductor_resume_clean,
|
||||
def _test__check_node_raid_jobs_with_multiple_jobs_failed(
|
||||
self, mock_notify_conductor_resume,
|
||||
mock_get_logical_disks, mock_get_drac_client):
|
||||
expected_logical_disk = {'size_gb': 558,
|
||||
'raid_level': '1',
|
||||
@ -327,3 +367,18 @@ class DracPeriodicTaskTestCase(db_base.DbTestCase):
|
||||
self.node.driver_internal_info)
|
||||
self.assertNotIn('logical_disks', self.node.raid_config)
|
||||
task.process_event.assert_called_once_with('fail')
|
||||
self.assertFalse(mock_notify_conductor_resume.called)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_clean')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_failed_in_clean(
|
||||
self, mock_notify_conductor_resume):
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
self._test__check_node_raid_jobs_with_multiple_jobs_failed(
|
||||
mock_notify_conductor_resume)
|
||||
|
||||
@mock.patch.object(manager_utils, 'notify_conductor_resume_deploy')
|
||||
def test__check_node_raid_jobs_with_multiple_jobs_failed_in_deploy(
|
||||
self, mock_notify_conductor_resume):
|
||||
self._test__check_node_raid_jobs_with_multiple_jobs_failed(
|
||||
mock_notify_conductor_resume)
|
||||
|
@ -166,7 +166,8 @@ class DracManageVirtualDisksTestCase(test_utils.BaseDracTest):
|
||||
drac_raid.create_virtual_disk(
|
||||
self.node, 'controller', ['disk1', 'disk2'], '1+0', 43008)
|
||||
|
||||
mock_validate_job_queue.assert_called_once_with(self.node)
|
||||
mock_validate_job_queue.assert_called_once_with(
|
||||
self.node, name_prefix='Config:RAID:controller')
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
'controller', ['disk1', 'disk2'], '1+0', 43008, None, None, None)
|
||||
|
||||
@ -182,7 +183,8 @@ class DracManageVirtualDisksTestCase(test_utils.BaseDracTest):
|
||||
self.node, 'controller', ['disk1', 'disk2'], '1+0', 43008,
|
||||
disk_name='name', span_length=3, span_depth=2)
|
||||
|
||||
mock_validate_job_queue.assert_called_once_with(self.node)
|
||||
mock_validate_job_queue.assert_called_once_with(
|
||||
self.node, name_prefix='Config:RAID:controller')
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
'controller', ['disk1', 'disk2'], '1+0', 43008, 'name', 3, 2)
|
||||
|
||||
@ -234,7 +236,8 @@ class DracManageVirtualDisksTestCase(test_utils.BaseDracTest):
|
||||
drac_raid._reset_raid_config(
|
||||
self.node, 'controller')
|
||||
|
||||
mock_validate_job_queue.assert_called_once_with(self.node)
|
||||
mock_validate_job_queue.assert_called_once_with(
|
||||
self.node, name_prefix='Config:RAID:controller')
|
||||
mock_client.reset_raid_config.assert_called_once_with(
|
||||
'controller')
|
||||
|
||||
@ -262,7 +265,8 @@ class DracManageVirtualDisksTestCase(test_utils.BaseDracTest):
|
||||
drac_raid.clear_foreign_config(
|
||||
self.node, 'RAID.Integrated.1-1')
|
||||
|
||||
mock_validate_job_queue.assert_called_once_with(self.node)
|
||||
mock_validate_job_queue.assert_called_once_with(
|
||||
self.node, 'Config:RAID:RAID.Integrated.1-1')
|
||||
mock_client.clear_foreign_config.assert_called_once_with(
|
||||
'RAID.Integrated.1-1')
|
||||
|
||||
@ -499,7 +503,8 @@ class DracCreateRaidConfigurationHelpersTestCase(test_utils.BaseDracTest):
|
||||
'Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1']
|
||||
|
||||
logical_disks = drac_raid._find_configuration(logical_disks,
|
||||
physical_disks)
|
||||
physical_disks,
|
||||
False)
|
||||
|
||||
self.assertEqual(expected_contoller,
|
||||
logical_disks[0]['controller'])
|
||||
@ -525,7 +530,8 @@ class DracCreateRaidConfigurationHelpersTestCase(test_utils.BaseDracTest):
|
||||
'Disk.Bay.6:Enclosure.Internal.0-1:RAID.Integrated.1-1']
|
||||
|
||||
logical_disks = drac_raid._find_configuration(logical_disks,
|
||||
physical_disks)
|
||||
physical_disks,
|
||||
False)
|
||||
|
||||
self.assertEqual(expected_contoller,
|
||||
logical_disks[0]['controller'])
|
||||
@ -553,7 +559,8 @@ class DracCreateRaidConfigurationHelpersTestCase(test_utils.BaseDracTest):
|
||||
physical_disks = self._generate_physical_disks()
|
||||
|
||||
logical_disks = drac_raid._find_configuration(logical_disks,
|
||||
physical_disks)
|
||||
physical_disks,
|
||||
False)
|
||||
|
||||
self.assertEqual(3, len(logical_disks))
|
||||
# step 1
|
||||
@ -591,6 +598,33 @@ class DracCreateRaidConfigurationHelpersTestCase(test_utils.BaseDracTest):
|
||||
'Disk.Bay.3:Enclosure.Internal.0-1:RAID.Integrated.1-1']},
|
||||
logical_disks)
|
||||
|
||||
def test__find_configuration_pending_delete(self):
|
||||
logical_disks = [
|
||||
{'size_mb': 102400,
|
||||
'raid_level': '5',
|
||||
'is_root_volume': True,
|
||||
'disk_type': 'hdd'}
|
||||
]
|
||||
physical_disks = self._generate_physical_disks()
|
||||
# No free space, but deletion pending means they're still usable.
|
||||
physical_disks = [disk._replace(free_size_mb=0)
|
||||
for disk in physical_disks]
|
||||
|
||||
expected_contoller = 'RAID.Integrated.1-1'
|
||||
expected_physical_disk_ids = [
|
||||
'Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1',
|
||||
'Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1',
|
||||
'Disk.Bay.2:Enclosure.Internal.0-1:RAID.Integrated.1-1']
|
||||
|
||||
logical_disks = drac_raid._find_configuration(logical_disks,
|
||||
physical_disks,
|
||||
True)
|
||||
|
||||
self.assertEqual(expected_contoller,
|
||||
logical_disks[0]['controller'])
|
||||
self.assertEqual(expected_physical_disk_ids,
|
||||
logical_disks[0]['physical_disks'])
|
||||
|
||||
|
||||
class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
@ -652,6 +686,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
[self.root_logical_disk] + self.nonroot_logical_disks)
|
||||
self.target_raid_configuration = {'logical_disks': self.logical_disks}
|
||||
self.node.target_raid_config = self.target_raid_configuration
|
||||
self.node.clean_step = {'foo': 'bar'}
|
||||
self.node.save()
|
||||
|
||||
def _generate_physical_disks(self):
|
||||
@ -664,26 +699,43 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', 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)
|
||||
def test_create_configuration(
|
||||
self, mock_commit_config, mock_validate_job_queue,
|
||||
mock_list_physical_disks, mock_get_drac_client):
|
||||
def _test_create_configuration(
|
||||
self, expected_state, mock_commit_config, mock_validate_job_queue,
|
||||
mock_list_physical_disks, mock__reset_raid_config,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
physical_disks = self._generate_physical_disks()
|
||||
mock_list_physical_disks.return_value = physical_disks
|
||||
mock_commit_config.return_value = '42'
|
||||
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}
|
||||
raid_controller = test_utils.make_raid_controller(
|
||||
raid_controller_dict)
|
||||
mock_client.list_raid_controllers.return_value = [raid_controller]
|
||||
mock__reset_raid_config.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
mock_client.create_virtual_disk.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
@ -696,10 +748,19 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
task.node, raid_controller='RAID.Integrated.1-1', reboot=False,
|
||||
realtime=True)
|
||||
|
||||
self.assertEqual(expected_state, return_value)
|
||||
self.node.refresh()
|
||||
self.assertEqual(['42'],
|
||||
self.node.driver_internal_info['raid_config_job_ids'])
|
||||
|
||||
def test_create_configuration_in_clean(self):
|
||||
self._test_create_configuration(states.CLEANWAIT)
|
||||
|
||||
def test_create_configuration_in_deploy(self):
|
||||
self.node.clean_step = None
|
||||
self.node.save()
|
||||
self._test_create_configuration(states.DEPLOYWAIT)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', autospec=True)
|
||||
@ -709,7 +770,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
autospec=True)
|
||||
def test_create_configuration_no_change(
|
||||
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
|
||||
physical_disks = self._generate_physical_disks()
|
||||
@ -721,7 +783,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=False, create_nonroot_volumes=False)
|
||||
task, create_root_volume=False, create_nonroot_volumes=False,
|
||||
delete_existing=False)
|
||||
|
||||
self.assertEqual(0, mock_client.create_virtual_disk.call_count)
|
||||
self.assertEqual(0, mock_commit_config.call_count)
|
||||
@ -731,6 +794,72 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
self.node.refresh()
|
||||
self.assertNotIn('raid_config_job_ids', self.node.driver_internal_info)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_virtual_disks', autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', 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)
|
||||
def test_create_configuration_delete_existing(
|
||||
self, mock_commit_config,
|
||||
mock_validate_job_queue,
|
||||
mock_list_physical_disks,
|
||||
mock_list_virtual_disks,
|
||||
mock__reset_raid_config,
|
||||
mock_get_drac_client):
|
||||
self.node.clean_step = None
|
||||
self.node.save()
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
|
||||
physical_disks = self._generate_physical_disks()
|
||||
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}
|
||||
raid_controller = test_utils.make_raid_controller(
|
||||
raid_controller_dict)
|
||||
mock_list_physical_disks.return_value = physical_disks
|
||||
mock_commit_config.return_value = '42'
|
||||
mock_client.list_raid_controllers.return_value = [raid_controller]
|
||||
mock__reset_raid_config.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
|
||||
mock_client.create_virtual_disk.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True
|
||||
}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=False,
|
||||
delete_existing=True)
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
'RAID.Integrated.1-1',
|
||||
['Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1',
|
||||
'Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1'],
|
||||
'1', 51200, None, 2, 1)
|
||||
mock_commit_config.assert_called_once_with(
|
||||
task.node, raid_controller='RAID.Integrated.1-1',
|
||||
realtime=True, reboot=False)
|
||||
|
||||
self.assertEqual(1, mock_commit_config.call_count)
|
||||
|
||||
self.assertEqual(states.DEPLOYWAIT, return_value)
|
||||
self.node.refresh()
|
||||
self.assertEqual(['42'],
|
||||
self.node.driver_internal_info['raid_config_job_ids'])
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', autospec=True)
|
||||
@ -765,7 +894,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
'RAID.Integrated.1-1',
|
||||
@ -821,7 +951,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_called_once_with(
|
||||
'RAID.Integrated.1-1',
|
||||
@ -873,7 +1004,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
'controller-2',
|
||||
@ -941,7 +1073,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
'RAID.Integrated.1-1',
|
||||
@ -1004,7 +1137,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
@ -1069,7 +1203,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
@ -1162,7 +1297,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
@ -1189,6 +1325,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', autospec=True)
|
||||
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
|
||||
autospec=True)
|
||||
@ -1196,7 +1333,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
autospec=True)
|
||||
def test_create_configuration_fails_with_sharing_disabled(
|
||||
self, mock_commit_config, mock_validate_job_queue,
|
||||
mock_list_physical_disks, mock_get_drac_client):
|
||||
mock_list_physical_disks, mock__reset_raid_config,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
|
||||
@ -1210,7 +1348,18 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
self.physical_disks = self.physical_disks[0:3]
|
||||
physical_disks = self._generate_physical_disks()
|
||||
mock_list_physical_disks.return_value = physical_disks
|
||||
|
||||
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}
|
||||
raid_controller = test_utils.make_raid_controller(
|
||||
raid_controller_dict)
|
||||
mock_client.list_raid_controllers.return_value = [raid_controller]
|
||||
mock_commit_config.return_value = '42'
|
||||
mock_client.create_virtual_disk.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
@ -1262,7 +1411,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
mock_client.create_virtual_disk.assert_has_calls(
|
||||
[mock.call(
|
||||
@ -1332,10 +1482,12 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
self.assertRaises(
|
||||
exception.DracOperationError,
|
||||
task.driver.raid.create_configuration,
|
||||
task, create_root_volume=True, create_nonroot_volumes=True)
|
||||
task, create_root_volume=True, create_nonroot_volumes=True,
|
||||
delete_existing=False)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', autospec=True)
|
||||
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
|
||||
autospec=True)
|
||||
@ -1346,7 +1498,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
def test_create_configuration_fails_if_not_enough_space(
|
||||
self, mock_create_virtual_disk, mock_commit_config,
|
||||
mock_validate_job_queue, mock_list_physical_disks,
|
||||
mock_get_drac_client):
|
||||
mock__reset_raid_config, mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
|
||||
@ -1362,6 +1514,21 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
self.physical_disks = self.physical_disks[0:3]
|
||||
physical_disks = self._generate_physical_disks()
|
||||
mock_list_physical_disks.return_value = physical_disks
|
||||
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}
|
||||
raid_controller = test_utils.make_raid_controller(
|
||||
raid_controller_dict)
|
||||
mock_client.list_raid_controllers.return_value = [raid_controller]
|
||||
mock__reset_raid_config.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
|
||||
mock_commit_config.return_value = '42'
|
||||
mock_create_virtual_disk.return_value = {
|
||||
@ -1377,6 +1544,8 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_physical_disks', autospec=True)
|
||||
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
|
||||
autospec=True)
|
||||
@ -1387,7 +1556,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
def test_create_configuration_fails_if_disk_already_reserved(
|
||||
self, mock_create_virtual_disk, mock_commit_config,
|
||||
mock_validate_job_queue, mock_list_physical_disks,
|
||||
mock_get_drac_client):
|
||||
mock__reset_raid_config, mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
|
||||
@ -1406,7 +1575,24 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
physical_disks = self._generate_physical_disks()
|
||||
mock_list_physical_disks.return_value = physical_disks
|
||||
|
||||
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}
|
||||
raid_controller = test_utils.make_raid_controller(
|
||||
raid_controller_dict)
|
||||
mock_client.list_raid_controllers.return_value = [raid_controller]
|
||||
|
||||
mock_commit_config.return_value = '42'
|
||||
mock__reset_raid_config.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
|
||||
mock_create_virtual_disk.return_value = {
|
||||
'is_reboot_required': constants.RebootRequired.optional,
|
||||
'is_commit_required': True}
|
||||
@ -1420,18 +1606,18 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, '_reset_raid_config', 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, '_reset_raid_config', spec_set=True,
|
||||
autospec=True)
|
||||
def test_delete_configuration(self, mock__reset_raid_config,
|
||||
mock_commit_config,
|
||||
mock_validate_job_queue,
|
||||
mock_list_raid_controllers,
|
||||
mock_get_drac_client):
|
||||
def _test_delete_configuration(self, expected_state,
|
||||
mock_commit_config,
|
||||
mock_validate_job_queue,
|
||||
mock_list_raid_controllers,
|
||||
mock__reset_raid_config,
|
||||
mock_get_drac_client):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_drac_client.return_value = mock_client
|
||||
raid_controller_dict = {
|
||||
@ -1459,11 +1645,19 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
task.node, raid_controller='RAID.Integrated.1-1', reboot=False,
|
||||
realtime=True)
|
||||
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
self.assertEqual(expected_state, return_value)
|
||||
self.node.refresh()
|
||||
self.assertEqual(['42'],
|
||||
self.node.driver_internal_info['raid_config_job_ids'])
|
||||
|
||||
def test_delete_configuration_in_clean(self):
|
||||
self._test_delete_configuration(states.CLEANWAIT)
|
||||
|
||||
def test_delete_configuration_in_deploy(self):
|
||||
self.node.clean_step = None
|
||||
self.node.save()
|
||||
self._test_delete_configuration(states.DEPLOYWAIT)
|
||||
|
||||
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(drac_raid, 'list_raid_controllers', autospec=True)
|
||||
@ -1568,7 +1762,7 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest):
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
return_value = task.driver.raid._execute_cleaning_foreign_drives(
|
||||
return_value = task.driver.raid._execute_foreign_drives(
|
||||
task, self.node)
|
||||
mock_resume.assert_called_once_with(
|
||||
task, 'cleaning', 'continue_node_clean')
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for deploy steps to ``raid`` interface of ``idrac``
|
||||
hardware type. The methods ``apply_configuration`` and
|
||||
``delete_configuration`` can be used as deploy steps.
|
||||
- |
|
||||
Adds a new ``delete_existing`` argument to the ``create_configuration``
|
||||
clean step on the ``idrac`` ``raid`` interface which can be used to
|
||||
delete existing virtual disks. The default for this argument is ``False``.
|
Loading…
x
Reference in New Issue
Block a user