From b3cc42878913fa54d3b88e61dd02923879962b60 Mon Sep 17 00:00:00 2001 From: paresh-sao Date: Thu, 26 Oct 2017 10:45:27 +0000 Subject: [PATCH] Changed '_update_persistent_boot' to set 'UefiTarget' boot device also removed 'mac' from 'set_one_time_boot' Adds modification in '_update_persistent_boot' to set 'UefiTarget' as boot device, without using 'mac' also removed 'mac' from 'set_one_time_boot' and 'update_persistent_boot' as revert of '25f4881730d80a9142d9cf181618b38185d33c91.' Change-Id: I2c0f95aed084f415b1c065f1a97936d75bdab366 Closes-Bug: #1727670 --- proliantutils/ilo/client.py | 4 +- proliantutils/ilo/operations.py | 2 +- proliantutils/ilo/ribcl.py | 6 +- proliantutils/ilo/ris.py | 44 ++++----- proliantutils/tests/ilo/ris_sample_outputs.py | 62 ++++++++++++ proliantutils/tests/ilo/test_client.py | 12 +-- proliantutils/tests/ilo/test_ris.py | 94 +++++++++---------- 7 files changed, 134 insertions(+), 90 deletions(-) diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index bf717191..09929a83 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -350,9 +350,9 @@ class IloClient(operations.IloOperations): """ return self._call_method('set_host_power', power) - def set_one_time_boot(self, value, mac=None): + def set_one_time_boot(self, value): """Configures a single boot from a specific device.""" - return self._call_method('set_one_time_boot', value, mac) + return self._call_method('set_one_time_boot', value) def insert_virtual_media(self, url, device='FLOPPY'): """Notifies iLO of the location of a virtual media diskette image.""" diff --git a/proliantutils/ilo/operations.py b/proliantutils/ilo/operations.py index 5294af8b..6f9dce15 100644 --- a/proliantutils/ilo/operations.py +++ b/proliantutils/ilo/operations.py @@ -145,7 +145,7 @@ class IloOperations(object): """ raise exception.IloCommandNotSupportedError(ERRMSG) - def set_one_time_boot(self, value, mac=None): + def set_one_time_boot(self, value): """Configures a single boot from a specific device.""" raise exception.IloCommandNotSupportedError(ERRMSG) diff --git a/proliantutils/ilo/ribcl.py b/proliantutils/ilo/ribcl.py index 93e1fcd7..1f0aa547 100644 --- a/proliantutils/ilo/ribcl.py +++ b/proliantutils/ilo/ribcl.py @@ -407,14 +407,10 @@ class RIBCLOperations(operations.IloOperations): raise exception.IloInvalidInputError( "Invalid input. The expected input is ON or OFF.") - def set_one_time_boot(self, value, mac=None): + def set_one_time_boot(self, value): """Configures a single boot from a specific device. :param value: specific device to which the boot option is set - :param mac: MAC value of the data NIC in case ISCSI target is - set as boot device. This value may not be used - here since RIBCL does not support setting ISCSI - target. However included here for consistency. """ dic = {'value': value} data = self._execute_command( diff --git a/proliantutils/ilo/ris.py b/proliantutils/ilo/ris.py index 66d7a3c4..8d0c52d8 100755 --- a/proliantutils/ilo/ris.py +++ b/proliantutils/ilo/ris.py @@ -1562,8 +1562,7 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): else: return None - def _update_persistent_boot(self, device_type=[], persistent=False, - mac=None): + def _update_persistent_boot(self, device_type=[], persistent=False): """Changes the persistent boot device order in BIOS boot mode for host Note: It uses first boot device from the device_type and ignores rest. @@ -1571,7 +1570,6 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): :param device_type: ordered list of boot devices :param persistent: Boolean flag to indicate if the device to be set as a persistent boot device - :param mac: intiator mac address, mandotory for iSCSI uefi boot :raises: IloError, on an error from iLO. :raises: IloCommandNotSupportedError, if the command is not supported on the server. @@ -1588,27 +1586,23 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): systems_uri = "/rest/v1/Systems/1" # Need to set this option first if device is 'UefiTarget' if new_device is 'UefiTarget': - if not mac: - msg = ('Mac is needed for iscsi uefi boot') - raise exception.IloInvalidInputError(msg) - - headers, bios_uri, bios_settings = self._check_bios_resource() - # Get the Boot resource and Mappings resource. - boot_settings = self._get_bios_boot_resource(bios_settings) - StructuredBootString = None - - for boot_setting in boot_settings['BootSources']: - if(mac.upper() in boot_setting['UEFIDevicePath'] and - 'iSCSI' in boot_setting['UEFIDevicePath']): - StructuredBootString = boot_setting['StructuredBootString'] + system = self._get_host_details() + uefi_devices = ( + system['Boot']['UefiTargetBootSourceOverrideSupported']) + iscsi_device = None + for device in uefi_devices: + if device is not None and 'iSCSI' in device: + iscsi_device = device break - if not StructuredBootString: - msg = ('MAC provided is Invalid "%s"' % mac) - raise exception.IloInvalidInputError(msg) + + if iscsi_device is None: + msg = 'No UEFI iSCSI bootable device found' + raise exception.IloError(msg) new_boot_settings = {} new_boot_settings['Boot'] = {'UefiTargetBootSourceOverride': - StructuredBootString} + iscsi_device} + status, headers, response = self._rest_patch(systems_uri, None, new_boot_settings) if status >= 300: @@ -1624,11 +1618,10 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): msg = self._get_extended_error(response) raise exception.IloError(msg) - def update_persistent_boot(self, device_type=[], mac=None): + def update_persistent_boot(self, device_type=[]): """Changes the persistent boot device order for the host :param device_type: ordered list of boot devices - :param mac: intiator mac address, mandatory for iSCSI uefi boot :raises: IloError, on an error from iLO. :raises: IloCommandNotSupportedError, if the command is not supported on the server. @@ -1640,18 +1633,17 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations): "devices: NETWORK, HDD," " ISCSI or CDROM.") - self._update_persistent_boot(device_type, persistent=True, mac=mac) + self._update_persistent_boot(device_type, persistent=True) - def set_one_time_boot(self, device, mac=None): + def set_one_time_boot(self, device): """Configures a single boot from a specific device. :param device: Device to be set as a one time boot device - :param mac: intiator mac address, optional parameter :raises: IloError, on an error from iLO. :raises: IloCommandNotSupportedError, if the command is not supported on the server. """ - self._update_persistent_boot([device], persistent=False, mac=mac) + self._update_persistent_boot([device], persistent=False) def get_one_time_boot(self): """Retrieves the current setting for the one time boot. diff --git a/proliantutils/tests/ilo/ris_sample_outputs.py b/proliantutils/tests/ilo/ris_sample_outputs.py index 9a5c0d1d..6afa0fd9 100755 --- a/proliantutils/tests/ilo/ris_sample_outputs.py +++ b/proliantutils/tests/ilo/ris_sample_outputs.py @@ -219,6 +219,68 @@ RESPONSE_BODY_FOR_REST_OP = """ } """ +RESPONSE_BODY_FOR_REST_OP_WITH_ISCSI = """ +{ + "Boot": { + "BootSourceOverrideEnabled": "Disabled", + "BootSourceOverrideSupported": [ + "None", + "Cd", + "Hdd", + "Usb", + "Utilities", + "Diags", + "BiosSetup", + "Pxe", + "UefiShell", + "UefiTarget" + ], + "BootSourceOverrideTarget": "None", + "UefiTargetBootSourceOverride": "None", + "UefiTargetBootSourceOverrideSupported": [ + "HD.Emb.1.2", + "Generic.USB.1.1", + "NIC.FlexLOM.1.1.IPv4", + "NIC.FlexLOM.1.1.IPv6", + "NIC.LOM.1.1.iSCSI", + "CD.Virtual.2.1" + ] + } +} +""" + +RESPONSE_BODY_FOR_REST_OP_WITH_ISCSI_AND_NONE = """ +{ + "Boot": { + "BootSourceOverrideEnabled": "Disabled", + "BootSourceOverrideSupported": [ + "None", + "Cd", + "Hdd", + "Usb", + "Utilities", + "Diags", + "BiosSetup", + "Pxe", + "UefiShell", + "UefiTarget" + ], + "BootSourceOverrideTarget": "None", + "UefiTargetBootSourceOverride": "None", + "UefiTargetBootSourceOverrideSupported": [ + "HD.Emb.1.2", + null, + "HD.Emb.2.1", + "HD.Emb.1.2", + "NIC.FlexLOM.1.1.IPv4", + "NIC.FlexLOM.1.1.IPv6", + "NIC.LOM.1.1.iSCSI", + "CD.Virtual.2.1" + ] + } +} +""" + HEADERS_FOR_REST_OP = [('content-length', '2729'), ('server', 'HP-iLO-Server/1.30'), ('etag', 'W/"B61EB245"'), diff --git a/proliantutils/tests/ilo/test_client.py b/proliantutils/tests/ilo/test_client.py index 288c888d..41052739 100644 --- a/proliantutils/tests/ilo/test_client.py +++ b/proliantutils/tests/ilo/test_client.py @@ -439,13 +439,7 @@ class IloClientTestCase(testtools.TestCase): @mock.patch.object(client.IloClient, '_call_method') def test_set_one_time_boot(self, call_mock): self.client.set_one_time_boot('CDROM') - call_mock.assert_called_once_with('set_one_time_boot', 'CDROM', None) - - @mock.patch.object(client.IloClient, '_call_method') - def test_set_one_time_boot_with_mac(self, call_mock): - mac = '3863bb43683c' - self.client.set_one_time_boot('ISCSI', mac) - call_mock.assert_called_once_with('set_one_time_boot', 'ISCSI', mac) + call_mock.assert_called_once_with('set_one_time_boot', 'CDROM') @mock.patch.object(client.IloClient, '_call_method') def test_insert_virtual_media(self, call_mock): @@ -818,13 +812,13 @@ class IloClientTestCase(testtools.TestCase): def test_set_one_time_boot_gen9(self, set_one_time_boot_mock): self.client.model = 'Gen9' self.client.set_one_time_boot('cdrom') - set_one_time_boot_mock.assert_called_once_with('cdrom', None) + set_one_time_boot_mock.assert_called_once_with('cdrom') @mock.patch.object(ribcl.RIBCLOperations, 'set_one_time_boot') def test_set_one_time_boot_gen8(self, set_one_time_boot_mock): self.client.model = 'Gen8' self.client.set_one_time_boot('cdrom') - set_one_time_boot_mock.assert_called_once_with('cdrom', None) + set_one_time_boot_mock.assert_called_once_with('cdrom') @mock.patch.object(ris.RISOperations, 'update_persistent_boot') def test_update_persistent_boot_gen9(self, update_persistent_boot_mock): diff --git a/proliantutils/tests/ilo/test_ris.py b/proliantutils/tests/ilo/test_ris.py index 531cab0b..007e28ed 100755 --- a/proliantutils/tests/ilo/test_ris.py +++ b/proliantutils/tests/ilo/test_ris.py @@ -944,13 +944,13 @@ class IloRisTestCase(testtools.TestCase): def test_set_one_time_boot_cdrom(self, update_persistent_boot_mock): self.client.set_one_time_boot('cdrom') update_persistent_boot_mock.assert_called_once_with( - ['cdrom'], persistent=False, mac=None) + ['cdrom'], persistent=False) @mock.patch.object(ris.RISOperations, '_update_persistent_boot') def test_set_one_time_boot_iscsi(self, update_persistent_boot_mock): - self.client.set_one_time_boot('ISCSI', '9cb654797870') + self.client.set_one_time_boot('ISCSI') update_persistent_boot_mock.assert_called_once_with( - ['ISCSI'], persistent=False, mac='9cb654797870') + ['ISCSI'], persistent=False) @mock.patch.object(ris.RISOperations, '_get_host_details') def test_get_persistent_boot_device_cdrom(self, get_host_details_mock): @@ -1065,13 +1065,13 @@ class IloRisTestCase(testtools.TestCase): def test_update_persistent_boot_cdrom(self, update_persistent_boot_mock): self.client.update_persistent_boot(['cdrom']) update_persistent_boot_mock.assert_called_once_with( - ['cdrom'], mac=None, persistent=True) + ['cdrom'], persistent=True) @mock.patch.object(ris.RISOperations, '_update_persistent_boot') def test_update_persistent_boot_iscsi(self, update_persistent_boot_mock): - self.client.update_persistent_boot(['ISCSI'], '9cb654797870') + self.client.update_persistent_boot(['ISCSI']) update_persistent_boot_mock.assert_called_once_with( - ['ISCSI'], mac='9cb654797870', persistent=True) + ['ISCSI'], persistent=True) @mock.patch.object(ris.RISOperations, '_update_persistent_boot') def test_update_persistent_boot_exc(self, update_persistent_boot_mock): @@ -1695,8 +1695,7 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): 'BootSourceOverrideTarget': 'Cd'} rest_patch_mock.return_value = (200, ris_outputs.GET_HEADERS, ris_outputs.REST_POST_RESPONSE) - self.client._update_persistent_boot(['cdrom'], mac=None, - persistent=False) + self.client._update_persistent_boot(['cdrom'], persistent=False) rest_patch_mock.assert_called_once_with(systems_uri, None, new_boot_settings) @@ -1708,8 +1707,7 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): 'BootSourceOverrideTarget': 'Cd'} rest_patch_mock.return_value = (200, ris_outputs.GET_HEADERS, ris_outputs.REST_POST_RESPONSE) - self.client._update_persistent_boot(['cdrom'], mac=None, - persistent=True) + self.client._update_persistent_boot(['cdrom'], persistent=True) rest_patch_mock.assert_called_once_with(systems_uri, None, new_boot_settings) @@ -1721,23 +1719,17 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): 'BootSourceOverrideTarget': 'UefiShell'} rest_patch_mock.return_value = (200, ris_outputs.GET_HEADERS, ris_outputs.REST_POST_RESPONSE) - self.client._update_persistent_boot(['UefiShell'], mac=None, + self.client._update_persistent_boot(['UefiShell'], persistent=True) rest_patch_mock.assert_called_once_with(systems_uri, None, new_boot_settings) - @mock.patch.object(ris.RISOperations, '_get_bios_boot_resource') - @mock.patch.object(ris.RISOperations, '_check_bios_resource') + @mock.patch.object(ris.RISOperations, '_get_host_details') @mock.patch.object(ris.RISOperations, '_rest_patch') - def test__update_persistent_boot_for_iscsi_mac_valid(self, rest_patch_mock, - check_bios_mock, - boot_mock): - bios_uri = '/rest/v1/systems/1/bios' - bios_settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) - check_bios_mock.return_value = (ris_outputs.GET_HEADERS, - bios_uri, bios_settings) - boot_settings = json.loads(ris_outputs.GET_BIOS_BOOT) - boot_mock.return_value = boot_settings + def test__update_persistent_boot_for_iscsi(self, rest_patch_mock, + get_host_mock): + get_host_mock.return_value = ( + json.loads(ris_outputs.RESPONSE_BODY_FOR_REST_OP_WITH_ISCSI)) systems_uri = '/rest/v1/Systems/1' new1_boot_settings = {} new1_boot_settings['Boot'] = {'UefiTargetBootSourceOverride': @@ -1751,33 +1743,41 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): ris_outputs.REST_POST_RESPONSE) calls = [mock.call(systems_uri, None, new1_boot_settings), mock.call(systems_uri, None, new2_boot_settings)] - self.client._update_persistent_boot(['ISCSI'], mac='C4346BB7EF30', - persistent=True) - check_bios_mock.assert_called_once_with() - boot_mock.assert_called_once_with(bios_settings) + self.client._update_persistent_boot(['ISCSI'], persistent=True) rest_patch_mock.assert_has_calls(calls) - @mock.patch.object(ris.RISOperations, '_get_bios_boot_resource') - @mock.patch.object(ris.RISOperations, '_check_bios_resource') - def test__update_persistent_boot_for_iscsi_mac_invalid(self, - check_bios_mock, - boot_mock): - bios_uri = '/rest/v1/systems/1/bios' - bios_settings = json.loads(ris_outputs.GET_BIOS_SETTINGS) - check_bios_mock.return_value = (ris_outputs.GET_HEADERS, - bios_uri, bios_settings) - boot_settings = json.loads(ris_outputs.GET_BIOS_BOOT) - boot_mock.return_value = boot_settings - self.assertRaises(exception.IloInvalidInputError, - self.client._update_persistent_boot, ['ISCSI'], - mac='234343553', persistent=True) - check_bios_mock.assert_called_once_with() - boot_mock.assert_called_once_with(bios_settings) + @mock.patch.object(ris.RISOperations, '_get_host_details') + @mock.patch.object(ris.RISOperations, '_rest_patch') + def test__update_persistent_boot_for_iscsi_with_none_device_present( + self, rest_patch_mock, get_host_mock): + get_host_mock.return_value = ( + json.loads( + ris_outputs.RESPONSE_BODY_FOR_REST_OP_WITH_ISCSI_AND_NONE)) + systems_uri = '/rest/v1/Systems/1' + new1_boot_settings = {} + new1_boot_settings['Boot'] = {'UefiTargetBootSourceOverride': + u'NIC.LOM.1.1.iSCSI'} + new2_boot_settings = {} + new2_boot_settings['Boot'] = {'BootSourceOverrideEnabled': + 'Continuous', 'BootSourceOverrideTarget': + 'UefiTarget'} - def test__update_persistent_boot_for_iscsi_mac_none(self): - self.assertRaises(exception.IloInvalidInputError, - self.client._update_persistent_boot, ['ISCSI'], - mac=None, persistent=True) + rest_patch_mock.return_value = (200, ris_outputs.GET_HEADERS, + ris_outputs.REST_POST_RESPONSE) + calls = [mock.call(systems_uri, None, new1_boot_settings), + mock.call(systems_uri, None, new2_boot_settings)] + self.client._update_persistent_boot(['ISCSI'], persistent=True) + rest_patch_mock.assert_has_calls(calls) + + @mock.patch.object(ris.RISOperations, '_get_host_details') + def test__update_persistent_boot_for_iscsi_not_found(self, + get_host_mock): + get_host_mock.return_value = ( + json.loads(ris_outputs.RESPONSE_BODY_FOR_REST_OP)) + self.assertRaisesRegex(exception.IloError, "No UEFI iSCSI bootable " + "device found", + self.client._update_persistent_boot, + ['ISCSI'], persistent=True) @mock.patch.object(ris.RISOperations, '_rest_patch') def test__update_persistent_boot_fail(self, rest_patch_mock): @@ -1789,7 +1789,7 @@ class TestRISOperationsPrivateMethods(testtools.TestCase): ris_outputs.REST_POST_RESPONSE) self.assertRaises(exception.IloError, self.client._update_persistent_boot, - ['FakeDevice'], mac=None, persistent=True) + ['FakeDevice'], persistent=True) rest_patch_mock.assert_called_once_with(systems_uri, None, new_boot_settings)