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