From 0d9b4ac66266aae809bc7f33cc2727f10901c753 Mon Sep 17 00:00:00 2001 From: kesper Date: Tue, 7 Jul 2020 07:37:51 +0000 Subject: [PATCH] Adds support for one button secure erase This commit will add support for one button secure erase for iLO5 server. Change-Id: I71203fa0c500c45d7bc7729c6ad418c11695f1f5 --- proliantutils/ilo/client.py | 15 +++++++ proliantutils/ilo/operations.py | 14 ++++++ proliantutils/redfish/redfish.py | 13 ++++++ .../redfish/resources/system/system.py | 44 ++++++++++++++++++ proliantutils/tests/ilo/test_client.py | 23 ++++++++++ .../tests/redfish/json_samples/system.json | 3 ++ .../redfish/resources/system/test_system.py | 45 +++++++++++++++++++ proliantutils/tests/redfish/test_redfish.py | 6 +++ 8 files changed, 163 insertions(+) diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index 24930a38..204ed1a5 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -79,6 +79,7 @@ SUPPORTED_REDFISH_METHODS = [ 'create_raid_configuration', 'delete_raid_configuration', 'do_disk_erase', + 'do_one_button_secure_erase', 'has_disk_erase_completed', 'get_product_name', 'get_host_post_state', @@ -874,6 +875,20 @@ class IloClient(operations.IloOperations): """ return self._call_method('do_disk_erase', disk_type, pattern) + def do_one_button_secure_erase(self): + """Perform the one button secure erase on the hardware. + + The One-button secure erase process resets iLO and deletes all licenses + stored there, resets BIOS settings, and deletes all AHS and warranty + data stored on the system. It also erases supported non-volatile + storage data and deletes any deployment settings profiles. + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + return self._call_method('do_one_button_secure_erase') + def get_available_disk_types(self): """Get the list of all disk type available in server diff --git a/proliantutils/ilo/operations.py b/proliantutils/ilo/operations.py index 25e0c6ad..7d3963cf 100644 --- a/proliantutils/ilo/operations.py +++ b/proliantutils/ilo/operations.py @@ -524,6 +524,20 @@ class IloOperations(object): """ raise exception.IloCommandNotSupportedError(ERRMSG) + def do_one_button_secure_erase(self): + """Perform the one button secure erase on the hardware. + + The One-button secure erase process resets iLO and deletes all licenses + stored there, resets BIOS settings, and deletes all AHS and warranty + data stored on the system. It also erases supported non-volatile + storage data and deletes any deployment settings profiles. + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) + def get_available_disk_types(self): """Get the list of all disk type available in server diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 7d22189e..d5241b72 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -1115,6 +1115,19 @@ class RedfishOperations(operations.IloOperations): sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) return sushy_system.has_disk_erase_completed() + def do_one_button_secure_erase(self): + """Perform the one button secure erase on the hardware. + + The One-button secure erase process resets iLO and deletes all licenses + stored there, resets BIOS settings, and deletes all AHS and warranty + data stored on the system. It also erases supported non-volatile + storage data and deletes any deployment settings profiles. + + :raises: IloError, on an error from iLO. + """ + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + sushy_system.do_one_button_secure_erase() + def get_current_bios_settings(self, only_allowed_settings=False): """Get current BIOS settings. diff --git a/proliantutils/redfish/resources/system/system.py b/proliantutils/redfish/resources/system/system.py index 6c70c926..e8fa66a9 100644 --- a/proliantutils/redfish/resources/system/system.py +++ b/proliantutils/redfish/resources/system/system.py @@ -60,10 +60,18 @@ class PowerButtonActionField(base.CompositeField): target_uri = base.Field('target', required=True) +class OneButtonSecureEraseActionField(base.CompositeField): + target_uri = base.Field('target', required=True) + + class HpeActionsField(base.CompositeField): computer_system_ext_powerbutton = ( PowerButtonActionField('#HpeComputerSystemExt.PowerButton')) + computer_system_ext_one_button_secure_erase = ( + OneButtonSecureEraseActionField( + '#HpeComputerSystemExt.SecureSystemErase')) + class HPESystem(system.System): """Class that extends the functionality of System resource class @@ -105,6 +113,42 @@ class HPESystem(system.System): return push_action + def _get_hpe_one_button_secure_erase_action_element(self): + one_button_secure_erase_action = ( + self._hpe_actions.computer_system_ext_one_button_secure_erase) + if not one_button_secure_erase_action: + raise exception.MissingAttributeError( + attribute=( + 'Oem/Hpe/Actions/#HpeComputerSystemExt.SecureSystemErase'), + resource=self.path) + + return one_button_secure_erase_action + + def do_one_button_secure_erase(self): + """Perform the one button secure erase on the hardware. + + The One-button secure erase process resets iLO and deletes all licenses + stored there, resets BIOS settings, and deletes all AHS and warranty + data stored on the system. It also erases supported non-volatile + storage data and deletes any deployment settings profiles. + + :raises: IloError, on an error from iLO. + """ + try: + target_uri = ( + self._get_hpe_one_button_secure_erase_action_element(). + target_uri) + data = { + "SystemROMAndiLOErase": True, + "UserDataErase": True + } + self._conn.post(target_uri, data=data) + except sushy.exceptions.SushyError as e: + msg = ("The Redfish controller failed to perform one button " + "secure erase operation on the hardware. Error: %(error)s" + % {'error': str(e)}) + raise exception.IloError(msg) + def push_power_button(self, target_value): """Reset the system in hpe exclusive manner. diff --git a/proliantutils/tests/ilo/test_client.py b/proliantutils/tests/ilo/test_client.py index 8ff69b78..b047dad8 100644 --- a/proliantutils/tests/ilo/test_client.py +++ b/proliantutils/tests/ilo/test_client.py @@ -940,6 +940,29 @@ class IloClientTestCase(testtools.TestCase): self.client.do_disk_erase, 'SSD', None) + @mock.patch.object(client.IloClient.cls, '_call_method') + def test_do_one_button_secure_erase(self, call_mock): + self.client.do_one_button_secure_erase() + self.assertTrue(call_mock.called) + + @mock.patch.object(ris.RISOperations, 'get_product_name') + def test_do_one_button_secure_erase_gen9(self, get_product_mock): + self.client.model = 'Gen9' + get_product_mock.return_value = 'ProLiant BL460c Gen9' + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + 'The specified operation is not supported ' + 'on current platform.', + self.client.do_one_button_secure_erase) + + @mock.patch.object(ribcl.RIBCLOperations, 'get_product_name') + def test_do_one_button_secure_erase_gen8(self, get_product_mock): + self.client.model = 'Gen8' + get_product_mock.return_value = 'ProLiant DL380 G8' + self.assertRaisesRegexp(exception.IloCommandNotSupportedError, + 'The specified operation is not supported ' + 'on current platform.', + self.client.do_one_button_secure_erase) + @mock.patch.object(client.IloClient.cls, '_call_method') def test_has_disk_erase_completed(self, call_mock): self.client.has_disk_erase_completed() diff --git a/proliantutils/tests/redfish/json_samples/system.json b/proliantutils/tests/redfish/json_samples/system.json index 3f26ae60..60fa9934 100644 --- a/proliantutils/tests/redfish/json_samples/system.json +++ b/proliantutils/tests/redfish/json_samples/system.json @@ -95,6 +95,9 @@ "ColdBoot" ], "target": "/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SystemReset/" + }, + "#HpeComputerSystemExt.SecureSystemErase": { + "target": "/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SecureSystemErase" } }, "SmartStorageConfig": [ diff --git a/proliantutils/tests/redfish/resources/system/test_system.py b/proliantutils/tests/redfish/resources/system/test_system.py index bc372e9b..01219223 100644 --- a/proliantutils/tests/redfish/resources/system/test_system.py +++ b/proliantutils/tests/redfish/resources/system/test_system.py @@ -53,6 +53,22 @@ class HPESystemTestCase(testtools.TestCase): self.assertEqual(sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI, self.sys_inst.supported_boot_mode) + def test__get_hpe_one_button_secure_erase_action_element(self): + value = self.sys_inst._get_hpe_one_button_secure_erase_action_element() + self.assertEqual("/redfish/v1/Systems/1/Actions/Oem/Hpe/" + "HpeComputerSystemExt.SecureSystemErase", + value.target_uri) + + def test__get_hpe_one_button_secure_erase_action_element_missing_action( + self): + (self.sys_inst._hpe_actions. + computer_system_ext_one_button_secure_erase) = None + self.assertRaisesRegex( + exception.MissingAttributeError, + 'Oem/Hpe/Actions/#HpeComputerSystemExt.SecureSystemErase is ' + 'missing', + self.sys_inst._get_hpe_one_button_secure_erase_action_element) + def test__get_hpe_push_power_button_action_element(self): value = self.sys_inst._get_hpe_push_power_button_action_element() self.assertEqual("/redfish/v1/Systems/1/Actions/Oem/Hpe/" @@ -885,6 +901,35 @@ class HPESystemTestCase(testtools.TestCase): "erase. Error:", self.sys_inst.has_disk_erase_completed) + @mock.patch.object(system.HPESystem, + '_get_hpe_one_button_secure_erase_action_element') + def test_do_one_button_secure_erase( + self, secure_erase_action_mock): + target_uri = ( + '/redfish/v1/Systems/1/Actions/Oem/Hpe/' + '#HpeComputerSystemExt.SecureSystemErase') + data = { + "SystemROMAndiLOErase": True, + "UserDataErase": True} + type(secure_erase_action_mock.return_value).target_uri = target_uri + self.sys_inst.do_one_button_secure_erase() + self.sys_inst._conn.post.assert_called_once_with(target_uri, data=data) + + @mock.patch.object(system.HPESystem, + '_get_hpe_one_button_secure_erase_action_element') + def test_do_one_button_secure_erase_failed( + self, secure_erase_action_mock): + target_uri = ( + '/redfish/v1/Systems/1/Actions/Oem/Hpe/' + '#HpeComputerSystemExt.SecureSystemErase') + type(secure_erase_action_mock.return_value).target_uri = target_uri + self.sys_inst._conn.post.side_effect = sushy.exceptions.SushyError + self.assertRaisesRegexp( + exception.IloError, + "The Redfish controller failed to perform one button " + "secure erase operation on the hardware. Error:", + self.sys_inst.do_one_button_secure_erase) + @mock.patch.object(system.HPESystem, '_get_drives_has_raid') @mock.patch.object(array_controller.HPEArrayControllerCollection, diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index ac8ba086..bd592c3e 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -1798,6 +1798,12 @@ class RedfishOperationsTestCase(testtools.TestCase): result = self.rf_client.get_host_post_state() self.assertEqual('PowerOff', result) + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_do_one_button_secure_erase(self, get_system_mock): + self.rf_client.do_one_button_secure_erase() + (get_system_mock.return_value. + do_one_button_secure_erase.assert_called_once()) + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') def test_do_disk_erase_hdd(self, get_system_mock): self.rf_client.do_disk_erase('HDD')