diff --git a/ironic/drivers/modules/drac/raid.py b/ironic/drivers/modules/drac/raid.py index a06ecc60de..39eed0d9de 100644 --- a/ironic/drivers/modules/drac/raid.py +++ b/ironic/drivers/modules/drac/raid.py @@ -1190,11 +1190,15 @@ class DracWSManRAID(base.RAIDInterface): 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_foreign_drives(task, node) - elif node.driver_internal_info['raid_config_substep'] == \ - 'completed': + substep = node.driver_internal_info['raid_config_substep'] + + if substep == 'delete_foreign_config': + foreign_drives = self._execute_foreign_drives(task, node) + if foreign_drives is None: + return self._convert_drives(task, node) + elif substep == 'physical_disk_conversion': + self._convert_drives(task, node) + elif substep == 'completed': self._complete_raid_substep(task, node) else: self._complete_raid_substep(task, node) @@ -1222,17 +1226,27 @@ class DracWSManRAID(base.RAIDInterface): LOG.info( "No foreign drives detected, so " "resume %s", "cleaning" if node.clean_step else "deployment") - self._complete_raid_substep(task, node) + return None else: - _commit_to_controllers( + return _commit_to_controllers( node, controllers, - substep='completed') + substep='physical_disk_conversion') def _complete_raid_substep(self, task, node): self._clear_raid_substep(node) self._resume(task) + def _convert_drives(self, task, node): + jbod = drac_constants.RaidStatus.jbod + drives_results = _change_physical_disk_mode( + node, mode=jbod) + if drives_results is None: + LOG.debug("Controller does not support drives " + "conversion on %(node_uuid)s", + {'node_uuid': node.uuid}) + self._complete_raid_substep(task, node) + def _clear_raid_substep(self, node): driver_internal_info = node.driver_internal_info driver_internal_info.pop('raid_config_substep', None) diff --git a/ironic/tests/unit/drivers/modules/drac/test_raid.py b/ironic/tests/unit/drivers/modules/drac/test_raid.py index 3e0309d22b..b8abba3860 100644 --- a/ironic/tests/unit/drivers/modules/drac/test_raid.py +++ b/ironic/tests/unit/drivers/modules/drac/test_raid.py @@ -22,7 +22,6 @@ 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 @@ -2021,39 +2020,19 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest): @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): + def test__execute_foreign_drives_with_no_foreign_drives( + self, mock_validate_job_queue, + mock_clear_foreign_config, + 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'] + raid_config_substep = 'clear_foreign_config' 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 @@ -2068,11 +2047,52 @@ class DracRaidInterfaceTestCase(test_utils.BaseDracTest): shared=False) as task: return_value = task.driver.raid._execute_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) + self.assertIsNone(None, return_value) + + @mock.patch.object(drac_common, 'get_drac_client', spec_set=True, + autospec=True) + @mock.patch.object(drac_raid, 'clear_foreign_config', spec_set=True, + 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__execute_foreign_drives_with_foreign_drives( + self, mock_commit_config, + mock_validate_job_queue, + mock_clear_foreign_config, + mock_get_drac_client): + mock_client = mock.Mock() + mock_get_drac_client.return_value = mock_client + + raid_config_params = ['RAID.Integrated.1-1'] + raid_config_substep = 'clear_foreign_config' + 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.optional, + 'is_commit_required': True + } + mock_commit_config.return_value = '42' + + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + return_value = task.driver.raid._execute_foreign_drives( + task, self.node) + + self.assertEqual(states.CLEANWAIT, return_value) + + self.assertEqual(['42'], + self.node.driver_internal_info['raid_config_job_ids']) + self.assertEqual('physical_disk_conversion', + self.node.driver_internal_info['raid_config_substep']) + self.assertEqual( + ['RAID.Integrated.1-1'], + self.node.driver_internal_info['raid_config_parameters']) + mock_commit_config.assert_called_once_with( + self.node, raid_controller='RAID.Integrated.1-1', reboot=False, + realtime=True) diff --git a/releasenotes/notes/idrac-drives-conversion-raid-to-jbod-de10755d1ec094ea.yaml b/releasenotes/notes/idrac-drives-conversion-raid-to-jbod-de10755d1ec094ea.yaml new file mode 100644 index 0000000000..868721518f --- /dev/null +++ b/releasenotes/notes/idrac-drives-conversion-raid-to-jbod-de10755d1ec094ea.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Hardware type ``idrac`` converts physical drives from + ``RAID`` to ``JBOD`` mode after RAID ``delete_configuration`` + cleaning step through raid interface. This ensures that the + individual disks freed by deleting the virtual disks + are visible to the OS. \ No newline at end of file