From 6857a6d000f7e61af872fd782092d5f4341d5f31 Mon Sep 17 00:00:00 2001 From: mpardhi23 Date: Wed, 10 Apr 2019 12:20:38 -0400 Subject: [PATCH] Implement ResetConfig and ClearForeignConfig functionality For raid deletion, existing delete_virtual_disk functionality is not freeing up foreign drives and spares, so have added ResetConfig and ClearForeignConfig functionality for freeing up foreign drives and spares. Change-Id: I76390dc4fcf8de2fe5aa3d660f77edcef4a4dec1 --- dracclient/client.py | 44 ++++++++++++ dracclient/resources/raid.py | 68 ++++++++++++++++++ dracclient/tests/test_raid.py | 71 +++++++++++++++++++ dracclient/tests/utils.py | 12 ++++ ...vice-invoke-clear_foreign_config-error.xml | 17 +++++ ...service-invoke-clear_foreign_config-ok.xml | 16 +++++ ...rvice-invoke-delete_virtual_disk-error.xml | 2 +- ..._service-invoke-delete_virtual_disk-ok.xml | 2 +- ...service-invoke-reset_raid_config-error.xml | 17 +++++ ...id_service-invoke-reset_raid_config-ok.xml | 16 +++++ 10 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-error.xml create mode 100644 dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml create mode 100644 dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml create mode 100644 dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml diff --git a/dracclient/client.py b/dracclient/client.py index aac18ca..3995420 100644 --- a/dracclient/client.py +++ b/dracclient/client.py @@ -768,6 +768,50 @@ class DRACClient(object): """ return self._raid_mgmt.delete_virtual_disk(virtual_disk) + def reset_raid_config(self, raid_controller): + """Delete all the virtual disks and unassign all hot spare physical disks + + The job to reset the RAID controller config will be in pending state. + For the changes to be applied, a config job must be created. + + :param raid_controller: id of the RAID controller + :returns: a dictionary containing: + - The is_commit_required key with the value always set to + True indicating that a config job must be created to + reset configuration. + - The is_reboot_required key with a RebootRequired enumerated + value indicating whether the server must be rebooted to + reset configuration. + :raises: WSManRequestFailure on request failures + :raises: WSManInvalidResponse when receiving invalid response + :raises: DRACOperationFailed on error reported back by the DRAC + interface + :raises: DRACUnexpectedReturnValue on return value mismatch + """ + return self._raid_mgmt.reset_raid_config(raid_controller) + + def clear_foreign_config(self, raid_controller): + """Free up foreign drives + + The job to clear foreign config will be in pending state. + For the changes to be applied, a config job must be created. + + :param raid_controller: id of the RAID controller + :returns: a dictionary containing: + - The is_commit_required key with the value always set to + True indicating that a config job must be created to + clear foreign configuration. + - The is_reboot_required key with a RebootRequired enumerated + value indicating whether the server must be rebooted to + clear foreign configuration. + :raises: WSManRequestFailure on request failures + :raises: WSManInvalidResponse when receiving invalid response + :raises: DRACOperationFailed on error reported back by the DRAC + interface + :raises: DRACUnexpectedReturnValue on return value mismatch + """ + return self._raid_mgmt.clear_foreign_config(raid_controller) + def commit_pending_raid_changes(self, raid_controller, reboot=False, start_time='TIME_NOW', realtime=False): """Applies all pending changes on a RAID controller diff --git a/dracclient/resources/raid.py b/dracclient/resources/raid.py index 669e4b1..743b9be 100644 --- a/dracclient/resources/raid.py +++ b/dracclient/resources/raid.py @@ -721,3 +721,71 @@ class RAIDManagement(object): return True return False + + def reset_raid_config(self, raid_controller): + """Delete all virtual disk and unassign all hotspares + + The job to reset the RAID controller config will be in pending state. + For the changes to be applied, a config job must be created. + + :param raid_controller: id of the RAID controller + :returns: a dictionary containing: + - The is_commit_required key with the value always set to + True indicating that a config job must be created to + reset configuration. + - The is_reboot_required key with a RebootRequired enumerated + value indicating whether the server must be rebooted to + reset configuration. + :raises: WSManRequestFailure on request failures + :raises: WSManInvalidResponse when receiving invalid response + :raises: DRACOperationFailed on error reported back by the DRAC + interface + :raises: DRACUnexpectedReturnValue on return value mismatch + """ + + selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem', + 'CreationClassName': 'DCIM_RAIDService', + 'SystemName': 'DCIM:ComputerSystem', + 'Name': 'DCIM:RAIDService'} + properties = {'Target': raid_controller} + + doc = self.client.invoke(uris.DCIM_RAIDService, 'ResetConfig', + selectors, properties, + expected_return_value=utils.RET_SUCCESS) + + return utils.build_return_dict(doc, uris.DCIM_RAIDService, + is_commit_required_value=True) + + def clear_foreign_config(self, raid_controller): + """Free up foreign drives + + The job to clear foreign config will be in pending state. + For the changes to be applied, a config job must be created. + + :param raid_controller: id of the RAID controller + :returns: a dictionary containing: + - The is_commit_required key with the value always set to + True indicating that a config job must be created to + clear foreign configuration. + - The is_reboot_required key with a RebootRequired enumerated + value indicating whether the server must be rebooted to + clear foreign configuration. + :raises: WSManRequestFailure on request failures + :raises: WSManInvalidResponse when receiving invalid response + :raises: DRACOperationFailed on error reported back by the DRAC + interface + :raises: DRACUnexpectedReturnValue on return value mismatch + """ + + selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem', + 'CreationClassName': 'DCIM_RAIDService', + 'SystemName': 'DCIM:ComputerSystem', + 'Name': 'DCIM:RAIDService'} + properties = {'Target': raid_controller} + + doc = self.client.invoke(uris.DCIM_RAIDService, 'ClearForeignConfig', + selectors, properties, + expected_return_value=utils.RET_SUCCESS) + + return utils.build_return_dict(doc, uris.DCIM_RAIDService, + is_commit_required_value=True) diff --git a/dracclient/tests/test_raid.py b/dracclient/tests/test_raid.py index c52851c..dcbfcbd 100644 --- a/dracclient/tests/test_raid.py +++ b/dracclient/tests/test_raid.py @@ -586,6 +586,77 @@ class ClientRAIDManagementTestCase(base.BaseTest): exceptions.DRACOperationFailed, self.drac_client.delete_virtual_disk, 'disk1') + @mock.patch.object(dracclient.client.WSManClient, 'invoke', + spec_set=True, autospec=True) + def test_reset_raid_config(self, mock_requests, mock_invoke): + expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem', + 'CreationClassName': 'DCIM_RAIDService', + 'SystemName': 'DCIM:ComputerSystem', + 'Name': 'DCIM:RAIDService'} + expected_properties = {'Target': self.raid_controller_fqdd} + mock_invoke.return_value = lxml.etree.fromstring( + test_utils.RAIDInvocations[uris.DCIM_RAIDService][ + 'ResetConfig']['ok']) + result = self.drac_client.reset_raid_config(self.raid_controller_fqdd) + self.assertEqual({'is_commit_required': True, + 'is_reboot_required': + constants.RebootRequired.optional}, + result) + mock_invoke.assert_called_once_with( + mock.ANY, uris.DCIM_RAIDService, 'ResetConfig', + expected_selectors, expected_properties, + expected_return_value=utils.RET_SUCCESS) + + @mock.patch.object(dracclient.client.WSManClient, + 'wait_until_idrac_is_ready', spec_set=True, + autospec=True) + def test_reset_raid_config_fail(self, mock_requests, + mock_wait_until_idrac_is_ready): + mock_requests.post( + 'https://1.2.3.4:443/wsman', + text=test_utils.RAIDInvocations[ + uris.DCIM_RAIDService]['ResetConfig']['error']) + + self.assertRaises( + exceptions.DRACOperationFailed, + self.drac_client.reset_raid_config, self.raid_controller_fqdd) + + @mock.patch.object(dracclient.client.WSManClient, 'invoke', + spec_set=True, autospec=True) + def test_clear_foreign_config(self, mock_requests, mock_invoke): + expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem', + 'CreationClassName': 'DCIM_RAIDService', + 'SystemName': 'DCIM:ComputerSystem', + 'Name': 'DCIM:RAIDService'} + expected_properties = {'Target': self.raid_controller_fqdd} + mock_invoke.return_value = lxml.etree.fromstring( + test_utils.RAIDInvocations[uris.DCIM_RAIDService][ + 'ClearForeignConfig']['ok']) + result = self.drac_client.clear_foreign_config( + self.raid_controller_fqdd) + self.assertEqual({'is_commit_required': True, + 'is_reboot_required': + constants.RebootRequired.optional}, + result) + mock_invoke.assert_called_once_with( + mock.ANY, uris.DCIM_RAIDService, 'ClearForeignConfig', + expected_selectors, expected_properties, + expected_return_value=utils.RET_SUCCESS) + + @mock.patch.object(dracclient.client.WSManClient, + 'wait_until_idrac_is_ready', spec_set=True, + autospec=True) + def test_clear_foreign_config_fail(self, mock_requests, + mock_wait_until_idrac_is_ready): + mock_requests.post( + 'https://1.2.3.4:443/wsman', + text=test_utils.RAIDInvocations[ + uris.DCIM_RAIDService]['ClearForeignConfig']['error']) + + self.assertRaises( + exceptions.DRACOperationFailed, + self.drac_client.clear_foreign_config, self.raid_controller_fqdd) + @mock.patch.object(dracclient.resources.job.JobManagement, 'create_config_job', spec_set=True, autospec=True) def test_commit_pending_raid_changes(self, mock_requests, diff --git a/dracclient/tests/utils.py b/dracclient/tests/utils.py index 0336119..136c190 100644 --- a/dracclient/tests/utils.py +++ b/dracclient/tests/utils.py @@ -253,6 +253,18 @@ RAIDInvocations = { 'raid_service-invoke-convert_physical_disks-ok'), 'error': load_wsman_xml( 'raid_service-invoke-convert_physical_disks-error'), + }, + 'ResetConfig': { + 'ok': load_wsman_xml( + 'raid_service-invoke-reset_raid_config-ok'), + 'error': load_wsman_xml( + 'raid_service-invoke-reset_raid_config-error'), + }, + 'ClearForeignConfig': { + 'ok': load_wsman_xml( + 'raid_service-invoke-clear_foreign_config-ok'), + 'error': load_wsman_xml( + 'raid_service-invoke-clear_foreign_config-error'), } } } diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-error.xml new file mode 100644 index 0000000..59494a5 --- /dev/null +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-error.xml @@ -0,0 +1,17 @@ + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse + uuid:f9487fcf-103a-103a-8002-fd0aa2bdb228 + uuid:000852e6-1040-1040-8997-a36fc6fe83b0 + + + + >No foreign drives detected + STOR018 + 2 + + + diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml new file mode 100644 index 0000000..dc303c5 --- /dev/null +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-clear_foreign_config-ok.xml @@ -0,0 +1,16 @@ + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ClearForeignConfigResponse + uuid:fefa06de-103a-103a-8002-fd0aa2bdb228 + uuid:05bc00f4-1040-1040-899d-a36fc6fe83b0 + + + + OPTIONAL + 0 + + + diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml index c964a6b..37d5da2 100644 --- a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-error.xml @@ -14,4 +14,4 @@ 2 - \ No newline at end of file + diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml index 0b3eff2..b1035c3 100644 --- a/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-delete_virtual_disk-ok.xml @@ -13,4 +13,4 @@ 0 - \ No newline at end of file + diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml new file mode 100644 index 0000000..cad10be --- /dev/null +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-error.xml @@ -0,0 +1,17 @@ + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ResetConfigResponse + uuid:f9487fcf-103a-103a-8002-fd0aa2bdb228 + uuid:000852e6-1040-1040-8997-a36fc6fe83b0 + + + + Virtual Disk not found + STOR028 + 2 + + + diff --git a/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml new file mode 100644 index 0000000..867f54a --- /dev/null +++ b/dracclient/tests/wsman_mocks/raid_service-invoke-reset_raid_config-ok.xml @@ -0,0 +1,16 @@ + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ResetConfigResponse + uuid:fefa06de-103a-103a-8002-fd0aa2bdb228 + uuid:05bc00f4-1040-1040-899d-a36fc6fe83b0 + + + + OPTIONAL + 0 + + +