From 04a2ec2574da233a41d32f70eab780b6c305ff31 Mon Sep 17 00:00:00 2001 From: Michal Hecko Date: Thu, 19 Dec 2024 10:33:24 +0100 Subject: [PATCH 03/55] feat(lvm_autoactivation): add lvm autoactivation Add LVM autoactivation mechanism to the upgrade initramfs. The core of the mechanism is based on a special udev rule that is triggered when a new device is detected. The rule then calls two lvm binaries (which are also included into the upgrade initrams) to activate the volume groups and logical volumes. --- .../enable_lvm_autoactivation/actor.py | 21 ++++++++ .../libraries/enable_lvm_autoactivation.py | 21 ++++++++ .../test_lvm_autoactivation_enablement.py | 50 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py new file mode 100644 index 00000000..aba60645 --- /dev/null +++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py @@ -0,0 +1,21 @@ +from leapp.actors import Actor +from leapp.libraries.actor import enable_lvm_autoactivation as enable_lvm_autoactivation_lib +from leapp.models import DistributionSignedRPM, UpgradeInitramfsTasks +from leapp.tags import FactsPhaseTag, IPUWorkflowTag + + +class EnableLVMAutoactivation(Actor): + """ + Enable LVM autoactivation in upgrade initramfs. + + Produce instructions for upgrade initramfs generation that will result in LVM + autoactivation in the initramfs. + """ + + name = 'enable_lvm_autoactivation' + consumes = (DistributionSignedRPM,) + produces = (UpgradeInitramfsTasks, ) + tags = (FactsPhaseTag, IPUWorkflowTag) + + def process(self): + enable_lvm_autoactivation_lib.emit_lvm_autoactivation_instructions() diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py new file mode 100644 index 00000000..e312277b --- /dev/null +++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py @@ -0,0 +1,21 @@ +from leapp.libraries.common.rpms import has_package +from leapp.libraries.stdlib import api +from leapp.models import DistributionSignedRPM, UpgradeInitramfsTasks + + +def emit_lvm_autoactivation_instructions(): + if not has_package(DistributionSignedRPM, 'lvm2'): + api.current_logger().debug( + 'Upgrade initramfs will not autoenable LVM devices - `lvm2` RPM is not installed.' + ) + return + + # the 69-dm-lvm.rules trigger pvscan and vgchange when LVM device is detected + files_to_include = [ + '/usr/sbin/pvscan', + '/usr/sbin/vgchange', + '/usr/lib/udev/rules.d/69-dm-lvm.rules' + ] + lvm_autoactivation_instructions = UpgradeInitramfsTasks(include_files=files_to_include) + + api.produce(lvm_autoactivation_instructions) diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py new file mode 100644 index 00000000..c5150aea --- /dev/null +++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py @@ -0,0 +1,50 @@ +from leapp.libraries.actor import enable_lvm_autoactivation +from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked +from leapp.libraries.stdlib import api +from leapp.models import DistributionSignedRPM, RPM, UpgradeInitramfsTasks + + +def test_emit_lvm_autoactivation_instructions_produces_correct_message(monkeypatch): + """Test that emit_lvm_autoactivation_instructions produces UpgradeInitramfsTasks with correct files.""" + lvm_package = RPM( + name='lvm2', + version='2', + release='1', + epoch='1', + packager='', + arch='x86_64', + pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51' + ) + + msgs = [ + DistributionSignedRPM(items=[lvm_package]) + ] + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs)) + monkeypatch.setattr(api, 'produce', produce_mocked()) + + enable_lvm_autoactivation.emit_lvm_autoactivation_instructions() + + assert api.produce.called == 1 + + produced_msg = api.produce.model_instances[0] + + assert isinstance(produced_msg, UpgradeInitramfsTasks) + + expected_files = [ + '/usr/sbin/pvscan', + '/usr/sbin/vgchange', + '/usr/lib/udev/rules.d/69-dm-lvm.rules' + ] + assert produced_msg.include_files == expected_files + + +def test_no_action_if_lvm_rpm_missing(monkeypatch): + msgs = [ + DistributionSignedRPM(items=[]) + ] + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs)) + monkeypatch.setattr(api, 'produce', produce_mocked()) + + enable_lvm_autoactivation.emit_lvm_autoactivation_instructions() + + assert api.produce.called == 0 -- 2.51.1