neil / rpms / python-blivet

Forked from rpms/python-blivet a year ago
Clone
f2ecff
From 43c5a6ef094e5f333a6dd47c467a1516488e2097 Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Mon, 24 May 2021 13:35:39 +0200
f2ecff
Subject: [PATCH 1/7] Remove action device from LVM reject list
f2ecff
f2ecff
Because the device doesn't depend on itself the existing code
f2ecff
won't remove the device we are trying to modify from the list.
f2ecff
f2ecff
Resolves: rhbz#1955942
f2ecff
---
f2ecff
 blivet/actionlist.py | 1 +
f2ecff
 1 file changed, 1 insertion(+)
f2ecff
f2ecff
diff --git a/blivet/actionlist.py b/blivet/actionlist.py
f2ecff
index d03e32b9..2de3fed3 100644
f2ecff
--- a/blivet/actionlist.py
f2ecff
+++ b/blivet/actionlist.py
f2ecff
@@ -260,6 +260,7 @@ class ActionList(object):
f2ecff
             log.debug("action: %s", action)
f2ecff
 
f2ecff
             # Remove lvm filters for devices we are operating on
f2ecff
+            lvm.lvm_cc_removeFilterRejectRegexp(action.device.name)
f2ecff
             for device in (d for d in devices if d.depends_on(action.device)):
f2ecff
                 lvm.lvm_cc_removeFilterRejectRegexp(device.name)
f2ecff
 
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From 2db8aa0aa6ea03c182f7e8e08cd1371ded13b71c Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Mon, 24 May 2021 14:49:12 +0200
f2ecff
Subject: [PATCH 2/7] Convert LVM filter lists to sets
f2ecff
f2ecff
To prevent devices being added multiple times and removed only
f2ecff
once.
f2ecff
f2ecff
Related: rhbz#1955942
f2ecff
---
f2ecff
 blivet/devicelibs/lvm.py | 12 ++++++------
f2ecff
 tests/devicetree_test.py |  6 +++---
f2ecff
 2 files changed, 9 insertions(+), 9 deletions(-)
f2ecff
f2ecff
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
f2ecff
index 121797ce..9e396cca 100644
f2ecff
--- a/blivet/devicelibs/lvm.py
f2ecff
+++ b/blivet/devicelibs/lvm.py
f2ecff
@@ -72,8 +72,8 @@ safe_name_characters = "0-9a-zA-Z._-"
f2ecff
 # Theoretically we can handle all that can be handled with the LVM --config
f2ecff
 # argument.  For every time we call an lvm_cc (lvm compose config) funciton
f2ecff
 # we regenerate the config_args with all global info.
f2ecff
-config_args_data = {"filterRejects": [],    # regular expressions to reject.
f2ecff
-                    "filterAccepts": []}   # regexp to accept
f2ecff
+config_args_data = {"filterRejects": set(),    # regular expressions to reject.
f2ecff
+                    "filterAccepts": set()}    # regexp to accept
f2ecff
 
f2ecff
 
f2ecff
 def _set_global_config():
f2ecff
@@ -125,7 +125,7 @@ def needs_config_refresh(fn):
f2ecff
 def lvm_cc_addFilterRejectRegexp(regexp):
f2ecff
     """ Add a regular expression to the --config string."""
f2ecff
     log.debug("lvm filter: adding %s to the reject list", regexp)
f2ecff
-    config_args_data["filterRejects"].append(regexp)
f2ecff
+    config_args_data["filterRejects"].add(regexp)
f2ecff
 
f2ecff
 
f2ecff
 @needs_config_refresh
f2ecff
@@ -134,15 +134,15 @@ def lvm_cc_removeFilterRejectRegexp(regexp):
f2ecff
     log.debug("lvm filter: removing %s from the reject list", regexp)
f2ecff
     try:
f2ecff
         config_args_data["filterRejects"].remove(regexp)
f2ecff
-    except ValueError:
f2ecff
+    except KeyError:
f2ecff
         log.debug("%s wasn't in the reject list", regexp)
f2ecff
         return
f2ecff
 
f2ecff
 
f2ecff
 @needs_config_refresh
f2ecff
 def lvm_cc_resetFilter():
f2ecff
-    config_args_data["filterRejects"] = []
f2ecff
-    config_args_data["filterAccepts"] = []
f2ecff
+    config_args_data["filterRejects"] = set()
f2ecff
+    config_args_data["filterAccepts"] = set()
f2ecff
 
f2ecff
 
f2ecff
 def determine_parent_lv(internal_lv, lvs, lv_info):
f2ecff
diff --git a/tests/devicetree_test.py b/tests/devicetree_test.py
f2ecff
index d1f4d8f3..ef163c0a 100644
f2ecff
--- a/tests/devicetree_test.py
f2ecff
+++ b/tests/devicetree_test.py
f2ecff
@@ -125,7 +125,7 @@ class DeviceTreeTestCase(unittest.TestCase):
f2ecff
         dt.actions._actions.append(Mock(name="fake action"))
f2ecff
 
f2ecff
         lvm.lvm_cc_addFilterRejectRegexp("xxx")
f2ecff
-        lvm.config_args_data["filterAccepts"].append("yyy")
f2ecff
+        lvm.config_args_data["filterAccepts"].add("yyy")
f2ecff
 
f2ecff
         dt.ignored_disks.append(names[0])
f2ecff
         dt.exclusive_disks.append(names[1])
f2ecff
@@ -144,8 +144,8 @@ class DeviceTreeTestCase(unittest.TestCase):
f2ecff
 
f2ecff
         self.assertEqual(dt._hidden, empty_list)
f2ecff
 
f2ecff
-        self.assertEqual(lvm.config_args_data["filterAccepts"], empty_list)
f2ecff
-        self.assertEqual(lvm.config_args_data["filterRejects"], empty_list)
f2ecff
+        self.assertEqual(lvm.config_args_data["filterAccepts"], set())
f2ecff
+        self.assertEqual(lvm.config_args_data["filterRejects"], set())
f2ecff
 
f2ecff
         self.assertEqual(dt.exclusive_disks, empty_list)
f2ecff
         self.assertEqual(dt.ignored_disks, empty_list)
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From e2540422945586ca45848a663e391a91b2fdd714 Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Tue, 27 Jul 2021 14:07:05 +0200
f2ecff
Subject: [PATCH 3/7] Switch LVM devices filter from "reject" to "accept" by
f2ecff
 default
f2ecff
f2ecff
We currently use the LVM reject filter to filter out hidden and
f2ecff
ignored devices, this commit changes the behaviour to reject all
f2ecff
devices by default and accept only physical volumes that are not
f2ecff
hidden or ignored. This is preparation for the switch from the
f2ecff
existing lvm.conf based filtering to the new devices file based
f2ecff
filtering introduced in LVM 2.03.12 which allows only listing
f2ecff
"accepted" devices. This allows us to support both the "old" and
f2ecff
"new" style filtering using the same code.
f2ecff
---
f2ecff
 blivet/actionlist.py                  |  5 +--
f2ecff
 blivet/devicelibs/lvm.py              | 62 +++++++++++----------------
f2ecff
 blivet/devices/lvm.py                 |  4 +-
f2ecff
 blivet/devicetree.py                  |  8 ++--
f2ecff
 blivet/formats/lvmpv.py               |  2 +
f2ecff
 blivet/populator/helpers/lvm.py       |  6 +++
f2ecff
 blivet/populator/helpers/partition.py |  8 ----
f2ecff
 blivet/populator/populator.py         |  4 +-
f2ecff
 tests/devicetree_test.py              | 37 ++++++++++++++--
f2ecff
 tests/populator_test.py               |  6 ++-
f2ecff
 10 files changed, 81 insertions(+), 61 deletions(-)
f2ecff
f2ecff
diff --git a/blivet/actionlist.py b/blivet/actionlist.py
f2ecff
index 2de3fed3..f3977401 100644
f2ecff
--- a/blivet/actionlist.py
f2ecff
+++ b/blivet/actionlist.py
f2ecff
@@ -259,10 +259,9 @@ class ActionList(object):
f2ecff
         for action in self._actions:
f2ecff
             log.debug("action: %s", action)
f2ecff
 
f2ecff
-            # Remove lvm filters for devices we are operating on
f2ecff
-            lvm.lvm_cc_removeFilterRejectRegexp(action.device.name)
f2ecff
             for device in (d for d in devices if d.depends_on(action.device)):
f2ecff
-                lvm.lvm_cc_removeFilterRejectRegexp(device.name)
f2ecff
+                if device.format.type == "lvmpv":
f2ecff
+                    lvm.lvm_devices_add(device.path)
f2ecff
 
f2ecff
     def _post_process(self, devices=None):
f2ecff
         """ Clean up relics from action queue execution. """
f2ecff
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
f2ecff
index 9e396cca..96d037b8 100644
f2ecff
--- a/blivet/devicelibs/lvm.py
f2ecff
+++ b/blivet/devicelibs/lvm.py
f2ecff
@@ -67,40 +67,29 @@ LVMETAD_SOCKET_PATH = "/run/lvm/lvmetad.socket"
f2ecff
 
f2ecff
 safe_name_characters = "0-9a-zA-Z._-"
f2ecff
 
f2ecff
-# Start config_args handling code
f2ecff
-#
f2ecff
-# Theoretically we can handle all that can be handled with the LVM --config
f2ecff
-# argument.  For every time we call an lvm_cc (lvm compose config) funciton
f2ecff
-# we regenerate the config_args with all global info.
f2ecff
-config_args_data = {"filterRejects": set(),    # regular expressions to reject.
f2ecff
-                    "filterAccepts": set()}    # regexp to accept
f2ecff
+# list of devices that LVM is allowed to use
f2ecff
+# with LVM >= 2.0.13 we'll use this for the --devices option and when creating
f2ecff
+# the /etc/lvm/devices/system.devices file
f2ecff
+# with older versions of LVM we will use this for the --config based filtering
f2ecff
+_lvm_devices = set()
f2ecff
 
f2ecff
 
f2ecff
 def _set_global_config():
f2ecff
     """lvm command accepts lvm.conf type arguments preceded by --config. """
f2ecff
 
f2ecff
-    filter_string = ""
f2ecff
-    rejects = config_args_data["filterRejects"]
f2ecff
-    for reject in rejects:
f2ecff
-        filter_string += ("\"r|/%s$|\"," % reject)
f2ecff
+    device_string = ""
f2ecff
+
f2ecff
+    # now explicitly "accept" all LVM devices
f2ecff
+    for device in _lvm_devices:
f2ecff
+        device_string += "\"a|%s$|\"," % device
f2ecff
 
f2ecff
-    if filter_string:
f2ecff
-        filter_string = "filter=[%s]" % filter_string.strip(",")
f2ecff
+    # now add all devices to the "reject" filter
f2ecff
+    device_string += "\"r|.*|\""
f2ecff
 
f2ecff
-    # XXX consider making /tmp/blivet.lvm.XXXXX, writing an lvm.conf there, and
f2ecff
-    #     setting LVM_SYSTEM_DIR
f2ecff
-    devices_string = 'preferred_names=["^/dev/mapper/", "^/dev/md/", "^/dev/sd"]'
f2ecff
-    if filter_string:
f2ecff
-        devices_string += " %s" % filter_string
f2ecff
+    filter_string = "filter=[%s]" % device_string
f2ecff
 
f2ecff
-    # for now ignore the LVM devices file and rely on our filters
f2ecff
-    if availability.LVMDEVICES.available:
f2ecff
-        devices_string += " use_devicesfile=0"
f2ecff
+    config_string = " devices { %s } " % filter_string
f2ecff
 
f2ecff
-    # devices_string can have (inside the brackets) "dir", "scan",
f2ecff
-    # "preferred_names", "filter", "cache_dir", "write_cache_state",
f2ecff
-    # "types", "sysfs_scan", "md_component_detection".  see man lvm.conf.
f2ecff
-    config_string = " devices { %s } " % (devices_string)  # strings can be added
f2ecff
     if not flags.lvm_metadata_backup:
f2ecff
         config_string += "backup {backup=0 archive=0} "
f2ecff
     if flags.debug:
f2ecff
@@ -122,27 +111,26 @@ def needs_config_refresh(fn):
f2ecff
 
f2ecff
 
f2ecff
 @needs_config_refresh
f2ecff
-def lvm_cc_addFilterRejectRegexp(regexp):
f2ecff
-    """ Add a regular expression to the --config string."""
f2ecff
-    log.debug("lvm filter: adding %s to the reject list", regexp)
f2ecff
-    config_args_data["filterRejects"].add(regexp)
f2ecff
+def lvm_devices_add(path):
f2ecff
+    """ Add a device (PV) to the list of devices LVM is allowed to use """
f2ecff
+    log.debug("lvm filter: device %s added to the list of allowed devices")
f2ecff
+    _lvm_devices.add(path)
f2ecff
 
f2ecff
 
f2ecff
 @needs_config_refresh
f2ecff
-def lvm_cc_removeFilterRejectRegexp(regexp):
f2ecff
-    """ Remove a regular expression from the --config string."""
f2ecff
-    log.debug("lvm filter: removing %s from the reject list", regexp)
f2ecff
+def lvm_devices_remove(path):
f2ecff
+    """ Remove a device (PV) to the list of devices LVM is allowed to use """
f2ecff
+    log.debug("lvm filter: device %s removed from the list of allowed devices")
f2ecff
     try:
f2ecff
-        config_args_data["filterRejects"].remove(regexp)
f2ecff
+        _lvm_devices.remove(path)
f2ecff
     except KeyError:
f2ecff
-        log.debug("%s wasn't in the reject list", regexp)
f2ecff
+        log.debug("%s wasn't in the devices list", path)
f2ecff
         return
f2ecff
 
f2ecff
 
f2ecff
 @needs_config_refresh
f2ecff
-def lvm_cc_resetFilter():
f2ecff
-    config_args_data["filterRejects"] = set()
f2ecff
-    config_args_data["filterAccepts"] = set()
f2ecff
+def lvm_devices_reset():
f2ecff
+    _lvm_devices.clear()
f2ecff
 
f2ecff
 
f2ecff
 def determine_parent_lv(internal_lv, lvs, lv_info):
f2ecff
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
f2ecff
index c61eeb4b..9c230f1b 100644
f2ecff
--- a/blivet/devices/lvm.py
f2ecff
+++ b/blivet/devices/lvm.py
f2ecff
@@ -273,8 +273,8 @@ class LVMVolumeGroupDevice(ContainerDevice):
f2ecff
         log_method_call(self, self.name, status=self.status)
f2ecff
         if not self.complete:
f2ecff
             for pv in self.pvs:
f2ecff
-                # Remove the PVs from the ignore filter so we can wipe them.
f2ecff
-                lvm.lvm_cc_removeFilterRejectRegexp(pv.name)
f2ecff
+                # add PVS to the list of LVM devices so we can wipe them.
f2ecff
+                lvm.lvm_devices_add(pv.path)
f2ecff
 
f2ecff
             # Don't run vgremove or vgreduce since there may be another VG with
f2ecff
             # the same name that we want to keep/use.
f2ecff
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
f2ecff
index f4ae1968..c6c1b440 100644
f2ecff
--- a/blivet/devicetree.py
f2ecff
+++ b/blivet/devicetree.py
f2ecff
@@ -96,7 +96,7 @@ class DeviceTreeBase(object):
f2ecff
 
f2ecff
         self._hidden = []
f2ecff
 
f2ecff
-        lvm.lvm_cc_resetFilter()
f2ecff
+        lvm.lvm_devices_reset()
f2ecff
 
f2ecff
         self.exclusive_disks = exclusive_disks or []
f2ecff
         self.ignored_disks = ignored_disks or []
f2ecff
@@ -879,7 +879,8 @@ class DeviceTreeBase(object):
f2ecff
         self._remove_device(device, force=True, modparent=False)
f2ecff
 
f2ecff
         self._hidden.append(device)
f2ecff
-        lvm.lvm_cc_addFilterRejectRegexp(device.name)
f2ecff
+        if device.format.type == "lvmpv":
f2ecff
+            lvm.lvm_devices_remove(device.path)
f2ecff
 
f2ecff
     def unhide(self, device):
f2ecff
         """ Restore a device's visibility.
f2ecff
@@ -905,7 +906,8 @@ class DeviceTreeBase(object):
f2ecff
                 self._hidden.remove(hidden)
f2ecff
                 self._devices.append(hidden)
f2ecff
                 hidden.add_hook(new=False)
f2ecff
-                lvm.lvm_cc_removeFilterRejectRegexp(hidden.name)
f2ecff
+                if hidden.format.type == "lvmpv":
f2ecff
+                    lvm.lvm_devices_add(hidden.path)
f2ecff
 
f2ecff
     def expand_taglist(self, taglist):
f2ecff
         """ Expands tags in input list into devices.
f2ecff
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
f2ecff
index ea84e9e4..3b00951f 100644
f2ecff
--- a/blivet/formats/lvmpv.py
f2ecff
+++ b/blivet/formats/lvmpv.py
f2ecff
@@ -124,6 +124,7 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
     def _create(self, **kwargs):
f2ecff
         log_method_call(self, device=self.device,
f2ecff
                         type=self.type, status=self.status)
f2ecff
+        lvm.lvm_devices_add(self.device)
f2ecff
 
f2ecff
         lvm._set_global_config()
f2ecff
 
f2ecff
@@ -138,6 +139,7 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
         except blockdev.LVMError:
f2ecff
             DeviceFormat._destroy(self, **kwargs)
f2ecff
         finally:
f2ecff
+            lvm.lvm_devices_remove(self.device)
f2ecff
             udev.settle()
f2ecff
 
f2ecff
     @property
f2ecff
diff --git a/blivet/populator/helpers/lvm.py b/blivet/populator/helpers/lvm.py
f2ecff
index c7adfa4e..9e7e4630 100644
f2ecff
--- a/blivet/populator/helpers/lvm.py
f2ecff
+++ b/blivet/populator/helpers/lvm.py
f2ecff
@@ -87,6 +87,12 @@ class LVMFormatPopulator(FormatPopulator):
f2ecff
     def _get_kwargs(self):
f2ecff
         kwargs = super(LVMFormatPopulator, self)._get_kwargs()
f2ecff
 
f2ecff
+        # new PV, add it to the LVM devices list and re-run pvs/lvs/vgs
f2ecff
+        lvm.lvm_devices_add(self.device.path)
f2ecff
+        pvs_info.drop_cache()
f2ecff
+        vgs_info.drop_cache()
f2ecff
+        lvs_info.drop_cache()
f2ecff
+
f2ecff
         pv_info = pvs_info.cache.get(self.device.path, None)
f2ecff
 
f2ecff
         name = udev.device_get_name(self.data)
f2ecff
diff --git a/blivet/populator/helpers/partition.py b/blivet/populator/helpers/partition.py
f2ecff
index f00323d1..8659bd48 100644
f2ecff
--- a/blivet/populator/helpers/partition.py
f2ecff
+++ b/blivet/populator/helpers/partition.py
f2ecff
@@ -24,7 +24,6 @@ import copy
f2ecff
 import six
f2ecff
 
f2ecff
 from ... import udev
f2ecff
-from ...devicelibs import lvm
f2ecff
 from ...devices import PartitionDevice
f2ecff
 from ...errors import DeviceError
f2ecff
 from ...formats import get_format
f2ecff
@@ -66,7 +65,6 @@ class PartitionDevicePopulator(DevicePopulator):
f2ecff
         if disk is None:
f2ecff
             # if the disk is still not in the tree something has gone wrong
f2ecff
             log.error("failure finding disk for %s", name)
f2ecff
-            lvm.lvm_cc_addFilterRejectRegexp(name)
f2ecff
             return
f2ecff
 
f2ecff
         if not disk.partitioned or not disk.format.supported:
f2ecff
@@ -78,12 +76,6 @@ class PartitionDevicePopulator(DevicePopulator):
f2ecff
             # and instantiate a PartitionDevice so our view of the layout is
f2ecff
             # complete.
f2ecff
             if not disk.partitionable or disk.format.type == "iso9660" or disk.format.hidden:
f2ecff
-                # there's no need to filter partitions on members of multipaths or
f2ecff
-                # fwraid members from lvm since multipath and dmraid are already
f2ecff
-                # active and lvm should therefore know to ignore them
f2ecff
-                if not disk.format.hidden:
f2ecff
-                    lvm.lvm_cc_addFilterRejectRegexp(name)
f2ecff
-
f2ecff
                 log.debug("ignoring partition %s on %s", name, disk.format.type)
f2ecff
                 return
f2ecff
 
f2ecff
diff --git a/blivet/populator/populator.py b/blivet/populator/populator.py
f2ecff
index 75bb1741..958593ec 100644
f2ecff
--- a/blivet/populator/populator.py
f2ecff
+++ b/blivet/populator/populator.py
f2ecff
@@ -317,10 +317,10 @@ class PopulatorMixin(object):
f2ecff
                 continue
f2ecff
 
f2ecff
             # Make sure lvm doesn't get confused by PVs that belong to
f2ecff
-            # incomplete VGs. We will remove the PVs from the reject list when/if
f2ecff
+            # incomplete VGs. We will add the PVs to the accept list when/if
f2ecff
             # the time comes to remove the incomplete VG and its PVs.
f2ecff
             for pv in vg.pvs:
f2ecff
-                lvm.lvm_cc_addFilterRejectRegexp(pv.name)
f2ecff
+                lvm.lvm_devices_remove(pv.path)
f2ecff
 
f2ecff
     def set_disk_images(self, images):
f2ecff
         """ Set the disk images and reflect them in exclusive_disks.
f2ecff
diff --git a/tests/devicetree_test.py b/tests/devicetree_test.py
f2ecff
index ef163c0a..3be4d572 100644
f2ecff
--- a/tests/devicetree_test.py
f2ecff
+++ b/tests/devicetree_test.py
f2ecff
@@ -124,8 +124,7 @@ class DeviceTreeTestCase(unittest.TestCase):
f2ecff
 
f2ecff
         dt.actions._actions.append(Mock(name="fake action"))
f2ecff
 
f2ecff
-        lvm.lvm_cc_addFilterRejectRegexp("xxx")
f2ecff
-        lvm.config_args_data["filterAccepts"].add("yyy")
f2ecff
+        lvm.lvm_devices_add("xxx")
f2ecff
 
f2ecff
         dt.ignored_disks.append(names[0])
f2ecff
         dt.exclusive_disks.append(names[1])
f2ecff
@@ -144,8 +143,7 @@ class DeviceTreeTestCase(unittest.TestCase):
f2ecff
 
f2ecff
         self.assertEqual(dt._hidden, empty_list)
f2ecff
 
f2ecff
-        self.assertEqual(lvm.config_args_data["filterAccepts"], set())
f2ecff
-        self.assertEqual(lvm.config_args_data["filterRejects"], set())
f2ecff
+        self.assertEqual(lvm._lvm_devices, set())
f2ecff
 
f2ecff
         self.assertEqual(dt.exclusive_disks, empty_list)
f2ecff
         self.assertEqual(dt.ignored_disks, empty_list)
f2ecff
@@ -438,6 +436,37 @@ class DeviceTreeTestCase(unittest.TestCase):
f2ecff
         self.assertEqual(tree.get_related_disks(sda), set([sda, sdb]))
f2ecff
         self.assertEqual(tree.get_related_disks(sdb), set([sda, sdb]))
f2ecff
 
f2ecff
+    def test_lvm_filter_hide_unhide(self):
f2ecff
+        tree = DeviceTree()
f2ecff
+
f2ecff
+        sda = DiskDevice("sda", size=Size("30 GiB"))
f2ecff
+        sdb = DiskDevice("sdb", size=Size("30 GiB"))
f2ecff
+
f2ecff
+        tree._add_device(sda)
f2ecff
+        tree._add_device(sdb)
f2ecff
+
f2ecff
+        self.assertTrue(sda in tree.devices)
f2ecff
+        self.assertTrue(sdb in tree.devices)
f2ecff
+
f2ecff
+        sda.format = get_format("lvmpv", device=sda.path)
f2ecff
+        sdb.format = get_format("lvmpv", device=sdb.path)
f2ecff
+
f2ecff
+        # LVMPhysicalVolume._create would do this
f2ecff
+        lvm.lvm_devices_add(sda.path)
f2ecff
+        lvm.lvm_devices_add(sdb.path)
f2ecff
+
f2ecff
+        self.assertSetEqual(lvm._lvm_devices, {sda.path, sdb.path})
f2ecff
+
f2ecff
+        tree.hide(sda)
f2ecff
+        self.assertSetEqual(lvm._lvm_devices, {sdb.path})
f2ecff
+        tree.hide(sdb)
f2ecff
+        self.assertSetEqual(lvm._lvm_devices, set())
f2ecff
+
f2ecff
+        tree.unhide(sda)
f2ecff
+        self.assertSetEqual(lvm._lvm_devices, {sda.path})
f2ecff
+        tree.unhide(sdb)
f2ecff
+        self.assertSetEqual(lvm._lvm_devices, {sda.path, sdb.path})
f2ecff
+
f2ecff
 
f2ecff
 class DeviceTreeIgnoredExclusiveMultipathTestCase(unittest.TestCase):
f2ecff
 
f2ecff
diff --git a/tests/populator_test.py b/tests/populator_test.py
f2ecff
index 2a8532f0..dd36c16a 100644
f2ecff
--- a/tests/populator_test.py
f2ecff
+++ b/tests/populator_test.py
f2ecff
@@ -13,6 +13,7 @@ from gi.repository import BlockDev as blockdev
f2ecff
 from blivet.devices import DiskDevice, DMDevice, FileDevice, LoopDevice
f2ecff
 from blivet.devices import MDRaidArrayDevice, MultipathDevice, OpticalDevice
f2ecff
 from blivet.devices import PartitionDevice, StorageDevice, NVDIMMNamespaceDevice
f2ecff
+from blivet.devicelibs import lvm
f2ecff
 from blivet.devicetree import DeviceTree
f2ecff
 from blivet.formats import get_device_format_class, get_format, DeviceFormat
f2ecff
 from blivet.formats.disklabel import DiskLabel
f2ecff
@@ -393,8 +394,7 @@ class PartitionDevicePopulatorTestCase(PopulatorHelperTestCase):
f2ecff
     @patch.object(DiskLabel, "parted_disk")
f2ecff
     @patch.object(DiskLabel, "parted_device")
f2ecff
     @patch.object(PartitionDevice, "probe")
f2ecff
-    # TODO: fix the naming of the lvm filter functions
f2ecff
-    @patch("blivet.devicelibs.lvm.lvm_cc_addFilterRejectRegexp")
f2ecff
+    @patch("blivet.devicelibs.lvm.lvm_devices_add")
f2ecff
     @patch("blivet.udev.device_get_major", return_value=88)
f2ecff
     @patch("blivet.udev.device_get_minor", return_value=19)
f2ecff
     @patch.object(DeviceTree, "get_device_by_name")
f2ecff
@@ -973,6 +973,8 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
f2ecff
                     self.assertTrue(vg_device is not None)
f2ecff
                     devicetree._remove_device(vg_device)
f2ecff
 
f2ecff
+                    self.assertIn(device.path, lvm._lvm_devices)
f2ecff
+
f2ecff
         get_device_by_uuid.reset_mock()
f2ecff
 
f2ecff
         # pv belongs to a valid vg not in the tree with two lvs
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From 15a63b01bd2b6e7fe197fade849f28b83407c166 Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Fri, 30 Jul 2021 14:01:04 +0200
f2ecff
Subject: [PATCH 4/7] Use LVM devices for filtering LVM devices with LVM >=
f2ecff
 2.02.13
f2ecff
f2ecff
---
f2ecff
 blivet/devicelibs/lvm.py | 38 +++++++++++++++++++++++++++++---------
f2ecff
 tests/populator_test.py  |  9 ++++-----
f2ecff
 2 files changed, 33 insertions(+), 14 deletions(-)
f2ecff
f2ecff
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
f2ecff
index 96d037b8..3ab1540b 100644
f2ecff
--- a/blivet/devicelibs/lvm.py
f2ecff
+++ b/blivet/devicelibs/lvm.py
f2ecff
@@ -67,6 +67,16 @@ LVMETAD_SOCKET_PATH = "/run/lvm/lvmetad.socket"
f2ecff
 
f2ecff
 safe_name_characters = "0-9a-zA-Z._-"
f2ecff
 
f2ecff
+if hasattr(blockdev.LVMTech, "DEVICES"):
f2ecff
+    try:
f2ecff
+        blockdev.lvm.is_tech_avail(blockdev.LVMTech.DEVICES, 0)  # pylint: disable=no-member
f2ecff
+    except blockdev.LVMError:
f2ecff
+        HAVE_LVMDEVICES = False
f2ecff
+    else:
f2ecff
+        HAVE_LVMDEVICES = True
f2ecff
+else:
f2ecff
+    HAVE_LVMDEVICES = False
f2ecff
+
f2ecff
 # list of devices that LVM is allowed to use
f2ecff
 # with LVM >= 2.0.13 we'll use this for the --devices option and when creating
f2ecff
 # the /etc/lvm/devices/system.devices file
f2ecff
@@ -79,25 +89,34 @@ def _set_global_config():
f2ecff
 
f2ecff
     device_string = ""
f2ecff
 
f2ecff
-    # now explicitly "accept" all LVM devices
f2ecff
-    for device in _lvm_devices:
f2ecff
-        device_string += "\"a|%s$|\"," % device
f2ecff
+    if not HAVE_LVMDEVICES:
f2ecff
+        # now explicitly "accept" all LVM devices
f2ecff
+        for device in _lvm_devices:
f2ecff
+            device_string += "\"a|%s$|\"," % device
f2ecff
 
f2ecff
-    # now add all devices to the "reject" filter
f2ecff
-    device_string += "\"r|.*|\""
f2ecff
+        # now add all devices to the "reject" filter
f2ecff
+        device_string += "\"r|.*|\""
f2ecff
 
f2ecff
-    filter_string = "filter=[%s]" % device_string
f2ecff
+        filter_string = "filter=[%s]" % device_string
f2ecff
 
f2ecff
-    config_string = " devices { %s } " % filter_string
f2ecff
+        config_string = " devices { %s } " % filter_string
f2ecff
+    else:
f2ecff
+        config_string = " "
f2ecff
 
f2ecff
     if not flags.lvm_metadata_backup:
f2ecff
         config_string += "backup {backup=0 archive=0} "
f2ecff
-    if flags.debug:
f2ecff
-        config_string += "log {level=7 file=/tmp/lvm.log syslog=0}"
f2ecff
+    config_string += "log {level=7 file=/tmp/lvm.log syslog=0}"
f2ecff
 
f2ecff
     blockdev.lvm.set_global_config(config_string)
f2ecff
 
f2ecff
 
f2ecff
+def _set_lvm_devices():
f2ecff
+    if not HAVE_LVMDEVICES:
f2ecff
+        return
f2ecff
+
f2ecff
+    blockdev.lvm.set_devices_filter(list(_lvm_devices))
f2ecff
+
f2ecff
+
f2ecff
 def needs_config_refresh(fn):
f2ecff
     if not availability.BLOCKDEV_LVM_PLUGIN.available:
f2ecff
         return lambda *args, **kwargs: None
f2ecff
@@ -105,6 +124,7 @@ def needs_config_refresh(fn):
f2ecff
     def fn_with_refresh(*args, **kwargs):
f2ecff
         ret = fn(*args, **kwargs)
f2ecff
         _set_global_config()
f2ecff
+        _set_lvm_devices()
f2ecff
         return ret
f2ecff
 
f2ecff
     return fn_with_refresh
f2ecff
diff --git a/tests/populator_test.py b/tests/populator_test.py
f2ecff
index dd36c16a..a9584319 100644
f2ecff
--- a/tests/populator_test.py
f2ecff
+++ b/tests/populator_test.py
f2ecff
@@ -897,6 +897,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
f2ecff
         device = Mock()
f2ecff
         device.parents = []
f2ecff
         device.size = Size("10g")
f2ecff
+        device.path = "/dev/sda1"
f2ecff
         devicetree._add_device(device)
f2ecff
 
f2ecff
         # pylint: disable=attribute-defined-outside-init
f2ecff
@@ -924,15 +925,13 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
f2ecff
         pv_info.pe_start = 0
f2ecff
         pv_info.pv_free = 0
f2ecff
 
f2ecff
-        device.path = sentinel.pv_path
f2ecff
-
f2ecff
         vg_device = Mock()
f2ecff
         vg_device.parents = []
f2ecff
         vg_device.lvs = []
f2ecff
         get_device_by_uuid.return_value = vg_device
f2ecff
 
f2ecff
         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
f2ecff
-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
f2ecff
+            mock_pvs_cache.return_value = {device.path: pv_info}
f2ecff
             with patch("blivet.udev.device_get_format", return_value=self.udev_type):
f2ecff
                 helper = self.helper_class(devicetree, data, device)
f2ecff
                 self.assertFalse(device in vg_device.parents)
f2ecff
@@ -957,7 +956,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
f2ecff
         pv_info.vg_pv_count = 1
f2ecff
 
f2ecff
         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
f2ecff
-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
f2ecff
+            mock_pvs_cache.return_value = {device.path: pv_info}
f2ecff
             with patch("blivet.static_data.lvm_info.VGsInfo.cache", new_callable=PropertyMock) as mock_vgs_cache:
f2ecff
                 mock_vgs_cache.return_value = {pv_info.vg_uuid: Mock()}
f2ecff
                 with patch("blivet.udev.device_get_format", return_value=self.udev_type):
f2ecff
@@ -1007,7 +1006,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
f2ecff
         get_device_by_uuid.side_effect = gdbu
f2ecff
 
f2ecff
         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
f2ecff
-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
f2ecff
+            mock_pvs_cache.return_value = {device.path: pv_info}
f2ecff
             with patch("blivet.static_data.lvm_info.VGsInfo.cache", new_callable=PropertyMock) as mock_vgs_cache:
f2ecff
                 mock_vgs_cache.return_value = {pv_info.vg_uuid: Mock()}
f2ecff
                 with patch("blivet.static_data.lvm_info.LVsInfo.cache", new_callable=PropertyMock) as mock_lvs_cache:
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From d4e1395de3691f30196b6b0e3b2c82e83b27afaf Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Fri, 30 Jul 2021 14:01:43 +0200
f2ecff
Subject: [PATCH 5/7] Make sure PVs are added/deleted to/from the LVM device
f2ecff
 file
f2ecff
f2ecff
We are using the --devices option when running LVM commands which
f2ecff
mean the newly created PV won't be added to the device list by
f2ecff
pvcreate so we need to do that manually.
f2ecff
---
f2ecff
 blivet/formats/lvmpv.py | 5 +++++
f2ecff
 1 file changed, 5 insertions(+)
f2ecff
f2ecff
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
f2ecff
index 3b00951f..71ec699f 100644
f2ecff
--- a/blivet/formats/lvmpv.py
f2ecff
+++ b/blivet/formats/lvmpv.py
f2ecff
@@ -131,6 +131,9 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
         ea_yes = blockdev.ExtraArg.new("-y", "")
f2ecff
         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
f2ecff
 
f2ecff
+        if lvm.HAVE_LVMDEVICES:
f2ecff
+            blockdev.lvm.devices_add(self.device)
f2ecff
+
f2ecff
     def _destroy(self, **kwargs):
f2ecff
         log_method_call(self, device=self.device,
f2ecff
                         type=self.type, status=self.status)
f2ecff
@@ -141,6 +144,8 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
         finally:
f2ecff
             lvm.lvm_devices_remove(self.device)
f2ecff
             udev.settle()
f2ecff
+            if lvm.HAVE_LVMDEVICES:
f2ecff
+                blockdev.lvm.devices_delete(self.device)
f2ecff
 
f2ecff
     @property
f2ecff
     def destroyable(self):
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From c221d313bde21fb2cba701b93fe0c57336cba8ec Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Thu, 14 Oct 2021 15:32:24 +0200
f2ecff
Subject: [PATCH 6/7] Ignore errors for LVM devices file actions
f2ecff
f2ecff
The LVM devices file feature might be disabled either locally or
f2ecff
globally by LVM config.
f2ecff
---
f2ecff
 blivet/formats/lvmpv.py | 10 ++++++++--
f2ecff
 1 file changed, 8 insertions(+), 2 deletions(-)
f2ecff
f2ecff
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
f2ecff
index 71ec699f..b27213cc 100644
f2ecff
--- a/blivet/formats/lvmpv.py
f2ecff
+++ b/blivet/formats/lvmpv.py
f2ecff
@@ -132,7 +132,10 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
f2ecff
 
f2ecff
         if lvm.HAVE_LVMDEVICES:
f2ecff
-            blockdev.lvm.devices_add(self.device)
f2ecff
+            try:
f2ecff
+                blockdev.lvm.devices_add(self.device)
f2ecff
+            except blockdev.LVMError as e:
f2ecff
+                log.debug("Failed to add newly created PV %s to the LVM devices file: %s", self.device, str(e))
f2ecff
 
f2ecff
     def _destroy(self, **kwargs):
f2ecff
         log_method_call(self, device=self.device,
f2ecff
@@ -145,7 +148,10 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
             lvm.lvm_devices_remove(self.device)
f2ecff
             udev.settle()
f2ecff
             if lvm.HAVE_LVMDEVICES:
f2ecff
-                blockdev.lvm.devices_delete(self.device)
f2ecff
+                try:
f2ecff
+                    blockdev.lvm.devices_delete(self.device)
f2ecff
+                except blockdev.LVMError as e:
f2ecff
+                    log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
f2ecff
 
f2ecff
     @property
f2ecff
     def destroyable(self):
f2ecff
-- 
f2ecff
2.31.1
f2ecff
f2ecff
f2ecff
From 6b96d4ead6890fffd95840b8935f71ecd9e310ef Mon Sep 17 00:00:00 2001
f2ecff
From: Vojtech Trefny <vtrefny@redhat.com>
f2ecff
Date: Tue, 19 Oct 2021 14:27:05 +0200
f2ecff
Subject: [PATCH 7/7] Add public functions to add/remove PV to/from the LVM
f2ecff
 system.devices
f2ecff
f2ecff
Anaconda needs to be able to add preexisting PVs to the file
f2ecff
during installation.
f2ecff
---
f2ecff
 blivet/formats/lvmpv.py | 28 ++++++++++++++++++++--------
f2ecff
 1 file changed, 20 insertions(+), 8 deletions(-)
f2ecff
f2ecff
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
f2ecff
index b27213cc..3fef667e 100644
f2ecff
--- a/blivet/formats/lvmpv.py
f2ecff
+++ b/blivet/formats/lvmpv.py
f2ecff
@@ -121,6 +121,24 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
     def supported(self):
f2ecff
         return super(LVMPhysicalVolume, self).supported and self._plugin.available
f2ecff
 
f2ecff
+    def lvmdevices_add(self):
f2ecff
+        if not lvm.HAVE_LVMDEVICES:
f2ecff
+            raise PhysicalVolumeError("LVM devices file feature is not supported")
f2ecff
+
f2ecff
+        try:
f2ecff
+            blockdev.lvm.devices_add(self.device)
f2ecff
+        except blockdev.LVMError as e:
f2ecff
+            log.debug("Failed to add PV %s to the LVM devices file: %s", self.device, str(e))
f2ecff
+
f2ecff
+    def lvmdevices_remove(self):
f2ecff
+        if not lvm.HAVE_LVMDEVICES:
f2ecff
+            raise PhysicalVolumeError("LVM devices file feature is not supported")
f2ecff
+
f2ecff
+        try:
f2ecff
+            blockdev.lvm.devices_delete(self.device)
f2ecff
+        except blockdev.LVMError as e:
f2ecff
+            log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
f2ecff
+
f2ecff
     def _create(self, **kwargs):
f2ecff
         log_method_call(self, device=self.device,
f2ecff
                         type=self.type, status=self.status)
f2ecff
@@ -132,10 +150,7 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
f2ecff
 
f2ecff
         if lvm.HAVE_LVMDEVICES:
f2ecff
-            try:
f2ecff
-                blockdev.lvm.devices_add(self.device)
f2ecff
-            except blockdev.LVMError as e:
f2ecff
-                log.debug("Failed to add newly created PV %s to the LVM devices file: %s", self.device, str(e))
f2ecff
+            self.lvmdevices_add()
f2ecff
 
f2ecff
     def _destroy(self, **kwargs):
f2ecff
         log_method_call(self, device=self.device,
f2ecff
@@ -148,10 +163,7 @@ class LVMPhysicalVolume(DeviceFormat):
f2ecff
             lvm.lvm_devices_remove(self.device)
f2ecff
             udev.settle()
f2ecff
             if lvm.HAVE_LVMDEVICES:
f2ecff
-                try:
f2ecff
-                    blockdev.lvm.devices_delete(self.device)
f2ecff
-                except blockdev.LVMError as e:
f2ecff
-                    log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
f2ecff
+                self.lvmdevices_remove()
f2ecff
 
f2ecff
     @property
f2ecff
     def destroyable(self):
f2ecff
-- 
f2ecff
2.31.1
f2ecff