From cd50fd1151531c48d34d14975f160c8913ccd56a Mon Sep 17 00:00:00 2001
From: liyingjun <yingjun.li@kylin-cloud.com>
Date: Wed, 24 Jul 2019 16:03:33 +0800
Subject: [PATCH] Fixes physical memory fetching for aarch64

The output for aarch64[1] `lshw -quiet -json` is a bit different from
x86_64, this will lead to 0 physical memory calculated currently. This
patch aims to make it compatible for aarch64 when getting physical memory

[1]: http://paste.openstack.org/show/754789/

Change-Id: Ib7b4ee857d8550e3d75ac8a53c61f0ecab45feff
---
 ironic_python_agent/hardware.py               |   5 +
 .../tests/unit/test_hardware.py               | 109 ++++++++++++++++++
 ...hysical-memory-arm64-957755f6cd91ad85.yaml |   6 +
 3 files changed, 120 insertions(+)
 create mode 100644 releasenotes/notes/fix-physical-memory-arm64-957755f6cd91ad85.yaml

diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py
index e9dd689a5..e1ae6855c 100644
--- a/ironic_python_agent/hardware.py
+++ b/ironic_python_agent/hardware.py
@@ -866,6 +866,11 @@ class GenericHardwareManager(HardwareManager):
                 if sys_child['id'] == 'core':
                     for core_child in sys_child['children']:
                         if _MEMORY_ID_RE.match(core_child['id']):
+                            if (not core_child.get("children") and
+                                    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)
diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py
index a36c52038..b14aa8783 100644
--- a/ironic_python_agent/tests/unit/test_hardware.py
+++ b/ironic_python_agent/tests/unit/test_hardware.py
@@ -565,6 +565,105 @@ LSHW_JSON_OUTPUT_V2 = ("""
 }
 """, "")
 
+LSHW_JSON_OUTPUT_ARM64 = ("""
+{
+  "id" : "debian",
+  "class" : "system",
+  "claimed" : true,
+  "description" : "Computer",
+  "width" : 64,
+  "capabilities" : {
+    "cp15_barrier" : true,
+    "setend" : true,
+    "swp" : true
+  },
+  "children" : [
+    {
+      "id" : "core",
+      "class" : "bus",
+      "claimed" : true,
+      "description" : "Motherboard",
+      "physid" : "0",
+      "children" : [
+        {
+          "id" : "memory",
+          "class" : "memory",
+          "claimed" : true,
+          "description" : "System memory",
+          "physid" : "0",
+          "units" : "bytes",
+          "size" : 4143972352
+        },
+        {
+          "id" : "cpu:0",
+          "class" : "processor",
+          "claimed" : true,
+          "physid" : "1",
+          "businfo" : "cpu@0",
+          "capabilities" : {
+            "fp" : "Floating point instructions",
+            "asimd" : "Advanced SIMD",
+            "evtstrm" : "Event stream",
+            "aes" : "AES instructions",
+            "pmull" : "PMULL instruction",
+            "sha1" : "SHA1 instructions",
+            "sha2" : "SHA2 instructions",
+            "crc32" : "CRC extension",
+            "cpuid" : true
+          }
+        },
+        {
+          "id" : "pci:0",
+          "class" : "bridge",
+          "claimed" : true,
+          "handle" : "PCIBUS:0002:e9",
+          "physid" : "100",
+          "businfo" : "pci@0002:e8:00.0",
+          "version" : "01",
+          "width" : 32,
+          "clock" : 33000000,
+          "configuration" : {
+            "driver" : "pcieport"
+          },
+          "capabilities" : {
+            "pci" : true,
+            "pm" : "Power Management",
+            "msi" : "Message Signalled Interrupts",
+            "pciexpress" : "PCI Express",
+            "bus_master" : "bus mastering",
+            "cap_list" : "PCI capabilities listing"
+          }
+        }
+      ]
+    },
+    {
+      "id" : "network:0",
+      "class" : "network",
+      "claimed" : true,
+      "description" : "Ethernet interface",
+      "physid" : "2",
+      "logicalname" : "enahisic2i2",
+      "serial" : "d0:ef:c1:e9:bf:33",
+      "configuration" : {
+        "autonegotiation" : "off",
+        "broadcast" : "yes",
+        "driver" : "hns",
+        "driverversion" : "2.0",
+        "firmware" : "N/A",
+        "link" : "no",
+        "multicast" : "yes",
+        "port" : "fibre"
+      },
+      "capabilities" : {
+        "ethernet" : true,
+        "physical" : "Physical interface",
+        "fibre" : "optical fibre"
+      }
+    }
+  ]
+}
+""", "")
+
 SMARTCTL_NORMAL_OUTPUT = ("""
 smartctl 6.2 2017-02-27 r4394 [x86_64-linux-3.10.0-693.21.1.el7.x86_64] (local build)
 Copyright (C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org
@@ -1400,6 +1499,16 @@ class TestGenericHardwareManager(base.IronicAgentTest):
         self.assertEqual(3952 * 1024 * 1024, mem.total)
         self.assertIsNone(mem.physical_mb)
 
+    @mock.patch('psutil.virtual_memory', autospec=True)
+    @mock.patch.object(utils, 'execute', autospec=True)
+    def test_get_memory_arm64_lshw(self, mocked_execute, mocked_psutil):
+        mocked_psutil.return_value.total = 3952 * 1024 * 1024
+        mocked_execute.return_value = LSHW_JSON_OUTPUT_ARM64
+        mem = self.hardware.get_memory()
+
+        self.assertEqual(3952 * 1024 * 1024, mem.total)
+        self.assertEqual(3952, mem.physical_mb)
+
     @mock.patch('ironic_python_agent.netutils.get_hostname', autospec=True)
     def test_list_hardware_info(self, mocked_get_hostname):
         self.hardware.list_network_interfaces = mock.Mock()
diff --git a/releasenotes/notes/fix-physical-memory-arm64-957755f6cd91ad85.yaml b/releasenotes/notes/fix-physical-memory-arm64-957755f6cd91ad85.yaml
new file mode 100644
index 000000000..5601d97b9
--- /dev/null
+++ b/releasenotes/notes/fix-physical-memory-arm64-957755f6cd91ad85.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fixes issue that 0 physical memory calculated for aarch64. Since output
+    for aarch64 `lshw -quiet -json` is a bit different from x86_64. This fix
+    is compatible with both x86_64 and arm64.