From de6f1d13d7f2f1cc7b7ee610c935385179a6edaa Mon Sep 17 00:00:00 2001 From: mhecko Date: Thu, 4 Apr 2024 14:22:48 +0200 Subject: [PATCH] check_microarch: refactor to handle possible future reqs --- .../actors/checkmicroarchitecture/actor.py | 0 .../libraries/checkmicroarchitecture.py | 73 +++++++++++++++++++ .../tests/test_checkmicroarchitecture.py | 21 ++++-- .../libraries/checkmicroarchitecture.py | 46 ------------ 4 files changed, 87 insertions(+), 53 deletions(-) rename repos/system_upgrade/{el8toel9 => common}/actors/checkmicroarchitecture/actor.py (100%) create mode 100644 repos/system_upgrade/common/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py rename repos/system_upgrade/{el8toel9 => common}/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py (79%) delete mode 100644 repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py b/repos/system_upgrade/common/actors/checkmicroarchitecture/actor.py similarity index 100% rename from repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py rename to repos/system_upgrade/common/actors/checkmicroarchitecture/actor.py diff --git a/repos/system_upgrade/common/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py b/repos/system_upgrade/common/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py new file mode 100644 index 0000000000..cc617203b5 --- /dev/null +++ b/repos/system_upgrade/common/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py @@ -0,0 +1,73 @@ +from collections import namedtuple + +from leapp import reporting +from leapp.libraries.common.config.architecture import ARCH_X86_64, matches_architecture +from leapp.libraries.common.config.version import get_target_major_version +from leapp.libraries.stdlib import api +from leapp.models import CPUInfo + +X86_64_BASELINE_FLAGS = ['cmov', 'cx8', 'fpu', 'fxsr', 'mmx', 'syscall', 'sse', 'sse2'] +X86_64_V2_FLAGS = ['cx16', 'lahf_lm', 'popcnt', 'pni', 'sse4_1', 'sse4_2', 'ssse3'] + +MicroarchInfo = namedtuple('MicroarchInfo', ('required_flags', 'extra_report_fields', 'microarch_ver')) + + +def _inhibit_upgrade(missing_flags, target_rhel, microarch_ver, extra_report_fields=None): + title = 'Current x86-64 microarchitecture is unsupported in {0}'.format(target_rhel) + summary = ('{0} has a higher CPU requirement than older versions, it now requires a CPU ' + 'compatible with {1} instruction set or higher.\n\n' + 'Missings flags detected are: {2}\n'.format(target_rhel, microarch_ver, ', '.join(missing_flags))) + + report_fields = [ + reporting.Title(title), + reporting.Summary(summary), + reporting.Severity(reporting.Severity.HIGH), + reporting.Groups([reporting.Groups.INHIBITOR]), + reporting.Groups([reporting.Groups.SANITY]), + reporting.Remediation(hint=('If case of using virtualization, virtualization platforms often allow ' + 'configuring a minimum denominator CPU model for compatibility when migrating ' + 'between different CPU models. Ensure that minimum requirements are not below ' + 'that of {0}\n').format(target_rhel)), + ] + + if extra_report_fields: + report_fields += extra_report_fields + + reporting.create_report(report_fields) + + +def process(): + """ + Check whether the processor matches the required microarchitecture. + """ + + if not matches_architecture(ARCH_X86_64): + api.current_logger().info('Architecture not x86-64. Skipping microarchitecture test.') + return + + cpuinfo = next(api.consume(CPUInfo)) + + rhel9_microarch_article = reporting.ExternalLink( + title='Building Red Hat Enterprise Linux 9 for the x86-64-v2 microarchitecture level', + url='https://red.ht/rhel-9-intel-microarchitectures' + ) + + rhel_major_to_microarch_reqs = { + '9': MicroarchInfo(microarch_ver='x86-64-v2', + required_flags=(X86_64_BASELINE_FLAGS + X86_64_V2_FLAGS), + extra_report_fields=[rhel9_microarch_article]), + } + + microarch_info = rhel_major_to_microarch_reqs.get(get_target_major_version()) + if not microarch_info: + api.current_logger().info('No known microarchitecture requirements are known for target RHEL%s.', + get_target_major_version()) + return + + missing_flags = [flag for flag in microarch_info.required_flags if flag not in cpuinfo.flags] + api.current_logger().debug('Required flags missing: %s', missing_flags) + if missing_flags: + _inhibit_upgrade(missing_flags, + 'RHEL{0}'.format(get_target_major_version()), + microarch_info.microarch_ver, + extra_report_fields=microarch_info.extra_report_fields) diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py b/repos/system_upgrade/common/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py similarity index 79% rename from repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py rename to repos/system_upgrade/common/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py index b7c850d9a0..b0624f2be0 100644 --- a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py +++ b/repos/system_upgrade/common/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py @@ -25,7 +25,13 @@ def test_not_x86_64_passes(monkeypatch, arch): assert not reporting.create_report.called -def test_valid_microarchitecture(monkeypatch): +@pytest.mark.parametrize( + ('target_ver', 'cpu_flags'), + [ + ('9.0', checkmicroarchitecture.X86_64_BASELINE_FLAGS + checkmicroarchitecture.X86_64_V2_FLAGS) + ] +) +def test_valid_microarchitecture(monkeypatch, target_ver, cpu_flags): """ Test no report is generated on a valid microarchitecture """ @@ -33,9 +39,8 @@ def test_valid_microarchitecture(monkeypatch): monkeypatch.setattr(reporting, "create_report", create_report_mocked()) monkeypatch.setattr(api, 'current_logger', logger_mocked()) - required_flags = checkmicroarchitecture.X86_64_BASELINE_FLAGS + checkmicroarchitecture.X86_64_V2_FLAGS - monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=ARCH_X86_64, - msgs=[CPUInfo(flags=required_flags)])) + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=ARCH_X86_64, dst_ver=target_ver, + msgs=[CPUInfo(flags=cpu_flags)])) checkmicroarchitecture.process() @@ -43,14 +48,16 @@ def test_valid_microarchitecture(monkeypatch): assert not reporting.create_report.called -def test_invalid_microarchitecture(monkeypatch): +@pytest.mark.parametrize('target_ver', ['9.0']) +def test_invalid_microarchitecture(monkeypatch, target_ver): """ Test report is generated on x86-64 architecture with invalid microarchitecture and the upgrade is inhibited """ monkeypatch.setattr(reporting, "create_report", create_report_mocked()) monkeypatch.setattr(api, 'current_logger', logger_mocked()) - monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=ARCH_X86_64, msgs=[CPUInfo()])) + monkeypatch.setattr(api, 'current_actor', + CurrentActorMocked(arch=ARCH_X86_64, msgs=[CPUInfo()], dst_ver=target_ver)) checkmicroarchitecture.process() @@ -60,6 +67,6 @@ def test_invalid_microarchitecture(monkeypatch): assert 'Architecture not x86-64. Skipping microarchitecture test.' not in api.current_logger().infomsg assert reporting.create_report.called == 1 assert 'microarchitecture is unsupported' in produced_title - assert 'RHEL9 has a higher CPU requirement' in produced_summary + assert 'has a higher CPU requirement' in produced_summary assert reporting.create_report.report_fields['severity'] == reporting.Severity.HIGH assert is_inhibitor(reporting.create_report.report_fields) diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py deleted file mode 100644 index 9c083d7eed..0000000000 --- a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py +++ /dev/null @@ -1,46 +0,0 @@ -from leapp import reporting -from leapp.libraries.common.config.architecture import ARCH_X86_64, matches_architecture -from leapp.libraries.stdlib import api -from leapp.models import CPUInfo - -X86_64_BASELINE_FLAGS = ['cmov', 'cx8', 'fpu', 'fxsr', 'mmx', 'syscall', 'sse', 'sse2'] -X86_64_V2_FLAGS = ['cx16', 'lahf_lm', 'popcnt', 'pni', 'sse4_1', 'sse4_2', 'ssse3'] - - -def _inhibit_upgrade(missing_flags): - title = 'Current x86-64 microarchitecture is unsupported in RHEL9' - summary = ('RHEL9 has a higher CPU requirement than older versions, it now requires a CPU ' - 'compatible with x86-64-v2 instruction set or higher.\n\n' - 'Missings flags detected are: {}\n'.format(', '.join(missing_flags))) - - reporting.create_report([ - reporting.Title(title), - reporting.Summary(summary), - reporting.ExternalLink(title='Building Red Hat Enterprise Linux 9 for the x86-64-v2 microarchitecture level', - url='https://red.ht/rhel-9-intel-microarchitectures'), - reporting.Severity(reporting.Severity.HIGH), - reporting.Groups([reporting.Groups.INHIBITOR]), - reporting.Groups([reporting.Groups.SANITY]), - reporting.Remediation(hint=('If case of using virtualization, virtualization platforms often allow ' - 'configuring a minimum denominator CPU model for compatibility when migrating ' - 'between different CPU models. Ensure that minimum requirements are not below ' - 'that of RHEL9\n')), - ]) - - -def process(): - """ - Check whether the processor matches the required microarchitecture. - """ - - if not matches_architecture(ARCH_X86_64): - api.current_logger().info('Architecture not x86-64. Skipping microarchitecture test.') - return - - cpuinfo = next(api.consume(CPUInfo)) - - required_flags = X86_64_BASELINE_FLAGS + X86_64_V2_FLAGS - missing_flags = [flag for flag in required_flags if flag not in cpuinfo.flags] - api.current_logger().debug('Required flags missing: %s', missing_flags) - if missing_flags: - _inhibit_upgrade(missing_flags)