Skip to content

Commit

Permalink
kernelcmdlineconfig: Use args from first entry when multiple entries …
Browse files Browse the repository at this point in the history
…are listed

Instead of erroring out when grubby lists multiple entries for the
default kernel, always use the `args=` and `root=` from the first one and create
a post-upgrade report. The report instruct user to ensure those are the
correct ones or to correct them.

This can happen, for example, if MAKEDEBUG=yes is set in
/etc/sysconfing/kernel.
  • Loading branch information
matejmatuska committed Oct 18, 2024
1 parent 99f546e commit 67f0a47
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,55 @@ def _extract_grubby_value(record):
return matches.group(2)


def report_multple_entries_for_default_kernel():
if use_cmdline_file():
report_hint = (
'After the system has been rebooted into the new version of RHEL,'
' check that configured default kernel cmdline arguments in /etc/kernel/cmdline '
' are correct. In case that different arguments are expected, update the file as needed.'
)
else:
report_hint = (
'After the system has been rebooted into the new version of RHEL,'
' check that configured default kernel cmdline arguments are set as expected, using'
' the `grub2-editenv list` command. '
' If different default arguments are expected, update them using grub2-editenv.\n'
' For example, consider that current booted kernel has correct kernel cmdline'
' arguments and /proc/cmdline contains:\n\n'
' BOOT_IMAGE=(hd0,msdos1)/vmlinuz-4.18.0-425.3.1.el8.x86_64'
' root=/dev/mapper/rhel_ibm--root ro console=tty0'
' console=ttyS0,115200 rd_NO_PLYMOUTH\n\n'
' then run the following grub2-editenv command:\n\n'
' # grub2-editenv - set "kernelopts=root=/dev/mapper/rhel_ibm--root'
' ro console=tty0 console=ttyS0,115200 rd_NO_PLYMOUTH"'
)

reporting.create_report([
reporting.Title('Ensure that expected default kernel cmdline arguments are set'),
reporting.Summary(
'During the upgrade we needed to modify the kernel command line arguments.'
' However, multiple bootloader entries with different arguments were found for the default'
' kernel (perhaps MAKEDEBUG=yes is set in /etc/sysconfig/kernel).'
' Leapp used the arguments from the first found entry of the target kernel'
' and set it as the new default kernel cmdline arguments for kernels installed in the future.'
),
reporting.Remediation(hint=report_hint),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([
reporting.Groups.BOOT,
reporting.Groups.KERNEL,
reporting.Groups.POST,
]),
reporting.RelatedResource('file', '/etc/kernel/cmdline'),
])


def retrieve_args_for_default_kernel(kernel_info):
# Copy the args for the default kernel to all kernels.
kernel_args = None
kernel_root = None
detected_multiple_entries = False

cmd = ['grubby', '--info', kernel_info.kernel_img_path]
output = stdlib.run(cmd, split=False)
for record in output['stdout'].splitlines():
Expand All @@ -122,26 +167,40 @@ def retrieve_args_for_default_kernel(kernel_info):
temp_kernel_args = _extract_grubby_value(record)

if kernel_args:
api.current_logger().warning('Grubby output is malformed:'
' `args=` is listed more than once.')
if kernel_args != temp_kernel_args:
raise ReadOfKernelArgsError('Grubby listed `args=` multiple'
' times with different values.')
kernel_args = _extract_grubby_value(record)
api.current_logger().warning(
'Grubby output listed `args=` multiple times with different values,'
' continuing with the first result'
)
detected_multiple_entries = True
else:
api.current_logger().warning('Grubby output listed `args=` more than once')
else:
kernel_args = temp_kernel_args
elif record.startswith('root='):
api.current_logger().warning('Grubby output is malformed:'
' `root=` is listed more than once.')
temp_kernel_root = _extract_grubby_value(record)

if kernel_root:
raise ReadOfKernelArgsError('Grubby listed `root=` multiple'
' times with different values')
kernel_root = _extract_grubby_value(record)
if kernel_root != temp_kernel_root:
api.current_logger().warning(
'Grubby output listed `root=` multiple times with different values,'
' continuing with the first result'
)
detected_multiple_entries = True
else:
api.current_logger().warning('Grubby output listed `root=` more than once')
else:
kernel_root = temp_kernel_root

if not kernel_args or not kernel_root:
raise ReadOfKernelArgsError(
'Failed to retrieve kernel command line to save for future installed'
' kernels: root={}, args={}'.format(kernel_root, kernel_args)
)

if detected_multiple_entries:
report_multple_entries_for_default_kernel()

return kernel_root, kernel_args


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

import pytest

from leapp import reporting
from leapp.exceptions import StopActorExecutionError
from leapp.libraries import stdlib
from leapp.libraries.actor import kernelcmdlineconfig
from leapp.libraries.common.config import architecture
from leapp.libraries.common.testutils import CurrentActorMocked
from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
from leapp.libraries.stdlib import api
from leapp.models import InstalledTargetKernelInfo, KernelCmdlineArg, TargetKernelCmdlineArgTasks

Expand Down Expand Up @@ -183,6 +184,49 @@ def test_kernelcmdline_config_no_version(monkeypatch):
assert not mocked_run.commands


SECOND_KERNEL_ARGS = ('ro rootflags=subvol=root'
' resume=/dev/mapper/luks-2c0df999-81ec-4a35-a1f9-b93afee8c6ad'
' rd.luks.uuid=luks-90a6412f-c588-46ca-9118-5aca35943d25'
' rd.luks.uuid=luks-2c0df999-81ec-4a35-a1f9-b93afee8c6ad'
)
SECOND_KERNEL_ROOT = 'UUID=1aa15850-2685-418d-95a6-f7266a2de83b'

@pytest.mark.parametrize(
'second_grubby_output',
(
TEMPLATE_GRUBBY_INFO_OUTPUT.format(SECOND_KERNEL_ARGS, SECOND_KERNEL_ROOT),
TEMPLATE_GRUBBY_INFO_OUTPUT.format(SAMPLE_KERNEL_ARGS, SECOND_KERNEL_ROOT),
TEMPLATE_GRUBBY_INFO_OUTPUT.format(SECOND_KERNEL_ARGS, SAMPLE_KERNEL_ROOT),
)
)
def test_kernelcmdline_config_mutiple_args(monkeypatch, second_grubby_output):
kernel_img_path = '/boot/vmlinuz-X'
kernel_info = InstalledTargetKernelInfo(pkg_nevra=TARGET_KERNEL_NEVRA,
uname_r='',
kernel_img_path=kernel_img_path,
initramfs_path='/boot/initramfs-X')

# For this test, we need to check we get the proper report if grubby --info
# outputs multiple different `root=` or `args=`
# and that the first ones are used
grubby_info_output = "\n".join((SAMPLE_GRUBBY_INFO_OUTPUT, second_grubby_output))

mocked_run = MockedRun(
outputs={" ".join(("grubby", "--info", kernel_img_path)): grubby_info_output,
}
)
monkeypatch.setattr(stdlib, 'run', mocked_run)
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
monkeypatch.setattr(reporting, "create_report", create_report_mocked())

root, args = kernelcmdlineconfig.retrieve_args_for_default_kernel(kernel_info)
assert root == SAMPLE_KERNEL_ROOT
assert args == SAMPLE_KERNEL_ARGS
assert reporting.create_report.called == 1
expected_title ='Ensure that expected default kernel cmdline arguments are set'
assert expected_title in reporting.create_report.report_fields['title']


def test_kernelcmdline_config_malformed_args(monkeypatch):
kernel_img_path = '/boot/vmlinuz-X'
kernel_info = InstalledTargetKernelInfo(pkg_nevra=TARGET_KERNEL_NEVRA,
Expand Down

0 comments on commit 67f0a47

Please sign in to comment.