Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check_microarch: require x86_64-v3 for RHEL10 #1196

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class CheckMicroarchitecture(Actor):
levels.

RHEL9 has a higher CPU requirement than older versions, it now requires a
CPU compatible with ``x86-64-v2`` instruction set or higher.
CPU compatible with ``x86-64-v2`` instruction set or higher. Similarly,
RHEL10 requires at least ``x86-64-v3`` instruction set.

.. table:: Required CPU features by microarchitecure level with a
corresponding flag as shown by ``lscpu``.
Expand All @@ -43,7 +44,15 @@ class CheckMicroarchitecture(Actor):
| | SSE4_2 | sse4_2 |
| | SSSE3 | ssse3 |
+------------+-------------+--------------------+
| ... | | |
| x86-64-v3 | AVX | avx |
| | AVX2 | avx2 |
| | BMI1 | bmi1 |
| | BMI2 | bmi2 |
| | F16C | f16c |
| | FMA | fma |
| | LZCNT | abm |
| | MOVBE | movbe |
| | OSXSAVE | xsave |
+------------+-------------+--------------------+

Note: To get the corresponding flag for the CPU feature consult the file
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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']
X86_64_V3_FLAGS = ['avx2', 'bmi1', 'bmi2', 'f16c', 'fma', 'abm', 'movbe', 'xsave']

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 a 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]),
'10': MicroarchInfo(microarch_ver='x86-64-v3',
required_flags=(X86_64_BASELINE_FLAGS + X86_64_V2_FLAGS + X86_64_V3_FLAGS),
extra_report_fields=[]),
}
Comment on lines +51 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a note to the OAMG-11275 ticket to not forget to implement the shortened URL when a documentation is created.


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()),
pirat89 marked this conversation as resolved.
Show resolved Hide resolved
microarch_info.microarch_ver,
extra_report_fields=microarch_info.extra_report_fields)
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,50 @@ def test_not_x86_64_passes(monkeypatch, arch):
assert not reporting.create_report.called


def test_valid_microarchitecture(monkeypatch):
ENTIRE_V2_FLAG_SET = checkmicroarchitecture.X86_64_BASELINE_FLAGS + checkmicroarchitecture.X86_64_V2_FLAGS
ENTIRE_V3_FLAG_SET = ENTIRE_V2_FLAG_SET + checkmicroarchitecture.X86_64_V3_FLAGS


@pytest.mark.parametrize(
('target_ver', 'cpu_flags'),
[
('9.0', ENTIRE_V2_FLAG_SET),
('10.0', ENTIRE_V3_FLAG_SET)
]
)
def test_valid_microarchitecture(monkeypatch, target_ver, cpu_flags):
"""
Test no report is generated on a valid microarchitecture
"""

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()

assert 'Architecture not x86-64. Skipping microarchitecture test.' not in api.current_logger.infomsg
assert not reporting.create_report.called


def test_invalid_microarchitecture(monkeypatch):
@pytest.mark.parametrize(
('target_ver', 'cpu_flags'),
(
('9.0', checkmicroarchitecture.X86_64_BASELINE_FLAGS),
('10.0', ENTIRE_V2_FLAG_SET),
)
)
def test_invalid_microarchitecture(monkeypatch, target_ver, cpu_flags):
"""
Test report is generated on x86-64 architecture with invalid microarchitecture and the upgrade is inhibited
"""

cpu_info = CPUInfo(flags=cpu_flags)
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=[cpu_info], dst_ver=target_ver))

checkmicroarchitecture.process()

Expand All @@ -60,6 +78,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)

This file was deleted.