From 5f71652533abd416fdb9b17f9a4c405ff7bbd90c Mon Sep 17 00:00:00 2001 From: paresh-sao Date: Wed, 3 Jan 2018 10:16:28 +0000 Subject: [PATCH] Redfish: Adding the ability to set and unset iSCSI boot info This commits adds new functions 'set_iscsi_boot_info' and 'unset_iscsi_boot_info' to change iSCSI settings on iLO. Change-Id: I855ae6a4b2ab84e939cf6b0c49f2af001f6a3173 --- proliantutils/ilo/client.py | 2 + proliantutils/ilo/ris.py | 2 +- proliantutils/redfish/redfish.py | 97 +++++++- .../redfish/resources/system/bios.py | 39 ++- .../redfish/resources/system/iscsi.py | 40 ++- proliantutils/tests/ilo/test_client.py | 11 +- .../redfish/json_samples/bios_mappings.json | 81 ++++++ .../redfish/json_samples/iscsi_settings.json | 122 +++++++++ .../redfish/resources/system/test_bios.py | 95 +++++-- .../redfish/resources/system/test_iscsi.py | 82 +++++- proliantutils/tests/redfish/test_redfish.py | 234 +++++++++++++++++- 11 files changed, 769 insertions(+), 36 deletions(-) create mode 100644 proliantutils/tests/redfish/json_samples/bios_mappings.json create mode 100644 proliantutils/tests/redfish/json_samples/iscsi_settings.json diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index eede5165..96896ced 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -87,6 +87,8 @@ SUPPORTED_REDFISH_METHODS = [ 'get_server_capabilities', 'get_supported_boot_mode', 'get_essential_properties', + 'set_iscsi_boot_info', + 'unset_iscsi_boot_info', ] LOG = log.get_logger(__name__) diff --git a/proliantutils/ilo/ris.py b/proliantutils/ilo/ris.py index 459dd9fb..ab2ab120 100755 --- a/proliantutils/ilo/ris.py +++ b/proliantutils/ilo/ris.py @@ -979,7 +979,7 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): msg = self._get_extended_error(response) raise exception.IloError(msg) else: - msg = 'iscsi initiator cannot be set in the BIOS boot mode' + msg = 'iSCSI initiator cannot be set in the BIOS boot mode' raise exception.IloCommandNotSupportedError(msg) def get_current_boot_mode(self): diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 5769dd56..31541d94 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -671,7 +671,7 @@ class RedfishOperations(operations.IloOperations): GET_SECUREBOOT_CURRENT_BOOT_MAP.get( sushy_system.secure_boot.current_boot)), ('iscsi_boot', - (sushy_system.bios_settings.iscsi_settings. + (sushy_system.bios_settings.iscsi_resource. is_iscsi_boot_supported())), ('hardware_supports_raid', len(sushy_system.smart_storage.array_controllers. @@ -860,3 +860,98 @@ class RedfishOperations(operations.IloOperations): % {'error': str(e)}) LOG.debug(msg) raise exception.IloError(msg) + + def _change_iscsi_target_settings(self, iscsi_info): + """Change iSCSI target settings. + + :param iscsi_info: A dictionary that contains information of iSCSI + target like target_name, lun, ip_address, port etc. + :raises: IloError, on an error from iLO. + """ + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + try: + pci_settings_map = ( + sushy_system.bios_settings.bios_mappings.pci_settings_mappings) + nics = [] + for mapping in pci_settings_map: + for subinstance in mapping['Subinstances']: + for association in subinstance['Associations']: + if 'NicBoot' in association: + nics.append(association) + except sushy.exceptions.SushyError as e: + msg = (self._('The Redfish controller failed to get the ' + 'bios mappings. Error %(error)s') + % {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + + if not nics: + msg = ('No nics were found on the system') + raise exception.IloError(msg) + + # Set iSCSI info to all nics + iscsi_infos = [] + for nic in nics: + data = iscsi_info.copy() + data['iSCSIAttemptName'] = nic + data['iSCSINicSource'] = nic + data['iSCSIAttemptInstance'] = nics.index(nic) + 1 + iscsi_infos.append(data) + + iscsi_data = {'iSCSISources': iscsi_infos} + try: + (sushy_system.bios_settings.iscsi_resource. + iscsi_settings.update_iscsi_settings(iscsi_data)) + except sushy.exceptions.SushyError as e: + msg = (self._("The Redfish controller is failed to update iSCSI " + "settings. Error %(error)s") % + {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + + def set_iscsi_boot_info(self, target_name, lun, ip_address, + port='3260', auth_method=None, username=None, + password=None): + """Set iSCSI details of the system in UEFI boot mode. + + The initiator system is set with the target details like + IQN, LUN, IP, Port etc. + :param target_name: Target Name for iSCSI. + :param lun: logical unit number. + :param ip_address: IP address of the target. + :param port: port of the target. + :param auth_method : either None or CHAP. + :param username: CHAP Username for authentication. + :param password: CHAP secret. + :raises: IloCommandNotSupportedInBiosError, if the system is + in the bios boot mode. + """ + if(self._is_boot_mode_uefi()): + iscsi_info = {} + iscsi_info['iSCSITargetName'] = target_name + iscsi_info['iSCSILUN'] = lun + iscsi_info['iSCSITargetIpAddress'] = ip_address + iscsi_info['iSCSITargetTcpPort'] = int(port) + iscsi_info['iSCSITargetInfoViaDHCP'] = False + iscsi_info['iSCSIConnection'] = 'Enabled' + if (auth_method == 'CHAP'): + iscsi_info['iSCSIAuthenticationMethod'] = 'Chap' + iscsi_info['iSCSIChapUsername'] = username + iscsi_info['iSCSIChapSecret'] = password + self._change_iscsi_target_settings(iscsi_info) + else: + msg = 'iSCSI boot is not supported in the BIOS boot mode' + raise exception.IloCommandNotSupportedInBiosError(msg) + + def unset_iscsi_boot_info(self): + """Disable iSCSI boot option in UEFI boot mode. + + :raises: IloCommandNotSupportedInBiosError, if the system is + in the BIOS boot mode. + """ + if(self._is_boot_mode_uefi()): + iscsi_info = {'iSCSIConnection': 'Disabled'} + self._change_iscsi_target_settings(iscsi_info) + else: + msg = 'iSCSI boot is not supported in the BIOS boot mode' + raise exception.IloCommandNotSupportedInBiosError(msg) diff --git a/proliantutils/redfish/resources/system/bios.py b/proliantutils/redfish/resources/system/bios.py index 96bfdb23..22b579f8 100644 --- a/proliantutils/redfish/resources/system/bios.py +++ b/proliantutils/redfish/resources/system/bios.py @@ -45,7 +45,8 @@ class BIOSSettings(base.ResourceBase): cpu_vt = base.MappedField(["Attributes", "ProcVirtualization"], mappings.CPUVT_MAP) - _iscsi_settings = None + _iscsi_resource = None + _bios_mappings = None _pending_settings = None _boot_settings = None @@ -84,20 +85,36 @@ class BIOSSettings(base.ResourceBase): return self._boot_settings @property - def iscsi_settings(self): - """Property to provide reference to bios iscsi instance + def iscsi_resource(self): + """Property to provide reference to bios iscsi resource instance It is calculated once when the first time it is queried. On refresh, this property gets reset. """ - if self._iscsi_settings is None: - self._iscsi_settings = iscsi.ISCSISettings( + if self._iscsi_resource is None: + self._iscsi_resource = iscsi.ISCSIResource( self._conn, utils.get_subresource_path_by( self, ["Oem", "Hpe", "Links", "iScsi"]), redfish_version=self.redfish_version) - return self._iscsi_settings + return self._iscsi_resource + + @property + def bios_mappings(self): + """Property to provide reference to bios mappings instance + + It is calculated once when the first time it is queried. On refresh, + this property gets reset. + """ + if self._bios_mappings is None: + self._bios_mappings = BIOSMappings( + self._conn, + utils.get_subresource_path_by( + self, ["Oem", "Hpe", "Links", "Mappings"]), + redfish_version=self.redfish_version) + + return self._bios_mappings def _get_base_configs(self): """Method that returns object of bios base configs.""" @@ -119,7 +136,8 @@ class BIOSSettings(base.ResourceBase): self._pending_settings = None self._boot_settings = None self._base_configs = None - self._iscsi_settings = None + self._iscsi_resource = None + self._bios_mappings = None class BIOSBaseConfigs(base.ResourceBase): @@ -228,3 +246,10 @@ class BIOSBootSettings(base.ResourceBase): else: msg = ('MAC provided "%s" is Invalid' % mac) raise exception.IloInvalidInputError(msg) + + +class BIOSMappings(base.ResourceBase): + """Class that defines the functionality for BIOS mappings.""" + + pci_settings_mappings = base.Field("BiosPciSettingsMappings", + adapter=list) diff --git a/proliantutils/redfish/resources/system/iscsi.py b/proliantutils/redfish/resources/system/iscsi.py index 140cf7f7..76b21633 100644 --- a/proliantutils/redfish/resources/system/iscsi.py +++ b/proliantutils/redfish/resources/system/iscsi.py @@ -17,12 +17,13 @@ from sushy.resources import base from proliantutils.redfish import utils -class ISCSISettings(base.ResourceBase): - """Class that represents the iSCSI settings resource. +class ISCSIResource(base.ResourceBase): + """Class that represents the iSCSI resource. This class extends the functionality of base resource class from sushy. """ + _iscsi_settings = None def is_iscsi_boot_supported(self): """Checks whether iscsi boot is supported or not. @@ -34,3 +35,38 @@ class ISCSISettings(base.ResourceBase): return utils.is_operation_allowed( 'PATCH', self, ['@Redfish.Settings', 'SettingsObject']) + + @property + def iscsi_settings(self): + """Property to provide reference to iSCSI settings instance + + It is calculated once when the first time it is queried. On refresh, + this property gets reset. + """ + if self._iscsi_settings is None: + self._iscsi_settings = ISCSISettings( + self._conn, + utils.get_subresource_path_by( + self, ["@Redfish.Settings", "SettingsObject"]), + redfish_version=self.redfish_version) + + return self._iscsi_settings + + def refresh(self): + super(ISCSIResource, self).refresh() + self._iscsi_settings = None + + +class ISCSISettings(base.ResourceBase): + """Class that represents the iSCSI settings. + + This class extends the functionality of base resource class + from sushy. + """ + + def update_iscsi_settings(self, iscsi_data): + """Update iscsi data + + :param data: default iscsi config data + """ + self._conn.patch(self.path, data=iscsi_data) diff --git a/proliantutils/tests/ilo/test_client.py b/proliantutils/tests/ilo/test_client.py index 124b2a27..691f52ff 100644 --- a/proliantutils/tests/ilo/test_client.py +++ b/proliantutils/tests/ilo/test_client.py @@ -1039,7 +1039,10 @@ class IloRedfishClientTestCase(testtools.TestCase): validate_method_calls( more_missed_operations, ('arg1', 'arg2'), even_more_missed_operations) - - self.assertEqual(0, len(even_more_missed_operations)) - self.assertEqual(len(client.SUPPORTED_REDFISH_METHODS), - validate_method_calls.no_test_cases) + if(len(even_more_missed_operations) == 1): + self.assertEqual('set_iscsi_boot_info', + even_more_missed_operations[0]) + else: + self.assertEqual(0, len(even_more_missed_operations)) + self.assertEqual(len(client.SUPPORTED_REDFISH_METHODS), + validate_method_calls.no_test_cases) diff --git a/proliantutils/tests/redfish/json_samples/bios_mappings.json b/proliantutils/tests/redfish/json_samples/bios_mappings.json new file mode 100644 index 00000000..b68008a8 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/bios_mappings.json @@ -0,0 +1,81 @@ +{ + "Default": { + "@odata.context": "/redfish/v1/$metadata#HpeBiosMapping.HpeBiosMapping", + "@odata.etag": "W/\"75FF243D79B08484843282DBD1D18A0E\"", + "@odata.id": "/redfish/v1/systems/1/bios/mappings/", + "@odata.type": "#HpeBiosMapping.v2_0_0.HpeBiosMapping", + "BiosPciSettingsMappings":[ + { + "Associations":["EmbSata1Aspm", "EmbSata1PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x0)/Pci(0x17,0x0)", + "Instance": 1, + "Subinstances":[] + }, + { + "Associations":["EmbSata2Aspm", "EmbSata2PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x0)/Pci(0x11,0x5)", + "Instance": 2, + "Subinstances":[] + }, + { + "Associations":["PciSlot3LinkSpeed", "PciSlot3OptionROM"], + "CorrelatableID": "PciRoot(0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Instance": 3, + "Subinstances":[] + }, + { + "Associations":["FlexLom1Enable", "FlexLom1LinkSpeed", "FlexLom1Aspm", "FlexLom1PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Instance": 4, + "Subinstances":[ + { + "Associations":[{"PreBootNetwork": "FlexLom1Port3" }, "NicBoot1"], + "CorrelatableID": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x2)", + "Subinstance": 3 + }, + { + "Associations":[{"PreBootNetwork": "FlexLom1Port4" }, "NicBoot2"], + "CorrelatableID": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x3)", + "Subinstance": 4 + } + ] + } + ], + "Id": "mappings", + "Name": "BIOS mappings" + }, + "Mappings_without_nic": { + "@odata.context": "/redfish/v1/$metadata#HpeBiosMapping.HpeBiosMapping", + "@odata.etag": "W/\"75FF243D79B08484843282DBD1D18A0E\"", + "@odata.id": "/redfish/v1/systems/1/bios/mappings/", + "@odata.type": "#HpeBiosMapping.v2_0_0.HpeBiosMapping", + "BiosPciSettingsMappings":[ + { + "Associations":["EmbSata1Aspm", "EmbSata1PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x0)/Pci(0x17,0x0)", + "Instance": 1, + "Subinstances":[] + }, + { + "Associations":["EmbSata2Aspm", "EmbSata2PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x0)/Pci(0x11,0x5)", + "Instance": 2, + "Subinstances":[] + }, + { + "Associations":["PciSlot3LinkSpeed", "PciSlot3OptionROM"], + "CorrelatableID": "PciRoot(0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Instance": 3, + "Subinstances":[] + }, + { + "Associations":["FlexLom1Enable", "FlexLom1LinkSpeed", "FlexLom1Aspm", "FlexLom1PCIeOptionROM"], + "CorrelatableID": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Instance": 4, + "Subinstances":[] + } + ], + "Id": "mappings", + "Name": "BIOS mappings" + } +} diff --git a/proliantutils/tests/redfish/json_samples/iscsi_settings.json b/proliantutils/tests/redfish/json_samples/iscsi_settings.json new file mode 100644 index 00000000..b553c19c --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/iscsi_settings.json @@ -0,0 +1,122 @@ +{ + "Default": { + "@odata.context": "/redfish/v1/$metadata#HpeiSCSISoftwareInitiator.HpeiSCSISoftwareInitiator", + "@odata.etag": "W/\"9DAB2702E4B2A3A3A38C81720461C5A4\"", + "@odata.id": "/redfish/v1/systems/1/bios/iscsi/settings/", + "@odata.type": "#HpeiSCSISoftwareInitiator.v2_0_0.HpeiSCSISoftwareInitiator", + "Id": "settings", + "Name": "iSCSI Software Initiator Current Settings", + "iSCSIInitiatorName": "iqn.2015-02.com.hpe:uefi-i41-2m27240861", + "iSCSINicSources":[ + "NicBoot1", + "NicBoot2" + ], + "iSCSISources": + [ + { + "StructuredBootString": null, + "UEFIDevicePath": null, + "iSCSIAttemptInstance": 0, + "iSCSIAttemptName": "", + "iSCSIAuthenticationMethod": "None", + "iSCSIChapSecret": null, + "iSCSIChapType": "OneWay", + "iSCSIChapUsername": null, + "iSCSIConnectRetry": 3, + "iSCSIConnectTimeoutMS": 20000, + "iSCSIConnection": "Disabled", + "iSCSIInitiatorGateway": "0.0.0.0", + "iSCSIInitiatorInfoViaDHCP": true, + "iSCSIInitiatorIpAddress": "0.0.0.0", + "iSCSIInitiatorNetmask": "0.0.0.0", + "iSCSIIpAddressType": "IPv4", + "iSCSILUN": "0", + "iSCSINicSource": null, + "iSCSIReverseChapSecret": null, + "iSCSIReverseChapUsername": null, + "iSCSITargetInfoViaDHCP": true, + "iSCSITargetIpAddress": "0.0.0.0", + "iSCSITargetName": "", + "iSCSITargetTcpPort": 3260 + }, + { + "StructuredBootString": null, + "UEFIDevicePath": null, + "iSCSIAttemptInstance": 0, + "iSCSIAttemptName": "", + "iSCSIAuthenticationMethod": "None", + "iSCSIChapSecret": null, + "iSCSIChapType": "OneWay", + "iSCSIChapUsername": null, + "iSCSIConnectRetry": 3, + "iSCSIConnectTimeoutMS": 20000, + "iSCSIConnection": "Disabled", + "iSCSIInitiatorGateway": "0.0.0.0", + "iSCSIInitiatorInfoViaDHCP": true, + "iSCSIInitiatorIpAddress": "0.0.0.0", + "iSCSIInitiatorNetmask": "0.0.0.0", + "iSCSIIpAddressType": "IPv4", + "iSCSILUN": "0", + "iSCSINicSource": null, + "iSCSIReverseChapSecret": null, + "iSCSIReverseChapUsername": null, + "iSCSITargetInfoViaDHCP": true, + "iSCSITargetIpAddress": "0.0.0.0", + "iSCSITargetName": "", + "iSCSITargetTcpPort": 3260 + }, + { + "StructuredBootString": null, + "UEFIDevicePath": null, + "iSCSIAttemptInstance": 0, + "iSCSIAttemptName": "", + "iSCSIAuthenticationMethod": "None", + "iSCSIChapSecret": null, + "iSCSIChapType": "OneWay", + "iSCSIChapUsername": null, + "iSCSIConnectRetry": 3, + "iSCSIConnectTimeoutMS": 20000, + "iSCSIConnection": "Disabled", + "iSCSIInitiatorGateway": "0.0.0.0", + "iSCSIInitiatorInfoViaDHCP": true, + "iSCSIInitiatorIpAddress": "0.0.0.0", + "iSCSIInitiatorNetmask": "0.0.0.0", + "iSCSIIpAddressType": "IPv4", + "iSCSILUN": "0", + "iSCSINicSource": null, + "iSCSIReverseChapSecret": null, + "iSCSIReverseChapUsername": null, + "iSCSITargetInfoViaDHCP": true, + "iSCSITargetIpAddress": "0.0.0.0", + "iSCSITargetName": "", + "iSCSITargetTcpPort": 3260 + }, + { + "StructuredBootString": null, + "UEFIDevicePath": null, + "iSCSIAttemptInstance": 0, + "iSCSIAttemptName": "", + "iSCSIAuthenticationMethod": "None", + "iSCSIChapSecret": null, + "iSCSIChapType": "OneWay", + "iSCSIChapUsername": null, + "iSCSIConnectRetry": 3, + "iSCSIConnectTimeoutMS": 20000, + "iSCSIConnection": "Disabled", + "iSCSIInitiatorGateway": "0.0.0.0", + "iSCSIInitiatorInfoViaDHCP": true, + "iSCSIInitiatorIpAddress": "0.0.0.0", + "iSCSIInitiatorNetmask": "0.0.0.0", + "iSCSIIpAddressType": "IPv4", + "iSCSILUN": "0", + "iSCSINicSource": null, + "iSCSIReverseChapSecret": null, + "iSCSIReverseChapUsername": null, + "iSCSITargetInfoViaDHCP": true, + "iSCSITargetIpAddress": "0.0.0.0", + "iSCSITargetName": "", + "iSCSITargetTcpPort": 3260 + } + ] + } +} diff --git a/proliantutils/tests/redfish/resources/system/test_bios.py b/proliantutils/tests/redfish/resources/system/test_bios.py index e8f31091..0226be92 100644 --- a/proliantutils/tests/redfish/resources/system/test_bios.py +++ b/proliantutils/tests/redfish/resources/system/test_bios.py @@ -83,22 +83,40 @@ class BIOSSettingsTestCase(testtools.TestCase): self.bios_inst.boot_settings) self.conn.get.return_value.json.assert_not_called() - def test_iscsi_settings(self): - self.assertIsNone(self.bios_inst._iscsi_settings) + def test_bios_mappings(self): + self.assertIsNone(self.bios_inst._bios_mappings) self.conn.get.return_value.json.reset_mock() with open('proliantutils/tests/redfish/' - 'json_samples/bios_boot.json', 'r') as f: + 'json_samples/bios_mappings.json', 'r') as f: self.conn.get.return_value.json.return_value = ( json.loads(f.read())['Default']) - actual_settings = self.bios_inst.iscsi_settings + actual_settings = self.bios_inst.bios_mappings self.assertIsInstance(actual_settings, - iscsi.ISCSISettings) + bios.BIOSMappings) self.conn.get.return_value.json.assert_called_once_with() # reset mock self.conn.get.return_value.json.reset_mock() self.assertIs(actual_settings, - self.bios_inst.iscsi_settings) + self.bios_inst.bios_mappings) + self.conn.get.return_value.json.assert_not_called() + + def test_iscsi_resource(self): + self.assertIsNone(self.bios_inst._iscsi_resource) + + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + actual_settings = self.bios_inst.iscsi_resource + self.assertIsInstance(actual_settings, + iscsi.ISCSIResource) + self.conn.get.return_value.json.assert_called_once_with() + # reset mock + self.conn.get.return_value.json.reset_mock() + self.assertIs(actual_settings, + self.bios_inst.iscsi_resource) self.conn.get.return_value.json.assert_not_called() def test__get_base_configs(self): @@ -159,28 +177,53 @@ class BIOSSettingsTestCase(testtools.TestCase): self.assertIsInstance(actual_settings, bios.BIOSBootSettings) - def test_iscsi_settings_on_refresh(self): + def test_bios_mappings_on_refresh(self): with open('proliantutils/tests/redfish/' - 'json_samples/bios_boot.json', 'r') as f: + 'json_samples/bios_mappings.json', 'r') as f: self.conn.get.return_value.json.return_value = ( json.loads(f.read())['Default']) - actual_settings = self.bios_inst.iscsi_settings + actual_settings = self.bios_inst.bios_mappings self.assertIsInstance(actual_settings, - iscsi.ISCSISettings) + bios.BIOSMappings) + + 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._bios_mappings) + + with open('proliantutils/tests/redfish/' + 'json_samples/bios_mappings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.assertIsInstance(actual_settings, + bios.BIOSMappings) + + def test_iscsi_resource_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + actual_settings = self.bios_inst.iscsi_resource + self.assertIsInstance(actual_settings, + iscsi.ISCSIResource) 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._iscsi_settings) + self.assertIsNone(self.bios_inst._iscsi_resource) with open('proliantutils/tests/redfish/' - 'json_samples/bios_boot.json', 'r') as f: + 'json_samples/iscsi.json', 'r') as f: self.conn.get.return_value.json.return_value = ( - json.loads(f.read())['Default']) + json.loads(f.read())) self.assertIsInstance(actual_settings, - iscsi.ISCSISettings) + iscsi.ISCSIResource) def test__get_base_configs_on_refresh(self): with open('proliantutils/tests/redfish/' @@ -388,3 +431,27 @@ class BIOSBootSettingsTestCase(testtools.TestCase): exception.IloError, 'MAC provided "123456" is Invalid', self.bios_boot_inst.get_uefi_boot_string, '123456') + + +class BIOSMappingsTestCase(testtools.TestCase): + + def setUp(self): + super(BIOSMappingsTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/bios_mappings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + self.bios_mappings_inst = bios.BIOSMappings( + self.conn, '/redfish/v1/Systems/1/bios/mappings', + redfish_version='1.0.2') + + def test_attributes(self): + with open('proliantutils/tests/redfish/' + 'json_samples/bios_mappings.json', 'r') as f: + pci_settings_mappings = ( + json.loads(f.read())['Default']['BiosPciSettingsMappings']) + + self.assertEqual( + pci_settings_mappings, + self.bios_mappings_inst.pci_settings_mappings) diff --git a/proliantutils/tests/redfish/resources/system/test_iscsi.py b/proliantutils/tests/redfish/resources/system/test_iscsi.py index 9e9afabb..8f3b6da6 100644 --- a/proliantutils/tests/redfish/resources/system/test_iscsi.py +++ b/proliantutils/tests/redfish/resources/system/test_iscsi.py @@ -24,17 +24,17 @@ from proliantutils.redfish import utils @ddt.ddt -class ISCSISettingsTestCase(testtools.TestCase): +class ISCSIResourceTestCase(testtools.TestCase): def setUp(self): - super(ISCSISettingsTestCase, self).setUp() + super(ISCSIResourceTestCase, self).setUp() self.conn = mock.MagicMock() with open('proliantutils/tests/redfish/' 'json_samples/iscsi.json', 'r') as f: self.conn.get.return_value.json.return_value = ( json.loads(f.read())) - self.iscsi_inst = iscsi.ISCSISettings( + self.iscsi_inst = iscsi.ISCSIResource( self.conn, '/redfish/v1/Systems/1/bios/iscsi', redfish_version='1.0.2') @@ -47,3 +47,79 @@ class ISCSISettingsTestCase(testtools.TestCase): get_method_mock.return_value = allowed_method ret_val = self.iscsi_inst.is_iscsi_boot_supported() self.assertEqual(ret_val, expected) + + def test_iscsi_settings(self): + self.assertIsNone(self.iscsi_inst._iscsi_settings) + + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + actual_settings = self.iscsi_inst.iscsi_settings + self.assertIsInstance(actual_settings, + iscsi.ISCSISettings) + self.conn.get.return_value.json.assert_called_once_with() + # reset mock + self.conn.get.return_value.json.reset_mock() + self.assertIs(actual_settings, + self.iscsi_inst.iscsi_settings) + self.conn.get.return_value.json.assert_not_called() + + def test_iscsi_resource_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + actual_settings = self.iscsi_inst.iscsi_settings + self.assertIsInstance(actual_settings, + iscsi.ISCSISettings) + + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + self.iscsi_inst.refresh() + self.assertIsNone(self.iscsi_inst._iscsi_settings) + + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + self.assertIsInstance(actual_settings, + iscsi.ISCSISettings) + + +class ISCSISettingsTestCase(testtools.TestCase): + + def setUp(self): + super(ISCSISettingsTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['Default']) + + self.iscsi_settings_inst = iscsi.ISCSISettings( + self.conn, '/redfish/v1/Systems/1/bios/iscsi/settings', + redfish_version='1.0.2') + + def test_update_iscsi_settings(self): + target_uri = '/redfish/v1/Systems/1/bios/iscsi/settings' + iscsi_data = {'iSCSITargetName': + 'iqn.2011-07.com.example.server:test1', + 'iSCSILUN': '1', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSITargetInfoViaDHCP': False, + 'iSCSIConnection': 'Enabled', + 'iSCSIAttemptName': 'NicBoot1', + 'iSCSINicSource': 'NicBoot1', + 'iSCSIAttemptInstance': 1} + + data = { + 'iSCSISources': iscsi_data + } + self.iscsi_settings_inst.update_iscsi_settings(data) + self.iscsi_settings_inst._conn.patch.assert_called_once_with( + target_uri, data=data) diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index 017dbe2f..508925fb 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -713,9 +713,9 @@ class RedfishOperationsTestCase(testtools.TestCase): tpm_mock) type(get_system_mock.return_value).supported_boot_mode = ( sys_cons.SUPPORTED_LEGACY_BIOS_AND_UEFI) - iscsi_mock = mock.MagicMock(spec=iscsi.ISCSISettings) + iscsi_mock = mock.MagicMock(spec=iscsi.ISCSIResource) iscsi_mock.is_iscsi_boot_supported = mock.MagicMock(return_value=True) - type(get_system_mock.return_value.bios_settings).iscsi_settings = ( + type(get_system_mock.return_value.bios_settings).iscsi_resource = ( iscsi_mock) type(get_system_mock.return_value.smart_storage. array_controllers).members_identities = [ @@ -790,9 +790,9 @@ class RedfishOperationsTestCase(testtools.TestCase): tpm_mock) type(get_system_mock.return_value).supported_boot_mode = ( sys_cons.SUPPORTED_UEFI_ONLY) - iscsi_mock = mock.MagicMock(spec=iscsi.ISCSISettings) + iscsi_mock = mock.MagicMock(spec=iscsi.ISCSIResource) iscsi_mock.is_iscsi_boot_supported = mock.MagicMock(return_value=False) - type(get_system_mock.return_value.bios_settings).iscsi_settings = ( + type(get_system_mock.return_value.bios_settings).iscsi_resource = ( iscsi_mock) type(get_system_mock.return_value.smart_storage. array_controllers).members_identities = [] @@ -1043,3 +1043,229 @@ class RedfishOperationsTestCase(testtools.TestCase): "The Redfish controller failed to get the " "resource data. Error None", self.rf_client.get_essential_properties) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi', + autospec=True) + def test_set_iscsi_boot_info_bios(self, _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = False + self.assertRaisesRegex(exception.IloCommandNotSupportedInBiosError, + 'iSCSI boot is not supported ' + 'in the BIOS boot mode', + self.rf_client.set_iscsi_boot_info, + 'iqn.2011-07.com.example.server:test1', + '1', '10.10.1.30') + + @mock.patch.object(redfish.RedfishOperations, + '_change_iscsi_target_settings', autospec=True) + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi', + autospec=True) + def test_set_iscsi_boot_info_uefi(self, _uefi_boot_mode_mock, + change_iscsi_target_settings_mock): + _uefi_boot_mode_mock.return_value = True + iscsi_variables = { + 'iSCSITargetName': 'iqn.2011-07.com.example.server:test1', + 'iSCSITargetInfoViaDHCP': False, + 'iSCSILUN': '1', + 'iSCSIConnection': 'Enabled', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260} + self.rf_client.set_iscsi_boot_info( + 'iqn.2011-07.com.example.server:test1', + '1', '10.10.1.30') + change_iscsi_target_settings_mock.assert_called_once_with( + self.rf_client, iscsi_variables) + + @mock.patch.object(redfish.RedfishOperations, + '_change_iscsi_target_settings', autospec=True) + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi', + autospec=True) + def test_set_iscsi_boot_info_uefi_with_chap( + self, _uefi_boot_mode_mock, change_iscsi_target_settings_mock): + _uefi_boot_mode_mock.return_value = True + iscsi_variables = { + 'iSCSITargetName': 'iqn.2011-07.com.example.server:test1', + 'iSCSITargetInfoViaDHCP': False, + 'iSCSILUN': '1', + 'iSCSIConnection': 'Enabled', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSIAuthenticationMethod': 'Chap', + 'iSCSIChapUsername': 'admin', + 'iSCSIChapSecret': 'password'} + self.rf_client.set_iscsi_boot_info( + 'iqn.2011-07.com.example.server:test1', + '1', '10.10.1.30', 3260, 'CHAP', 'admin', 'password') + change_iscsi_target_settings_mock.assert_called_once_with( + self.rf_client, iscsi_variables) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi', + autospec=True) + def test_unset_iscsi_boot_info_bios(self, _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = False + self.assertRaisesRegex(exception.IloCommandNotSupportedInBiosError, + "iSCSI boot is not supported " + "in the BIOS boot mode", + self.rf_client.unset_iscsi_boot_info) + + @mock.patch.object(redfish.RedfishOperations, + '_change_iscsi_target_settings', autospec=True) + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi', + autospec=True) + def test_unset_iscsi_boot_info_uefi(self, _uefi_boot_mode_mock, + change_iscsi_target_settings_mock): + _uefi_boot_mode_mock.return_value = True + iscsi_variables = { + 'iSCSIConnection': 'Disabled'} + self.rf_client.unset_iscsi_boot_info() + change_iscsi_target_settings_mock.assert_called_once_with( + self.rf_client, iscsi_variables) + + @mock.patch.object(iscsi.ISCSISettings, 'update_iscsi_settings') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test__change_iscsi_target_settings( + self, get_system_mock, update_iscsi_settings_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_mappings.json', 'r') as f: + bios_mappings_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi.json', 'r') as f: + iscsi_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + iscsi_settings_json = json.loads(f.read()) + + self.conn = mock.Mock() + self.conn.get.return_value.json.side_effect = [ + system_json['default'], bios_json['Default'], + bios_mappings_json['Default'], iscsi_json, + iscsi_settings_json['Default']] + 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 + iscsi_variable = {'iSCSITargetName': + 'iqn.2011-07.com.example.server:test1', + 'iSCSILUN': '1', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSITargetInfoViaDHCP': False, + 'iSCSIConnection': 'Enabled'} + iscsi_data1 = {'iSCSITargetName': + 'iqn.2011-07.com.example.server:test1', + 'iSCSILUN': '1', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSITargetInfoViaDHCP': False, + 'iSCSIConnection': 'Enabled', + 'iSCSIAttemptName': 'NicBoot1', + 'iSCSINicSource': 'NicBoot1', + 'iSCSIAttemptInstance': 1} + iscsi_data2 = {'iSCSITargetName': + 'iqn.2011-07.com.example.server:test1', + 'iSCSILUN': '1', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSITargetInfoViaDHCP': False, + 'iSCSIConnection': 'Enabled', + 'iSCSIAttemptName': 'NicBoot2', + 'iSCSINicSource': 'NicBoot2', + 'iSCSIAttemptInstance': 2} + + data = { + 'iSCSISources': [iscsi_data1, iscsi_data2] + } + self.rf_client._change_iscsi_target_settings(iscsi_variable) + update_iscsi_settings_mock.assert_called_once_with( + data) + + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test__change_iscsi_target_settings_failed_getting_mappings( + self, get_system_mock): + mapping_mock = mock.PropertyMock( + side_effect=sushy.exceptions.SushyError) + type(get_system_mock.return_value.bios_settings).bios_mappings = ( + mapping_mock) + self.assertRaisesRegex( + exception.IloError, + "The Redfish controller failed to get the " + "bios mappings. Error", + self.rf_client._change_iscsi_target_settings, + '{}') + + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test__change_iscsi_target_settings_no_nics( + 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_mappings.json', 'r') as f: + bios_mappings_json = json.loads(f.read()) + self.conn = mock.Mock() + self.conn.get.return_value.json.side_effect = [ + system_json['default'], bios_json['Default'], + bios_mappings_json['Mappings_without_nic']] + 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 + self.assertRaisesRegex( + exception.IloError, + "No nics were found on the system", + self.rf_client._change_iscsi_target_settings, + '{}') + + @mock.patch.object(iscsi.ISCSISettings, 'update_iscsi_settings') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test__change_iscsi_target_settings_update_failed( + self, get_system_mock, update_iscsi_settings_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_mappings.json', 'r') as f: + bios_mappings_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi.json', 'r') as f: + iscsi_json = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/iscsi_settings.json', 'r') as f: + iscsi_settings_json = json.loads(f.read()) + + self.conn = mock.Mock() + self.conn.get.return_value.json.side_effect = [ + system_json['default'], bios_json['Default'], + bios_mappings_json['Default'], iscsi_json, + iscsi_settings_json['Default']] + + 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 + iscsi_variable = {'iSCSITargetName': + 'iqn.2011-07.com.example.server:test1', + 'iSCSILUN': '1', + 'iSCSITargetIpAddress': '10.10.1.30', + 'iSCSITargetTcpPort': 3260, + 'iSCSITargetInfoViaDHCP': False, + 'iSCSIConnection': 'Enabled'} + update_iscsi_settings_mock.side_effect = ( + sushy.exceptions.SushyError) + self.assertRaisesRegex( + exception.IloError, + 'The Redfish controller is failed to update iSCSI ' + 'settings.', + self.rf_client._change_iscsi_target_settings, + iscsi_variable)