From 21549e746d5b80ffee884da20ba3086db0dddfb0 Mon Sep 17 00:00:00 2001 From: vmud213 Date: Wed, 27 Jun 2018 12:34:36 +0530 Subject: [PATCH] iLO RIS: Add support to manage BIOS settings Adds support to get current BIOS settings, default BIOS settings and pending BIOS settings for Gen 9 systems. Also provides support to update the BIOS configuration with the provided configuration. Change-Id: I5f8ed4e5c0ee4abf472b261846829d877522258e --- proliantutils/ilo/client.py | 72 ++++ proliantutils/ilo/constants.py | 29 ++ proliantutils/ilo/operations.py | 64 ++++ proliantutils/ilo/ris.py | 124 +++++++ proliantutils/tests/ilo/ris_sample_outputs.py | 316 ++++++++++++++++++ proliantutils/tests/ilo/test_client.py | 29 ++ proliantutils/tests/ilo/test_ris.py | 247 ++++++++++++++ proliantutils/tests/test_utils.py | 75 +++++ proliantutils/utils.py | 13 + 9 files changed, 969 insertions(+) diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index 883b2238..737e0075 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -26,12 +26,15 @@ SUPPORTED_RIS_METHODS = [ 'activate_license', 'clear_secure_boot_keys', 'eject_virtual_media', + 'get_current_bios_settings', 'get_current_boot_mode', 'get_host_post_state', + 'get_default_bios_settings', 'get_host_power_status', 'get_http_boot_url', 'get_ilo_firmware_version_as_major_minor', 'get_one_time_boot', + 'get_pending_bios_settings', 'get_pending_boot_mode', 'get_persistent_boot_device', 'get_product_name', @@ -47,6 +50,7 @@ SUPPORTED_RIS_METHODS = [ 'reset_ilo_credential', 'reset_secure_boot_keys', 'reset_server', + 'set_bios_settings', 'set_host_power', 'set_http_boot_url', 'set_one_time_boot', @@ -668,3 +672,71 @@ class IloClient(operations.IloOperations): not supported on the server """ return self._call_method('get_host_post_state') + + def get_current_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of current BIOS settings is returned. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + return self._call_method('get_current_bios_settings', + only_allowed_settings) + + def get_pending_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of pending BIOS settings. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + return self._call_method('get_pending_bios_settings', + only_allowed_settings) + + def set_bios_settings(self, data=None, only_allowed_settings=True): + """Sets current BIOS settings to the provided data. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be set. If False, all the BIOS settings supported by + iLO and present in the 'data' are set. + :param: data: a dictionary of BIOS settings to be applied. Depending + on the 'only_allowed_settings', either only the allowed + settings are set or all the supported settings that are in the + 'data' are set. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + return self._call_method('set_bios_settings', data, + only_allowed_settings) + + def get_default_bios_settings(self, only_allowed_settings=True): + """Get default BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of default BIOS settings(factory settings). + Depending on the 'only_allowed_settings', either only + the allowed settings are returned or all the supported + settings are returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + return self._call_method('get_default_bios_settings', + only_allowed_settings) diff --git a/proliantutils/ilo/constants.py b/proliantutils/ilo/constants.py index d6bdc843..dc384881 100644 --- a/proliantutils/ilo/constants.py +++ b/proliantutils/ilo/constants.py @@ -18,3 +18,32 @@ SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY = 'legacy bios only' SUPPORTED_BOOT_MODE_UEFI_ONLY = 'uefi only' SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI = 'legacy bios and uefi' +SUPPORTED_BIOS_PROPERTIES = { + "AdvancedMemProtection", + "AutoPowerOn", + "BootMode", + "BootOrderPolicy", + "CollabPowerControl", + "DynamicPowerCapping", + "DynamicPowerResponse", + "IntelligentProvisioning", + "IntelPerfMonitoring", + "IntelProcVtd", + "IntelQpiFreq", + "IntelTxt", + "PowerProfile", + "PowerRegulator", + "ProcAes", + "ProcCoreDisable", + "ProcHyperthreading", + "ProcNoExecute", + "ProcTurbo", + "ProcVirtualization", + "SecureBootStatus", + "Sriov", + "ThermalConfig", + "ThermalShutdown", + "TpmState", + "TpmType", + "UefiOptimizedBoot" +} diff --git a/proliantutils/ilo/operations.py b/proliantutils/ilo/operations.py index 98ff47d0..91a0ae15 100644 --- a/proliantutils/ilo/operations.py +++ b/proliantutils/ilo/operations.py @@ -381,3 +381,67 @@ class IloOperations(object): not supported on the server """ raise exception.IloCommandNotSupportedError(ERRMSG) + + def get_current_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of current BIOS settings is returned. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) + + def get_pending_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of pending BIOS settings. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) + + def set_bios_settings(self, data=None, only_allowed_settings=True): + """Sets current BIOS settings to the provided data. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be set. If False, all the BIOS settings supported by + iLO and present in the 'data' are set. + :param: data: a dictionary of BIOS settings to be applied. Depending + on the 'only_allowed_settings', either only the allowed + settings are set or all the supported settings that are in the + 'data' are set. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) + + def get_default_bios_settings(self, only_allowed_settings=True): + """Get default BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of default BIOS settings(factory settings). + Depending on the 'only_allowed_settings', either only the + allowed settings are returned or all the supported settings + are returned. + :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/ris.py b/proliantutils/ilo/ris.py index 1539354a..9d5e7055 100755 --- a/proliantutils/ilo/ris.py +++ b/proliantutils/ilo/ris.py @@ -19,11 +19,13 @@ import retrying from proliantutils import exception from proliantutils.ilo import common +from proliantutils.ilo import constants from proliantutils.ilo import firmware_controller from proliantutils.ilo import mappings from proliantutils.ilo import operations from proliantutils import log from proliantutils import rest +from proliantutils import utils """ Currently this class supports only secure boot and firmware settings related API's . @@ -1850,3 +1852,125 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): return system['Oem']['Hp']['PostState'] raise exception.IloError("Attribute 'Oem/Hp/PostState' " "not found on system.") + + def get_current_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of current BIOS settings is returned. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + headers, bios_uri, bios_settings = self._check_bios_resource() + # Remove the "links" section + bios_settings.pop("links", None) + if only_allowed_settings: + return utils.apply_bios_properties_filter( + bios_settings, constants.SUPPORTED_BIOS_PROPERTIES) + return bios_settings + + def get_pending_bios_settings(self, only_allowed_settings=True): + """Get current BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of pending BIOS settings. Depending + on the 'only_allowed_settings', either only the allowed + settings are returned or all the supported settings are + returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + headers, bios_uri, bios_settings = self._check_bios_resource() + try: + settings_config_uri = bios_settings['links']['Settings']['href'] + except KeyError: + msg = ("Settings resource not found. Couldn't get pending BIOS " + "Settings.") + raise exception.IloCommandNotSupportedError(msg) + + status, headers, config = self._rest_get(settings_config_uri) + if status != 200: + msg = self._get_extended_error(config) + raise exception.IloError(msg) + + # Remove the "links" section + config.pop("links", None) + + if only_allowed_settings: + return utils.apply_bios_properties_filter( + config, constants.SUPPORTED_BIOS_PROPERTIES) + return config + + def set_bios_settings(self, data=None, only_allowed_settings=True): + """Sets current BIOS settings to the provided data. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be set. If False, all the BIOS settings supported by + iLO and present in the 'data' are set. + :param: data: a dictionary of BIOS settings to be applied. Depending + on the 'only_allowed_settings', either only the allowed + settings are set or all the supported settings that are in + the 'data' are set. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + if only_allowed_settings and data: + refined_data = utils.apply_bios_properties_filter( + data, constants.SUPPORTED_BIOS_PROPERTIES) + self._change_bios_setting(refined_data) + return + + if data: + self._change_bios_setting(data) + + def get_default_bios_settings(self, only_allowed_settings=True): + """Get default BIOS settings. + + :param: only_allowed_settings: True when only allowed BIOS settings + are to be returned. If False, All the BIOS settings supported + by iLO are returned. + :return: a dictionary of default BIOS settings(factory settings). + Depending on the 'only_allowed_settings', either only the + allowed settings are returned or all the supported settings + are returned. + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is not supported + on the server. + """ + headers_bios, bios_uri, bios_settings = self._check_bios_resource() + # Get the BaseConfig resource. + try: + base_config_uri = bios_settings['links']['BaseConfigs']['href'] + except KeyError: + msg = ("BaseConfigs resource not found. Couldn't apply the BIOS " + "Settings.") + raise exception.IloCommandNotSupportedError(msg) + + status, headers, config = self._rest_get(base_config_uri) + if status != 200: + msg = self._get_extended_error(config) + raise exception.IloError(msg) + + for cfg in config['BaseConfigs']: + default_settings = cfg.get('default') + if default_settings: + break + else: + msg = ("Default BIOS Settings not found in 'BaseConfigs' " + "resource.") + raise exception.IloCommandNotSupportedError(msg) + + if only_allowed_settings: + return utils.apply_bios_properties_filter( + default_settings, constants.SUPPORTED_BIOS_PROPERTIES) + return default_settings diff --git a/proliantutils/tests/ilo/ris_sample_outputs.py b/proliantutils/tests/ilo/ris_sample_outputs.py index 52d80566..819f728c 100755 --- a/proliantutils/tests/ilo/ris_sample_outputs.py +++ b/proliantutils/tests/ilo/ris_sample_outputs.py @@ -1299,6 +1299,7 @@ GET_BIOS_SETTINGS = """ "Dhcpv4": "Enabled", "DynamicPowerCapping": "Auto", "DynamicPowerResponse": "Fast", + "EmbNicEnable": "Enabled", "EmbSasEnable": "Enabled", "EmbSata1Enable": "Enabled", "EmbSata2Enable": "Enabled", @@ -1420,6 +1421,7 @@ GET_BIOS_SETTINGS = """ "Sriov": "Enabled", "ThermalConfig": "OptimalCooling", "ThermalShutdown": "Enabled", + "TimeFormat": "Utc", "TimeZone": "Unspecified", "Tpm2Operation": "NoAction", "Tpm2Visibility": "Visible", @@ -1474,6 +1476,162 @@ GET_BIOS_SETTINGS = """ """ +GET_BIOS_PENDING_SETTINGS = """ + + { + "AcpiRootBridgePxm": "Enabled", + "AcpiSlit": "Enabled", + "AdjSecPrefetch": "Enabled", + "AdminEmail": "", + "AdminName": "", + "AdminOtherInfo": "", + "AdminPassword": null, + "AdminPhone": "", + "AdvancedMemProtection": "AdvancedEcc", + "AsrStatus": "Enabled", + "AsrTimeoutMinutes": "10", + "AssetTagProtection": "Unlocked", + "AutoPowerOn": "RestoreLastState", + "BootMode": "Uefi", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "", + "DaylightSavingsTime": "Disabled", + "DcuIpPrefetcher": "Enabled", + "DcuStreamPrefetcher": "Enabled", + "Description": "This is the Platform/BIOS Configuration (RBSU) \ + Pending Settings", + "Dhcpv4": "Enabled", + "DynamicPowerCapping": "Auto", + "DynamicPowerResponse": "Fast", + "EmbNicEnable": "Enabled", + "EmbSata1Enable": "Enabled", + "EmbSata2Enable": "Enabled", + "EmbVideoConnection": "Auto", + "EmbeddedDiagnostics": "Enabled", + "EmbeddedDiagsMode": "Auto", + "EmbeddedSata": "Ahci", + "EmbeddedSerialPort": "Com1Irq4", + "EmbeddedUefiShell": "Enabled", + "EmbeddedUserPartition": "Disabled", + "EmsConsole": "Disabled", + "EnergyPerfBias": "BalancedPerf", + "EraseUserDefaults": "No", + "ExtendedAmbientTemp": "Disabled", + "ExtendedMemTest": "Disabled", + "F11BootMenu": "Enabled", + "FCScanPolicy": "CardConfig", + "FanFailPolicy": "Shutdown", + "FanInstallReq": "EnableMessaging", + "HwPrefetcher": "Enabled", + "IntelDmiLinkFreq": "Auto", + "IntelNicDmaChannels": "Enabled", + "IntelPerfMonitoring": "Disabled", + "IntelProcVtd": "Enabled", + "IntelligentProvisioning": "Enabled", + "InternalSDCardSlot": "Enabled", + "IoNonPostedPrefetching": "Enabled", + "Ipv4Address": "0.0.0.0", + "Ipv4Gateway": "0.0.0.0", + "Ipv4PrimaryDNS": "0.0.0.0", + "Ipv4SecondaryDNS": "0.0.0.0", + "Ipv4SubnetMask": "0.0.0.0", + "Ipv6Duid": "Auto", + "MaxMemBusFreqMHz": "Auto", + "MaxPcieSpeed": "MaxSupported", + "MemFastTraining": "Enabled", + "MinProcIdlePkgState": "C6Retention", + "MinProcIdlePower": "C6", + "MixedPowerSupplyReporting": "Enabled", + "Modified": "2018-06-25T22:36:55+00:00", + "Name": "BIOS Pending Settings", + "NetworkBootRetry": "Enabled", + "NicBoot1": "NetworkBoot", + "NicBoot2": "Disabled", + "NicBoot3": "Disabled", + "NicBoot4": "Disabled", + "NmiDebugButton": "Enabled", + "NodeInterleaving": "Disabled", + "NumaGroupSizeOpt": "Clustered", + "OldAdminPassword": null, + "OldPowerOnPassword": null, + "PciBusPadding": "Enabled", + "PciSlot1Enable": "Enabled", + "PcieExpressEcrcSupport": "Disabled", + "PostF1Prompt": "Delayed20Sec", + "PowerButton": "Enabled", + "PowerOnDelay": "None", + "PowerOnLogo": "Enabled", + "PowerOnPassword": null, + "PowerProfile": "BalancedPowerPerf", + "PowerRegulator": "StaticHighPerf", + "PreBootNetwork": "Auto", + "ProcAes": "Enabled", + "ProcCoreDisable": 0, + "ProcNoExecute": "Enabled", + "ProcVirtualization": "Enabled", + "ProcX2Apic": "Enabled", + "ProductId": "719061-B21", + "QpiSnoopConfig": "Standard", + "RedundantPowerSupply": "BalancedMode", + "RemovableFlashBootSeq": "ExternalKeysFirst", + "RestoreDefaults": "No", + "RestoreManufacturingDefaults": "No", + "RomSelection": "CurrentRom", + "SataSecureErase": "Disabled", + "SaveUserDefaults": "No", + "SecureBootStatus": "Disabled", + "SerialConsoleBaudRate": "115200", + "SerialConsoleEmulation": "Vt100Plus", + "SerialConsolePort": "Auto", + "SerialNumber": "SGH449WW5B", + "ServerAssetTag": "", + "ServerName": "", + "ServerOtherInfo": "", + "ServerPrimaryOs": "", + "ServiceEmail": "", + "ServiceName": "", + "ServiceOtherInfo": "", + "ServicePhone": "", + "Slot1StorageBoot": "AllTargets", + "Sriov": "Enabled", + "ThermalConfig": "OptimalCooling", + "ThermalShutdown": "Enabled", + "TimeFormat": "Utc", + "TimeZone": "UtcP530", + "TpmState": "NotPresent", + "TpmType": "NoTpm", + "Type": "HpBios.1.2.0", + "UefiOptimizedBoot": "Enabled", + "UefiPxeBoot": "Auto", + "UefiShellBootOrder": "Disabled", + "UefiShellStartup": "Disabled", + "UefiShellStartupLocation": "Auto", + "UefiShellStartupUrl": "", + "UrlBootFile": "", + "Usb3Mode": "Auto", + "UsbBoot": "Enabled", + "UsbControl": "UsbEnabled", + "UtilityLang": "English", + "VirtualInstallDisk": "Disabled", + "VirtualSerialPort": "Com2Irq3", + "VlanControl": "Disabled", + "VlanId": 0, + "VlanPriority": 0, + "WakeOnLan": "Enabled", + "links": + { + "self": + { + "href": "/rest/v1/systems/1/bios/Settings" + } + } + } + +""" + GET_BIOS_BOOT = """ { @@ -1923,6 +2081,7 @@ GET_BASE_CONFIG = """ "TcmVisibility": "Visible", "ThermalConfig": "OptimalCooling", "ThermalShutdown": "Enabled", + "TimeFormat": "Utc", "TimeZone": "UtcM7", "Tpm2Operation": "NoAction", "Tpm2Ppi": "Disabled", @@ -1971,6 +2130,163 @@ GET_BASE_CONFIG = """ } } """ +GET_DEFAULT_CONFIG = """ + { + "AcpiRootBridgePxm": "Enabled", + "AcpiSlit": "Enabled", + "AdjSecPrefetch": "Enabled", + "AdminEmail": "", + "AdminName": "", + "AdminOtherInfo": "", + "AdminPassword": "", + "AdminPhone": "", + "AdvancedMemProtection": "AdvancedEcc", + "AsrStatus": "Enabled", + "AsrTimeoutMinutes": "10", + "AssetTagProtection": "Unlocked", + "AutoPowerOn": "RestoreLastState", + "BootMode": "Uefi", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "", + "DcuIpPrefetcher": "Enabled", + "DcuStreamPrefetcher": "Enabled", + "Description": "BIOS System Defaults", + "Dhcpv4": "Enabled", + "DynamicPowerCapping": "Auto", + "DynamicPowerResponse": "Fast", + "EmbNicEnable": "Enabled", + "EmbSas1Boot": "AllTargets", + "EmbSata1Enable": "Enabled", + "EmbSata2Enable": "Enabled", + "EmbVideoConnection": "Auto", + "EmbeddedDiagnostics": "Enabled", + "EmbeddedDiagsMode": "Auto", + "EmbeddedSata": "Ahci", + "EmbeddedSerialPort": "Com1Irq4", + "EmbeddedUefiShell": "Enabled", + "EmbeddedUserPartition": "Disabled", + "EmsConsole": "Disabled", + "EnergyPerfBias": "BalancedPerf", + "EraseUserDefaults": "No", + "ExtendedAmbientTemp": "Disabled", + "ExtendedMemTest": "Disabled", + "F11BootMenu": "Enabled", + "FCScanPolicy": "AllTargets", + "FanFailPolicy": "Shutdown", + "FanInstallReq": "EnableMessaging", + "HwPrefetcher": "Enabled", + "IntelDmiLinkFreq": "Auto", + "IntelNicDmaChannels": "Enabled", + "IntelPerfMonitoring": "Disabled", + "IntelProcVtd": "Enabled", + "IntelQpiFreq": "Auto", + "IntelQpiLinkEn": "Auto", + "IntelQpiPowerManagement": "Enabled", + "IntelTxt": "Disabled", + "IntelligentProvisioning": "Enabled", + "InternalSDCardSlot": "Enabled", + "IoNonPostedPrefetching": "Enabled", + "Ipv4Address": "0.0.0.0", + "Ipv4Gateway": "0.0.0.0", + "Ipv4PrimaryDNS": "0.0.0.0", + "Ipv4SecondaryDNS": "0.0.0.0", + "Ipv4SubnetMask": "0.0.0.0", + "MaxMemBusFreqMHz": "Auto", + "MaxPcieSpeed": "MaxSupported", + "MemFastTraining": "Enabled", + "MinProcIdlePkgState": "C6Retention", + "MinProcIdlePower": "C6", + "MixedPowerSupplyReporting": "Enabled", + "NetworkBootRetry": "Enabled", + "NicBoot1": "NetworkBoot", + "NicBoot2": "Disabled", + "NicBoot3": "Disabled", + "NicBoot4": "Disabled", + "NmiDebugButton": "Enabled", + "NodeInterleaving": "Disabled", + "NumaGroupSizeOpt": "Clustered", + "OldAdminPassword": "", + "OldPowerOnPassword": "", + "PciBusPadding": "Enabled", + "PciSlot1Enable": "Enabled", + "PostF1Prompt": "Delayed20Sec", + "PowerButton": "Enabled", + "PowerOnDelay": "None", + "PowerOnLogo": "Enabled", + "PowerOnPassword": "", + "PowerProfile": "BalancedPowerPerf", + "PowerRegulator": "DynamicPowerSavings", + "PreBootNetwork": "Auto", + "ProcAes": "Enabled", + "ProcCoreDisable": 0, + "ProcNoExecute": "Enabled", + "ProcVirtualization": "Enabled", + "ProcX2Apic": "Enabled", + "QpiBandwidthOpt": "Balanced", + "QpiSnoopConfig": "Standard", + "RedundantPowerSupply": "BalancedMode", + "RemovableFlashBootSeq": "ExternalKeysFirst", + "RestoreDefaults": "No", + "RestoreManufacturingDefaults": "No", + "SataSecureErase": "Disabled", + "SaveUserDefaults": "No", + "SecureBoot": "Disabled", + "SecureBootStatus": "Disabled", + "SerialConsoleBaudRate": "115200", + "SerialConsoleEmulation": "Vt100Plus", + "SerialConsolePort": "Auto", + "ServerAssetTag": "", + "ServerName": "", + "ServerOtherInfo": "", + "ServerPrimaryOs": "", + "ServiceEmail": "", + "ServiceName": "", + "ServiceOtherInfo": "", + "ServicePhone": "", + "Slot1StorageBoot": "AllTargets", + "Slot2StorageBoot": "AllTargets", + "Slot3StorageBoot": "AllTargets", + "Slot4StorageBoot": "AllTargets", + "Slot5StorageBoot": "AllTargets", + "Slot6StorageBoot": "AllTargets", + "Sriov": "Enabled", + "TcmOperation": "Disable", + "TcmVisibility": "Visible", + "ThermalConfig": "OptimalCooling", + "ThermalShutdown": "Enabled", + "TimeZone": "UtcM7", + "Tpm2Operation": "NoAction", + "Tpm2Ppi": "Disabled", + "Tpm2Visibility": "Visible", + "TpmBinding": "Disabled", + "TpmOperation": "Disable", + "TpmState": "NotPresent", + "TpmType": "NoTpm", + "TpmUefiOpromMeasuring": "Enabled", + "TpmVisibility": "Visible", + "UefiOptimizedBoot": "Enabled", + "UefiPxeBoot": "Auto", + "UefiShellBootOrder": "Disabled", + "UefiShellStartup": "Disabled", + "UefiShellStartupLocation": "Auto", + "UefiShellStartupUrl": "", + "UrlBootFile": "", + "Usb3Mode": "Auto", + "UsbBoot": "Enabled", + "UsbControl": "UsbEnabled", + "UtilityLang": "English", + "VideoOptions": "BothVideoEnabled", + "VirtualInstallDisk": "Disabled", + "VirtualSerialPort": "Com2Irq3", + "VlanControl": "Disabled", + "VlanId": 0, + "VlanPriority": 0, + "WakeOnLan": "Enabled" + } +""" GET_ISCSI_PATCH = """ { "iSCSIBootSources": [ diff --git a/proliantutils/tests/ilo/test_client.py b/proliantutils/tests/ilo/test_client.py index bbc53563..6c7f0262 100644 --- a/proliantutils/tests/ilo/test_client.py +++ b/proliantutils/tests/ilo/test_client.py @@ -920,6 +920,35 @@ class IloClientTestCase(testtools.TestCase): self.client.reset_server() self.assertTrue(reset_server_mock.called) + @mock.patch.object(ris.RISOperations, 'get_current_bios_settings') + def test_get_current_bios_settings_gen9(self, cur_bios_settings_mock): + self.client.model = 'Gen9' + apply_filter = True + self.client.get_current_bios_settings(apply_filter) + cur_bios_settings_mock.assert_called_once_with(True) + + @mock.patch.object(ris.RISOperations, 'get_pending_bios_settings') + def test_get_pending_bios_settings_gen9(self, pending_bios_settings_mock): + self.client.model = 'Gen9' + apply_filter = True + self.client.get_pending_bios_settings(apply_filter) + pending_bios_settings_mock.assert_called_once_with(True) + + @mock.patch.object(ris.RISOperations, 'get_default_bios_settings') + def test_get_default_bios_settings_gen9(self, def_bios_settings_mock): + self.client.model = 'Gen9' + apply_filter = False + self.client.get_default_bios_settings(apply_filter) + def_bios_settings_mock.assert_called_once_with(False) + + @mock.patch.object(ris.RISOperations, 'set_bios_settings') + def test_set_bios_settings_gen9(self, bios_settings_mock): + self.client.model = 'Gen9' + apply_filter = False + d = {'a': 'blah', 'b': 'blah blah'} + self.client.set_bios_settings(d, apply_filter) + bios_settings_mock.assert_called_once_with(d, False) + @mock.patch.object(client.IloClient, '_call_method') @mock.patch.object(snmp_cpqdisk_sizes, 'get_local_gb') def test_get_essential_prop_no_snmp_ris(self, diff --git a/proliantutils/tests/ilo/test_ris.py b/proliantutils/tests/ilo/test_ris.py index 266b07a9..bc9358a4 100755 --- a/proliantutils/tests/ilo/test_ris.py +++ b/proliantutils/tests/ilo/test_ris.py @@ -28,6 +28,7 @@ from proliantutils.ilo import common from proliantutils.ilo import constants from proliantutils.ilo import ris from proliantutils.tests.ilo import ris_sample_outputs as ris_outputs +from proliantutils import utils class IloRisTestCaseInitTestCase(testtools.TestCase): @@ -1312,6 +1313,252 @@ class IloRisTestCase(testtools.TestCase): self.client.get_host_post_state) get_details_mock.assert_called_once_with() + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_current_bios_settings_filter_true(self, check_bios_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + settings.pop("links", None) + expected_value = {k: settings[k] for k in ( + constants.SUPPORTED_BIOS_PROPERTIES) if k in settings} + actual_value = self.client.get_current_bios_settings(True) + check_bios_mock.assert_called_once_with() + self.assertEqual(actual_value, expected_value) + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_current_bios_settings_filter_false(self, check_bios_mock, + bios_filter_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + settings.pop("links", None) + actual_value = self.client.get_current_bios_settings(False) + check_bios_mock.assert_called_once_with() + bios_filter_mock.assert_not_called() + self.assertEqual(actual_value, settings) + + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_pending_bios_settings_no_links(self, check_bios_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + settings.pop("links", None) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + self.assertRaises(exception.IloCommandNotSupportedError, + self.client.get_pending_bios_settings, False) + check_bios_mock.assert_called_once_with() + + @mock.patch.object(ris.RISOperations, '_get_extended_error') + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_pending_bios_settings_filter_true(self, check_bios_mock, + get_mock, get_ext_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + settings_uri = "/rest/v1/systems/1/bios/Settings" + pending_settings = json.loads(ris_outputs.GET_BIOS_PENDING_SETTINGS) + pending_settings.pop("Description", None) + get_mock.return_value = (200, ris_outputs.GET_HEADERS, + pending_settings) + expected_value = {k: pending_settings[k] for k in ( + constants.SUPPORTED_BIOS_PROPERTIES) if k in pending_settings} + actual_value = self.client.get_pending_bios_settings(True) + self.assertEqual(actual_value, expected_value) + get_mock.assert_called_once_with(settings_uri) + check_bios_mock.assert_called_once_with() + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_get_extended_error') + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_pending_bios_settings_filter_false(self, check_bios_mock, + get_mock, get_ext_mock, + bios_filter_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + settings_uri = "/rest/v1/systems/1/bios/Settings" + pending_settings = json.loads(ris_outputs.GET_BIOS_PENDING_SETTINGS) + get_mock.return_value = (200, ris_outputs.GET_HEADERS, + pending_settings) + actual_value = self.client.get_pending_bios_settings(False) + self.assertEqual(actual_value, pending_settings) + get_mock.assert_called_once_with(settings_uri) + check_bios_mock.assert_called_once_with() + bios_filter_mock.assert_not_called() + + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_default_bios_settings_filter_true(self, check_bios_mock, + rest_get_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + base_config = json.loads(ris_outputs.GET_BASE_CONFIG) + rest_get_mock.return_value = (200, 'HEADERS', base_config) + default_settings = None + for cfg in base_config['BaseConfigs']: + default_settings = cfg.get('default', None) + if default_settings is not None: + break + expected_value = {k: default_settings[k] for k in ( + constants.SUPPORTED_BIOS_PROPERTIES) if k in default_settings} + actual_value = self.client.get_default_bios_settings(True) + check_bios_mock.assert_called_once_with() + rest_get_mock.assert_called_once_with( + "/rest/v1/systems/1/bios/BaseConfigs") + self.assertEqual(expected_value, actual_value) + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_default_bios_settings_filter_false( + self, check_bios_mock, rest_get_mock, filter_mock): + + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + base_config = json.loads(ris_outputs.GET_BASE_CONFIG) + rest_get_mock.return_value = (200, 'HEADERS', base_config) + default_settings = None + for cfg in base_config['BaseConfigs']: + default_settings = cfg.get('default', None) + if default_settings is not None: + break + expected_value = default_settings + actual_value = self.client.get_default_bios_settings(False) + check_bios_mock.assert_called_once_with() + rest_get_mock.assert_called_once_with( + "/rest/v1/systems/1/bios/BaseConfigs") + self.assertEqual(expected_value, actual_value) + filter_mock.assert_not_called() + + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_default_bios_settings_no_links(self, check_bios_mock): + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + settings.pop("links", None) + self.assertRaises(exception.IloCommandNotSupportedError, + self.client.get_default_bios_settings, False) + check_bios_mock.assert_called_once_with() + + @mock.patch.object(ris.RISOperations, '_get_extended_error') + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_default_bios_settings_check_extended_error( + self, check_bios_mock, rest_get_mock, ext_err_mock): + + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + base_config = json.loads(ris_outputs.GET_BASE_CONFIG) + rest_get_mock.return_value = (201, 'HEADERS', base_config) + self.assertRaises(exception.IloError, + self.client.get_default_bios_settings, False) + check_bios_mock.assert_called_once_with() + ext_err_mock.assert_called_once_with(base_config) + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_get_extended_error') + @mock.patch.object(ris.RISOperations, '_rest_get') + @mock.patch.object(ris.RISOperations, '_check_bios_resource') + def test_get_default_bios_settings_no_default_settings( + self, check_bios_mock, rest_get_mock, ext_err_mock, filter_mock): + + bios_uri = '/rest/v1/systems/1/bios' + settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) + check_bios_mock.return_value = (ris_outputs.GET_HEADERS, + bios_uri, settings) + base_config = json.loads(ris_outputs.GET_BASE_CONFIG) + default_val = base_config["BaseConfigs"][0].pop("default") + base_config["BaseConfigs"][0]["no_default"] = default_val + rest_get_mock.return_value = (200, 'HEADERS', base_config) + self.assertRaises(exception.IloCommandNotSupportedError, + self.client.get_default_bios_settings, False) + check_bios_mock.assert_called_once_with() + ext_err_mock.assert_not_called() + filter_mock.assert_not_called() + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_change_bios_setting') + def test_set_bios_settings_no_data_apply_filter(self, change_bios_mock, + filter_mock): + apply_filter = True + data = None + self.client.set_bios_settings(data, apply_filter) + change_bios_mock.assert_not_called() + filter_mock.assert_not_called() + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_change_bios_setting') + def test_set_bios_settings_no_data_no_filter(self, change_bios_mock, + filter_mock): + apply_filter = False + data = None + self.client.set_bios_settings(data, apply_filter) + change_bios_mock.assert_not_called() + filter_mock.assert_not_called() + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_change_bios_setting') + def test_set_bios_settings_filter_true(self, change_bios_mock, + filter_mock): + data = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "" + } + expected = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + } + filter_mock.return_value = expected + apply_filter = True + self.client.set_bios_settings(data, apply_filter) + change_bios_mock.assert_called_once_with(expected) + filter_mock.assert_called_once_with( + data, constants.SUPPORTED_BIOS_PROPERTIES) + + @mock.patch.object(utils, 'apply_bios_properties_filter') + @mock.patch.object(ris.RISOperations, '_change_bios_setting') + def test_set_bios_settings_filter_false(self, change_bios_mock, + filter_mock): + data = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "" + } + apply_filter = False + self.client.set_bios_settings(data, apply_filter) + change_bios_mock.assert_called_once_with(data) + filter_mock.assert_not_called() + class TestRISOperationsPrivateMethods(testtools.TestCase): diff --git a/proliantutils/tests/test_utils.py b/proliantutils/tests/test_utils.py index 8bab99f0..c5457dac 100644 --- a/proliantutils/tests/test_utils.py +++ b/proliantutils/tests/test_utils.py @@ -259,3 +259,78 @@ class UtilsTestCase(testtools.TestCase): self.assertRaises(exception.ImageRefValidationFailed, utils.validate_href, href) head_mock.assert_called_once_with(href) + + def test_apply_bios_properties_filter(self): + data = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "" + } + filter_to_be_applied = { + "AdminName", + "BootMode", + "ServerName", + "TimeFormat", + "CustomPostMessage" + } + + expected = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "CustomPostMessage": "" + } + actual = utils.apply_bios_properties_filter( + data, filter_to_be_applied) + self.assertEqual(expected, actual) + + def test_apply_bios_properties_filter_no_filter(self): + data = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "" + } + filter_to_be_applied = None + + expected = { + "AdminName": "Administrator", + "BootMode": "LEGACY", + "ServerName": "Gen9 server", + "TimeFormat": "Ist", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsOnly", + "CustomPostMessage": "" + } + actual = utils.apply_bios_properties_filter( + data, filter_to_be_applied) + self.assertEqual(expected, actual) + + def test_apply_bios_properties_filter_no_settings(self): + data = None + filter_to_be_applied = { + "AdminName", + "BootMode", + "ServerName", + "TimeFormat", + "CustomPostMessage" + } + + expected = None + actual = utils.apply_bios_properties_filter( + data, filter_to_be_applied) + self.assertEqual(expected, actual) diff --git a/proliantutils/utils.py b/proliantutils/utils.py index 290848e1..8f20ea3b 100644 --- a/proliantutils/utils.py +++ b/proliantutils/utils.py @@ -154,3 +154,16 @@ def validate_href(image_href): raise exception.ImageRefValidationFailed(image_href=image_href, reason=e) return response + + +def apply_bios_properties_filter(settings, filter_to_be_applied): + """Applies the filter to return the dict of filtered BIOS properties. + + :param settings: dict of BIOS settings on which filter to be applied. + :param filter_to_be_applied: set of keys to be applied as filter. + :returns: A dictionary of filtered BIOS settings. + """ + if not settings or not filter_to_be_applied: + return settings + + return {k: settings[k] for k in filter_to_be_applied if k in settings}