Blame SOURCES/0011-Fix-ignoring-disk-devices-with-parents-or-children.patch

5fed29
From f19140993e94be9e58c8a01c18f1907792f59927 Mon Sep 17 00:00:00 2001
5fed29
From: Vojtech Trefny <vtrefny@redhat.com>
5fed29
Date: Wed, 5 Aug 2020 13:44:38 +0200
5fed29
Subject: [PATCH] Fix ignoring disk devices with parents or children
5fed29
5fed29
For disk-like devices like multipath we should allow to ignore
5fed29
these by simply ignoring the mpath device or by ignoring all of its
5fed29
drives.
5fed29
5fed29
- when ignoring the "mpatha" device we should also ignore "sda" and
5fed29
"sdb"
5fed29
- when ignoring both "sda" and "sdb" we should also ignore "mpatha"
5fed29
- when ignoring only "sda" we should not ignore "mpatha" (we don't
5fed29
want to deal with an "incomplete" multipath device in the tree)
5fed29
5fed29
This is consistent with the existing behaviour when using exclusive
5fed29
disks (or "ignoredisks --only-use" in kickstart).
5fed29
5fed29
Resolves: rhbz#1866243
5fed29
---
5fed29
 blivet/devicetree.py     |  51 ++++++++-----
5fed29
 tests/devicetree_test.py | 157 ++++++++++++++++++++++++++++-----------
5fed29
 2 files changed, 146 insertions(+), 62 deletions(-)
5fed29
5fed29
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
5fed29
index 5cc360e1..2afb0d0e 100644
5fed29
--- a/blivet/devicetree.py
5fed29
+++ b/blivet/devicetree.py
5fed29
@@ -907,31 +907,48 @@ class DeviceTreeBase(object):
5fed29
                 hidden.add_hook(new=False)
5fed29
                 lvm.lvm_cc_removeFilterRejectRegexp(hidden.name)
5fed29
 
5fed29
+    def _disk_in_taglist(self, disk, taglist):
5fed29
+        # Taglist is a list containing mix of disk names and tags into which disk may belong.
5fed29
+        # Check if it does. Raise ValueError if unknown tag is encountered.
5fed29
+        if disk.name in taglist:
5fed29
+            return True
5fed29
+        tags = [t[1:] for t in taglist if t.startswith("@")]
5fed29
+        for tag in tags:
5fed29
+            if tag not in Tags.__members__:
5fed29
+                raise ValueError("unknown ignoredisk tag '@%s' encountered" % tag)
5fed29
+            if Tags(tag) in disk.tags:
5fed29
+                return True
5fed29
+        return False
5fed29
+
5fed29
     def _is_ignored_disk(self, disk):
5fed29
         """ Checks config for lists of exclusive and ignored disks
5fed29
             and returns if the given one should be ignored
5fed29
         """
5fed29
-
5fed29
-        def disk_in_taglist(disk, taglist):
5fed29
-            # Taglist is a list containing mix of disk names and tags into which disk may belong.
5fed29
-            # Check if it does. Raise ValueError if unknown tag is encountered.
5fed29
-            if disk.name in taglist:
5fed29
-                return True
5fed29
-            tags = [t[1:] for t in taglist if t.startswith("@")]
5fed29
-            for tag in tags:
5fed29
-                if tag not in Tags.__members__:
5fed29
-                    raise ValueError("unknown ignoredisk tag '@%s' encountered" % tag)
5fed29
-                if Tags(tag) in disk.tags:
5fed29
-                    return True
5fed29
-            return False
5fed29
-
5fed29
-        return ((self.ignored_disks and disk_in_taglist(disk, self.ignored_disks)) or
5fed29
-                (self.exclusive_disks and not disk_in_taglist(disk, self.exclusive_disks)))
5fed29
+        return ((self.ignored_disks and self._disk_in_taglist(disk, self.ignored_disks)) or
5fed29
+                (self.exclusive_disks and not self._disk_in_taglist(disk, self.exclusive_disks)))
5fed29
 
5fed29
     def _hide_ignored_disks(self):
5fed29
         # hide any subtrees that begin with an ignored disk
5fed29
         for disk in [d for d in self._devices if d.is_disk]:
5fed29
-            if self._is_ignored_disk(disk):
5fed29
+            is_ignored = self.ignored_disks and self._disk_in_taglist(disk, self.ignored_disks)
5fed29
+            is_exclusive = self.exclusive_disks and self._disk_in_taglist(disk, self.exclusive_disks)
5fed29
+
5fed29
+            if is_ignored:
5fed29
+                if len(disk.children) == 1:
5fed29
+                    if not all(self._is_ignored_disk(d) for d in disk.children[0].parents):
5fed29
+                        raise DeviceTreeError("Including only a subset of raid/multipath member disks is not allowed.")
5fed29
+
5fed29
+                    # and also children like fwraid or mpath
5fed29
+                    self.hide(disk.children[0])
5fed29
+
5fed29
+                # this disk is ignored: ignore it and all it's potential parents
5fed29
+                for p in disk.parents:
5fed29
+                    self.hide(p)
5fed29
+
5fed29
+                # and finally hide the disk itself
5fed29
+                self.hide(disk)
5fed29
+
5fed29
+            if self.exclusive_disks and not is_exclusive:
5fed29
                 ignored = True
5fed29
                 # If the filter allows all members of a fwraid or mpath, the
5fed29
                 # fwraid or mpath itself is implicitly allowed as well. I don't
5fed29
diff --git a/tests/devicetree_test.py b/tests/devicetree_test.py
5fed29
index a8f369cf..6032e7f6 100644
5fed29
--- a/tests/devicetree_test.py
5fed29
+++ b/tests/devicetree_test.py
5fed29
@@ -370,51 +370,6 @@ class DeviceTreeTestCase(unittest.TestCase):
5fed29
         self.assertTrue(sdb in tree.devices)
5fed29
         self.assertTrue(sdc in tree.devices)
5fed29
 
5fed29
-        # now test exclusive_disks special cases for multipath
5fed29
-        sda.format = get_format("multipath_member", exists=True)
5fed29
-        sdb.format = get_format("multipath_member", exists=True)
5fed29
-        sdc.format = get_format("multipath_member", exists=True)
5fed29
-        mpatha = MultipathDevice("mpatha", parents=[sda, sdb, sdc])
5fed29
-        tree._add_device(mpatha)
5fed29
-
5fed29
-        tree.ignored_disks = []
5fed29
-        tree.exclusive_disks = ["mpatha"]
5fed29
-
5fed29
-        with patch.object(tree, "hide") as hide:
5fed29
-            tree._hide_ignored_disks()
5fed29
-            self.assertFalse(hide.called)
5fed29
-
5fed29
-        tree._hide_ignored_disks()
5fed29
-        self.assertTrue(sda in tree.devices)
5fed29
-        self.assertTrue(sdb in tree.devices)
5fed29
-        self.assertTrue(sdc in tree.devices)
5fed29
-        self.assertTrue(mpatha in tree.devices)
5fed29
-
5fed29
-        # all members in exclusive_disks implies the mpath in exclusive_disks
5fed29
-        tree.exclusive_disks = ["sda", "sdb", "sdc"]
5fed29
-        with patch.object(tree, "hide") as hide:
5fed29
-            tree._hide_ignored_disks()
5fed29
-            self.assertFalse(hide.called)
5fed29
-
5fed29
-        tree._hide_ignored_disks()
5fed29
-        self.assertTrue(sda in tree.devices)
5fed29
-        self.assertTrue(sdb in tree.devices)
5fed29
-        self.assertTrue(sdc in tree.devices)
5fed29
-        self.assertTrue(mpatha in tree.devices)
5fed29
-
5fed29
-        tree.exclusive_disks = ["sda", "sdb"]
5fed29
-        with patch.object(tree, "hide") as hide:
5fed29
-            tree._hide_ignored_disks()
5fed29
-            hide.assert_any_call(mpatha)
5fed29
-            hide.assert_any_call(sdc)
5fed29
-
5fed29
-        # verify that hide works as expected
5fed29
-        tree._hide_ignored_disks()
5fed29
-        self.assertTrue(sda in tree.devices)
5fed29
-        self.assertTrue(sdb in tree.devices)
5fed29
-        self.assertFalse(sdc in tree.devices)
5fed29
-        self.assertFalse(mpatha in tree.devices)
5fed29
-
5fed29
     def test_get_related_disks(self):
5fed29
         tree = DeviceTree()
5fed29
 
5fed29
@@ -447,3 +402,115 @@ class DeviceTreeTestCase(unittest.TestCase):
5fed29
         tree.unhide(sda)
5fed29
         self.assertEqual(tree.get_related_disks(sda), set([sda, sdb]))
5fed29
         self.assertEqual(tree.get_related_disks(sdb), set([sda, sdb]))
5fed29
+
5fed29
+
5fed29
+class DeviceTreeIgnoredExclusiveMultipathTestCase(unittest.TestCase):
5fed29
+
5fed29
+    def setUp(self):
5fed29
+        self.tree = DeviceTree()
5fed29
+
5fed29
+        self.sda = DiskDevice("sda")
5fed29
+        self.sdb = DiskDevice("sdb")
5fed29
+        self.sdc = DiskDevice("sdc")
5fed29
+
5fed29
+        self.tree._add_device(self.sda)
5fed29
+        self.tree._add_device(self.sdb)
5fed29
+        self.tree._add_device(self.sdc)
5fed29
+
5fed29
+        self.assertTrue(self.sda in self.tree.devices)
5fed29
+        self.assertTrue(self.sdb in self.tree.devices)
5fed29
+        self.assertTrue(self.sdc in self.tree.devices)
5fed29
+
5fed29
+        # now test exclusive_disks special cases for multipath
5fed29
+        self.sda.format = get_format("multipath_member", exists=True)
5fed29
+        self.sdb.format = get_format("multipath_member", exists=True)
5fed29
+        self.sdc.format = get_format("multipath_member", exists=True)
5fed29
+        self.mpatha = MultipathDevice("mpatha", parents=[self.sda, self.sdb, self.sdc])
5fed29
+        self.tree._add_device(self.mpatha)
5fed29
+
5fed29
+    def test_exclusive_disks_multipath_1(self):
5fed29
+        # multipath is exclusive -> all disks should be exclusive
5fed29
+        self.tree.ignored_disks = []
5fed29
+        self.tree.exclusive_disks = ["mpatha"]
5fed29
+
5fed29
+        with patch.object(self.tree, "hide") as hide:
5fed29
+            self.tree._hide_ignored_disks()
5fed29
+            self.assertFalse(hide.called)
5fed29
+
5fed29
+        self.tree._hide_ignored_disks()
5fed29
+        self.assertTrue(self.sda in self.tree.devices)
5fed29
+        self.assertTrue(self.sdb in self.tree.devices)
5fed29
+        self.assertTrue(self.sdc in self.tree.devices)
5fed29
+        self.assertTrue(self.mpatha in self.tree.devices)
5fed29
+
5fed29
+    def test_exclusive_disks_multipath_2(self):
5fed29
+        # all disks exclusive -> mpath should also be exclusive
5fed29
+        self.tree.exclusive_disks = ["sda", "sdb", "sdc"]
5fed29
+        with patch.object(self.tree, "hide") as hide:
5fed29
+            self.tree._hide_ignored_disks()
5fed29
+            self.assertFalse(hide.called)
5fed29
+
5fed29
+        self.tree._hide_ignored_disks()
5fed29
+        self.assertTrue(self.sda in self.tree.devices)
5fed29
+        self.assertTrue(self.sdb in self.tree.devices)
5fed29
+        self.assertTrue(self.sdc in self.tree.devices)
5fed29
+        self.assertTrue(self.mpatha in self.tree.devices)
5fed29
+
5fed29
+    def test_exclusive_disks_multipath_3(self):
5fed29
+        # some disks exclusive -> mpath should be hidden
5fed29
+        self.tree.exclusive_disks = ["sda", "sdb"]
5fed29
+        with patch.object(self.tree, "hide") as hide:
5fed29
+            self.tree._hide_ignored_disks()
5fed29
+            hide.assert_any_call(self.mpatha)
5fed29
+            hide.assert_any_call(self.sdc)
5fed29
+
5fed29
+        # verify that hide works as expected
5fed29
+        self.tree._hide_ignored_disks()
5fed29
+        self.assertTrue(self.sda in self.tree.devices)
5fed29
+        self.assertTrue(self.sdb in self.tree.devices)
5fed29
+        self.assertFalse(self.sdc in self.tree.devices)
5fed29
+        self.assertFalse(self.mpatha in self.tree.devices)
5fed29
+
5fed29
+    def test_ignored_disks_multipath_1(self):
5fed29
+        # mpatha ignored -> disks should be hidden
5fed29
+        self.tree.ignored_disks = ["mpatha"]
5fed29
+        self.tree.exclusive_disks = []
5fed29
+
5fed29
+        with patch.object(self.tree, "hide") as hide:
5fed29
+            self.tree._hide_ignored_disks()
5fed29
+            hide.assert_any_call(self.mpatha)
5fed29
+            hide.assert_any_call(self.sda)
5fed29
+            hide.assert_any_call(self.sdb)
5fed29
+            hide.assert_any_call(self.sdc)
5fed29
+
5fed29
+        self.tree._hide_ignored_disks()
5fed29
+        self.assertFalse(self.sda in self.tree.devices)
5fed29
+        self.assertFalse(self.sdb in self.tree.devices)
5fed29
+        self.assertFalse(self.sdc in self.tree.devices)
5fed29
+        self.assertFalse(self.mpatha in self.tree.devices)
5fed29
+
5fed29
+    def test_ignored_disks_multipath_2(self):
5fed29
+        # all disks ignored -> mpath should be hidden
5fed29
+        self.tree.ignored_disks = ["sda", "sdb", "sdc"]
5fed29
+        self.tree.exclusive_disks = []
5fed29
+
5fed29
+        with patch.object(self.tree, "hide") as hide:
5fed29
+            self.tree._hide_ignored_disks()
5fed29
+            hide.assert_any_call(self.mpatha)
5fed29
+            hide.assert_any_call(self.sda)
5fed29
+            hide.assert_any_call(self.sdb)
5fed29
+            hide.assert_any_call(self.sdc)
5fed29
+
5fed29
+        self.tree._hide_ignored_disks()
5fed29
+        self.assertFalse(self.sda in self.tree.devices)
5fed29
+        self.assertFalse(self.sdb in self.tree.devices)
5fed29
+        self.assertFalse(self.sdc in self.tree.devices)
5fed29
+        self.assertFalse(self.mpatha in self.tree.devices)
5fed29
+
5fed29
+    def test_ignored_disks_multipath_3(self):
5fed29
+        # some disks ignored -> error
5fed29
+        self.tree.ignored_disks = ["sda", "sdb"]
5fed29
+        self.tree.exclusive_disks = []
5fed29
+
5fed29
+        with self.assertRaises(DeviceTreeError):
5fed29
+            self.tree._hide_ignored_disks()
5fed29
-- 
5fed29
2.25.4
5fed29