From a83cde9f9352a7b70f274c1e3fe13ef390e503a7 Mon Sep 17 00:00:00 2001 From: ankit Date: Thu, 18 Aug 2016 10:58:56 +0000 Subject: [PATCH] Fix Inspection failure in Gen7 Inspection is failing for Gen7 Servers. Failure occurs because proliantutils is not compatible with Gen7 servers. This commit adds the Gen7 support in proliantutils. Change-Id: Ic3eaa57f3d1606751e5da2320bb4dbdd556f27cc Closes-Bug: #1613794 --- AUTHORS | 1 - ChangeLog | 8 - proliantutils/ilo/client.py | 1 + proliantutils/ilo/ribcl.py | 96 +++++++-- .../tests/ilo/ribcl_sample_outputs.py | 195 ++++++++++++++++++ proliantutils/tests/ilo/test_ribcl.py | 83 +++++++- 6 files changed, 355 insertions(+), 29 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4f3e77d..4aa498a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,7 +3,6 @@ Aparna Vikraman Debayan Ray Jim Mankovich Nisha Agarwal -Paresh Sao Pratyusha Ramakrishnan G Shivanand Tendulker diff --git a/ChangeLog b/ChangeLog index 68a4066..240bbba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,6 @@ CHANGES ======= -2.1.10 ------- - -* Fix for 'raid_config' validation error message -* Providing detailed error message for hpssa -* Fix for InvalidInputError exception -* Fix to accommodate very quick firmware update - 2.1.9 ----- diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index bc62f1d..3d3ca9c 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -68,6 +68,7 @@ class IloClient(operations.IloOperations): self.info = {'address': host, 'username': login, 'password': password} self.host = host self.model = self.ribcl.get_product_name() + self.ribcl.init_model_based_tags(self.model) LOG.debug(self._("IloClient object created. " "Model: %(model)s"), {'model': self.model}) diff --git a/proliantutils/ilo/ribcl.py b/proliantutils/ilo/ribcl.py index 272aa97..4a830f7 100644 --- a/proliantutils/ilo/ribcl.py +++ b/proliantutils/ilo/ribcl.py @@ -72,8 +72,12 @@ class RIBCLOperations(operations.IloOperations): Implements the base class using RIBCL scripting language to talk to the iLO. """ + def __init__(self, host, login, password, timeout=60, port=443, cacert=None): + """Constructor for RIBCLOperations. + + """ self.host = host self.login = login self.password = password @@ -88,6 +92,30 @@ class RIBCLOperations(operations.IloOperations): if self.cacert is None: urllib3.disable_warnings(urllib3_exceptions.InsecureRequestWarning) + def init_model_based_tags(self, model): + """Initializing the model based memory and NIC information tags. + + It should be called just after instantiating a RIBCL object. + + ribcl = ribcl.RIBCLOperations(host, login, password, timeout, + port, cacert=cacert) + model = ribcl.get_product_name() + ribcl.init_model_based_tags(model) + + Again, model attribute is also set here on the RIBCL object. + + :param model: the model string + """ + self.model = model + if 'G7' in self.model: + self.MEMORY_SIZE_TAG = "MEMORY_SIZE" + self.MEMORY_SIZE_NOT_PRESENT_TAG = "Not Installed" + self.NIC_INFORMATION_TAG = "NIC_INFOMATION" + else: + self.MEMORY_SIZE_TAG = "TOTAL_MEMORY_SIZE" + self.MEMORY_SIZE_NOT_PRESENT_TAG = "N/A" + self.NIC_INFORMATION_TAG = "NIC_INFORMATION" + def _request_ilo(self, root, extra_headers=None): """Send RIBCL XML data to iLO. @@ -752,10 +780,10 @@ class RIBCLOperations(operations.IloOperations): :raises:IloError if iLO returns an error in command execution. """ - data = self.get_host_health_data() - properties = {} - properties['memory_mb'] = self._parse_memory_embedded_health(data) + properties = { + 'memory_mb': self._parse_memory_embedded_health(data) + } cpus, cpu_arch = self._parse_processor_embedded_health(data) properties['cpus'] = cpus properties['cpu_arch'] = cpu_arch @@ -809,25 +837,23 @@ class RIBCLOperations(operations.IloOperations): :param data: the output returned by get_host_health_data() :returns: memory size in MB. :raises IloError, if unable to get the memory details. - """ memory_mb = 0 - memory = self.get_value_as_list((data['GET_EMBEDDED_HEALTH_DATA'] - ['MEMORY']), 'MEMORY_DETAILS_SUMMARY') + memory = self._get_memory_details_value_based_on_model(data) + if memory is None: msg = "Unable to get memory data. Error: Data missing" raise exception.IloError(msg) total_memory_size = 0 - for item in memory: - for val in item.values(): - memsize = val['TOTAL_MEMORY_SIZE']['VALUE'] - if memsize != 'N/A': - memory_bytes = ( - strutils.string_to_bytes( - memsize.replace(' ', ''), return_int=True)) - memory_mb = int(memory_bytes / (1024 * 1024)) - total_memory_size = total_memory_size + memory_mb + for memory_item in memory: + memsize = memory_item[self.MEMORY_SIZE_TAG]["VALUE"] + if memsize != self.MEMORY_SIZE_NOT_PRESENT_TAG: + memory_bytes = ( + strutils.string_to_bytes( + memsize.replace(' ', ''), return_int=True)) + memory_mb = int(memory_bytes / (1024 * 1024)) + total_memory_size = total_memory_size + memory_mb return total_memory_size def _parse_processor_embedded_health(self, data): @@ -943,7 +969,8 @@ class RIBCLOperations(operations.IloOperations): """ nic_data = self.get_value_as_list((data['GET_EMBEDDED_HEALTH_DATA'] - ['NIC_INFORMATION']), 'NIC') + [self.NIC_INFORMATION_TAG]), 'NIC') + if nic_data is None: msg = "Unable to get NIC details. Data missing" raise exception.IloError(msg) @@ -952,12 +979,14 @@ class RIBCLOperations(operations.IloOperations): try: port = item['NETWORK_PORT']['VALUE'] mac = item['MAC_ADDRESS']['VALUE'] - location = item['LOCATION']['VALUE'] - if location == 'Embedded': - nic_dict[port] = mac + self._update_nic_data_from_nic_info_based_on_model(nic_dict, + item, port, + mac) + except KeyError: msg = "Unable to get NIC details. Data missing" raise exception.IloError(msg) + return nic_dict def _get_firmware_embedded_health(self, data): @@ -1126,6 +1155,35 @@ class RIBCLOperations(operations.IloOperations): }) return root + def _get_memory_details_value_based_on_model(self, data): + """This method gives memory details based on model. + + :param data: the output returned by get_host_health_data() + :returns : a list of memory details. + """ + if 'G7' in self.model: + return (data['GET_EMBEDDED_HEALTH_DATA']['MEMORY'] + ['MEMORY_COMPONENTS']['MEMORY_COMPONENT']) + else: + return (data['GET_EMBEDDED_HEALTH_DATA']['MEMORY'] + ['MEMORY_DETAILS_SUMMARY']).values() + + def _update_nic_data_from_nic_info_based_on_model(self, nic_dict, item, + port, mac): + """This method updates with port number and corresponding mac + + :param nic_dict: dictionary contains port number and corresponding mac + :param item: dictionary containing nic details + :param port: Port number + :param mac: mac-address + """ + if 'G7' in self.model: + nic_dict[port] = mac + else: + location = item['LOCATION']['VALUE'] + if location == 'Embedded': + nic_dict[port] = mac + # The below block of code is there only for backward-compatibility # reasons (before commit 47608b6 for ris-support). diff --git a/proliantutils/tests/ilo/ribcl_sample_outputs.py b/proliantutils/tests/ilo/ribcl_sample_outputs.py index 07cdba6..4ff89b4 100644 --- a/proliantutils/tests/ilo/ribcl_sample_outputs.py +++ b/proliantutils/tests/ilo/ribcl_sample_outputs.py @@ -1231,6 +1231,201 @@ GET_HOST_POWER_READINGS = ''' ''' +GET_EMBEDDED_HEALTH_OUTPUT_GEN7 = ''' +{ + "GET_EMBEDDED_HEALTH_DATA": { + "MEMORY": { + "MEMORY_COMPONENTS": { + "MEMORY_COMPONENT": [ + { + "MEMORY_SPEED": { + "VALUE": "0 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "Not Installed" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 1G" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "1333 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "8192 MB" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 2D" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "1333 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "8192 MB" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 3A" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "0 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "Not Installed" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 4H" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "1333 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "8192 MB" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 5E" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "0 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "Not Installed" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 6B" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "1333 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "8192 MB" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 7I" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "0 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "Not Installed" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 8F" + } + }, + { + "MEMORY_SPEED": { + "VALUE": "0 MHz" + }, + "MEMORY_SIZE": { + "VALUE": "Not Installed" + }, + "MEMORY_LOCATION": { + "VALUE": "PROC 1 DIMM 9C" + } + } + ] + } + }, + "NIC_INFOMATION": { + "NIC": [ + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:60" + }, + "NETWORK_PORT": { + "VALUE": "Port 1" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:62" + }, + "NETWORK_PORT": { + "VALUE": "Port 2" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:64" + }, + "NETWORK_PORT": { + "VALUE": "Port 3" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:66" + }, + "NETWORK_PORT": { + "VALUE": "Port 4" + } + } + ], + "iSCSI": [ + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:61" + }, + "NETWORK_PORT": { + "VALUE": "Port 1" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:63" + }, + "NETWORK_PORT": { + "VALUE": "Port 2" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:65" + }, + "NETWORK_PORT": { + "VALUE": "Port 3" + } + }, + { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:67" + }, + "NETWORK_PORT": { + "VALUE": "Port 4" + } + } + ], + "iLO": { + "MAC_ADDRESS": { + "VALUE": "78:ac:c0:fe:49:68" + }, + "NETWORK_PORT": { + "VALUE": "iLO Dedicated Network Port" + } + } + } + }, + "RESPONSE": { + "MESSAGE": "No error", + "STATUS": "0x0000" + }, + "VERSION": "2.23" +} +''' + GET_EMBEDDED_HEALTH_OUTPUT = ''' { "GET_EMBEDDED_HEALTH_DATA": { diff --git a/proliantutils/tests/ilo/test_ribcl.py b/proliantutils/tests/ilo/test_ribcl.py index 25baae4..48dd1c0 100644 --- a/proliantutils/tests/ilo/test_ribcl.py +++ b/proliantutils/tests/ilo/test_ribcl.py @@ -61,6 +61,8 @@ class MaskedRequestDataTestCase(unittest.TestCase): self.assertIn(xml_data, str(self.maskedRequestData)) +@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name', + lambda x: 'ProLiant DL580 Gen8') class IloRibclTestCaseInitTestCase(unittest.TestCase): @mock.patch.object(urllib3, 'disable_warnings') @@ -94,7 +96,21 @@ class IloRibclTestCase(unittest.TestCase): def setUp(self): super(IloRibclTestCase, self).setUp() - self.ilo = ribcl.RIBCLOperations("x.x.x.x", "admin", "Admin", 60, 443) + self.ilo = ribcl.RIBCLOperations("x.x.x.x", "admin", + "Admin", 60, 443) + self.ilo.init_model_based_tags('ProLiant DL580 Gen8') + + def test_init_model_based_tags_gen7(self): + self.ilo.init_model_based_tags('Proliant DL380 G7') + self.assertEqual(self.ilo.MEMORY_SIZE_TAG, "MEMORY_SIZE") + self.assertEqual(self.ilo.MEMORY_SIZE_NOT_PRESENT_TAG, "Not Installed") + self.assertEqual(self.ilo.NIC_INFORMATION_TAG, "NIC_INFOMATION") + + def test_init_model_based_tags(self): + self.ilo.init_model_based_tags('ProLiant DL580 Gen8') + self.assertEqual(self.ilo.MEMORY_SIZE_TAG, "TOTAL_MEMORY_SIZE") + self.assertEqual(self.ilo.MEMORY_SIZE_NOT_PRESENT_TAG, "N/A") + self.assertEqual(self.ilo.NIC_INFORMATION_TAG, "NIC_INFORMATION") @mock.patch.object(ribcl.RIBCLOperations, '_serialize_xml') @mock.patch.object(requests, 'post') @@ -528,13 +544,39 @@ class IloRibclTestCase(unittest.TestCase): json_data) def test__parse_memory_embedded_health(self): + self.ilo.init_model_based_tags('Proliant DL580 Gen8') data = constants.GET_EMBEDDED_HEALTH_OUTPUT json_data = json.loads(data) memory_mb = self.ilo._parse_memory_embedded_health(json_data) self.assertEqual('32768', str(memory_mb)) self.assertTrue(type(memory_mb), int) + def test__parse_memory_embedded_health_gen7(self): + self.ilo.model = 'Proliant DL380 G7' + self.ilo.init_model_based_tags('Proliant DL380 G7') + data = constants.GET_EMBEDDED_HEALTH_OUTPUT_GEN7 + json_data = json.loads(data) + memory_mb = self.ilo._parse_memory_embedded_health(json_data) + self.assertEqual('32768', str(memory_mb)) + self.assertTrue(type(memory_mb), int) + + def test__parse_nics_embedded_health_gen7(self): + self.ilo.model = 'Proliant DL380 G7' + self.ilo.init_model_based_tags('Proliant DL380 G7') + data = constants.GET_EMBEDDED_HEALTH_OUTPUT_GEN7 + json_data = json.loads(data) + expected_output = {u'Port 4': u'78:ac:c0:fe:49:66', + u'Port 3': u'78:ac:c0:fe:49:64', + u'Port 2': u'78:ac:c0:fe:49:62', + u'Port 1': u'78:ac:c0:fe:49:60'} + nic_data = self.ilo._parse_nics_embedded_health(json_data) + self.assertIsInstance(nic_data, dict) + for key, val in nic_data.items(): + self.assertIn("Port", key) + self.assertEqual(expected_output, nic_data) + def test__parse_nics_embedded_health(self): + self.ilo.init_model_based_tags('Proliant DL580 Gen8') data = constants.GET_EMBEDDED_HEALTH_OUTPUT json_data = json.loads(data) expected_output = {u'Port 4': u'40:a8:f0:1e:86:77', @@ -827,6 +869,45 @@ class IloRibclTestCase(unittest.TestCase): 'raw_fw_file.bin', 'invalid_component') + def test__get_memory_details_value_based_on_model_gen7(self): + self.ilo.model = 'Proliant DL380 G7' + data = constants.GET_EMBEDDED_HEALTH_OUTPUT_GEN7 + self.assertIn('MEMORY_COMPONENTS', data) + self.assertIn('MEMORY_COMPONENT', data) + + def test__get_memory_details_value_based_on_model(self): + self.ilo.model = 'ProLiant DL580 Gen8' + data = constants.GET_EMBEDDED_HEALTH_OUTPUT + self.assertIn('MEMORY_DETAILS_SUMMARY', data) + + def test__update_nic_data_from_nic_info_based_on_model_gen7(self): + self.ilo.model = 'Proliant DL380 G7' + nic_dict = {} + item = {'NETWORK_PORT': {'VALUE': 'Port 1'}, + 'MAC_ADDRESS': {'VALUE': '78:ac:c0:fe:49:60'}} + port = 'Port 1' + mac = '78:ac:c0:fe:49:60' + expected_result = {'Port 1': '78:ac:c0:fe:49:60'} + self.ilo._update_nic_data_from_nic_info_based_on_model( + nic_dict, item, port, mac) + self.assertEqual(expected_result, nic_dict) + + def test__update_nic_data_from_nic_info_based_on_model(self): + self.ilo.model = 'ProLiant DL580 Gen8' + nic_dict = {} + item = {'NETWORK_PORT': {'VALUE': 'Port 1'}, + 'STATUS': {'VALUE': 'Unknown'}, + 'PORT_DESCRIPTION': {'VALUE': 'N/A'}, + 'LOCATION': {'VALUE': 'Embedded'}, + 'MAC_ADDRESS': {'VALUE': '40:a8:f0:1e:86:74'}, + 'IP_ADDRESS': {'VALUE': 'N/A'}} + port = 'Port 1' + mac = '40:a8:f0:1e:86:74' + expected_result = {'Port 1': '40:a8:f0:1e:86:74'} + self.ilo._update_nic_data_from_nic_info_based_on_model( + nic_dict, item, port, mac) + self.assertEqual(expected_result, nic_dict) + class IloRibclTestCaseBeforeRisSupport(unittest.TestCase):