diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index 3f022d83..6e9be0b2 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -82,7 +82,8 @@ SUPPORTED_REDFISH_METHODS = [ 'set_secure_boot_mode', 'reset_secure_boot_keys', 'clear_secure_boot_keys', - 'get_server_capabilities' + 'get_server_capabilities', + 'get_supported_boot_mode', ] LOG = log.get_logger(__name__) diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 43cf118c..3e90d5f5 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -19,12 +19,14 @@ import sushy from sushy import utils from proliantutils import exception +from proliantutils.ilo import constants as ilo_cons from proliantutils.ilo import firmware_controller from proliantutils.ilo import operations from proliantutils import log from proliantutils.redfish import main from proliantutils.redfish.resources.manager import constants as mgr_cons from proliantutils.redfish.resources.system import constants as sys_cons +from proliantutils.redfish import utils as rf_utils """ Class specific for Redfish APIs. @@ -85,6 +87,14 @@ BOOT_OPTION_MAP = {'BOOT_ONCE': True, VIRTUAL_MEDIA_MAP = {'FLOPPY': mgr_cons.VIRTUAL_MEDIA_FLOPPY, 'CDROM': mgr_cons.VIRTUAL_MEDIA_CD} +SUPPORTED_BOOT_MODE_MAP = { + sys_cons.SUPPORTED_LEGACY_BIOS_ONLY: ( + ilo_cons.SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY), + sys_cons.SUPPORTED_UEFI_ONLY: ilo_cons.SUPPORTED_BOOT_MODE_UEFI_ONLY, + sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI: ( + ilo_cons.SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI) +} + LOG = log.get_logger(__name__) @@ -600,6 +610,26 @@ class RedfishOperations(operations.IloOperations): LOG.debug(msg) raise exception.IloError(msg) + def get_supported_boot_mode(self): + """Get the system supported boot modes. + + :return: any one of the following proliantutils.ilo.constants: + + SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY, + SUPPORTED_BOOT_MODE_UEFI_ONLY, + SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI + :raises: IloError, if account not found or on an error from iLO. + """ + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + try: + return SUPPORTED_BOOT_MODE_MAP.get( + sushy_system.supported_boot_mode) + except sushy.exceptions.SushyError as e: + msg = (self._('The Redfish controller failed to get the ' + 'supported boot modes. Error: %s') % e) + LOG.debug(msg) + raise exception.IloError(msg) + def get_server_capabilities(self): """Returns the server capabilities @@ -611,12 +641,16 @@ class RedfishOperations(operations.IloOperations): sushy_manager = self._get_sushy_manager(PROLIANT_MANAGER_ID) try: count = len(sushy_system.pci_devices.gpu_devices) + boot_mode = rf_utils.get_supported_boot_mode( + sushy_system.supported_boot_mode) capabilities.update( {'pci_gpu_devices': count, 'ilo_firmware_version': sushy_manager.firmware_version, 'rom_firmware_version': sushy_system.rom_version, 'server_model': sushy_system.model, - 'nic_capacity': sushy_system.pci_devices.max_nic_capacity}) + 'nic_capacity': sushy_system.pci_devices.max_nic_capacity, + 'boot_mode_bios': boot_mode.boot_mode_bios, + 'boot_mode_uefi': boot_mode.boot_mode_uefi}) tpm_state = sushy_system.bios_settings.tpm_state capabilities.update( @@ -634,6 +668,7 @@ class RedfishOperations(operations.IloOperations): ('secure_boot', GET_SECUREBOOT_CURRENT_BOOT_MAP.get( sushy_system.secure_boot.current_boot)),) if value}) + except sushy.exceptions.SushyError as e: msg = (self._("The Redfish controller is unable to get " "resource or its members. Error " diff --git a/proliantutils/redfish/resources/system/constants.py b/proliantutils/redfish/resources/system/constants.py index 3ac25a0c..e0c1d284 100644 --- a/proliantutils/redfish/resources/system/constants.py +++ b/proliantutils/redfish/resources/system/constants.py @@ -55,3 +55,9 @@ TPM_NOT_PRESENT = 'Tpm not present' CPUVT_ENABLED = 'cpu_vt enabled' CPUVT_DISABLED = 'cpu_vt disabled' + +# System supported boot mode contants + +SUPPORTED_LEGACY_BIOS_ONLY = 'legacy bios only' +SUPPORTED_UEFI_ONLY = 'uefi only' +SUPPORTED_LEGACY_BIOS_AND_UEFI = 'legacy bios and uefi' diff --git a/proliantutils/redfish/resources/system/mappings.py b/proliantutils/redfish/resources/system/mappings.py index 70d6ddef..e68a05eb 100644 --- a/proliantutils/redfish/resources/system/mappings.py +++ b/proliantutils/redfish/resources/system/mappings.py @@ -69,3 +69,11 @@ CPUVT_MAP = { 'Enabled': constants.CPUVT_ENABLED, 'Disabled': constants.CPUVT_DISABLED } + +# Supported boot mode map + +SUPPORTED_BOOT_MODE = { + 0: constants.SUPPORTED_LEGACY_BIOS_ONLY, + 2: constants.SUPPORTED_LEGACY_BIOS_AND_UEFI, + 3: constants.SUPPORTED_UEFI_ONLY +} diff --git a/proliantutils/redfish/resources/system/system.py b/proliantutils/redfish/resources/system/system.py index 34213721..8326bf60 100644 --- a/proliantutils/redfish/resources/system/system.py +++ b/proliantutils/redfish/resources/system/system.py @@ -21,6 +21,7 @@ from sushy.resources.system import system from proliantutils import exception from proliantutils import log from proliantutils.redfish.resources.system import bios +from proliantutils.redfish.resources.system import constants from proliantutils.redfish.resources.system import mappings from proliantutils.redfish.resources.system import pci_device from proliantutils.redfish.resources.system import secure_boot @@ -59,6 +60,12 @@ class HPESystem(system.System): model = base.Field(['Model']) rom_version = base.Field(['Oem', 'Hpe', 'Bios', 'Current', 'VersionString']) + + supported_boot_mode = base.MappedField( + ['Oem', 'Hpe', 'Bios', 'UefiClass'], mappings.SUPPORTED_BOOT_MODE, + default=constants.SUPPORTED_LEGACY_BIOS_ONLY) + """System supported boot mode.""" + _hpe_actions = HpeActionsField(['Oem', 'Hpe', 'Actions'], required=True) """Oem specific system extensibility actions""" diff --git a/proliantutils/redfish/utils.py b/proliantutils/redfish/utils.py index cca88eab..9474c68d 100644 --- a/proliantutils/redfish/utils.py +++ b/proliantutils/redfish/utils.py @@ -14,9 +14,17 @@ __author__ = 'HPE' +import collections + import six from proliantutils import exception +from proliantutils.redfish.resources.system import constants as sys_cons + + +# Representation of supported boot modes +SupportedBootModes = collections.namedtuple( + 'SupportedBootModes', ['boot_mode_bios', 'boot_mode_uefi']) def get_subresource_path_by(resource, subresource_path): @@ -49,3 +57,27 @@ def get_subresource_path_by(resource, subresource_path): resource=resource.path) return body['@odata.id'] + + +def get_supported_boot_mode(supported_boot_mode): + """Return bios and uefi support. + + :param supported_boot_mode: Supported boot modes + :return: A tuple of 'true'/'false' based on bios and uefi + support respectively. + """ + boot_mode_bios = 'false' + boot_mode_uefi = 'false' + if (supported_boot_mode == + sys_cons.SUPPORTED_LEGACY_BIOS_ONLY): + boot_mode_bios = 'true' + elif (supported_boot_mode == + sys_cons.SUPPORTED_UEFI_ONLY): + boot_mode_uefi = 'true' + elif (supported_boot_mode == + sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI): + boot_mode_bios = 'true' + boot_mode_uefi = 'true' + + return SupportedBootModes(boot_mode_bios=boot_mode_bios, + boot_mode_uefi=boot_mode_uefi) diff --git a/proliantutils/tests/redfish/resources/system/test_system.py b/proliantutils/tests/redfish/resources/system/test_system.py index 6bef11d9..5f89aa36 100644 --- a/proliantutils/tests/redfish/resources/system/test_system.py +++ b/proliantutils/tests/redfish/resources/system/test_system.py @@ -41,6 +41,10 @@ class HPESystemTestCase(testtools.TestCase): self.conn, '/redfish/v1/Systems/1', redfish_version='1.0.2') + def test_attributes(self): + self.assertEqual(sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI, + self.sys_inst.supported_boot_mode) + def test__get_hpe_push_power_button_action_element(self): value = self.sys_inst._get_hpe_push_power_button_action_element() self.assertEqual("/redfish/v1/Systems/1/Actions/Oem/Hpe/" diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index c39a390e..39110779 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -15,11 +15,13 @@ import json +import ddt import mock import sushy import testtools from proliantutils import exception +from proliantutils.ilo import constants as ilo_cons from proliantutils.redfish import main from proliantutils.redfish import redfish from proliantutils.redfish.resources.account_service import account @@ -33,6 +35,7 @@ from proliantutils.redfish.resources.system import system as pro_sys from sushy.resources.system import system +@ddt.ddt class RedfishOperationsTestCase(testtools.TestCase): @mock.patch.object(main, 'HPESushy', autospec=True) @@ -648,6 +651,22 @@ class RedfishOperationsTestCase(testtools.TestCase): 'No account found with username: foo', self.rf_client.reset_ilo_credential, 'fake-password') + @ddt.data((sys_cons.SUPPORTED_LEGACY_BIOS_ONLY, + ilo_cons.SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY), + (sys_cons.SUPPORTED_UEFI_ONLY, + ilo_cons.SUPPORTED_BOOT_MODE_UEFI_ONLY), + (sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI, + ilo_cons.SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI)) + @ddt.unpack + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_get_supported_boot_mode(self, supported_boot, + expected_boot_val, + get_system_mock): + type(get_system_mock.return_value).supported_boot_mode = ( + supported_boot) + actual_val = self.rf_client.get_supported_boot_mode() + self.assertEqual(expected_boot_val, actual_val) + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') @mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager') def test_get_server_capabilities(self, get_manager_mock, get_system_mock): @@ -669,6 +688,8 @@ class RedfishOperationsTestCase(testtools.TestCase): tpm_mock = mock.PropertyMock(return_value=sys_cons.TPM_PRESENT_ENABLED) type(get_system_mock.return_value.bios_settings).tpm_state = ( tpm_mock) + type(get_system_mock.return_value).supported_boot_mode = ( + sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI) actual = self.rf_client.get_server_capabilities() expected = {'pci_gpu_devices': 1, 'sriov_enabled': 'true', 'secure_boot': 'true', 'cpu_vt': 'true', @@ -676,7 +697,9 @@ class RedfishOperationsTestCase(testtools.TestCase): 'ilo_firmware_version': 'iLO 5 v1.15', 'nic_capacity': '1Gb', 'trusted_boot': 'true', - 'server_model': 'ProLiant DL180 Gen10'} + 'server_model': 'ProLiant DL180 Gen10', + 'boot_mode_bios': 'true', + 'boot_mode_uefi': 'true'} self.assertEqual(expected, actual) @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') @@ -708,12 +731,15 @@ class RedfishOperationsTestCase(testtools.TestCase): tpm_mock = mock.PropertyMock(return_value=sys_cons.TPM_NOT_PRESENT) type(get_system_mock.return_value.bios_settings).tpm_state = ( tpm_mock) + type(get_system_mock.return_value).supported_boot_mode = ( + sys_cons.SUPPORTED_UEFI_ONLY) actual = self.rf_client.get_server_capabilities() expected = {'pci_gpu_devices': 1, 'rom_firmware_version': 'U31 v1.00 (03/11/2017)', 'ilo_firmware_version': 'iLO 5 v1.15', 'nic_capacity': '1Gb', - 'server_model': 'ProLiant DL180 Gen10'} + 'server_model': 'ProLiant DL180 Gen10', + 'boot_mode_bios': 'false', 'boot_mode_uefi': 'true'} self.assertEqual(expected, actual) @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') diff --git a/proliantutils/tests/redfish/test_utils.py b/proliantutils/tests/redfish/test_utils.py index 584ee52e..d9fb76d9 100644 --- a/proliantutils/tests/redfish/test_utils.py +++ b/proliantutils/tests/redfish/test_utils.py @@ -22,6 +22,7 @@ import mock import testtools from proliantutils import exception +from proliantutils.redfish.resources.system import constants as sys_cons from proliantutils.redfish.resources.system import system from proliantutils.redfish import utils @@ -69,3 +70,15 @@ class UtilsTestCase(testtools.TestCase): '"subresource_path" cannot be empty', utils.get_subresource_path_by, self.sys_inst, []) + + @ddt.data((sys_cons.SUPPORTED_LEGACY_BIOS_ONLY, + ('true', 'false')), + (sys_cons.SUPPORTED_UEFI_ONLY, + ('false', 'true')), + (sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI, + ('true', 'true'))) + @ddt.unpack + def test_get_supported_boot_modes(self, boot_mode, + expected_boot_modes): + actual_boot_modes = utils.get_supported_boot_mode(boot_mode) + self.assertEqual(expected_boot_modes, actual_boot_modes)