From ae072a408e86cbc44a2ba09b273ae623895e7827 Mon Sep 17 00:00:00 2001 From: Nguyen Van Trung Date: Tue, 17 Jul 2018 08:28:36 +0700 Subject: [PATCH] Follow-up to BIOS configuration feature This path will process following items: - Allow setting along with different iRMC versions. - Fix bug which relate to boolean values during setting. - Store string value when perform get BIOS setting. - Remove .key() and allow working in python3. NOTE: Integer value under string has accepted for BIOS input already (tested). e.g: {"name": "cpu_active_processor_cores","value": "2"} Tested with TX2540 M1 successfully. Change-Id: Ie79992b09754987d1891fffbf106ab1fdc3fc48b --- scciclient/irmc/elcm.py | 67 +++++++++- scciclient/tests/irmc/test_elcm.py | 194 +++++++++++++++++++++++++++-- 2 files changed, 245 insertions(+), 16 deletions(-) diff --git a/scciclient/irmc/elcm.py b/scciclient/irmc/elcm.py index 4909255..d39bc27 100644 --- a/scciclient/irmc/elcm.py +++ b/scciclient/irmc/elcm.py @@ -17,6 +17,7 @@ eLCM functionality. """ import collections +import six import time from oslo_serialization import jsonutils @@ -98,7 +99,6 @@ BIOS_CONFIGURATION_DICTIONARY = { "sata_mode": "SataConfig_SataMode", "secure_boot_control_enabled": "SecurityConfig_SecureBootControlEnabled", "secure_boot_mode": "SecurityConfig_SecureBootMode", - "serial_port_io_config": "SerialPortConfig_IOConfig", "single_root_io_virtualization_support_enabled": "PciConfig_SingleRootIOVirtualizationSupportEnabled", "storage_option_rom_policy": "CsmConfig_StorageOptionRomPolicy", @@ -243,6 +243,44 @@ def elcm_request(irmc_info, method, path, **kwargs): return r +def elcm_profile_get_versions(irmc_info): + """send an eLCM request to get profile versions + + :param irmc_info: node info + :returns: dict object of profiles if succeed + { + "Server":{ + "@Version": "1.01", + "AdapterConfigIrmc":{ + "@Version": "1.00" + }, + "HWConfigurationIrmc":{ + "@Version": "1.00" + }, + "SystemConfig":{ + "IrmcConfig":{ + "@Version": "1.02" + }, + "BiosConfig":{ + "@Version": "1.02" + } + } + } + } + :raises: SCCIClientError if SCCI failed + """ + # Send GET request to the server + resp = elcm_request(irmc_info, + method='GET', + path=URL_PATH_PROFILE_MGMT + 'version') + + if resp.status_code == 200: + return _parse_elcm_response_body_as_json(resp) + else: + raise scci.SCCIClientError(('Failed to get profile versions with ' + 'error code %s' % resp.status_code)) + + def elcm_profile_list(irmc_info): """send an eLCM request to list all profiles @@ -1043,10 +1081,29 @@ def set_bios_configuration(irmc_info, settings): } } } + + versions = elcm_profile_get_versions(irmc_info) + server_version = versions['Server'].get('@Version') + bios_version = \ + versions['Server']['SystemConfig']['BiosConfig'].get('@Version') + + if server_version: + bios_config_data['Server']['@Version'] = server_version + if bios_version: + bios_config_data['Server']['SystemConfig']['BiosConfig']['@Version'] = \ + bios_version + configs = {} for setting_param in settings: setting_name = setting_param.get("name") setting_value = setting_param.get("value") + # Revert-conversion from a string of True/False to boolean. + # It will be raise failed if put "True" or "False" string value. + if isinstance(setting_value, six.string_types): + if setting_value.lower() == "true": + setting_value = True + elif setting_value.lower() == "false": + setting_value = False try: type_config, config = BIOS_CONFIGURATION_DICTIONARY[ setting_name].split("_") @@ -1058,7 +1115,7 @@ def set_bios_configuration(irmc_info, settings): raise BiosConfigNotFound("Invalid BIOS setting: %s" % setting_param) bios_config_data['Server']['SystemConfig']['BiosConfig'].update(configs) - restore_bios_config(irmc_info=irmc_info, bios_config=bios_config_data) + restore_bios_config(irmc_info, bios_config_data) def get_bios_settings(irmc_info): @@ -1071,10 +1128,12 @@ def get_bios_settings(irmc_info): bios_config = backup_bios_config(irmc_info)['bios_config'] bios_config_data = bios_config['Server']['SystemConfig']['BiosConfig'] settings = [] - for setting_param in BIOS_CONFIGURATION_DICTIONARY.keys(): + + # TODO(trungnv): Allow working with multi levels of BIOS dictionary. + for setting_param in BIOS_CONFIGURATION_DICTIONARY: type_config, config = BIOS_CONFIGURATION_DICTIONARY[ setting_param].split("_") if config in bios_config_data.get(type_config, {}): - value = bios_config_data[type_config][config] + value = six.text_type(bios_config_data[type_config][config]) settings.append({'name': setting_param, 'value': value}) return settings diff --git a/scciclient/tests/irmc/test_elcm.py b/scciclient/tests/irmc/test_elcm.py index db455d2..8b7f83f 100644 --- a/scciclient/tests/irmc/test_elcm.py +++ b/scciclient/tests/irmc/test_elcm.py @@ -248,6 +248,51 @@ class ELCMTestCase(testtools.TestCase): self.assertEqual('UNAUTHORIZED', str(e)) + def test_elcm_profile_get_versions_failed(self): + self.requests_mock.register_uri( + 'GET', + self._create_server_url(elcm.URL_PATH_PROFILE_MGMT) + 'version', + status_code=503) + + self.assertRaises(scci.SCCIClientError, + elcm.elcm_profile_get_versions, + self.irmc_info) + + def test_elcm_profile_get_versions_ok(self): + self.requests_mock.register_uri( + 'GET', + self._create_server_url(elcm.URL_PATH_PROFILE_MGMT) + 'version', + text=(self.RESPONSE_TEMPLATE % { + 'json_text': + '"Server":{' + ' "@Version": "1.01",' + ' "AdapterConfigIrmc": {' + ' "@Version": "1.00"' + ' },' + ' "SystemConfig": {' + ' "BiosConfig": {' + ' "@Version": "1.02"' + ' }' + ' }' + '}'})) + + result = elcm.elcm_profile_get_versions(self.irmc_info) + + expected = { + "Server": { + "@Version": "1.01", + "AdapterConfigIrmc": { + "@Version": "1.00" + }, + "SystemConfig": { + "BiosConfig": { + "@Version": "1.02" + } + } + } + } + self.assertEqual(expected, result) + def test_elcm_profile_get_not_found(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( @@ -2299,14 +2344,30 @@ class ELCMTestCase(testtools.TestCase): self.irmc_info, elcm.PROFILE_RAID_CONFIG) @mock.patch.object(elcm, 'restore_bios_config') - def test_set_bios_configuration(self, restore_bios_config_mock): + @mock.patch.object(elcm, 'elcm_profile_get_versions') + def test_set_bios_configuration_without_versions(self, + get_versions_mock, + restore_bios_config_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", - "value": True + "value": "True" }, { "name": "hyper_threading_enabled", - "value": True + "value": "True" }] + + get_versions_mock.return_value = { + "Server": { + "AdapterConfigIrmc": { + "@Version": "1.00" + }, + "SystemConfig": { + "BiosConfig": { + } + } + } + } + bios_config_data = { 'Server': { 'SystemConfig': { @@ -2322,20 +2383,129 @@ class ELCMTestCase(testtools.TestCase): } } elcm.set_bios_configuration(self.irmc_info, settings) - restore_bios_config_mock.assert_called_once_with( - irmc_info=self.irmc_info, bios_config=bios_config_data) + restore_bios_config_mock.assert_called_once_with(self.irmc_info, + bios_config_data) - def test_set_bios_configuration_not_found(self): + @mock.patch.object(elcm, 'restore_bios_config') + @mock.patch.object(elcm, 'elcm_profile_get_versions') + def test_set_bios_configuration_with_versions(self, + get_versions_mock, + restore_bios_config_mock): + settings = [{ + "name": "single_root_io_virtualization_support_enabled", + "value": "True" + }, { + "name": "hyper_threading_enabled", + "value": "True" + }] + + get_versions_mock.return_value = { + "Server": { + "@Version": "1.01", + "AdapterConfigIrmc": { + "@Version": "1.00" + }, + "SystemConfig": { + "BiosConfig": { + "@Version": "1.02" + } + } + } + } + + bios_config = { + 'Server': { + 'SystemConfig': { + 'BiosConfig': { + 'PciConfig': { + 'SingleRootIOVirtualizationSupportEnabled': True + }, + 'CpuConfig': { + 'HyperThreadingEnabled': True, + }, + "@Version": "1.02" + } + }, + "@Version": "1.01" + } + } + elcm.set_bios_configuration(self.irmc_info, settings) + restore_bios_config_mock.assert_called_once_with(self.irmc_info, + bios_config) + + @mock.patch.object(elcm, 'elcm_profile_get_versions') + def test_set_bios_configuration_not_found(self, + get_versions_mock): + settings = [{ + "name": "single_root_io_virtualization_support_enabled", + "value": "True" + }, { + "name": "setting1", + "value": "True" + }] + + get_versions_mock.return_value = { + "Server": { + "@Version": "1.01", + "AdapterConfigIrmc": { + "@Version": "1.00" + }, + "SystemConfig": { + "BiosConfig": { + "@Version": "1.02" + } + } + } + } + + self.assertRaises(elcm.BiosConfigNotFound, elcm.set_bios_configuration, + self.irmc_info, settings) + + @mock.patch.object(elcm, 'restore_bios_config') + @mock.patch.object(elcm, 'elcm_profile_get_versions') + def test_set_bios_configuration_with_boolean_input( + self, get_versions_mock, restore_bios_config_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": True }, { - "name": "setting1", - "value": True + "name": "hyper_threading_enabled", + "value": False }] - self.assertRaises(elcm.BiosConfigNotFound, elcm.set_bios_configuration, - self.irmc_info, settings) + get_versions_mock.return_value = { + "Server": { + "@Version": "1.01", + "AdapterConfigIrmc": { + "@Version": "1.00" + }, + "SystemConfig": { + "BiosConfig": { + "@Version": "1.02" + } + } + } + } + + bios_config = { + 'Server': { + 'SystemConfig': { + 'BiosConfig': { + 'PciConfig': { + 'SingleRootIOVirtualizationSupportEnabled': True + }, + 'CpuConfig': { + 'HyperThreadingEnabled': False, + }, + "@Version": "1.02" + } + }, + "@Version": "1.01" + } + } + elcm.set_bios_configuration(self.irmc_info, settings) + restore_bios_config_mock.assert_called_once_with(self.irmc_info, + bios_config) @mock.patch.object(elcm, 'backup_bios_config') def test_get_bios_settings(self, backup_bios_config_mock): @@ -2359,10 +2529,10 @@ class ELCMTestCase(testtools.TestCase): result = elcm.get_bios_settings(self.irmc_info) expect_settings = [{ "name": "single_root_io_virtualization_support_enabled", - "value": True + "value": "True" }, { "name": "hyper_threading_enabled", - "value": True + "value": "True" }] self.assertItemsEqual(expect_settings, result) backup_bios_config_mock.assert_called_once_with(