From f5ebd93dda30af9c800402d9a14d8aa85c84a838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Reh=C3=A1k?= Date: Fri, 25 Sep 2020 16:14:28 +0200 Subject: [PATCH] Inhibit upgrade if multiple kernel-debug pkgs are installed When multiple kernel-debug packages are present, leapp can't process the transaction in some cases, so we inhibit the upgrade and present the user with hints on removing the surplus debug kernels. Note that the added actor is basically a search-and-replace copy of CheckInstalledDevelKernels, which solves the same problem for a different package. I don't see many reasons to merge them into one. Derived from: commit 2ce678fe8613c0d96ff720b7374466695aa6dc42 (#457) --- .../checkinstalleddebugkernels/actor.py | 23 ++++++++++ .../libraries/checkinstalleddebugkernels.py | 42 +++++++++++++++++++ .../unit_test_checkinstalleddebugkernels.py | 36 ++++++++++++++++ .../libraries/checkinstalleddevelkernels.py | 2 +- 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/actor.py create mode 100644 repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/libraries/checkinstalleddebugkernels.py create mode 100644 repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/tests/unit_test_checkinstalleddebugkernels.py diff --git a/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/actor.py b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/actor.py new file mode 100644 index 0000000000..2dccf4bd52 --- /dev/null +++ b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/actor.py @@ -0,0 +1,23 @@ +from leapp.actors import Actor +from leapp.models import InstalledRedHatSignedRPM +from leapp.tags import IPUWorkflowTag, ChecksPhaseTag +from leapp.reporting import Report +from leapp.libraries.actor import checkinstalleddebugkernels + + +class CheckInstalledDebugKernels(Actor): + """ + Inhibit IPU (in-place upgrade) when multiple debug kernels are installed. + + Because of an issue in DNF, the transaction can't be validated if there's + more than one package named kernel-debug. Therefore, in this case, we + inhibit the upgrade with a clearer remediation. + """ + + name = 'check_installed_debug_kernels' + consumes = (InstalledRedHatSignedRPM,) + produces = (Report,) + tags = (IPUWorkflowTag, ChecksPhaseTag) + + def process(self): + checkinstalleddebugkernels.process() diff --git a/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/libraries/checkinstalleddebugkernels.py b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/libraries/checkinstalleddebugkernels.py new file mode 100644 index 0000000000..00c245b211 --- /dev/null +++ b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/libraries/checkinstalleddebugkernels.py @@ -0,0 +1,42 @@ +from leapp import reporting +from leapp.libraries.stdlib import api +from leapp.models import InstalledRedHatSignedRPM + + +def get_kernel_rpm_release(rpm): + """ + Get the release of a kernel RPM as an integer. + + :param rpm: An instance of an RPM derived model. + """ + return int(rpm.release.split('.')[0]) + + +def get_kernel_debug_rpms(): + """ + Get all installed kernel-debug packages ordered by release number (ascending). + """ + rpms = next(api.consume(InstalledRedHatSignedRPM), InstalledRedHatSignedRPM()) + return sorted([pkg for pkg in rpms.items if pkg.name == 'kernel-debug'], key=get_kernel_rpm_release) + + +def process(): + pkgs = get_kernel_debug_rpms() + if len(pkgs) > 1: + title = 'Multiple debug kernels installed' + summary = ('DNF cannot produce a valid upgrade transaction when' + ' multiple kernel-debug packages are installed.') + hint = ('Remove all but one kernel-debug packages before running Leapp again.') + all_but_latest_kernel_debug = pkgs[:-1] + packages = ['{n}-{v}-{r}'.format(n=pkg.name, v=pkg.version, r=pkg.release) + for pkg in all_but_latest_kernel_debug] + commands = [['yum', '-y', 'remove'] + packages] + reporting.create_report([ + reporting.Title(title), + reporting.Summary(summary), + reporting.Severity(reporting.Severity.HIGH), + reporting.Tags([reporting.Tags.KERNEL]), + reporting.Flags([reporting.Flags.INHIBITOR]), + reporting.Remediation(hint=hint, commands=commands), + reporting.RelatedResource('package', 'kernel-debug') + ]) diff --git a/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/tests/unit_test_checkinstalleddebugkernels.py b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/tests/unit_test_checkinstalleddebugkernels.py new file mode 100644 index 0000000000..365b729bc7 --- /dev/null +++ b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddebugkernels/tests/unit_test_checkinstalleddebugkernels.py @@ -0,0 +1,36 @@ +import pytest + +from leapp.models import InstalledRedHatSignedRPM, RPM, Report +from leapp.snactor.fixture import current_actor_context + + +RH_PACKAGER = 'Red Hat, Inc. ' + +ballast1 = [ + RPM(name='b1', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='kernel', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='b2', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s') +] +ballast2 = [ + RPM(name='b3', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='kernel', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='b4', version='1', release='1', epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s') +] +debug_kernels = [ + RPM(name='kernel-debug', version='3.10.0', release='957.27.4.el7', + epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='kernel-debug', version='3.10.0', release='957.35.1.el7', + epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s'), + RPM(name='kernel-debug', version='3.10.0', release='957.43.1.el7', + epoch='1', packager=RH_PACKAGER, arch='noarch', pgpsig='s') +] + + +@pytest.mark.parametrize('n', [0, 1, 2, 3]) +def test_process_debug_kernels(current_actor_context, n): + current_actor_context.feed(InstalledRedHatSignedRPM(items=ballast1+debug_kernels[:n]+ballast2)) + current_actor_context.run() + if n < 2: + assert not current_actor_context.consume(Report) + else: + assert current_actor_context.consume(Report) diff --git a/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddevelkernels/libraries/checkinstalleddevelkernels.py b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddevelkernels/libraries/checkinstalleddevelkernels.py index 99c6a4bbaa..35d6a6705d 100644 --- a/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddevelkernels/libraries/checkinstalleddevelkernels.py +++ b/repos/system_upgrade/el7toel8/actors/kernel/checkinstalleddevelkernels/libraries/checkinstalleddevelkernels.py @@ -38,5 +38,5 @@ def process(): reporting.Tags([reporting.Tags.KERNEL]), reporting.Flags([reporting.Flags.INHIBITOR]), reporting.Remediation(hint=hint, commands=commands), - reporting.RelatedResource('package', 'kernel') + reporting.RelatedResource('package', 'kernel-devel') ])