From 694ea7425daf8494740e995105e53fb2743c6b00 Mon Sep 17 00:00:00 2001
From: Fedor Tarasenko <feodor.tarasenko@gmail.com>
Date: Mon, 2 Nov 2020 13:36:31 +0300
Subject: [PATCH] Support using LABEL as identifier for rootfs

Add possibility to use disk LABEL to identify rootfs uuid for
Software RAID deployment

Change-Id: I77f36e70ddc539af0190db1c1abe0fb2c66f34b4
Story: 2008303
Task: 41188
---
 ironic_python_agent/extensions/image.py       |  7 ++++-
 .../tests/unit/extensions/test_image.py       | 30 +++++++++++++++----
 ...label-as-rootfs-uuid-d9a3827180f1a238.yaml |  6 ++++
 3 files changed, 37 insertions(+), 6 deletions(-)
 create mode 100644 releasenotes/notes/software-raid-use-label-as-rootfs-uuid-d9a3827180f1a238.yaml

diff --git a/ironic_python_agent/extensions/image.py b/ironic_python_agent/extensions/image.py
index f5050df87..69ebcb912 100644
--- a/ironic_python_agent/extensions/image.py
+++ b/ironic_python_agent/extensions/image.py
@@ -61,7 +61,8 @@ def _get_partition(device, uuid):
 
     try:
         _rescan_device(device)
-        lsblk = utils.execute('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE', device)
+        lsblk = utils.execute(
+            'lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL', device)
         report = lsblk[0]
         for line in report.split('\n'):
             part = {}
@@ -84,6 +85,10 @@ def _get_partition(device, uuid):
                 LOG.debug("Partition %(uuid)s found on device "
                           "%(dev)s", {'uuid': uuid, 'dev': device})
                 return '/dev/' + part.get('KNAME')
+            if part.get('LABEL') == uuid:
+                LOG.debug("Partition %(uuid)s found on device "
+                          "%(dev)s", {'uuid': uuid, 'dev': device})
+                return '/dev/' + part.get('KNAME')
         else:
             # NOTE(TheJulia): We may want to consider moving towards using
             # findfs in the future, if we're comfortable with the execution
diff --git a/ironic_python_agent/tests/unit/extensions/test_image.py b/ironic_python_agent/tests/unit/extensions/test_image.py
index 636d56ad3..1f3b48dfc 100644
--- a/ironic_python_agent/tests/unit/extensions/test_image.py
+++ b/ironic_python_agent/tests/unit/extensions/test_image.py
@@ -1109,7 +1109,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
                               delay_on_retry=True),
                     mock.call('udevadm', 'settle'),
-                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE',
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
                               self.fake_dev)]
         mock_execute.assert_has_calls(expected)
         self.assertFalse(mock_dispatch.called)
@@ -1133,7 +1133,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
                               delay_on_retry=True),
                     mock.call('udevadm', 'settle'),
-                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE',
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
                               self.fake_dev)]
         mock_execute.assert_has_calls(expected)
         self.assertFalse(mock_dispatch.called)
@@ -1156,7 +1156,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
                               delay_on_retry=True),
                     mock.call('udevadm', 'settle'),
-                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE',
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
                               self.fake_dev),
                     mock.call('findfs', 'UUID=%s' % self.fake_root_uuid),
                     mock.call('findfs', 'PARTUUID=%s' % self.fake_root_uuid)]
@@ -1176,7 +1176,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
                               delay_on_retry=True),
                     mock.call('udevadm', 'settle'),
-                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE',
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
                               self.fake_dev)]
         mock_execute.assert_has_calls(expected)
         self.assertFalse(mock_dispatch.called)
@@ -1187,6 +1187,26 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         mock_is_md_device.side_effect = [False, False]
         lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
         KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
+        KNAME="test2" UUID="903e7bf9-8a13-4f7f-811b-25dc16faf6f7" TYPE="part" \
+                      LABEL="%s"''' % self.fake_root_uuid)
+        mock_execute.side_effect = (None, None, [lsblk_output])
+
+        root_part = image._get_partition(self.fake_dev, self.fake_root_uuid)
+        self.assertEqual('/dev/test2', root_part)
+        expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
+                              delay_on_retry=True),
+                    mock.call('udevadm', 'settle'),
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
+                              self.fake_dev)]
+        mock_execute.assert_has_calls(expected)
+        self.assertFalse(mock_dispatch.called)
+
+    @mock.patch.object(hardware, 'is_md_device', autospec=True)
+    def test__get_partition_label(self, mock_is_md_device, mock_execute,
+                                  mock_dispatch):
+        mock_is_md_device.side_effect = [False, False]
+        lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
+        KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
         KNAME="test2" PARTUUID="%s" TYPE="part"''' % self.fake_root_uuid)
         mock_execute.side_effect = (None, None, [lsblk_output])
 
@@ -1195,7 +1215,7 @@ efibootmgr: ** Warning ** : Boot0005 has same label ironic1\n
         expected = [mock.call('partx', '-u', self.fake_dev, attempts=3,
                               delay_on_retry=True),
                     mock.call('udevadm', 'settle'),
-                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE',
+                    mock.call('lsblk', '-PbioKNAME,UUID,PARTUUID,TYPE,LABEL',
                               self.fake_dev)]
         mock_execute.assert_has_calls(expected)
         self.assertFalse(mock_dispatch.called)
diff --git a/releasenotes/notes/software-raid-use-label-as-rootfs-uuid-d9a3827180f1a238.yaml b/releasenotes/notes/software-raid-use-label-as-rootfs-uuid-d9a3827180f1a238.yaml
new file mode 100644
index 000000000..5403712ac
--- /dev/null
+++ b/releasenotes/notes/software-raid-use-label-as-rootfs-uuid-d9a3827180f1a238.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    For Software RAID, the IPA will use partition LABEL along with UUID and PARTUUID
+    passed from the conductor to identify the root partition. The root file system 
+    LABEL can be set as value of the ``rootfs_uuid`` image metadata property.