diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index 04141415..68358193 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -77,6 +77,7 @@ SUPPORTED_REDFISH_METHODS = [ 'update_persistent_boot', 'set_pending_boot_mode', 'reset_ilo_credential', + 'reset_bios_to_default', ] LOG = log.get_logger(__name__) diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 49c62a38..0ae1d0b1 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -611,3 +611,18 @@ class RedfishOperations(operations.IloOperations): LOG.debug(msg) raise exception.IloError(msg) return capabilities + + def reset_bios_to_default(self): + """Resets the BIOS settings to default values. + + :raises: IloError, on an error from iLO. + """ + try: + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + sushy_system.bios_settings.update_bios_to_default() + except sushy.exceptions.SushyError as e: + msg = (self._("The Redfish controller is unable to update bios " + "settings to default Error %(error)s") % + {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) diff --git a/proliantutils/redfish/resources/system/bios.py b/proliantutils/redfish/resources/system/bios.py index 66562685..5dac0623 100644 --- a/proliantutils/redfish/resources/system/bios.py +++ b/proliantutils/redfish/resources/system/bios.py @@ -32,11 +32,13 @@ BOOT_SOURCE_TARGET_TO_PARTIAL_STRING_MAP = { class BIOSSettings(base.ResourceBase): + """Class that defines the functionality for BIOS Resources.""" boot_mode = base.MappedField(["Attributes", "BootMode"], mappings.GET_BIOS_BOOT_MODE_MAP) _pending_settings = None _boot_settings = None + _base_configs = None @property def pending_settings(self): @@ -70,8 +72,37 @@ class BIOSSettings(base.ResourceBase): return self._boot_settings + def _get_base_configs(self): + """Property to provide reference to bios settings instance""" + if self._base_configs is None: + self._base_configs = BIOSBaseConfigs( + self._conn, utils.get_subresource_path_by( + self, ["Oem", "Hpe", "Links", "BaseConfigs"]), + redfish_version=self.redfish_version) + + return self._base_configs + + def update_bios_to_default(self): + """Updates bios default settings""" + self.pending_settings.update_bios_data( + self._get_base_configs().default_config) + + def refresh(self): + super(BIOSSettings, self).refresh() + self._pending_settings = None + self._boot_settings = None + self._base_configs = None + + +class BIOSBaseConfigs(base.ResourceBase): + """Class that defines the functionality for BIOS base configuration.""" + + default_config = base.Field( + "BaseConfigs", adapter=lambda base_configs: base_configs[0]['default']) + class BIOSPendingSettings(base.ResourceBase): + """Class that defines the functionality for BIOS settings.""" boot_mode = base.MappedField(["Attributes", "BootMode"], mappings.GET_BIOS_BOOT_MODE_MAP) @@ -89,7 +120,17 @@ class BIOSPendingSettings(base.ResourceBase): if boot_mode == sys_cons.BIOS_BOOT_MODE_UEFI: bios_properties['UefiOptimizedBoot'] = 'Enabled' - self._conn.patch(self._path, bios_properties) + self._conn.patch(self.path, bios_properties) + + def update_bios_data(self, data): + """Update bios data + + :param data: default bios config data + """ + bios_settings_data = { + 'Attributes': data + } + self._conn.post(self.path, bios_settings_data) class BIOSBootSettings(base.ResourceBase): diff --git a/proliantutils/tests/redfish/json_samples/bios_base_configs.json b/proliantutils/tests/redfish/json_samples/bios_base_configs.json new file mode 100644 index 00000000..75846131 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/bios_base_configs.json @@ -0,0 +1,238 @@ +{ + "@odata.context": "/redfish/v1/$metadata#HpeBaseConfigs.HpeBaseConfigs", + "@odata.etag": "W/\"181015940C22575757F4180F335F8F57\"", + "@odata.id": "/redfish/v1/systems/1/bios/baseconfigs/", + "@odata.type": "#HpeBaseConfigs.v2_0_0.HpeBaseConfigs", + "BaseConfigs": [ + { + "default": { + "AcpiHpet": "Enabled", + "AcpiRootBridgePxm": "Enabled", + "AcpiSlit": "Enabled", + "AdjSecPrefetch": "Enabled", + "AdminEmail": "", + "AdminName": "", + "AdminOtherInfo": "", + "AdminPhone": "", + "AdvancedMemProtection": "AdvancedEcc", + "AsrStatus": "Enabled", + "AsrTimeoutMinutes": "Timeout10", + "AssetTagProtection": "Unlocked", + "AutoPowerOn": "RestoreLastState", + "BootMode": "Uefi", + "BootOrderPolicy": "RetryIndefinitely", + "ChannelInterleaving": "Enabled", + "Chipset_TpmFeatureEnableOrDisable": "Disabled", + "Chipset_TpmFeatureType": "Chipset-TpmFeature:NONE", + "CollabPowerControl": "Enabled", + "ConsistentDevNaming": "LomsAndSlots", + "CustomPostMessage": "", + "DaylightSavingsTime": "Disabled", + "DcuIpPrefetcher": "Enabled", + "DcuStreamPrefetcher": "Enabled", + "Dhcpv4": "Enabled", + "DynamicPowerCapping": "Disabled", + "EmbNicAspm": "Disabled", + "EmbNicEnable": "Auto", + "EmbNicLinkSpeed": "Auto", + "EmbNicPCIeOptionROM": "Enabled", + "EmbSas1Aspm": "Disabled", + "EmbSas1LinkSpeed": "Auto", + "EmbSas1PcieOptionROM": "Enabled", + "EmbSata1Enable": "Auto", + "EmbSata1PCIeOptionROM": "Enabled", + "EmbSata2Enable": "Auto", + "EmbSata2PCIeOptionROM": "Enabled", + "EmbVideoConnection": "Auto", + "EmbeddedDiagnostics": "Enabled", + "EmbeddedDiagsMode": "Auto", + "EmbeddedSata": "Ahci", + "EmbeddedSerialPort": "Com2Irq3", + "EmbeddedUefiShell": "Enabled", + "EmsConsole": "Disabled", + "EnabledCoresPerProc": 0, + "EnergyEfficientTurbo": "Enabled", + "EnergyPerfBias": "BalancedPerf", + "EraseUserDefaults": "No", + "ExtendedAmbientTemp": "Disabled", + "ExtendedMemTest": "Disabled", + "F11BootMenu": "Enabled", + "FCScanPolicy": "CardConfig", + "FanFailPolicy": "Shutdown", + "FanInstallReq": "EnableMessaging", + "FlexLom1Aspm": "Disabled", + "FlexLom1LinkSpeed": "Auto", + "FlexLom1PCIeOptionROM": "Enabled", + "HpeScalablePmemBackupState": "Complete", + "HpeScalablePmemConfigurationRestoration": "Disabled", + "HpeScalablePmemFunctionalityEnabled": "Disabled", + "HpeScalablePmemStorageInitialize": "Disabled", + "HttpSupport": "Auto", + "HwPrefetcher": "Enabled", + "IntelDmiLinkFreq": "Auto", + "IntelNicDmaChannels": "Enabled", + "IntelPerfMonitoring": "Disabled", + "IntelProcVtd": "Enabled", + "IntelUpiFreq": "Auto", + "IntelUpiLinkEn": "Auto", + "IntelUpiPowerManagement": "Enabled", + "IntelligentProvisioning": "Enabled", + "InternalSDCardSlot": "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", + "Ipv6Address": "::", + "Ipv6ConfigPolicy": "Automatic", + "Ipv6Duid": "Auto", + "Ipv6Gateway": "::", + "Ipv6PrimaryDNS": "::", + "Ipv6SecondaryDNS": "::", + "LocalRemoteThreshold": "Auto", + "MaxMemBusFreqMHz": "Auto", + "MaxPcieSpeed": "PerPortCtrl", + "MemClearWarmReset": "Disabled", + "MemFastTraining": "Enabled", + "MemMirrorMode": "Full", + "MemPatrolScrubbing": "Enabled", + "MemRefreshRate": "Refreshx2", + "MemoryRemap": "NoAction", + "MinProcIdlePkgState": "C6Retention", + "MinProcIdlePower": "C6", + "MixedPowerSupplyReporting": "Enabled", + "NetworkBootRetry": "Enabled", + "NetworkBootRetryCount": 20, + "NicBoot1": "NetworkBoot", + "NicBoot3": "Disabled", + "NicBoot4": "Disabled", + "NodeInterleaving": "Disabled", + "NumaGroupSizeOpt": "Flat", + "NvDimmNMemInterleaving": "Disabled", + "NvmeOptionRom": "Enabled", + "PciResourcePadding": "Normal", + "PciSlot1Aspm": "Disabled", + "PciSlot1LinkSpeed": "Auto", + "PciSlot1OptionROM": "Enabled", + "PciSlot2Aspm": "Disabled", + "PciSlot2LinkSpeed": "Auto", + "PciSlot2OptionROM": "Enabled", + "PciSlot3Aspm": "Disabled", + "PciSlot3LinkSpeed": "Auto", + "PciSlot3OptionROM": "Enabled", + "PciSlot4Aspm": "Disabled", + "PciSlot4LinkSpeed": "Auto", + "PciSlot4OptionROM": "Enabled", + "PciSlot5Aspm": "Disabled", + "PciSlot5LinkSpeed": "Auto", + "PciSlot5OptionROM": "Enabled", + "PciSlot6Aspm": "Disabled", + "PciSlot6LinkSpeed": "Auto", + "PciSlot6OptionROM": "Enabled", + "PersistentMemAddressRangeScrub": "Enabled", + "PersistentMemBackupPowerPolicy": "WaitForBackupPower", + "PersistentMemScanMem": "Enabled", + "PostBootProgress": "Disabled", + "PostDiscoveryMode": "ForceFullDiscovery", + "PostF1Prompt": "Delayed20Sec", + "PowerButton": "Enabled", + "PowerOnDelay": "NoDelay", + "PowerOnLogo": "Enabled", + "PowerRegulator": "DynamicPowerSavings", + "PreBootNetwork": "Auto", + "PrebootNetworkEnvPolicy": "Auto", + "PrebootNetworkProxy": "", + "ProcAes": "Enabled", + "ProcHyperthreading": "Enabled", + "ProcTurbo": "Enabled", + "ProcVirtualization": "Enabled", + "ProcX2Apic": "Enabled", + "Processor1LogicalNvdimm1SizeGiB": 0, + "Processor1LogicalNvdimm2SizeGiB": 0, + "Processor1ScalablePmemAvailableGiB": 0, + "Processor2LogicalNvdimm1SizeGiB": 0, + "Processor2LogicalNvdimm2SizeGiB": 0, + "Processor2ScalablePmemAvailableGiB": 0, + "Processor3LogicalNvdimm1SizeGiB": 0, + "Processor3LogicalNvdimm2SizeGiB": 0, + "Processor3ScalablePmemAvailableGiB": 0, + "Processor4LogicalNvdimm1SizeGiB": 0, + "Processor4LogicalNvdimm2SizeGiB": 0, + "Processor4ScalablePmemAvailableGiB": 0, + "ProcessorJitterControl": "Disabled", + "ProcessorJitterControlFrequency": 0, + "RedundantPowerSupply": "BalancedMode", + "RemovableFlashBootSeq": "ExternalKeysFirst", + "RestoreDefaults": "No", + "RestoreManufacturingDefaults": "No", + "SataSecureErase": "Disabled", + "SaveUserDefaults": "No", + "ScalablePmemCapacity": 0, + "SecureBootStatus": "Disabled", + "SerialConsoleBaudRate": "BaudRate115200", + "SerialConsoleEmulation": "Vt100Plus", + "SerialConsolePort": "Auto", + "ServerAssetTag": "", + "ServerName": "", + "ServerOtherInfo": "", + "ServerPrimaryOs": "", + "ServiceEmail": "", + "ServiceName": "", + "ServiceOtherInfo": "", + "ServicePhone": "", + "SetupBrowserSelection": "Auto", + "SpannedLogicalNvdimm1AvailableMemoryGiB": 0, + "SpannedLogicalNvdimm1SizeGiB": 0, + "SpannedLogicalNvdimm1StartingDomainId": 0, + "SpannedLogicalNvdimm1StartingDomainSize": 0, + "SpannedLogicalNvdimm2AvailableMemoryGiB": 0, + "SpannedLogicalNvdimm2SizeGiB": 0, + "SpannedLogicalNvdimm2StartingDomainId": 0, + "SpannedLogicalNvdimm2StartingDomainSize": 0, + "Sriov": "Enabled", + "SubNumaClustering": "Disabled", + "ThermalConfig": "OptimalCooling", + "ThermalShutdown": "Enabled", + "TimeFormat": "Utc", + "TimeZone": "Utc0", + "TpmChipId": "None", + "TpmFips": "NotSpecified", + "TpmState": "NotPresent", + "TpmType": "NoTpm", + "UefiOptimizedBoot": "Enabled", + "UefiSerialDebugLevel": "Disabled", + "UefiShellBootOrder": "Disabled", + "UefiShellScriptVerification": "Disabled", + "UefiShellStartup": "Disabled", + "UefiShellStartupLocation": "Auto", + "UefiShellStartupUrl": "", + "UefiShellStartupUrlFromDhcp": "Disabled", + "UncoreFreqScaling": "Auto", + "UpiPrefetcher": "Enabled", + "UrlBootFile": "", + "UrlBootFile2": "", + "UrlBootFile3": "", + "UrlBootFile4": "", + "UsbBoot": "Enabled", + "UsbControl": "UsbEnabled", + "UserDefaultsState": "Disabled", + "UtilityLang": "English", + "VirtualInstallDisk": "Disabled", + "VirtualSerialPort": "Com1Irq4", + "VlanControl": "Disabled", + "VlanId": 0, + "VlanPriority": 0, + "WakeOnLan": "Enabled", + "WorkloadProfile": "GeneralPowerEfficientCompute", + "XptPrefetcher": "Enabled", + "iSCSIPolicy": "SoftwareInitiator" + } + } + ], + "Capabilities": { + "BaseConfig": true, + "BaseConfigs": false + }, + "Id": "baseconfigs", + "Name": "BIOS Default Settings" +} diff --git a/proliantutils/tests/redfish/resources/system/test_bios.py b/proliantutils/tests/redfish/resources/system/test_bios.py index 693490b5..48558e54 100644 --- a/proliantutils/tests/redfish/resources/system/test_bios.py +++ b/proliantutils/tests/redfish/resources/system/test_bios.py @@ -78,6 +78,105 @@ class BIOSSettingsTestCase(testtools.TestCase): self.bios_inst.boot_settings) self.conn.get.return_value.json.assert_not_called() + def test__get_base_configs(self): + self.assertIsNone(self.bios_inst._base_configs) + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + default_settings = self.bios_inst._get_base_configs() + self.assertIsInstance(default_settings, bios.BIOSBaseConfigs) + + def test_pending_settings_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['BIOS_pending_settings_default']) + actual_settings = self.bios_inst.pending_settings + self.assertIsInstance(actual_settings, + bios.BIOSPendingSettings) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.bios_inst.refresh() + self.assertIsNone(self.bios_inst._pending_settings) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['BIOS_pending_settings_default']) + + self.assertIsInstance(actual_settings, + bios.BIOSPendingSettings) + + def test_boot_settings_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios_boot.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + actual_settings = self.bios_inst.boot_settings + self.assertIsInstance(actual_settings, + bios.BIOSBootSettings) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.bios_inst.refresh() + self.assertIsNone(self.bios_inst._boot_settings) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios_boot.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.assertIsInstance(actual_settings, + bios.BIOSBootSettings) + + def test__get_base_configs_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + default_settings = self.bios_inst._get_base_configs() + self.assertIsInstance(default_settings, bios.BIOSBaseConfigs) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.bios_inst.refresh() + self.assertIsNone(self.bios_inst._base_configs) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + self.assertIsInstance(default_settings, bios.BIOSBaseConfigs) + + +class BIOSBaseConfigsTestCase(testtools.TestCase): + + def setUp(self): + super(BIOSBaseConfigsTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.bios_base_inst = bios.BIOSBaseConfigs( + self.conn, '/redfish/v1/Systems/1/bios/baseconfigs', + redfish_version='1.0.2') + + def test_attributes(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + bios_default = json.loads(f.read())['BaseConfigs'][0]['default'] + + self.assertEqual(bios_default, self.bios_base_inst.default_config) + class BIOSPendingSettingsTestCase(testtools.TestCase): @@ -114,6 +213,18 @@ class BIOSPendingSettingsTestCase(testtools.TestCase): self.bios_settings_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/1/bios/settings', data) + def test_update_bios_data(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + bios_settings = json.loads(f.read())['BaseConfigs'][0]['default'] + target_uri = '/redfish/v1/Systems/1/bios/settings' + data = { + 'Attributes': bios_settings + } + self.bios_settings_inst.update_bios_data(bios_settings) + self.bios_settings_inst._conn.post.assert_called_once_with(target_uri, + data) + class BIOSBootSettingsTestCase(testtools.TestCase): diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index 2853afa3..419aa440 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -26,7 +26,9 @@ from proliantutils.redfish.resources.account_service import account from proliantutils.redfish.resources.account_service import account_service from proliantutils.redfish.resources.manager import manager from proliantutils.redfish.resources.manager import virtual_media +from proliantutils.redfish.resources.system import bios from proliantutils.redfish.resources.system import constants as sys_cons +from proliantutils.redfish.resources.system import system as pro_sys from sushy.resources.system import system @@ -667,3 +669,49 @@ class RedfishOperationsTestCase(testtools.TestCase): gpu_mock) self.assertRaises(exception.IloError, self.rf_client.get_server_capabilities) + + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + @mock.patch.object(bios.BIOSPendingSettings, 'update_bios_data') + def test_reset_bios_to_default(self, update_bios_mock, get_system_mock): + with open('proliantutils/tests/redfish/' + 'json_samples/system.json', 'r') as f: + system_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + bios_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + bios_default_json = json.loads(f.read()) + self.conn = mock.Mock() + self.conn.get.return_value.json.side_effect = [ + system_json['default'], bios_json['Default'], + bios_json['BIOS_pending_settings_default'], bios_default_json] + self.sys_inst = pro_sys.HPESystem(self.conn, + '/redfish/v1/Systems/437XR1138R2', + redfish_version='1.0.2') + get_system_mock.return_value = self.sys_inst + data = bios_default_json['BaseConfigs'][0]['default'] + self.rf_client.reset_bios_to_default() + update_bios_mock.assert_called_once_with(data) + + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_reset_bios_to_default_fail(self, get_system_mock): + with open('proliantutils/tests/redfish/' + 'json_samples/system.json', 'r') as f: + system_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/bios.json', 'r') as f: + bios_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/bios_base_configs.json', 'r') as f: + bios_default_json = json.loads(f.read()) + self.conn = mock.Mock() + self.conn.get.return_value.json.side_effect = [ + system_json['default'], bios_json['Default'], + bios_json['BIOS_pending_settings_default'], bios_default_json] + (get_system_mock.return_value.bios_settings. + update_bios_to_default.side_effect) = sushy.exceptions.SushyError + self.assertRaisesRegex( + exception.IloError, + "The Redfish controller is unable to update bios settings" + " to default", self.rf_client.reset_bios_to_default)