From 746f65bd8481aac32abb12768590e809697449e4 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Wed, 28 Apr 2021 12:26:43 -0400 Subject: [PATCH] Fix getting memory size in some lshw output Due to a regression in lshw introduced by https://github.com/lyonel/lshw/pull/60, there are some versions in the wild that do not return sizes for memory banks <32GiB. In those cases, work around the problem by looking at the top-level size (if available) to find the total size. Previously we assumed that we only needed the top-level size when there was no list of memory banks. The issue is fixed upstream by https://github.com/lyonel/lshw/pull/65, but the erroneous patch is still present in the lshw-B.02.19.2-5.el8 package in CentOS 8.4 and 8.5. Note from Backport to Victoria branch: The stable test data was moved sometime during the Wallaby development cycle to a separate file, where as in Victoria and earlier, it is based in the test file itself. The required content was moved into the test file in line with where it was in the later versions. Change-Id: I6eb5981d28b9ae368239af0c1d0ec32ff79d95b3 Story: #2008865 Task: 42395 (cherry picked from commit ed791d97786f4ed37bf7b9f18eac8e2af46c3766) (cherry picked from commit bae3aec172df5b6ca9d609f29ea9feb9f6d11f13) (cherry picked from commit 97ce08d039099f569c48a2348c784e71e3693829) --- ironic_python_agent/hardware.py | 14 +- .../tests/unit/test_hardware.py | 194 ++++++++++++++++++ ...-no-memory-bank-size-05ea71987362986e.yaml | 9 + 3 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/lshw-no-memory-bank-size-05ea71987362986e.yaml diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py index a15cc1fd8..8ecc813a7 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -207,16 +207,16 @@ def _calc_memory(sys_dict): for core_child in sys_child['children']: if not _MEMORY_ID_RE.match(core_child['id']): continue - if (not core_child.get("children") - and core_child.get('size')): + if core_child.get('size'): value = ("%(size)s %(units)s" % core_child) physical += int(UNIT_CONVERTER(value).to ('MB').magnitude) - for bank in core_child.get('children', ()): - if bank.get('size'): - value = ("%(size)s %(units)s" % bank) - physical += int(UNIT_CONVERTER(value).to - ('MB').magnitude) + else: + for bank in core_child.get('children', ()): + if bank.get('size'): + value = ("%(size)s %(units)s" % bank) + physical += int(UNIT_CONVERTER(value).to + ('MB').magnitude) return physical diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index 29d7bc646..af5b971ac 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -585,6 +585,190 @@ LSHW_JSON_OUTPUT_V2 = (""" } """, "") +LSHW_JSON_OUTPUT_NO_MEMORY_BANK_SIZE = (""" +{ + "id" : "bumblebee", + "class" : "system", + "claimed" : true, + "handle" : "DMI:0001", + "description" : "Rack Mount Chassis", + "product" : "ABCD", + "vendor" : "ABCD", + "version" : "1234", + "serial" : "1234", + "width" : 64, + "configuration" : { + "boot" : "normal", + "chassis" : "rackmount", + "family" : "Intel Grantley EP", + "sku" : "NULL", + "uuid" : "00010002-0003-0004-0005-000600070008" + }, + "capabilities" : { + "smbios-2.8" : "SMBIOS version 2.8", + "dmi-2.7" : "DMI version 2.7", + "vsyscall32" : "32-bit processes" + }, + "children" : [ + { + "id" : "core", + "class" : "bus", + "claimed" : true, + "handle" : "DMI:0002", + "description" : "Motherboard", + "product" : "ABCD", + "vendor" : "ABCD", + "physid" : "0", + "version" : "1234", + "serial" : "1234", + "slot" : "NULL", + "children" : [ + { + "id" : "memory:0", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:004A", + "description" : "System Memory", + "physid" : "4a", + "slot" : "System board or motherboard", + "units" : "bytes", + "size" : 34359738368, + "children" : [ + { + "id" : "bank:0", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:004C", + "description" : "DIMM Synchronous 2133 MHz (0.5 ns)", + "product" : "36ASF2G72PZ-2G1A2", + "vendor" : "Micron", + "physid" : "0", + "serial" : "101B6543", + "slot" : "DIMM_A0", + "width" : 64, + "clock" : 2133000000 + }, + { + "id" : "bank:1", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:004E", + "description" : "DIMM Synchronous [empty]", + "product" : "NO DIMM", + "vendor" : "NO DIMM", + "physid" : "1", + "serial" : "NO DIMM", + "slot" : "DIMM_A1" + }, + { + "id" : "bank:2", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:004F", + "description" : "DIMM Synchronous 2133 MHz (0.5 ns)", + "product" : "36ASF2G72PZ-2G1A2", + "vendor" : "Micron", + "physid" : "2", + "serial" : "101B654E", + "slot" : "DIMM_A2", + "width" : 64, + "clock" : 2133000000 + }, + { + "id" : "bank:3", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0051", + "description" : "DIMM Synchronous [empty]", + "product" : "NO DIMM", + "vendor" : "NO DIMM", + "physid" : "3", + "serial" : "NO DIMM", + "slot" : "DIMM_A3" + } + ] + }, + { + "id" : "memory:1", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0052", + "description" : "System Memory", + "physid" : "52", + "slot" : "System board or motherboard", + "units" : "bytes", + "size" : 34359738368, + "children" : [ + { + "id" : "bank:0", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0054", + "description" : "DIMM Synchronous 2133 MHz (0.5 ns)", + "product" : "36ASF2G72PZ-2G1A2", + "vendor" : "Micron", + "physid" : "0", + "serial" : "101B6545", + "slot" : "DIMM_A4", + "width" : 64, + "clock" : 2133000000 + }, + { + "id" : "bank:1", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0056", + "description" : "DIMM Synchronous [empty]", + "product" : "NO DIMM", + "vendor" : "NO DIMM", + "physid" : "1", + "serial" : "NO DIMM", + "slot" : "DIMM_A5" + }, + { + "id" : "bank:2", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0057", + "description" : "DIMM Synchronous 2133 MHz (0.5 ns)", + "product" : "36ASF2G72PZ-2G1A2", + "vendor" : "Micron", + "physid" : "2", + "serial" : "101B6540", + "slot" : "DIMM_A6", + "width" : 64, + "clock" : 2133000000 + }, + { + "id" : "bank:3", + "class" : "memory", + "claimed" : true, + "handle" : "DMI:0059", + "description" : "DIMM Synchronous [empty]", + "product" : "NO DIMM", + "vendor" : "NO DIMM", + "physid" : "3", + "serial" : "NO DIMM", + "slot" : "DIMM_A7" + } + ] + }, + { + "id" : "memory:4", + "class" : "memory", + "physid" : "1" + }, + { + "id" : "memory:5", + "class" : "memory", + "physid" : "2" + } + ] + } + ] +} +""", "") + LSHW_JSON_OUTPUT_ARM64 = (""" { "id" : "debian", @@ -1611,6 +1795,16 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual(3952 * 1024 * 1024, mem.total) self.assertEqual(65536, mem.physical_mb) + @mock.patch('psutil.virtual_memory', autospec=True) + @mock.patch.object(utils, 'execute', autospec=True) + def test_get_memory_psutil_bank_size(self, mocked_execute, mocked_psutil): + mocked_psutil.return_value.total = 3952 * 1024 * 1024 + mocked_execute.return_value = LSHW_JSON_OUTPUT_NO_MEMORY_BANK_SIZE + mem = self.hardware.get_memory() + + self.assertEqual(3952 * 1024 * 1024, mem.total) + self.assertEqual(65536, mem.physical_mb) + @mock.patch('psutil.virtual_memory', autospec=True) @mock.patch.object(utils, 'execute', autospec=True) def test_get_memory_psutil_exception_v1(self, mocked_execute, diff --git a/releasenotes/notes/lshw-no-memory-bank-size-05ea71987362986e.yaml b/releasenotes/notes/lshw-no-memory-bank-size-05ea71987362986e.yaml new file mode 100644 index 000000000..ce31079d7 --- /dev/null +++ b/releasenotes/notes/lshw-no-memory-bank-size-05ea71987362986e.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + The lshw package version B.02.19.2-5 on CentOS 8.4 and 8.5 contains a `bug + `_ that prevents the + size of individual memory banks from being reported, with the result that + the total memory size would be reported as 0 in some places. The total + memory size is now taken from lshw's total memory size output (which does + not suffer from the same problem) when available.