diff --git a/proliantutils/exception.py b/proliantutils/exception.py index 0c455a84..14756c88 100644 --- a/proliantutils/exception.py +++ b/proliantutils/exception.py @@ -80,6 +80,16 @@ class IloCommandNotSupportedInBiosError(IloCommandNotSupportedError): super(IloCommandNotSupportedInBiosError, self).__init__(message) +class IloLogicalDriveNotFoundError(IloError): + """Logical drive not found error. + + This exception is raised when iLO client library unable to find + any logical drive on storage controller + """ + def __init__(self, message, errorcode=None): + super(IloLogicalDriveNotFoundError, self).__init__(message) + + class IloLoginFailError(IloError): """iLO Login Failed. diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index 737e0075..668984b4 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -1,4 +1,4 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. +# Copyright 2018 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -25,6 +25,7 @@ from proliantutils.redfish import redfish SUPPORTED_RIS_METHODS = [ 'activate_license', 'clear_secure_boot_keys', + 'delete_raid_configuration', 'eject_virtual_media', 'get_current_bios_settings', 'get_current_boot_mode', @@ -68,6 +69,7 @@ SUPPORTED_RIS_METHODS = [ ] SUPPORTED_REDFISH_METHODS = [ + 'delete_raid_configuration', 'get_product_name', 'get_host_post_state', 'get_host_power_status', @@ -637,6 +639,15 @@ class IloClient(operations.IloOperations): """ return self._call_method('activate_license', key) + def delete_raid_configuration(self): + """Deletes the logical drives from the system + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + return self._call_method('delete_raid_configuration') + def update_firmware(self, firmware_url, component_type): """Updates the given firmware on the server diff --git a/proliantutils/ilo/operations.py b/proliantutils/ilo/operations.py index 91a0ae15..2b9de2cc 100644 --- a/proliantutils/ilo/operations.py +++ b/proliantutils/ilo/operations.py @@ -445,3 +445,12 @@ class IloOperations(object): on the server. """ raise exception.IloCommandNotSupportedError(ERRMSG) + + def delete_raid_configuration(self): + """Deletes the logical drives from the system + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) diff --git a/proliantutils/ilo/ribcl.py b/proliantutils/ilo/ribcl.py index c861d573..67150c57 100644 --- a/proliantutils/ilo/ribcl.py +++ b/proliantutils/ilo/ribcl.py @@ -1,4 +1,4 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. +# Copyright 2018 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -1209,6 +1209,17 @@ class RIBCLOperations(operations.IloOperations): """ self._raise_command_not_supported("get_host_post_state") + def delete_raid_configuration(self): + """Delete the raid configuration on the hardware. + + Loops through each SmartStorageConfig controller and clears the + raid configuration. + + :raises: IloError, on an error from iLO + :raises: IloCommandNotSupportedError + """ + self._raise_command_not_supported("delete_raid_configuration") + # The below block of code is there only for backward-compatibility # reasons (before commit 47608b6 for ris-support). diff --git a/proliantutils/ilo/ris.py b/proliantutils/ilo/ris.py index 9d5e7055..1cd0ca8a 100755 --- a/proliantutils/ilo/ris.py +++ b/proliantutils/ilo/ris.py @@ -1,4 +1,4 @@ -# Copyright 2017 Hewlett Packard Enterprise Development Company, L.P. +# Copyright 2018 Hewlett Packard Enterprise Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -1974,3 +1974,20 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): return utils.apply_bios_properties_filter( default_settings, constants.SUPPORTED_BIOS_PROPERTIES) return default_settings + + def _raise_command_not_supported(self, method): + platform = self.get_product_name() + msg = ("`%(method)s` is not supported on %(platform)s" % + {'method': method, 'platform': platform}) + raise (exception.IloCommandNotSupportedError(msg)) + + def delete_raid_configuration(self): + """Delete the raid configuration on the hardware. + + Loops through each SmartStorageConfig controller and clears the + raid configuration. + + :raises: IloError, on an error from iLO + :raises: IloCommandNotSupportedError + """ + self._raise_command_not_supported("delete_raid_configuration") diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 0dcbbb48..f897120b 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -1,4 +1,4 @@ -# Copyright 2017 Hewlett Packard Enterprise Development LP +# Copyright 2018 Hewlett Packard Enterprise Development LP # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -1050,3 +1050,8 @@ class RedfishOperations(operations.IloOperations): """ sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) return GET_POST_STATE_MAP.get(sushy_system.post_state) + + def delete_raid_configuration(self): + """Delete the raid configuration on the hardware.""" + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + sushy_system.delete_raid() diff --git a/proliantutils/redfish/resources/system/smart_storage_config.py b/proliantutils/redfish/resources/system/smart_storage_config.py new file mode 100644 index 00000000..5f8be9e1 --- /dev/null +++ b/proliantutils/redfish/resources/system/smart_storage_config.py @@ -0,0 +1,55 @@ +# Copyright 2018 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from proliantutils import exception +from proliantutils import log +from sushy.resources import base + + +LOG = log.get_logger(__name__) + + +class LogicalDriveListField(base.ListField): + volume_unique_identifier = base.Field('VolumeUniqueIdentifier', + required=True) + + +class HPESmartStorageConfig(base.ResourceBase): + """Class that defines the functionality for SmartSorageConfig Resources.""" + + controller_id = base.Field("Id") + + logical_drives = LogicalDriveListField("LogicalDrives", default=[]) + + settings_uri = base.Field(["@Redfish.Settings", + "SettingsObject", "@odata.id"]) + + def delete_raid(self): + """Clears the RAID configuration from the system. + + """ + if not self.logical_drives: + msg = ('No logical drives found on the controller ' + '%(controller)s' % {'controller': str(self.controller_id)}) + LOG.debug(msg) + raise exception.IloLogicalDriveNotFoundError(msg) + + lds = [{ + 'Actions': [{"Action": "LogicalDriveDelete"}], + 'VolumeUniqueIdentifier': + logical_drive.volume_unique_identifier} + for logical_drive in self.logical_drives] + + data = {'LogicalDrives': lds, 'DataGuard': 'Permissive'} + self._conn.put(self.settings_uri, data=data) diff --git a/proliantutils/redfish/resources/system/system.py b/proliantutils/redfish/resources/system/system.py index ecd7b70e..a6b16483 100644 --- a/proliantutils/redfish/resources/system/system.py +++ b/proliantutils/redfish/resources/system/system.py @@ -1,4 +1,4 @@ -# Copyright 2017 Hewlett Packard Enterprise Development LP +# Copyright 2018 Hewlett Packard Enterprise Development LP # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -17,6 +17,7 @@ __author__ = 'HPE' import sushy from sushy.resources import base from sushy.resources.system import system +from sushy import utils as sushy_utils from proliantutils import exception from proliantutils import log @@ -27,6 +28,7 @@ from proliantutils.redfish.resources.system import mappings from proliantutils.redfish.resources.system import memory from proliantutils.redfish.resources.system import pci_device from proliantutils.redfish.resources.system import secure_boot +from proliantutils.redfish.resources.system import smart_storage_config from proliantutils.redfish.resources.system.storage import simple_storage from proliantutils.redfish.resources.system.storage import \ smart_storage as hpe_smart_storage @@ -71,6 +73,11 @@ class HPESystem(system.System): 'Boot', 'UefiTargetBootSourceOverride@Redfish.AllowableValues'], adapter=list)) + + smart_storage_config_identities = base.Field( + ['Oem', 'Hpe', 'SmartStorageConfig'], + adapter=sushy_utils.get_members_identities) + supported_boot_mode = base.MappedField( ['Oem', 'Hpe', 'Bios', 'UefiClass'], mappings.SUPPORTED_BOOT_MODE, default=constants.SUPPORTED_LEGACY_BIOS_ONLY) @@ -323,3 +330,51 @@ class HPESystem(system.System): self._memory.refresh(force=False) return self._memory + + def get_smart_storage_config(self, smart_storage_config_url): + """Returns a SmartStorageConfig Instance for each controller.""" + return (smart_storage_config. + HPESmartStorageConfig(self._conn, smart_storage_config_url, + redfish_version=self.redfish_version)) + + def check_smart_storage_config_ids(self): + """Check SmartStorageConfig controllers is there in hardware. + + :raises: IloError, on an error from iLO. + """ + if self.smart_storage_config_identities is None: + msg = ('The Redfish controller failed to get the ' + 'SmartStorageConfig controller configurations.') + LOG.debug(msg) + raise exception.IloError(msg) + + def delete_raid(self): + """Delete the raid configuration on the hardware. + + Loops through each SmartStorageConfig controller and clears the + raid configuration. + + :raises: IloError, on an error from iLO. + """ + self.check_smart_storage_config_ids() + any_exceptions = [] + ld_exc_count = 0 + for config_id in self.smart_storage_config_identities: + try: + ssc_obj = self.get_smart_storage_config(config_id) + ssc_obj.delete_raid() + except exception.IloLogicalDriveNotFoundError as e: + ld_exc_count += 1 + except sushy.exceptions.SushyError as e: + any_exceptions.append((config_id, str(e))) + + if any_exceptions: + msg = ('The Redfish controller failed to delete the ' + 'raid configuration in one or more controllers with ' + 'Error: %(error)s' % {'error': str(any_exceptions)}) + raise exception.IloError(msg) + + if ld_exc_count == len(self.smart_storage_config_identities): + msg = ('No logical drives are found in any controllers. Nothing ' + 'to delete.') + raise exception.IloLogicalDriveNotFoundError(msg) diff --git a/proliantutils/tests/ilo/test_client.py b/proliantutils/tests/ilo/test_client.py index 6c7f0262..399879c3 100644 --- a/proliantutils/tests/ilo/test_client.py +++ b/proliantutils/tests/ilo/test_client.py @@ -756,6 +756,29 @@ class IloClientTestCase(testtools.TestCase): self.client.activate_license('fake-key') call_mock.assert_called_once_with('activate_license', 'fake-key') + @mock.patch.object(client.IloClient, '_call_method') + def test_delete_raid_configuration(self, call_mock): + self.client.delete_raid_configuration() + call_mock.assert_called_once_with('delete_raid_configuration') + + @mock.patch.object(ris.RISOperations, 'get_product_name') + def test_delete_raid_configuration_gen9(self, get_product_mock): + self.client.model = 'Gen9' + get_product_mock.return_value = 'ProLiant BL460c Gen9' + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + '`delete_raid_configuration` is not supported ' + 'on ProLiant BL460c Gen9', + self.client.delete_raid_configuration) + + @mock.patch.object(ribcl.RIBCLOperations, 'get_product_name') + def test_delete_raid_configuration_gen8(self, get_product_mock): + self.client.model = 'Gen8' + get_product_mock.return_value = 'ProLiant DL380 G8' + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + '`delete_raid_configuration` is not supported ' + 'on ProLiant DL380 G8', + self.client.delete_raid_configuration) + @mock.patch.object(ris.RISOperations, 'eject_virtual_media') def test_eject_virtual_media_gen9(self, eject_virtual_media_mock): self.client.model = 'Gen9' diff --git a/proliantutils/tests/ilo/test_ribcl.py b/proliantutils/tests/ilo/test_ribcl.py index f42741ea..4206245d 100644 --- a/proliantutils/tests/ilo/test_ribcl.py +++ b/proliantutils/tests/ilo/test_ribcl.py @@ -1055,5 +1055,13 @@ class IloRibclTestCaseBeforeRisSupport(unittest.TestCase): 'ProLiant DL380 G7', self.ilo.get_host_post_state) + @mock.patch.object(ribcl.RIBCLOperations, 'get_product_name') + def test_delete_raid_configuration(self, product_name_mock): + product_name_mock.return_value = constants.GET_PRODUCT_NAME + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + 'ProLiant DL380 G7', + self.ilo.delete_raid_configuration) + + if __name__ == '__main__': unittest.main() diff --git a/proliantutils/tests/ilo/test_ris.py b/proliantutils/tests/ilo/test_ris.py index bc9358a4..9566f87a 100755 --- a/proliantutils/tests/ilo/test_ris.py +++ b/proliantutils/tests/ilo/test_ris.py @@ -2551,3 +2551,10 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): ret = self.client._is_raid_supported() self.assertEqual(ret, expt_ret) get_array_mock.assert_called_once_with() + + @mock.patch.object(ris.RISOperations, 'get_product_name') + def test_delete_raid_configuration(self, product_name_mock): + product_name_mock.return_value = 'ProLiant BL460c Gen9' + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + 'ProLiant BL460c Gen9', + self.client.delete_raid_configuration) diff --git a/proliantutils/tests/redfish/json_samples/smart_storage_config.json b/proliantutils/tests/redfish/json_samples/smart_storage_config.json new file mode 100644 index 00000000..41e48ecb --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/smart_storage_config.json @@ -0,0 +1,87 @@ +{ + "@Redfish.Settings": { + "@odata.type": "#Settings.v1_0_0.Settings", + "ETag": "78F92741", + "Messages": [ + { + "MessageId": "SmartStorageMessages.2.0.0.Success" + } + ], + "SettingsObject": { + "@odata.id": "/redfish/v1/systems/1/smartstorageconfig/settings/" + }, + "Time": "2017-10-31T12:12:35+00:00" + }, + "@odata.context": "/redfish/v1/$metadata#SmartStorageConfig.SmartStorageConfig", + "@odata.etag": "W/\"90107B96DAE4060606D29991827C7EF7\"", + "@odata.id": "/redfish/v1/systems/1/smartstorageconfig/", + "@odata.type": "#SmartStorageConfig.v2_0_0.SmartStorageConfig", + "CurrentParallelSurfaceScanCount": null, + "DataGuard": "Strict", + "DegradedPerformanceOptimization": null, + "DriveWriteCache": null, + "ElevatorSort": null, + "EncryptionConfiguration": "None", + "EncryptionEULA": null, + "ExpandPriority": null, + "FlexibleLatencySchedulerSetting": null, + "Id": "smartstorageconfig", + "InconsistencyRepairPolicy": null, + "Location": "Slot 0", + "LocationFormat": "PCISlot", + "LogicalDrives": [ + { + "Accelerator": "ControllerCache", + "BlockSizeBytes": 512, + "CapacityBlocks": 4688319664, + "CapacityGiB": 2235, + "DataDrives": [ + "2I:1:2", + "2I:1:1" + ], + "DriveLocationFormat": "ControllerPort:Box:Bay", + "LegacyBootPriority": "None", + "LogicalDriveName": "01A27294PFJHD0ARCA218H 63E0", + "LogicalDriveNumber": 1, + "ParityGroupCount": 0, + "Raid": "Raid0", + "SpareDrives": [], + "SpareRebuildMode": null, + "StripSizeBytes": 262144, + "StripeSizeBytes": 524288, + "VolumeUniqueIdentifier": "600508B1001C045A9BAAC9F4F49498AE" + } + ], + "MonitorAndPerformanceAnalysisDelaySeconds": null, + "NoBatteryWriteCache": null, + "Oem": { + "Hpe": { + "@odata.type": "#HpeBiosExt.v2_0_0.HpeBiosExt", + "SettingsObject": { + "UnmodifiedETag": "W/\"1BBCED8C1E405050504A92724569294F\"" + } + } + }, + "PhysicalDrives": [ + { + "LegacyBootPriority": "None", + "Location": "1I:1:2", + "LocationFormat": "ControllerPort:Box:Bay" + } + ], + "Ports": [ + { + "OperatingModeAfterReboot": "Mixed", + "PortIndex": 0 + } + ], + "PowerModeAfterReboot": "MaxPerformance", + "PredictiveSpareRebuild": null, + "QueueDepth": null, + "ReadCachePercent": null, + "RebuildPriority": null, + "SurfaceScanAnalysisDelaySeconds": null, + "SurfaceScanAnalysisPriority": null, + "SurvivalPowerMode": "Enabled", + "WriteCacheBypassThresholdKiB": null +} diff --git a/proliantutils/tests/redfish/json_samples/system.json b/proliantutils/tests/redfish/json_samples/system.json index e4d703c6..3f26ae60 100644 --- a/proliantutils/tests/redfish/json_samples/system.json +++ b/proliantutils/tests/redfish/json_samples/system.json @@ -97,6 +97,11 @@ "target": "/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SystemReset/" } }, + "SmartStorageConfig": [ + { + "@odata.id": "/redfish/v1/systems/1/smartstorageconfig/" + } + ], "AggregateHealthStatus": { "AgentlessManagementService": "Unavailable", "BiosOrHardwareHealth": { diff --git a/proliantutils/tests/redfish/resources/system/test_smart_storage_config.py b/proliantutils/tests/redfish/resources/system/test_smart_storage_config.py new file mode 100644 index 00000000..9d58dc21 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/test_smart_storage_config.py @@ -0,0 +1,63 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + +import mock +import testtools + +from proliantutils import exception +from proliantutils.redfish.resources.system import smart_storage_config + + +class HPESmartStorageConfigTestCase(testtools.TestCase): + + def setUp(self): + super(HPESmartStorageConfigTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/smart_storage_config.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.load(f)) + + self.ssc_inst = smart_storage_config.HPESmartStorageConfig( + self.conn, '/redfish/v1/Systems/1/smartstorageconfig', + redfish_version='1.0.2') + + def test_attributes(self): + self.assertEqual('smartstorageconfig', self.ssc_inst.controller_id) + self.assertEqual( + '600508B1001C045A9BAAC9F4F49498AE', + self.ssc_inst.logical_drives[0].volume_unique_identifier) + self.assertEqual("/redfish/v1/systems/1/smartstorageconfig/settings/", + self.ssc_inst.settings_uri) + + def test_delete_raid(self): + settings_uri = "/redfish/v1/systems/1/smartstorageconfig/settings/" + data = { + "LogicalDrives": [{ + "Actions": [{"Action": "LogicalDriveDelete"}], + "VolumeUniqueIdentifier": "600508B1001C045A9BAAC9F4F49498AE"}], + "DataGuard": "Permissive", + } + self.ssc_inst.delete_raid() + self.ssc_inst._conn.put.assert_called_once_with(settings_uri, + data=data) + + def test_delete_raid_logical_drive_not_found(self): + type(self.ssc_inst).logical_drives = mock.PropertyMock( + return_value=[]) + self.assertRaises(exception.IloLogicalDriveNotFoundError, + self.ssc_inst.delete_raid) diff --git a/proliantutils/tests/redfish/resources/system/test_system.py b/proliantutils/tests/redfish/resources/system/test_system.py index 84a5e2d3..2d40c3ea 100644 --- a/proliantutils/tests/redfish/resources/system/test_system.py +++ b/proliantutils/tests/redfish/resources/system/test_system.py @@ -1,4 +1,4 @@ -# Copyright 2017 Hewlett Packard Enterprise Development LP +# Copyright 2018 Hewlett Packard Enterprise Development LP # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -25,6 +25,7 @@ from proliantutils.redfish.resources.system import constants as sys_cons from proliantutils.redfish.resources.system import ethernet_interface from proliantutils.redfish.resources.system import memory from proliantutils.redfish.resources.system import secure_boot +from proliantutils.redfish.resources.system import smart_storage_config from proliantutils.redfish.resources.system.storage import simple_storage from proliantutils.redfish.resources.system.storage import smart_storage from proliantutils.redfish.resources.system.storage import storage @@ -497,3 +498,65 @@ class HPESystemTestCase(testtools.TestCase): def test_get_host_post_state(self): expected = sys_cons.POST_STATE_FINISHEDPOST self.assertEqual(expected, self.sys_inst.post_state) + + @mock.patch.object(smart_storage_config, 'HPESmartStorageConfig', + autospec=True) + def test_get_smart_storage_config(self, mock_ssc): + ssc_element = '/redfish/v1/systems/1/smartstorageconfig/' + ssc_inst = self.sys_inst.get_smart_storage_config(ssc_element) + self.assertIsInstance(ssc_inst, + smart_storage_config.HPESmartStorageConfig. + __class__) + mock_ssc.assert_called_once_with( + self.conn, "/redfish/v1/systems/1/smartstorageconfig/", + redfish_version='1.0.2') + + @mock.patch.object(system.HPESystem, 'get_smart_storage_config') + def test_delete_raid(self, get_smart_storage_config_mock): + config_id = ['/redfish/v1/systems/1/smartstorageconfig/'] + type(self.sys_inst).smart_storage_config_identities = ( + mock.PropertyMock(return_value=config_id)) + self.sys_inst.delete_raid() + get_smart_storage_config_mock.assert_called_once_with(config_id[0]) + (get_smart_storage_config_mock.return_value. + delete_raid.assert_called_once_with()) + + @mock.patch.object(system.HPESystem, 'get_smart_storage_config') + def test_delete_raid_controller_failed(self, + get_smart_storage_config_mock): + config_id = ['/redfish/v1/systems/1/smartstorageconfig/', + '/redfish/v1/systems/1/smartstorageconfig1/', + '/redfish/v1/systems/1/smartstorageconfig2/'] + type(self.sys_inst).smart_storage_config_identities = ( + mock.PropertyMock(return_value=config_id)) + get_smart_storage_config_mock.return_value.delete_raid.side_effect = ( + [None, sushy.exceptions.SushyError, None]) + self.assertRaisesRegex( + exception.IloError, + "The Redfish controller failed to delete the " + "raid configuration in one or more controllers with", + self.sys_inst.delete_raid) + + @mock.patch.object(system.HPESystem, 'get_smart_storage_config') + def test_delete_raid_logical_drive_not_found( + self, get_smart_storage_config_mock): + config_id = ['/redfish/v1/systems/1/smartstorageconfig/', + '/redfish/v1/systems/1/smartstorageconfig1/'] + type(self.sys_inst).smart_storage_config_identities = ( + mock.PropertyMock(return_value=config_id)) + get_smart_storage_config_mock.return_value.delete_raid.side_effect = ( + exception.IloLogicalDriveNotFoundError('No logical drive found')) + self.assertRaisesRegex( + exception.IloError, + "No logical drives are found in any controllers. " + "Nothing to delete.", + self.sys_inst.delete_raid) + + def test_check_smart_storage_config_ids(self): + type(self.sys_inst).smart_storage_config_identities = ( + mock.PropertyMock(return_value=None)) + self.assertRaisesRegex( + exception.IloError, + "The Redfish controller failed to get the SmartStorageConfig " + "controller configurations", + self.sys_inst.check_smart_storage_config_ids) diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index 1b007332..ddfc04f1 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -1454,3 +1454,8 @@ class RedfishOperationsTestCase(testtools.TestCase): type(get_system_mock.return_value).post_state = post_state result = self.rf_client.get_host_post_state() self.assertEqual('PowerOff', result) + + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_delete_raid_configuration(self, get_system_mock): + self.rf_client.delete_raid_configuration() + get_system_mock.return_value.delete_raid.assert_called_once_with()