From 1311f924b361bbe30b0b7940ed6771acff68653d Mon Sep 17 00:00:00 2001 From: alisha-k-kalladassery Date: Thu, 19 Jan 2023 14:36:43 +0530 Subject: [PATCH 1/6] Firmware Update for SH without profile-Module/Example/Testcase --- examples/server_hardware.py | 24 ++++++++++++++ .../resources/servers/server_hardware.py | 31 +++++++++++++++++++ .../resources/servers/test_server_hardware.py | 23 ++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/examples/server_hardware.py b/examples/server_hardware.py index 4b81fb656..cb2a942d7 100644 --- a/examples/server_hardware.py +++ b/examples/server_hardware.py @@ -146,6 +146,30 @@ server_power = server.update_power_state(configuration) print("Successfully changed the power state of server '{name}' to '{powerState}'".format(**server_power)) +# Perform a firmware update on server +# Firmware update can only be done on server hardware(Gen10 and later) with no server profile assigned, and server hardware +# should be in powered off state +compliance_configuration = { + "firmwareBaselineId": config['server_hardware']['firmware_baseline_id'], + "serverUUID": server.data['uuid'] +} +firmware_update_configuration = [ + { "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/" + config['server_hardware']['firmware_baseline_id'], + "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} + } +] +if server: + if server.data['state'] == 'NoProfileApplied': + if server.data['powerState'] == 'Off': + firmware_compliance = server.check_firmware_compliance(compliance_configuration) + if firmware_compliance['serverFirmwareUpdateRequired']: + print("Updating firmware for the server hardware..") + server.perform_firmware_update(firmware_update_configuration) + else: + print("No Firmware Update required for the server") + else: + print("Firmware Update can be done on Server Hardware with no profile attached.") + # Refresh server state configuration = { "refreshState": "RefreshPending" diff --git a/hpeOneView/resources/servers/server_hardware.py b/hpeOneView/resources/servers/server_hardware.py index e888acad4..0fa5ed5cf 100644 --- a/hpeOneView/resources/servers/server_hardware.py +++ b/hpeOneView/resources/servers/server_hardware.py @@ -326,3 +326,34 @@ def get_local_storage(self, ip=None): uri = "{}?ip={}".format(uri, ip) return self._helper.do_get(uri) + + def check_firmware_compliance(self, configuration, timeout=-1, custom_headers=None): + """ + Checks the firmware compliance of a server with the selected firmware baseline. + Returns the compliance status of each individual component as well as the overall + firmware compliance status of the server. + + Args: + configuration: Firmware Compliance Configuration + + Returns: + Resource + """ + uri = "{}/firmware-compliance".format(self.URI) + return self._helper.do_post(uri, configuration, timeout=timeout, custom_headers=custom_headers) + + @ensure_resource_client + def perform_firmware_update(self, configuration, timeout=-1, custom_headers=None): + """ + Performs a specific patch operation on the firmware settings for the given server. + If the server supports the particular operation, the operation is performed and a response is + returned to the caller with the results. + + Args: + configuration: Firmware Update Configuration + + Returns: + Updated Resource + """ + uri = uri = "{}/firmware/settings".format(self.data["uri"]) + return self.patch_request(uri, configuration, timeout=timeout, custom_headers=custom_headers) diff --git a/tests/unit/resources/servers/test_server_hardware.py b/tests/unit/resources/servers/test_server_hardware.py index 38aea7d0c..b0692d8f6 100644 --- a/tests/unit/resources/servers/test_server_hardware.py +++ b/tests/unit/resources/servers/test_server_hardware.py @@ -281,3 +281,26 @@ def test_get_local_storage_with_ip(self, mock_get): self._server_hardware.get_local_storage(ip='172.16.8.4') mock_get.assert_called_once_with(uri_rest_call) + + @mock.patch.object(ResourceHelper, 'do_post') + def test_check_firmware_compliance(self, mock_post): + self._server_hardware.check_firmware_compliance(configuration={"firmwareBaselineId": "abcd-1234-defg", + "serverUUID": "1234567-8901"}) + + mock_post.assert_called_once_with('/rest/server-hardware/firmware-compliance', {"firmwareBaselineId": "abcd-1234-defg", + "serverUUID": "1234567-8901"}, timeout=-1, custom_headers=None ) + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_called_once(self, mock_patch): + uri_rest_call= '{}/firmware/settings'.format(self.uri) + self._server_hardware.perform_firmware_update([ + { "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} + }]) + + mock_patch.assert_called_once_with(uri_rest_call, + [{ "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} + }], + custom_headers=None, + timeout=-1) From fb0983b27b1be15fa3c56efdebb62c1f02a51924 Mon Sep 17 00:00:00 2001 From: alisha-k-kalladassery Date: Fri, 27 Jan 2023 09:36:39 +0530 Subject: [PATCH 2/6] Sanity Fix --- examples/server_hardware.py | 8 +++----- hpeOneView/resources/servers/server_hardware.py | 2 +- .../resources/servers/test_server_hardware.py | 17 ++++++++--------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/examples/server_hardware.py b/examples/server_hardware.py index cb2a942d7..448dfdcc2 100644 --- a/examples/server_hardware.py +++ b/examples/server_hardware.py @@ -153,11 +153,9 @@ "firmwareBaselineId": config['server_hardware']['firmware_baseline_id'], "serverUUID": server.data['uuid'] } -firmware_update_configuration = [ - { "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/" + config['server_hardware']['firmware_baseline_id'], - "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} - } -] +firmware_update_configuration = [{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/" + config['server_hardware']['firmware_baseline_id'], + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }] if server: if server.data['state'] == 'NoProfileApplied': if server.data['powerState'] == 'Off': diff --git a/hpeOneView/resources/servers/server_hardware.py b/hpeOneView/resources/servers/server_hardware.py index 0fa5ed5cf..f6cbe66bb 100644 --- a/hpeOneView/resources/servers/server_hardware.py +++ b/hpeOneView/resources/servers/server_hardware.py @@ -355,5 +355,5 @@ def perform_firmware_update(self, configuration, timeout=-1, custom_headers=None Returns: Updated Resource """ - uri = uri = "{}/firmware/settings".format(self.data["uri"]) + uri = "{}/firmware/settings".format(self.data["uri"]) return self.patch_request(uri, configuration, timeout=timeout, custom_headers=custom_headers) diff --git a/tests/unit/resources/servers/test_server_hardware.py b/tests/unit/resources/servers/test_server_hardware.py index b0692d8f6..0f49b278f 100644 --- a/tests/unit/resources/servers/test_server_hardware.py +++ b/tests/unit/resources/servers/test_server_hardware.py @@ -288,19 +288,18 @@ def test_check_firmware_compliance(self, mock_post): "serverUUID": "1234567-8901"}) mock_post.assert_called_once_with('/rest/server-hardware/firmware-compliance', {"firmwareBaselineId": "abcd-1234-defg", - "serverUUID": "1234567-8901"}, timeout=-1, custom_headers=None ) + "serverUUID": "1234567-8901"}, timeout=-1, custom_headers=None) @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_called_once(self, mock_patch): - uri_rest_call= '{}/firmware/settings'.format(self.uri) - self._server_hardware.perform_firmware_update([ - { "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} - }]) + uri_rest_call = '{}/firmware/settings'.format(self.uri) + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) mock_patch.assert_called_once_with(uri_rest_call, - [{ "op": "replace", "value": {"baselineUri":"/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType":"FirmwareOnlyOfflineMode", "installationPolicy":"LowerThanBaseline"} - }], + [{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }], custom_headers=None, timeout=-1) From d02ac2493650f3034fd4bb589dcbe350223cbaf0 Mon Sep 17 00:00:00 2001 From: nabhajit-ray Date: Wed, 1 Feb 2023 16:58:18 +0530 Subject: [PATCH 3/6] Firmware Update Changes --- examples/server_hardware.py | 14 +--- .../resources/servers/server_hardware.py | 43 ++++++++++- .../resources/servers/test_server_hardware.py | 75 +++++++++++++++++++ 3 files changed, 121 insertions(+), 11 deletions(-) diff --git a/examples/server_hardware.py b/examples/server_hardware.py index 448dfdcc2..49f7293a3 100644 --- a/examples/server_hardware.py +++ b/examples/server_hardware.py @@ -157,16 +157,10 @@ "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} }] if server: - if server.data['state'] == 'NoProfileApplied': - if server.data['powerState'] == 'Off': - firmware_compliance = server.check_firmware_compliance(compliance_configuration) - if firmware_compliance['serverFirmwareUpdateRequired']: - print("Updating firmware for the server hardware..") - server.perform_firmware_update(firmware_update_configuration) - else: - print("No Firmware Update required for the server") - else: - print("Firmware Update can be done on Server Hardware with no profile attached.") + firmware_compliance = server.check_firmware_compliance(compliance_configuration) + if firmware_compliance['serverFirmwareUpdateRequired']: + print("Updating firmware for the server hardware..") + server.perform_firmware_update(firmware_update_configuration) # Refresh server state configuration = { diff --git a/hpeOneView/resources/servers/server_hardware.py b/hpeOneView/resources/servers/server_hardware.py index f6cbe66bb..572bb2b0a 100644 --- a/hpeOneView/resources/servers/server_hardware.py +++ b/hpeOneView/resources/servers/server_hardware.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import re from future import standard_library @@ -28,6 +29,12 @@ from hpeOneView.resources.resource import (Resource, ResourceUtilizationMixin, ResourcePatchMixin, ensure_resource_client) +SERVER_HARWARE_BELOW_GEN10 = 'Server Hardware generation is below Gen10' +SERVER_PROFILE_ATTACHED = 'Server Hardware has a Profile attached' +SERVER_POWERED_ON = 'Server Hardware is in Powered On state' +ONGOING_FIRMWARE_UPDATE = 'Server Hardware is undergoing a firmware update' +ILO_ADVANCED_LICENSE_REQUIRED = 'Requires an HPE iLO Advanced license for monitored hardware' + class ServerHardware(ResourcePatchMixin, ResourceUtilizationMixin, Resource): """ @@ -342,6 +349,39 @@ def check_firmware_compliance(self, configuration, timeout=-1, custom_headers=No uri = "{}/firmware-compliance".format(self.URI) return self._helper.do_post(uri, configuration, timeout=timeout, custom_headers=custom_headers) + @ensure_resource_client + def validate_server_hardware_for_firmware_update(self): + """ + Performs a validation for the prerequisites before firmware update. + Checks if the server hardware is in powered off state, No server profile attached to server + hardware, server hardware model is Gen10 or above, server hardware has advanced ilo license type. + + """ + state = self.data["state"] + server_profile_uri = self.data["serverProfileUri"] + power_state = self.data["powerState"] + generation = self.data["mpModel"] + license_type = self.data["mpLicenseType"] + + validation_error_list = [] + + matches = re.findall("\d+$", generation) + if int(matches[0]) < 5: + validation_error_list.append(SERVER_HARWARE_BELOW_GEN10) + if server_profile_uri: + validation_error_list.append(SERVER_PROFILE_ATTACHED) + if state == "UpdatingFirmware": + validation_error_list.append(ONGOING_FIRMWARE_UPDATE) + if power_state != "Off": + validation_error_list.append(SERVER_POWERED_ON) + if license_type != "iLO Advanced": + validation_error_list.append(ILO_ADVANCED_LICENSE_REQUIRED) + + if len(validation_error_list) > 0: + raise ValueError(validation_error_list) + else: + return True + @ensure_resource_client def perform_firmware_update(self, configuration, timeout=-1, custom_headers=None): """ @@ -356,4 +396,5 @@ def perform_firmware_update(self, configuration, timeout=-1, custom_headers=None Updated Resource """ uri = "{}/firmware/settings".format(self.data["uri"]) - return self.patch_request(uri, configuration, timeout=timeout, custom_headers=custom_headers) + if self.validate_server_hardware_for_firmware_update(): + return self.patch_request(uri, configuration, timeout=timeout, custom_headers=custom_headers) diff --git a/tests/unit/resources/servers/test_server_hardware.py b/tests/unit/resources/servers/test_server_hardware.py index 0f49b278f..52a6d9aa8 100644 --- a/tests/unit/resources/servers/test_server_hardware.py +++ b/tests/unit/resources/servers/test_server_hardware.py @@ -293,6 +293,7 @@ def test_check_firmware_compliance(self, mock_post): @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_called_once(self, mock_patch): uri_rest_call = '{}/firmware/settings'.format(self.uri) + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} }]) @@ -303,3 +304,77 @@ def test_perform_firmware_update_called_once(self, mock_patch): }], custom_headers=None, timeout=-1) + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_with_sh_powered_on_should_error(self, mock_patch): + uri_rest_call = '{}/firmware/settings'.format(self.uri) + expected_error_list = ['Server Hardware is in Powered On state'] + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "On", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + + try: + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) + except ValueError as e: + self.assertEqual(expected_error_list, e.args[0]) + else: + self.fail("Expected error not raised") + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_with_profile_attached_should_error(self, mock_patch): + uri_rest_call = '{}/firmware/settings'.format(self.uri) + expected_error_list = ["Server Hardware has a Profile attached"] + self._server_hardware.data = {"uri": self.uri, "state": "ProfileApplied", "serverProfileUri": "some_uri", "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + + try: + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) + except ValueError as e: + self.assertEqual(expected_error_list, e.args[0]) + else: + self.fail("Expected error not raised") + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_with_server_below_gen10_should_error(self, mock_patch): + uri_rest_call = '{}/firmware/settings'.format(self.uri) + expected_error_list = ["Server Hardware generation is below Gen10"] + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO4", "mpLicenseType": "iLO Advanced"} + + try: + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) + except ValueError as e: + self.assertEqual(expected_error_list, e.args[0]) + else: + self.fail("Expected error not raised") + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_with_an_ongoing_update_profile_attached_should_error(self, mock_patch): + uri_rest_call = '{}/firmware/settings'.format(self.uri) + expected_error_list = ["Server Hardware has a Profile attached", "Server Hardware is undergoing a firmware update"] + self._server_hardware.data = {"uri": self.uri, "state": "UpdatingFirmware", "powerState": "Off", "serverProfileUri": "some_uri", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + + try: + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) + except ValueError as e: + self.assertEqual(expected_error_list, e.args[0]) + else: + self.fail("Expected error not raised") + + @mock.patch.object(ResourcePatchMixin, 'patch_request') + def test_perform_firmware_update_with_no_ilo_advanced_license_should_error(self, mock_patch): + uri_rest_call = '{}/firmware/settings'.format(self.uri) + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileAttached", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO"} + expected_error_list = ["Requires an HPE iLO Advanced license for monitored hardware"] + try: + self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }]) + except ValueError as e: + self.assertEqual(expected_error_list, e.args[0]) + else: + self.fail("Expected error not raised") \ No newline at end of file From f65070311d12d1e28fc4440c577b0c6f8d9841a7 Mon Sep 17 00:00:00 2001 From: nabhajit-ray Date: Wed, 1 Feb 2023 18:07:20 +0530 Subject: [PATCH 4/6] Flake8 Fixes --- examples/certificate_rabbitmq.py | 4 +- examples/licenses.py | 2 +- examples/migration/migrate.py | 4 +- examples/roles.py | 6 +-- hpeOneView/connection.py | 2 +- .../resources/servers/test_server_hardware.py | 50 +++++++++++-------- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/examples/certificate_rabbitmq.py b/examples/certificate_rabbitmq.py index 49ed75b27..5a67d582a 100644 --- a/examples/certificate_rabbitmq.py +++ b/examples/certificate_rabbitmq.py @@ -52,7 +52,7 @@ response = oneview_client.certificate_rabbitmq.generate(certificate_ca_signed_client) pprint(response) except HPEOneViewException as e: - print (e.msg) + print(e.msg) if e.oneview_response: print(e.oneview_response.get('recommendedActions')) @@ -63,7 +63,7 @@ response = oneview_client.certificate_rabbitmq.generate(certificate_self_signed_client) pprint(response) except HPEOneViewException as e: - print (e.msg) + print(e.msg) if e.oneview_response: print(e.oneview_response.get('recommendedActions')) diff --git a/examples/licenses.py b/examples/licenses.py index f58fb6f65..cf4755671 100644 --- a/examples/licenses.py +++ b/examples/licenses.py @@ -59,7 +59,7 @@ pprint(license) # Delete License by ID -print ("\n\n ********** Delete the license by ID: **********") +print("\n\n ********** Delete the license by ID: **********") print(uri) oneview_client.licenses.delete(uri) try: diff --git a/examples/migration/migrate.py b/examples/migration/migrate.py index 6b40c6638..0a95b077a 100644 --- a/examples/migration/migrate.py +++ b/examples/migration/migrate.py @@ -102,7 +102,7 @@ def get_secure_headers(self): if self._secure_header['Auth'] is None: raise Exception('Auth token for the header is undefined. No Session ID available. Status: {0}.'.format(r.status_code)) return self._secure_header - except ValueError as e: + except ValueError: raise Exception('Failure to get a JSON value from the response. Status: {0}.'.format(r.status_code)) except KeyError: raise Exception('Failure to access the sessionID from the response. Status: {0}. JSON: {1}'.format(r.status_code, r.json())) @@ -224,7 +224,7 @@ def poll_for_task(self, calling_url, response): else: logging.debug("Exception during get call, response was not set") logging.debug("Unable to get the task tree for {0}".format(full_rest_url)) - return(task_state, task_status) + return (task_state, task_status) except ValueError as e: raise Exception('Error getting the JSON results from the task. Originating request on URL: {0}. Exception: {1}'.format(calling_url, e)) except Exception as e: diff --git a/examples/roles.py b/examples/roles.py index f093a8b61..d4cda071c 100644 --- a/examples/roles.py +++ b/examples/roles.py @@ -32,14 +32,14 @@ oneview_client = OneViewClient(config) -print ('Get role by name:') +print('Get role by name:') role = oneview_client.roles.get('Infrastructure administrator') pprint(role) -print ('\nGet role by URI:') +print('\nGet role by URI:') role = oneview_client.roles.get('/rest/roles/Infrastructure administrator') pprint(role) -print ('\nGet all roles:') +print('\nGet all roles:') roles = oneview_client.roles.get_all() pprint(roles) diff --git a/hpeOneView/connection.py b/hpeOneView/connection.py index a6777aa05..cfb53b953 100644 --- a/hpeOneView/connection.py +++ b/hpeOneView/connection.py @@ -455,7 +455,7 @@ def login(self, cred, sessionID=None, verbose=False): if self._validateVersion is False: self.validateVersion() except Exception: - raise(HPEOneViewException('Failure during login attempt.\n %s' % traceback.format_exc())) + raise (HPEOneViewException('Failure during login attempt.\n %s' % traceback.format_exc())) cred['loginMsgAck'] = True # This will handle the login acknowledgement message self._cred = cred diff --git a/tests/unit/resources/servers/test_server_hardware.py b/tests/unit/resources/servers/test_server_hardware.py index 52a6d9aa8..8c917347e 100644 --- a/tests/unit/resources/servers/test_server_hardware.py +++ b/tests/unit/resources/servers/test_server_hardware.py @@ -293,7 +293,8 @@ def test_check_firmware_compliance(self, mock_post): @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_called_once(self, mock_patch): uri_rest_call = '{}/firmware/settings'.format(self.uri) - self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, + "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} }]) @@ -307,14 +308,15 @@ def test_perform_firmware_update_called_once(self, mock_patch): @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_with_sh_powered_on_should_error(self, mock_patch): - uri_rest_call = '{}/firmware/settings'.format(self.uri) expected_error_list = ['Server Hardware is in Powered On state'] - self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "On", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, + "powerState": "On", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} try: self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }]) + "firmwareInstallType": "FirmwareOnlyOfflineMode", + "installationPolicy": "LowerThanBaseline"} + }]) except ValueError as e: self.assertEqual(expected_error_list, e.args[0]) else: @@ -322,14 +324,15 @@ def test_perform_firmware_update_with_sh_powered_on_should_error(self, mock_patc @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_with_profile_attached_should_error(self, mock_patch): - uri_rest_call = '{}/firmware/settings'.format(self.uri) expected_error_list = ["Server Hardware has a Profile attached"] - self._server_hardware.data = {"uri": self.uri, "state": "ProfileApplied", "serverProfileUri": "some_uri", "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + self._server_hardware.data = {"uri": self.uri, "state": "ProfileApplied", "serverProfileUri": "some_uri", + "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} try: self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }]) + "firmwareInstallType": "FirmwareOnlyOfflineMode", + "installationPolicy": "LowerThanBaseline"} + }]) except ValueError as e: self.assertEqual(expected_error_list, e.args[0]) else: @@ -337,14 +340,15 @@ def test_perform_firmware_update_with_profile_attached_should_error(self, mock_p @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_with_server_below_gen10_should_error(self, mock_patch): - uri_rest_call = '{}/firmware/settings'.format(self.uri) expected_error_list = ["Server Hardware generation is below Gen10"] - self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO4", "mpLicenseType": "iLO Advanced"} + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileApplied", "serverProfileUri": None, + "powerState": "Off", "mpModel": "iLO4", "mpLicenseType": "iLO Advanced"} try: self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }]) + "firmwareInstallType": "FirmwareOnlyOfflineMode", + "installationPolicy": "LowerThanBaseline"} + }]) except ValueError as e: self.assertEqual(expected_error_list, e.args[0]) else: @@ -352,14 +356,15 @@ def test_perform_firmware_update_with_server_below_gen10_should_error(self, mock @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_with_an_ongoing_update_profile_attached_should_error(self, mock_patch): - uri_rest_call = '{}/firmware/settings'.format(self.uri) expected_error_list = ["Server Hardware has a Profile attached", "Server Hardware is undergoing a firmware update"] - self._server_hardware.data = {"uri": self.uri, "state": "UpdatingFirmware", "powerState": "Off", "serverProfileUri": "some_uri", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} + self._server_hardware.data = {"uri": self.uri, "state": "UpdatingFirmware", "powerState": "Off", + "serverProfileUri": "some_uri", "mpModel": "iLO5", "mpLicenseType": "iLO Advanced"} try: self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }]) + "firmwareInstallType": "FirmwareOnlyOfflineMode", + "installationPolicy": "LowerThanBaseline"} + }]) except ValueError as e: self.assertEqual(expected_error_list, e.args[0]) else: @@ -367,14 +372,15 @@ def test_perform_firmware_update_with_an_ongoing_update_profile_attached_should_ @mock.patch.object(ResourcePatchMixin, 'patch_request') def test_perform_firmware_update_with_no_ilo_advanced_license_should_error(self, mock_patch): - uri_rest_call = '{}/firmware/settings'.format(self.uri) - self._server_hardware.data = {"uri": self.uri, "state": "NoProfileAttached", "serverProfileUri": None, "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO"} + self._server_hardware.data = {"uri": self.uri, "state": "NoProfileAttached", "serverProfileUri": None, + "powerState": "Off", "mpModel": "iLO5", "mpLicenseType": "iLO"} expected_error_list = ["Requires an HPE iLO Advanced license for monitored hardware"] try: self._server_hardware.perform_firmware_update([{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/sdsdfsdf", - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }]) + "firmwareInstallType": "FirmwareOnlyOfflineMode", + "installationPolicy": "LowerThanBaseline"} + }]) except ValueError as e: self.assertEqual(expected_error_list, e.args[0]) else: - self.fail("Expected error not raised") \ No newline at end of file + self.fail("Expected error not raised") From f6c5b529971e7ebfad29a2536b34aa2e41eedbb6 Mon Sep 17 00:00:00 2001 From: Alisha K Date: Fri, 10 Feb 2023 15:08:25 +0530 Subject: [PATCH 5/6] Endpoint Support Example separation for firmware update --- endpoints-support.md | 2 + examples/server_hardware.py | 16 ----- examples/server_hardware_firmware_update.py | 80 +++++++++++++++++++++ 3 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 examples/server_hardware_firmware_update.py diff --git a/endpoints-support.md b/endpoints-support.md index b9c11b31a..3a35ca48c 100755 --- a/endpoints-support.md +++ b/endpoints-support.md @@ -369,6 +369,8 @@ | /rest/server-hardware/{id}/firmware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | /rest/server-hardware/discovery | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | /rest/server-hardware/{id}/localStorageV2 | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| +| /rest/server-hardware/firmware-compliance | POST | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| +| /rest/server-hardware/{id}/firmware/settings | PATCH | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| | **Server Hardware Types** | | /rest/server-hardware-types | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | /rest/server-hardware-types/{id} | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| diff --git a/examples/server_hardware.py b/examples/server_hardware.py index 49f7293a3..4b81fb656 100644 --- a/examples/server_hardware.py +++ b/examples/server_hardware.py @@ -146,22 +146,6 @@ server_power = server.update_power_state(configuration) print("Successfully changed the power state of server '{name}' to '{powerState}'".format(**server_power)) -# Perform a firmware update on server -# Firmware update can only be done on server hardware(Gen10 and later) with no server profile assigned, and server hardware -# should be in powered off state -compliance_configuration = { - "firmwareBaselineId": config['server_hardware']['firmware_baseline_id'], - "serverUUID": server.data['uuid'] -} -firmware_update_configuration = [{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/" + config['server_hardware']['firmware_baseline_id'], - "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} - }] -if server: - firmware_compliance = server.check_firmware_compliance(compliance_configuration) - if firmware_compliance['serverFirmwareUpdateRequired']: - print("Updating firmware for the server hardware..") - server.perform_firmware_update(firmware_update_configuration) - # Refresh server state configuration = { "refreshState": "RefreshPending" diff --git a/examples/server_hardware_firmware_update.py b/examples/server_hardware_firmware_update.py new file mode 100644 index 000000000..18e5cfab9 --- /dev/null +++ b/examples/server_hardware_firmware_update.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +### +# (C) Copyright [2023] 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 hpeOneView.oneview_client import OneViewClient +from config_loader import try_load_from_file + +config = { + "ip": "", + "credentials": { + "userName": "", + "password": "" + } +} + +# Try load config from a file (if there is a config file) +config = try_load_from_file(config) + +variant = 'Synergy' +options = { + "hostname": config['server_hostname'], + "username": config['server_username'], + "password": config['server_password'], + "licensingIntent": "OneView", + "configurationState": "Managed" +} + +oneview_client = OneViewClient(config) +server_hardwares = oneview_client.server_hardware + +# Get list of all server hardware resources +servers = [] +print("Get list of all server hardware resources") +server_hardware_all = server_hardwares.get_all() +for serv in server_hardware_all: + print(' %s' % serv['name']) + servers.append(serv['name']) + +# Get recently added server hardware resource by name +if server_hardware_all: + server = server_hardwares.get_by_name(servers[0]) + print(server.data) + +# Request power operation to change the power state of the physical server. +configuration = { + "powerState": "Off", + "powerControl": "MomentaryPress" +} +if server: + server_power = server.update_power_state(configuration) + print("Successfully changed the power state of server '{name}' to '{powerState}'".format(**server_power)) + +# Perform a firmware update on server +# Firmware update can only be done on server hardware(Gen10 and later) with no server profile assigned, and server hardware +# should be in powered off state +compliance_configuration = { + "firmwareBaselineId": config['server_hardware']['firmware_baseline_id'], + "serverUUID": server.data['uuid'] +} +firmware_update_configuration = [{"op": "replace", "value": {"baselineUri": "/rest/firmware-drivers/" + config['server_hardware']['firmware_baseline_id'], + "firmwareInstallType": "FirmwareOnlyOfflineMode", "installationPolicy": "LowerThanBaseline"} + }] +if server: + firmware_compliance = server.check_firmware_compliance(compliance_configuration) + if firmware_compliance['serverFirmwareUpdateRequired']: + print("Updating firmware for the server hardware..") + server.perform_firmware_update(firmware_update_configuration) From cab021270eb0a68eddaaa6c5d9556f6a5a05105d Mon Sep 17 00:00:00 2001 From: Alisha K Date: Fri, 10 Feb 2023 15:19:10 +0530 Subject: [PATCH 6/6] Endpoint Support update --- endpoints-support.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/endpoints-support.md b/endpoints-support.md index 3a35ca48c..59fc3f917 100755 --- a/endpoints-support.md +++ b/endpoints-support.md @@ -349,28 +349,28 @@ | /rest/scopes/{id} | DELETE | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | /rest/scopes/{id} | PATCH | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | **Server Hardware** | -| /rest/server-hardware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id} | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id} | DELETE | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: | -| /rest/server-hardware/{id}/bios | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/environmentalConfiguration | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/environmentalConfiguration | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/iloSsoUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/javaRemoteConsoleUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/mpFirmwareVersion | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/physicalServerHardware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/powerState | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/refreshState | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/remoteConsoleUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/utilization | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id} | PATCH | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/*/firmware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/firmware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/discovery | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/{id}/localStorageV2 | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| -| /rest/server-hardware/firmware-compliance | POST | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| -| /rest/server-hardware/{id}/firmware/settings | PATCH | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| +| /rest/server-hardware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id} | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id} | DELETE | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign: | :heavy_minus_sign: | +| /rest/server-hardware/{id}/bios | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/environmentalConfiguration | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/environmentalConfiguration | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/iloSsoUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/javaRemoteConsoleUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/mpFirmwareVersion | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/physicalServerHardware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/powerState | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/refreshState | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/remoteConsoleUrl | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/utilization | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id} | PATCH | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/*/firmware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/firmware | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/discovery | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/{id}/localStorageV2 | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|:white_check_mark: | +| /rest/server-hardware/firmware-compliance | POST | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| :heavy_minus_sign: | +| /rest/server-hardware/{id}/firmware/settings | PATCH | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |:heavy_minus_sign:|:heavy_minus_sign: |:heavy_minus_sign: |:heavy_minus_sign:| :heavy_minus_sign: | | **Server Hardware Types** | | /rest/server-hardware-types | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:| | /rest/server-hardware-types/{id} | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark:|:white_check_mark: |:white_check_mark: |:white_check_mark:|