From fbfdc49140d6d3145a08a35a34ebf92818c8c865 Mon Sep 17 00:00:00 2001
From: Arne Wiebalck <Arne.Wiebalck@cern.ch>
Date: Fri, 12 Jul 2019 15:53:06 +0200
Subject: [PATCH] Include empty devices when listing block devices

When listing block devices, empty devices are not listed by
default. In order to clean up broken software RAID devices,
however, we need to list these as well. This patch adds the
corresponding option to 'lsblk', makes sure the device type
filtering handles the additional device type ('md' instead
of 'raid*' when an md device has only spares), and takes
care of lsblk reporting size '' for empty devices.

Story: #2006215
Task: #35807
Change-Id: I523e2ed90f3a477b5f5f27054b65fcfd26239ba2
---
 ironic_python_agent/hardware.py                 | 12 +++++++-----
 ironic_python_agent/tests/unit/test_hardware.py | 12 ++++++------
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py
index e92b40b67..e219bd42e 100644
--- a/ironic_python_agent/hardware.py
+++ b/ironic_python_agent/hardware.py
@@ -265,7 +265,7 @@ def list_all_block_devices(block_type='disk',
                     "Cause: %(error)s", {'path': disk_by_path_dir, 'error': e})
 
     columns = ['KNAME', 'MODEL', 'SIZE', 'ROTA', 'TYPE']
-    report = utils.execute('lsblk', '-Pbi', '-o{}'.format(','.join(columns)),
+    report = utils.execute('lsblk', '-Pbia', '-o{}'.format(','.join(columns)),
                            check_exit_code=[0])[0]
     lines = report.splitlines()
     context = pyudev.Context()
@@ -289,10 +289,12 @@ def list_all_block_devices(block_type='disk',
         # Other possible type values, which we skip recording:
         #   lvm, part, rom, loop
         if devtype != block_type:
-            if devtype is not None and 'raid' in devtype and not ignore_raid:
+            if (devtype is not None and
+                any(x in devtype for x in ['raid', 'md']) and
+                not ignore_raid):
                 LOG.debug(
-                    "TYPE detected to contain 'raid', signifying a RAID "
-                    "volume. Found: {!r}".format(line))
+                    "TYPE detected to contain 'raid or 'md', signifying a "
+                    "RAID volume. Found: {!r}".format(line))
             else:
                 LOG.debug(
                     "TYPE did not match. Wanted: {!r} but found: {!r}".format(
@@ -339,7 +341,7 @@ def list_all_block_devices(block_type='disk',
 
         devices.append(BlockDevice(name=name,
                                    model=device['MODEL'],
-                                   size=int(device['SIZE']),
+                                   size=int(device['SIZE'] or 0),
                                    rotational=bool(int(device['ROTA'])),
                                    vendor=_get_device_info(device['KNAME'],
                                                            'block', 'vendor'),
diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py
index 03bb36878..2b403ffeb 100644
--- a/ironic_python_agent/tests/unit/test_hardware.py
+++ b/ironic_python_agent/tests/unit/test_hardware.py
@@ -1103,7 +1103,7 @@ class TestGenericHardwareManager(base.IronicAgentTest):
         mocked_execute.return_value = (BLK_DEVICE_TEMPLATE, '')
         self.assertEqual('/dev/sdb', self.hardware.get_os_install_device())
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         mock_cached_node.assert_called_once_with()
 
@@ -1125,7 +1125,7 @@ class TestGenericHardwareManager(base.IronicAgentTest):
         # should always be smaller
         self.assertEqual('/dev/md0', self.hardware.get_os_install_device())
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         mock_cached_node.assert_called_once_with()
 
@@ -1144,7 +1144,7 @@ class TestGenericHardwareManager(base.IronicAgentTest):
         ex = self.assertRaises(errors.DeviceNotFound,
                                self.hardware.get_os_install_device)
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         self.assertIn(str(4 * units.Gi), ex.details)
         mock_cached_node.assert_called_once_with()
@@ -3068,7 +3068,7 @@ class TestModuleFunctions(base.IronicAgentTest):
         mocked_execute.return_value = (BLK_DEVICE_TEMPLATE_SMALL, '')
         result = hardware.list_all_block_devices()
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         self.assertEqual(BLK_DEVICE_TEMPLATE_SMALL_DEVICES, result)
         mocked_udev.assert_called_once_with()
@@ -3087,7 +3087,7 @@ class TestModuleFunctions(base.IronicAgentTest):
         mocked_execute.return_value = (RAID_BLK_DEVICE_TEMPLATE, '')
         result = hardware.list_all_block_devices()
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         self.assertEqual(RAID_BLK_DEVICE_TEMPLATE_DEVICES, result)
         mocked_udev.assert_called_once_with()
@@ -3100,7 +3100,7 @@ class TestModuleFunctions(base.IronicAgentTest):
         mocked_execute.return_value = ('TYPE="foo" MODEL="model"', '')
         result = hardware.list_all_block_devices()
         mocked_execute.assert_called_once_with(
-            'lsblk', '-Pbi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
+            'lsblk', '-Pbia', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
             check_exit_code=[0])
         self.assertEqual([], result)
         mocked_udev.assert_called_once_with()