From 1a2637b1a375fbe03c5333da789e2e126ec74601 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 10 Feb 2025 15:28:21 +0100 Subject: [PATCH] stages: replace "logger" binary in the dracut chroot This commit replaces the `/usr/bin/logger` binary in the dracut chroot with a bind mount to `/usr/bin/true` to silence the spam that we get from dracut during initramfs generation: ``` logger: socket /dev/log: No such file or directory ``` Unfortunately I could not find a nicer way, it seems it is not possible to simply pass `sysloglvl=0` via the commandline or an environment. The extra complication here is that the dracut stage mounts `devtmpfs` which will likely include: ``` /dev/log -> /run/systemd/journal/dev-log ``` but of course inside this chroot there is no `/run` which leads to these messages. Closes: https://github.com/osbuild/osbuild/issues/1976 --- stages/org.osbuild.dracut | 31 +++++++++++++++++++++++++++++-- stages/test/test_dracut.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/stages/org.osbuild.dracut b/stages/org.osbuild.dracut index 05a56682..451ef42d 100755 --- a/stages/org.osbuild.dracut +++ b/stages/org.osbuild.dracut @@ -1,4 +1,8 @@ #!/usr/bin/python3 +import contextlib +import os +import os.path +import subprocess import sys import osbuild.api @@ -10,6 +14,22 @@ def yesno(name: str, value: bool) -> str: return f"--{prefix}{name}" +@contextlib.contextmanager +def bind_mount_logger(tree: str) -> None: + logger_tree_path = os.path.join(tree, "usr/bin/logger") + if not os.path.exists(logger_tree_path): + # no logger -> nothing to do + yield + return + # make logger a "noop" + true_tree_path = os.path.join(tree, "usr/bin/true") + subprocess.run(["mount", "--rbind", true_tree_path, logger_tree_path], check=True) + try: + yield + finally: + subprocess.run(["umount", logger_tree_path], check=False) + + # pylint: disable=too-many-branches def main(tree, options): kernels = options["kernel"] @@ -82,8 +102,15 @@ def main(tree, options): if initoverlayfs: initfs_bin = "/usr/bin/initoverlayfs-install" - with Chroot(tree) as chroot: - chroot.run([initfs_bin, "--no-hostonly", "--kver", kver] + opts, check=True) + # the chroot.run() call below will mount /dev with "devtmpfs", this + # is needed, see pr #1846 but it means we have likely have a + # /dev/log -> /run/systemd/journal/dev-log + # symlink and dracut will try to log on it but end up writing + # 5k of "logger: socket /dev/log: No such file or directory" + # messages. See also issue #1976 + with bind_mount_logger(tree): + with Chroot(tree) as chroot: + chroot.run([initfs_bin, "--no-hostonly", "--kver", kver] + opts, check=True) return 0 diff --git a/stages/test/test_dracut.py b/stages/test/test_dracut.py index 99530589..4037b50a 100644 --- a/stages/test/test_dracut.py +++ b/stages/test/test_dracut.py @@ -29,3 +29,31 @@ def test_dracut_with_initoverlayfs(mocked_run, tmp_path, stage_module, with_init run_argv = args[0] assert run_argv[0] == "chroot" assert run_argv[2] == expected_argv2 + + +@patch("subprocess.run") +def test_dracut_logger(mocked_run, tmp_path, stage_module): + fake_logger_path = tmp_path / "usr/bin/logger" + fake_logger_path.parent.mkdir(parents=True) + fake_logger_path.write_text("") + fake_true_path = tmp_path / "usr/bin/true" + fake_true_path.write_text("") + + options = { + "kernel": [ + "5.14.0-247.el9.x86_64", + ] + } + stage_module.main(tmp_path.as_posix(), options) + assert len(mocked_run.call_args_list) == 9 + args, kwargs = mocked_run.call_args_list[0] # bind-mount is the 1th call + assert kwargs.get("check") is True + run_argv = args[0] + assert run_argv == [ + "mount", "--rbind", + fake_true_path.as_posix(), fake_logger_path.as_posix(), + ] + args, kwargs = mocked_run.call_args_list[8] # umount is the 9th call + assert kwargs.get("check") is False + run_argv = args[0] + assert run_argv == ["umount", fake_logger_path.as_posix()]