From bae3aec172df5b6ca9d609f29ea9feb9f6d11f13 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. Change-Id: I6eb5981d28b9ae368239af0c1d0ec32ff79d95b3 Story: #2008865 Task: 42395 (cherry picked from commit ed791d97786f4ed37bf7b9f18eac8e2af46c3766) --- ironic_python_agent/hardware.py | 14 +- .../tests/unit/samples/hardware_samples.py | 184 ++++++++++++++++++ .../tests/unit/test_hardware.py | 10 + ...-no-memory-bank-size-05ea71987362986e.yaml | 9 + 4 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 abda1f1a1..f6ebb92ba 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -222,16 +222,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/samples/hardware_samples.py b/ironic_python_agent/tests/unit/samples/hardware_samples.py index f398f60f8..3ab541537 100644 --- a/ironic_python_agent/tests/unit/samples/hardware_samples.py +++ b/ironic_python_agent/tests/unit/samples/hardware_samples.py @@ -543,6 +543,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", diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index 4135985e0..ad3a8f652 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -1046,6 +1046,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 = hws.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.