From 2646484407bef15688fb4838c2f61d06f2098f81 Mon Sep 17 00:00:00 2001 From: Petr Stodulka Date: Wed, 30 Apr 2025 12:54:22 +0200 Subject: [PATCH 40/43] Fix parsing of the kernel cmdline Original parsing has been splitting string tokens by "=" without a limit, means that e.g. root=UUID=some-id has been split to (root, UUID, some-id) and and stored just "root" and "UUID" strings in the parsed msg, instead of "root" and "UUID=some-id". So split the key=value just based on the first occurence of "=" instead. JIRA: RHELMISC-12490 Co-Authored-By: Karolina Kula --- .../common/actors/scankernelcmdline/actor.py | 16 ++--- .../libraries/scankernelcmdline.py | 23 +++++++ .../tests/test_scankernelcmdline.py | 67 +++++++++++++++++++ 3 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py create mode 100644 repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/actor.py b/repos/system_upgrade/common/actors/scankernelcmdline/actor.py index 9f8fef30..2f1a5ae2 100644 --- a/repos/system_upgrade/common/actors/scankernelcmdline/actor.py +++ b/repos/system_upgrade/common/actors/scankernelcmdline/actor.py @@ -1,12 +1,12 @@ from leapp.actors import Actor -from leapp.libraries.stdlib import run -from leapp.models import KernelCmdline, KernelCmdlineArg +from leapp.libraries.actor import scankernelcmdline +from leapp.models import KernelCmdline from leapp.tags import FactsPhaseTag, IPUWorkflowTag class ScanKernelCmdline(Actor): """ - No documentation has been provided for the scan_kernel_cmdline actor. + Scan the kernel command line of the booted system. """ name = 'scan_kernel_cmdline' @@ -15,12 +15,4 @@ class ScanKernelCmdline(Actor): tags = (FactsPhaseTag, IPUWorkflowTag) def process(self): - cmdline = run(['cat', '/proc/cmdline'])['stdout'].strip() - parameters = [] - for parameter in cmdline.split(' '): - if '=' in parameter: - kv = parameter.split('=') - parameters.append(KernelCmdlineArg(key=kv[0], value=kv[1])) - else: - parameters.append(KernelCmdlineArg(key=parameter)) - self.produce(KernelCmdline(parameters=parameters)) + scankernelcmdline.parse_cmdline_input() diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py b/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py new file mode 100644 index 00000000..9cffa70e --- /dev/null +++ b/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py @@ -0,0 +1,23 @@ +from leapp.libraries.stdlib import api, CalledProcessError, run +from leapp.models import KernelCmdline, KernelCmdlineArg + + +def get_cmdline_input(): + try: + cmdline_input = run(['cat', '/proc/cmdline'])['stdout'].strip() + return cmdline_input + except (OSError, CalledProcessError): + api.current_logger().debug('Executing `cat /proc/cmdline` failed', exc_info=True) + return '' + + +def parse_cmdline_input(): + cmdline = get_cmdline_input() + parameters = [] + for parameter in cmdline.split(' '): + if '=' in parameter: + kv = parameter.split('=', 1) + parameters.append(KernelCmdlineArg(key=kv[0], value=kv[1])) + else: + parameters.append(KernelCmdlineArg(key=parameter)) + api.produce(KernelCmdline(parameters=parameters)) diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py b/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py new file mode 100644 index 00000000..ff79054f --- /dev/null +++ b/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py @@ -0,0 +1,67 @@ +import pytest + +from leapp.libraries.actor import scankernelcmdline +from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked +from leapp.libraries.stdlib import api, CalledProcessError +from leapp.models import KernelCmdline, KernelCmdlineArg + + +def mock_cmd_output(): + expected_cmd_output = ( + 'BOOT_IMAGE=(hd0,msdos1)/vmlinuz-xxx root=UUID=some_uid ro console=tty0' + ' console=ttyS0,115200 rd_NO_PLYMOUTH biosdevname=0 net.ifnames=0 crashkernel=auto' + ) + return expected_cmd_output + + +def test_cmdline_output(monkeypatch): + + monkeypatch.setattr(scankernelcmdline, 'get_cmdline_input', mock_cmd_output) + current_actor = CurrentActorMocked(src_ver='8.10', dst_ver='9.6') + monkeypatch.setattr(api, 'current_actor', current_actor) + monkeypatch.setattr(api, 'produce', produce_mocked()) + + scankernelcmdline.parse_cmdline_input() + + expected_params = [KernelCmdlineArg(key=k, value=v) for k, v in [ + ('BOOT_IMAGE', '(hd0,msdos1)/vmlinuz-xxx'), + ('root', 'UUID=some_uid'), + ('ro', None), + ('console', 'tty0'), + ('console', 'ttyS0,115200'), + ('rd_NO_PLYMOUTH', None), + ('biosdevname', '0'), + ('net.ifnames', '0'), + ('crashkernel', 'auto')]] + + expected_output_msg = KernelCmdline(parameters=expected_params) + assert api.produce.model_instances + assert expected_output_msg == api.produce.model_instances[0] + + +def test_cmdline_content(monkeypatch): + + def run_mocked(cmd, **kwargs): + assert cmd == ['cat', '/proc/cmdline'] + output = mock_cmd_output() + return {'stdout': output} + + monkeypatch.setattr(scankernelcmdline, 'run', run_mocked) + cmd_output = scankernelcmdline.get_cmdline_input() + expected_cmd_output = mock_cmd_output() + + assert cmd_output == expected_cmd_output + + +@pytest.mark.parametrize('is_os_error', [True, False]) +def test_cmdline_run_failed(monkeypatch, is_os_error): + + def run_mocked_error(cmd, **kwargs): + assert cmd == ['cat', '/proc/cmdline'] + if is_os_error: + raise OSError('OSError raised') + raise CalledProcessError("CalledProcessError raised", cmd, "result") + + monkeypatch.setattr(scankernelcmdline, 'run', run_mocked_error) + cmd_output = scankernelcmdline.get_cmdline_input() + assert cmd_output == '' -- 2.49.0