From ee4dca3a7eb12d87e361889449e46f4d0e122c97 Mon Sep 17 00:00:00 2001 From: Monica Pardhi Date: Tue, 31 Aug 2021 11:43:56 +0000 Subject: [PATCH] Fix for H755 RAID controller from converting to JBOD mode In case of H755 RAID controller, exisiting virtual disks get deleted and moves physical disks into 'ready' state. Moreover, it creates another job to convert each physical disk to 'RAID-0'. This change excludes H755 RAID controller from conversion of physical disks to 'RAID-0' when mode is 'JBOD'. Change-Id: Id6de320c8e8a9ca21fac277718c405c657f58a3a --- dracclient/resources/raid.py | 23 +++- dracclient/tests/test_raid.py | 118 +++++++++++++++--- .../wsman_mocks/controller_view-enum-ok.xml | 49 ++++++++ .../physical_disk_view-enum-ok.xml | 37 ++++++ 4 files changed, 206 insertions(+), 21 deletions(-) diff --git a/dracclient/resources/raid.py b/dracclient/resources/raid.py index 3522158..5c4db13 100644 --- a/dracclient/resources/raid.py +++ b/dracclient/resources/raid.py @@ -911,6 +911,12 @@ class RAIDManagement(object): RAID to JBOD or vice versa. It does this by only converting the disks that are not already in the correct state. + In case of H755 RAID controller, exisiting virtual disks get deleted + and moves physical disks into 'ready' state. Moreover, it creates + another job to convert each physical disk to 'RAID-0'. + Modified change excludes H755 RAID controller from conversion of + physical disks to 'RAID-0' when mode is 'JBOD'. + :param mode: constants.RaidStatus enumeration that indicates the mode to change the disks to. :param controllers_to_physical_disk_ids: Dictionary of controllers and @@ -932,11 +938,12 @@ class RAIDManagement(object): physical_disks = self.list_physical_disks() raid = constants.RaidStatus.raid + jbod = constants.RaidStatus.jbod + all_controllers = self.list_raid_controllers() if not controllers_to_physical_disk_ids: controllers_to_physical_disk_ids = collections.defaultdict(list) - all_controllers = self.list_raid_controllers() for physical_d in physical_disks: # Weed out disks that are not attached to a RAID controller if self.is_raid_controller(physical_d.controller, @@ -946,6 +953,20 @@ class RAIDManagement(object): physical_disk_ids.append(physical_d.id) + '''In case of H755 RAID controller, exisiting virtual disks get deleted + and moves physical disks into 'ready' state. Moreover, it creates + another job to convert each physical disk to RAID-0. + With below change, it excludes the H755 RAID controller from conversion + of physical disks when mode is 'JBOD' + ''' + if mode == jbod: + for cntlr in all_controllers: + if cntlr.model.startswith("PERC H755") and \ + cntlr.id in controllers_to_physical_disk_ids: + LOG.debug("Excluding {} from converting to " + "non-RAID mode".format(cntlr.model)) + del controllers_to_physical_disk_ids[cntlr.id] + '''Modify controllers_to_physical_disk_ids dict by inspecting desired status vs current status of each controller's disks. Raise exception if there are any failed drives or diff --git a/dracclient/tests/test_raid.py b/dracclient/tests/test_raid.py index 0793ca5..baba0c8 100644 --- a/dracclient/tests/test_raid.py +++ b/dracclient/tests/test_raid.py @@ -40,12 +40,15 @@ class ClientRAIDManagementTestCase(base.BaseTest): **test_utils.FAKE_ENDPOINT) self.raid_controller_fqdd = "RAID.Integrated.1-1" self.boss_controller_fqdd = "AHCI.Slot.3-1" + self.h755_controller_fqdd = "RAID.SL.8-1" cntl_dict = {'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'], 'AHCI.Integrated.1-1': ['Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Integrated.1-1', - 'Disk.Bay.1:Enclosure.Internal.0-1:AHCI.Integrated.1-1']} + 'Disk.Bay.1:Enclosure.Internal.0-1:AHCI.Integrated.1-1'], + 'RAID.SL.8-1': + ['Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.8-1']} self.controllers_to_physical_disk_ids = cntl_dict self.disk_1 = raid.PhysicalDisk( id='Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1', @@ -119,6 +122,24 @@ class ClientRAIDManagementTestCase(base.BaseTest): device_protocol=None, bus=None) + self.disk_5 = raid.PhysicalDisk( + id='Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.8-1', + description='Disk 0 in Backplane 1 of Int RAID Controller 1', + controller='RAID.SL.8-1', + manufacturer='ATA', + model='ST91000640NS', + media_type='hdd', + interface_type='sata', + size_mb=953344, + free_size_mb=953344, + serial_number='9XG4SLGZ', + firmware_version='AA09', + status='ok', + raid_status='ready', + sas_address='500056B37789ABE3', + device_protocol=None, + bus=None) + @mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready', spec_set=True, autospec=True) @@ -1226,7 +1247,8 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_check_disks_status_bad(self, mock_requests): mode = constants.RaidStatus.raid disk_2 = self.disk_2._replace(raid_status='FAKE_STATUS') - physical_disks = [self.disk_1, disk_2, self.disk_3, self.disk_4] + physical_disks = [self.disk_1, disk_2, self.disk_3, self.disk_4, + self.disk_5] raid_mgt = self.drac_client._raid_mgmt self.assertRaises(ValueError, @@ -1244,7 +1266,8 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_check_disks_status_fail(self, mock_requests): mode = constants.RaidStatus.raid disk_2_failed = self.disk_2._replace(raid_status='failed') - physical_disks = [self.disk_1, disk_2_failed, self.disk_3, self.disk_4] + physical_disks = [self.disk_1, disk_2_failed, self.disk_3, self.disk_4, + self.disk_5] raid_mgt = self.drac_client._raid_mgmt self.assertRaises(ValueError, @@ -1263,7 +1286,7 @@ class ClientRAIDManagementTestCase(base.BaseTest): raid_mgt = self.drac_client._raid_mgmt mode = constants.RaidStatus.raid physical_disks = [self.disk_1, self.disk_2, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] raid_cntl_to_phys_disk_ids = raid_mgt._check_disks_status( mode, physical_disks, self.controllers_to_physical_disk_ids) @@ -1274,7 +1297,7 @@ class ClientRAIDManagementTestCase(base.BaseTest): disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] jbod_cntl_to_phys_disk_ids = raid_mgt._check_disks_status( mode, physical_disks, self.controllers_to_physical_disk_ids) @@ -1284,7 +1307,8 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_check_disks_status_change_state(self, mock_requests): raid_mgt = self.drac_client._raid_mgmt mode = constants.RaidStatus.jbod - physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4] + physical_disks = [self.disk_1, self.disk_2, self.disk_3, + self.disk_4, self.disk_5] jbod_cntl_to_phys_disk_ids = raid_mgt._check_disks_status( mode, physical_disks, self.controllers_to_physical_disk_ids) @@ -1295,7 +1319,7 @@ class ClientRAIDManagementTestCase(base.BaseTest): disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] raid_cntl_to_phys_disk_ids = raid_mgt._check_disks_status( mode, physical_disks, self.controllers_to_physical_disk_ids) raid_len = len(raid_cntl_to_phys_disk_ids['RAID.Integrated.1-1']) @@ -1305,7 +1329,8 @@ class ClientRAIDManagementTestCase(base.BaseTest): mode = constants.RaidStatus.raid disk_1_bad = self.disk_1._replace(raid_status='FAKE_STATUS') disk_2_failed = self.disk_2._replace(raid_status='failed') - physical_disks = [disk_1_bad, disk_2_failed, self.disk_3, self.disk_4] + physical_disks = [disk_1_bad, disk_2_failed, self.disk_3, + self.disk_4, self.disk_5] raid_mgt = self.drac_client._raid_mgmt self.assertRaises(ValueError, @@ -1343,11 +1368,40 @@ class ClientRAIDManagementTestCase(base.BaseTest): cvt_phys_disks_return_value, 'AHCI.Integrated.1-1': cvt_phys_disks_return_value} + cntl_dict = {'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'], + 'AHCI.Integrated.1-1': + ['Disk.Bay.0:Enclosure.Internal.0-1:AHCI.Integrated.1-1', + 'Disk.Bay.1:Enclosure.Internal.0-1:AHCI.Integrated.1-1']} results = self.drac_client.change_physical_disk_state( - mode, self.controllers_to_physical_disk_ids) + mode, cntl_dict) self.assertEqual(results['conversion_results'], expected_return_value) + @mock.patch.object(dracclient.client.WSManClient, + 'wait_until_idrac_is_ready', spec_set=True, + autospec=True) + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'convert_physical_disks', spec_set=True, + autospec=True) + def test_change_physical_disk_state_jbod_h755( + self, mock_requests, + mock_convert_physical_disks, + wait_until_idrac_is_ready): + mode = constants.RaidStatus.jbod + mock_requests.post( + 'https://1.2.3.4:443/wsman', + text=test_utils.RAIDEnumerations[uris.DCIM_ControllerView]['ok']) + + cntl_dict = {'RAID.SL.8-1': + ['Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.8-1']} + self.drac_client.change_physical_disk_state( + mode, cntl_dict) + + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'list_raid_controllers', spec_set=True, + autospec=True) @mock.patch.object(dracclient.resources.raid.RAIDManagement, 'list_physical_disks', spec_set=True, autospec=True) @@ -1357,12 +1411,14 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_change_physical_disk_state_raid( self, mock_requests, mock_convert_physical_disks, - mock_list_physical_disks): + mock_list_physical_disks, + mock_list_raid_controllers): mode = constants.RaidStatus.raid disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') + disk_5_non_raid = self.disk_5._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, disk_5_non_raid] mock_list_physical_disks.return_value = physical_disks boss_return_value = {'is_commit_required': False, 'is_reboot_required': @@ -1370,24 +1426,34 @@ class ClientRAIDManagementTestCase(base.BaseTest): raid_return_value = {'is_commit_required': True, 'is_reboot_required': constants.RebootRequired.true} + h755_return_value = {'is_commit_required': True, + 'is_reboot_required': + constants.RebootRequired.true} mock_convert_physical_disks.return_value = raid_return_value results = self.drac_client.change_physical_disk_state( mode, self.controllers_to_physical_disk_ids) - self.assertEqual(len(results['conversion_results']), 2) + self.assertEqual(len(results['conversion_results']), 3) self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'], boss_return_value) self.assertEqual(results['conversion_results']['RAID.Integrated.1-1'], raid_return_value) + self.assertEqual(results['conversion_results']['RAID.SL.8-1'], + h755_return_value) + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'list_raid_controllers', spec_set=True, + autospec=True) @mock.patch.object(dracclient.resources.raid.RAIDManagement, 'list_physical_disks', spec_set=True, autospec=True) def test_change_physical_disk_state_none( self, mock_requests, - mock_list_physical_disks): + mock_list_physical_disks, + mock_list_raid_controllers): mode = constants.RaidStatus.raid - physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4] + physical_disks = [self.disk_1, self.disk_2, self.disk_3, self.disk_4, + self.disk_5] mock_list_physical_disks.return_value = physical_disks expected_return_value = {'is_commit_required': False, 'is_reboot_required': @@ -1399,6 +1465,9 @@ class ClientRAIDManagementTestCase(base.BaseTest): self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'], expected_return_value) + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'list_raid_controllers', spec_set=True, + autospec=True) @mock.patch.object(dracclient.resources.raid.RAIDManagement, 'list_physical_disks', spec_set=True, autospec=True) @@ -1410,12 +1479,13 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_change_physical_disk_state_not_supported( self, mock_requests, mock_convert_physical_disks, - mock_list_physical_disks): + mock_list_physical_disks, + mock_list_raid_controllers): mode = constants.RaidStatus.raid disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] mock_list_physical_disks.return_value = physical_disks expected_return_value = {'is_commit_required': False, 'is_reboot_required': @@ -1427,6 +1497,9 @@ class ClientRAIDManagementTestCase(base.BaseTest): self.assertEqual(results['conversion_results']['AHCI.Integrated.1-1'], expected_return_value) + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'list_raid_controllers', spec_set=True, + autospec=True) @mock.patch.object(dracclient.resources.raid.RAIDManagement, 'list_physical_disks', spec_set=True, autospec=True) @@ -1438,12 +1511,13 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_change_physical_disk_state_raise_drac_operation_other( self, mock_requests, mock_convert_physical_disks, - mock_list_physical_disks): + mock_list_physical_disks, + mock_list_raid_controllers): mode = constants.RaidStatus.raid disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] mock_list_physical_disks.return_value = physical_disks self.assertRaisesRegexp( exceptions.DRACOperationFailed, @@ -1452,6 +1526,9 @@ class ClientRAIDManagementTestCase(base.BaseTest): mode, self.controllers_to_physical_disk_ids) + @mock.patch.object(dracclient.resources.raid.RAIDManagement, + 'list_raid_controllers', spec_set=True, + autospec=True) @mock.patch.object(dracclient.resources.raid.RAIDManagement, 'list_physical_disks', spec_set=True, autospec=True) @@ -1462,12 +1539,13 @@ class ClientRAIDManagementTestCase(base.BaseTest): def test_change_physical_disk_state_raise_other( self, mock_requests, mock_convert_physical_disks, - mock_list_physical_disks): + mock_list_physical_disks, + mock_list_raid_controllers): mode = constants.RaidStatus.raid disk_1_non_raid = self.disk_1._replace(raid_status='non-RAID') disk_2_non_raid = self.disk_2._replace(raid_status='non-RAID') physical_disks = [disk_1_non_raid, disk_2_non_raid, - self.disk_3, self.disk_4] + self.disk_3, self.disk_4, self.disk_5] mock_list_physical_disks.return_value = physical_disks self.assertRaisesRegexp( Exception, diff --git a/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml b/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml index 069a0d8..0fa4097 100644 --- a/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml +++ b/dracclient/tests/wsman_mocks/controller_view-enum-ok.xml @@ -93,6 +93,55 @@ 0 0 + + 1 + + 1 + 8192 + 0 + 0 + 0 + 4 + 52.13.2-3661 + 0 + Unknown + DELL + 2 + Unknown + RAID Controller in SL 8 + + 1 + 0 + RAID.SL.8-1 + 0 + RAID.SL.8-1 + + 20210831081620.000000+000 + 20210831081620.000000+000 + + + 10E2 + + 1AE1 + 1028 + 1000 + 1 + 0 + 0 + PERC H755 Front + 0 + 0 + 52CEA7F06A603500 + 1 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 0 + diff --git a/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml b/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml index 791fa59..f960083 100644 --- a/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml +++ b/dracclient/tests/wsman_mocks/physical_disk_view-enum-ok.xml @@ -199,6 +199,43 @@ 0 0 + + 512 + 6 + 0 + Disk 0 in Backplane 1 of Int RAID Controller 1 + 2 + Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.8-1 + 599550590976 + 0 + Disk.Bay.0:Enclosure.Internal.0-1:RAID.SL.8-1 + 20150226180025.000000+000 + 20150226180025.000000+000 + SEAGATE + 2 + 33 + 2014 + 3 + 0 + ST600MM0006 + None + 0 + CN07YX587262248G01MHA02 + 0 + 1 + 1 + 255 + LS0A + 1 + 5000C5007764FF6D + 0 + S0M3EVL6 + 599550590976 + 0 + None + 0 + 0 + 7 3E