From 517f17481685afbabea6750b57d71a736f9a157e Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 25 May 2023 17:02:39 +0200 Subject: [PATCH] Do not add new PVs to the LVM devices file if it doesn't exist and VGs are present If there is a preexisting VG on the system when we create a new PV and the LVM devices file doesn't exist we will create it and add only the new PV to it which means the preexisting VG will now be ignored by LVM tools. This change skips adding newly created PVs to the devices file in the same way 'pvcreate' and 'vgcreate' do. --- blivet/devicelibs/lvm.py | 3 + blivet/formats/lvmpv.py | 17 ++++- tests/unit_tests/formats_tests/__init__.py | 1 + tests/unit_tests/formats_tests/lvmpv_test.py | 73 ++++++++++++++++++++ 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 tests/unit_tests/formats_tests/lvmpv_test.py diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py index 16a8e8f8..dc7d0cbe 100644 --- a/blivet/devicelibs/lvm.py +++ b/blivet/devicelibs/lvm.py @@ -84,6 +84,9 @@ if hasattr(blockdev.LVMTech, "DEVICES"): else: HAVE_LVMDEVICES = False + +LVM_DEVICES_FILE = "/etc/lvm/devices/system.devices" + # 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 diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py index cb01b2f3..65acedbe 100644 --- a/blivet/formats/lvmpv.py +++ b/blivet/formats/lvmpv.py @@ -36,7 +36,7 @@ from ..size import Size from ..errors import PhysicalVolumeError from . import DeviceFormat, register_device_format from .. import udev -from ..static_data.lvm_info import pvs_info +from ..static_data.lvm_info import pvs_info, vgs_info import logging log = logging.getLogger("blivet") @@ -121,10 +121,21 @@ class LVMPhysicalVolume(DeviceFormat): def supported(self): return super(LVMPhysicalVolume, self).supported and self._plugin.available - def lvmdevices_add(self): + def lvmdevices_add(self, force=True): + """ Add this PV to the LVM system devices file + :keyword force: whether to add the PV even if the system devices file doesn't exist and + VGs are present in the system + :type force: bool + """ + if not lvm.HAVE_LVMDEVICES: raise PhysicalVolumeError("LVM devices file feature is not supported") + if not os.path.exists(lvm.LVM_DEVICES_FILE) and vgs_info.cache and not force: + log.debug("Not adding %s to devices file: %s doesn't exist and there are VGs present in the system", + self.device, lvm.LVM_DEVICES_FILE) + return + try: blockdev.lvm.devices_add(self.device) except blockdev.LVMError as e: @@ -151,7 +162,7 @@ class LVMPhysicalVolume(DeviceFormat): # with lvmdbusd we need to call the pvcreate without --devices otherwise lvmdbusd # wouldn't be able to find the newly created pv and the call would fail blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes]) - self.lvmdevices_add() + self.lvmdevices_add(force=False) else: blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes]) diff --git a/tests/unit_tests/formats_tests/__init__.py b/tests/unit_tests/formats_tests/__init__.py index d678900b..95c7a25b 100644 --- a/tests/unit_tests/formats_tests/__init__.py +++ b/tests/unit_tests/formats_tests/__init__.py @@ -2,6 +2,7 @@ from .device_test import * from .disklabel_test import * from .init_test import * from .luks_test import * +from .lvmpv_test import * from .methods_test import * from .misc_test import * from .selinux_test import * diff --git a/tests/unit_tests/formats_tests/lvmpv_test.py b/tests/unit_tests/formats_tests/lvmpv_test.py new file mode 100644 index 00000000..6490c7d4 --- /dev/null +++ b/tests/unit_tests/formats_tests/lvmpv_test.py @@ -0,0 +1,73 @@ +try: + from unittest.mock import patch +except ImportError: + from mock import patch + +from contextlib import contextmanager + +import unittest + +from blivet.formats.lvmpv import LVMPhysicalVolume + + +class LVMPVNodevTestCase(unittest.TestCase): + + @contextmanager + def patches(self): + patchers = dict() + mocks = dict() + + patchers["blockdev"] = patch("blivet.formats.lvmpv.blockdev") + patchers["lvm"] = patch("blivet.formats.lvmpv.lvm") + patchers["vgs_info"] = patch("blivet.formats.lvmpv.vgs_info") + patchers["os"] = patch("blivet.formats.lvmpv.os") + + for name, patcher in patchers.items(): + mocks[name] = patcher.start() + + yield mocks + + for patcher in patchers.values(): + patcher.stop() + + def test_lvm_devices(self): + fmt = LVMPhysicalVolume(device="/dev/test") + + with self.patches() as mock: + # LVM devices file not enabled/supported -> devices_add should not be called + mock["lvm"].HAVE_LVMDEVICES = False + + fmt._create() + + mock["blockdev"].lvm.devices_add.assert_not_called() + + with self.patches() as mock: + # LVM devices file enabled and devices file exists -> devices_add should be called + mock["lvm"].HAVE_LVMDEVICES = True + mock["os"].path.exists.return_value = True + + fmt._create() + + mock["blockdev"].lvm.devices_add.assert_called_with("/dev/test") + + with self.patches() as mock: + # LVM devices file enabled and devices file doesn't exist + # and no existing VGs present -> devices_add should be called + mock["lvm"].HAVE_LVMDEVICES = True + mock["os"].path.exists.return_value = False + mock["vgs_info"].cache = {} + + fmt._create() + + mock["blockdev"].lvm.devices_add.assert_called_with("/dev/test") + + with self.patches() as mock: + # LVM devices file enabled and devices file doesn't exist + # and existing VGs present -> devices_add should not be called + mock["lvm"].HAVE_LVMDEVICES = True + mock["os"].path.exists.return_value = False + mock["vgs_info"].cache = {"fake_vg_uuid": "fake_vg_data"} + + fmt._create() + + mock["blockdev"].lvm.devices_add.assert_not_called() -- 2.43.0