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