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
This commit is contained in:
Michael Vogt 2025-02-10 15:28:21 +01:00 committed by Simon de Vlieger
parent ed732b36d8
commit 1a2637b1a3
2 changed files with 57 additions and 2 deletions

View file

@ -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

View file

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