diff --git a/repos/system_upgrade/el8toel9/actors/checkarmbootloader/actor.py b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/actor.py new file mode 100644 index 0000000000..b4938ced60 --- /dev/null +++ b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/actor.py @@ -0,0 +1,25 @@ +import leapp.libraries.actor.checkarmbootloader as checkarmbootloader +from leapp.actors import Actor +from leapp.reporting import Report +from leapp.tags import ChecksPhaseTag, IPUWorkflowTag + + +class CheckArmBootloader(Actor): + """ + Inhibit ARM system upgrades on path with incompatible kernel/bootloader + + Due to an incompatibility of RHEL8 bootloader with newer versions of kernel + on RHEL9 since version 9.5, the upgrade cannot be performed as the old + bootloader cannot load the new kernel when entering the interim phase. + + This is temporary workaround until the issue is resolved. + + """ + + name = 'check_arm_bootloader' + consumes = () + produces = (Report,) + tags = (ChecksPhaseTag, IPUWorkflowTag,) + + def process(self): + checkarmbootloader.process() diff --git a/repos/system_upgrade/el8toel9/actors/checkarmbootloader/libraries/checkarmbootloader.py b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/libraries/checkarmbootloader.py new file mode 100644 index 0000000000..a5fdffe95d --- /dev/null +++ b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/libraries/checkarmbootloader.py @@ -0,0 +1,54 @@ +from leapp import reporting +from leapp.libraries.common.config.architecture import ARCH_ARM64, matches_architecture +from leapp.libraries.common.config.version import get_source_version, get_target_version, matches_target_version +from leapp.libraries.stdlib import api + + +def _inhibit_upgrade(): + title = 'Upgrade RHEL {} to RHEL {} not possible for ARM machines.'.format( + get_source_version(), get_target_version()) + summary = ( + 'Due to the incompatibility of the RHEL 8 bootloader with a newer version of kernel on RHEL {}' + ' for ARM machines, the direct upgrade cannot be performed to this RHEL' + ' system version now. The fix is not expected to be delivered during the RHEL 9.5 lifetime.' + .format(get_target_version()) + ) + + reporting.create_report([ + reporting.Title(title), + reporting.Summary(summary), + reporting.ExternalLink( + title='Known issues for the RHEL 8.10 to RHEL 9.5 upgrade', + url='https://red.ht/upgrading-rhel8-to-rhel9-known-issues'), + reporting.Severity(reporting.Severity.HIGH), + reporting.Groups([reporting.Groups.INHIBITOR]), + reporting.Groups([reporting.Groups.SANITY]), + reporting.Remediation(hint=( + 'To upgrade to the RHEL {} version, first in-place upgrade to RHEL 9.4 instead' + ' using the leapp `--target=9.4` option. After you finish the upgrade - including' + ' all required manual post-upgrade steps as well -' + ' update to the newer minor version using the dnf tool. In case of using Red Hat' + ' subscription-manager, do not forget to change the lock version to the newer one' + ' or unset the version lock before using DNF to be able to perform the minor version update.' + ' You can use e.g. `subscription-manager release --unset` command for that.' + .format(get_target_version()) + )), + ]) + + +def process(): + """ + Check whether the upgrade path will use a target kernel compatible with the source bootloader on ARM systems + """ + + if not matches_architecture(ARCH_ARM64): + api.current_logger().info('Architecture not ARM. Skipping bootloader check.') + return + + if matches_target_version('< 9.5'): + api.current_logger().info(( + 'Upgrade on ARM architecture on a compatible path ({} to {}). ' + 'Skipping bootloader check.').format(get_source_version(), get_target_version())) + return + + _inhibit_upgrade() diff --git a/repos/system_upgrade/el8toel9/actors/checkarmbootloader/tests/test_checkarmbootloader.py b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/tests/test_checkarmbootloader.py new file mode 100644 index 0000000000..97c01e7701 --- /dev/null +++ b/repos/system_upgrade/el8toel9/actors/checkarmbootloader/tests/test_checkarmbootloader.py @@ -0,0 +1,67 @@ +import pytest + +from leapp import reporting +from leapp.libraries.actor import checkarmbootloader +from leapp.libraries.common.config.architecture import ARCH_ARM64, ARCH_SUPPORTED +from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked +from leapp.libraries.stdlib import api +from leapp.utils.report import is_inhibitor + + +@pytest.mark.parametrize("arch", [arch for arch in ARCH_SUPPORTED if not arch == ARCH_ARM64]) +def test_not_x86_64_passes(monkeypatch, arch): + """ + Test no report is generated on an architecture different from ARM + """ + + monkeypatch.setattr(reporting, "create_report", create_report_mocked()) + monkeypatch.setattr(api, 'current_logger', logger_mocked()) + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=arch)) + + checkarmbootloader.process() + + assert 'Architecture not ARM.' in api.current_logger.infomsg[0] + assert not reporting.create_report.called + + +@pytest.mark.parametrize("target_version", ["9.2", "9.4"]) +def test_valid_path(monkeypatch, target_version): + """ + Test no report is generated on a supported path + """ + + monkeypatch.setattr(reporting, "create_report", create_report_mocked()) + monkeypatch.setattr(api, 'current_logger', logger_mocked()) + monkeypatch.setattr( + api, 'current_actor', + CurrentActorMocked(arch=ARCH_ARM64, src_ver='8.10', dst_ver=target_version) + ) + + checkarmbootloader.process() + + assert 'Upgrade on ARM architecture on a compatible path' in api.current_logger.infomsg[0] + assert not reporting.create_report.called + + +def test_invalid_path(monkeypatch): + """ + Test report is generated on a invalid upgrade path + """ + + monkeypatch.setattr(reporting, "create_report", create_report_mocked()) + monkeypatch.setattr(api, 'current_logger', logger_mocked()) + monkeypatch.setattr( + api, 'current_actor', + CurrentActorMocked(arch=ARCH_ARM64, src_ver='8.10', dst_ver='9.5') + ) + + checkarmbootloader.process() + + produced_title = reporting.create_report.report_fields.get('title') + produced_summary = reporting.create_report.report_fields.get('summary') + + assert reporting.create_report.called == 1 + assert 'not possible for ARM machines' in produced_title + assert 'Due to the incompatibility' in produced_summary + assert reporting.create_report.report_fields['severity'] == reporting.Severity.HIGH + assert is_inhibitor(reporting.create_report.report_fields)