Repository: osbuild/osbuild
Pull request #1558 (2024-01-30 08:52:51)

stages(zipl.inst): support appending kernel options
In some cases it could useful to add additional kernel options without
modifying BLS config, so any subsequent call to `zipl` would ignore them.
We are going to use this to append `ignition.firstboot` to kernel cmdline
for CoreOS on s390x.

dustymabe: @mvo5 mind a review? 
dustymabe: @thozza can you add a new review now that we have simplified this and dropped it down to a single commit? 
dustymabe: Thanks @mvo5 - @nikita-dubrovskii can you add some tests here? 
nikita-dubrovskii: > This looks fine, I would love to see some basic testing, I attached a quick draft what I have in mind. [0001-test-add-simple-zipl_inst-test.patch.txt](https://github.com/osbuild/osbuild/files/14168339/0001-test-add-simple-zipl_inst-test.patch.txt)

I've added this patch + extended it for empty `kernel_opts_append`  case
dustymabe: Rebased this and approved tests to run. @mvo5 should we enable auto-merge or wait for more reviewers?
dustymabe: fixed a lint error

Patch:
diff --git a/stages/org.osbuild.zipl.inst b/stages/org.osbuild.zipl.inst
index a9bea045..caca9f82 100755
--- a/stages/org.osbuild.zipl.inst
+++ b/stages/org.osbuild.zipl.inst
@@ -28,6 +28,14 @@ SCHEMA_2 = r"""
     "location": {
       "type": "number"
     },
+    "kernel_opts_append": {
+      "description": "Additional kernel options to add to the discovered options",
+      "type": "array",
+      "items": {
+        "description": "A single kernel command line option",
+        "type": "string"
+      }
+    },
     "blocksize": {
       "type": "number",
       "default": 512
@@ -85,6 +93,7 @@ def find_kernel(root, kernel: str):
 def main(paths, devices, options):
     kver = options["kernel"]
     location = options["location"]
+    append_kopts = options.get("kernel_opts_append", [])
     blocksize = options.get("blocksize", 512)
 
     root = paths["mounts"]
@@ -100,7 +109,7 @@ def main(paths, devices, options):
                     "--target", f"{root}/boot",
                     "--image", kernel,
                     "--ramdisk", initrd,
-                    "--parameters", kopts,
+                    "--parameters", f"{kopts} {' '.join(append_kopts)}" if append_kopts else kopts,
                     "--targetbase", device,
                     "--targettype", "SCSI",
                     "--targetblocksize", str(blocksize),
diff --git a/tools/osbuild-depsolve-dnf b/tools/osbuild-depsolve-dnf
index a54473b8..1938fe1e 100755
--- a/tools/osbuild-depsolve-dnf
+++ b/tools/osbuild-depsolve-dnf
@@ -121,6 +121,11 @@ class Solver():
         # we set the expiration to a short time period, rather than 0.
         repo.metadata_expire = desc.get("metadata_expire", "20s")
 
+        # This option if True disables modularization filtering. Effectively
+        # disabling modularity for given repository.
+        if "module_hotfixes" in desc:
+            repo.module_hotfixes = desc["module_hotfixes"]
+
         return repo
 
     @staticmethod


Test patch:
diff --git a/stages/test/test_zipl_inst.py b/stages/test/test_zipl_inst.py
new file mode 100644
index 00000000..8e867fbb
--- /dev/null
+++ b/stages/test/test_zipl_inst.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python3
+
+import os
+import textwrap
+from unittest.mock import patch
+
+from osbuild.testutil import make_fake_tree
+
+STAGE_NAME = "org.osbuild.zipl.inst"
+
+
+@patch("subprocess.run")
+def test_zipl_inst_default(mocked_run, tmp_path, stage_module):
+    make_fake_tree(tmp_path, {
+        "/boot/loader/entries/ostree-1-fedora-coreos.conf": textwrap.dedent("""\
+        title Fedora CoreOS 39.20240206.dev.0 (ostree:0)
+        version 1
+        options ignition.platform.id=qemu ostree=/ostree/boot.1/fedora-coreos/abcd/0
+        linux /vmlinuz-6.6.14-200.fc39.s390x
+        initrd /initramfs-6.6.14-200.fc39.s390x.img
+        """),
+        "/vmlinuz-6.6.14-200.fc39.s390x": "fake-vmlinuz",
+        "/initramfs-6.6.14-200.fc39.s390x.img": "fake-initramfs.img",
+    })
+    fake_paths = {
+        "mounts": os.fspath(tmp_path),
+        "devices": "/run/osbuild/dev",
+    }
+    fake_devices = {
+        "disk": {
+            "path": "some-device-path",
+        }
+    }
+    fake_options = {
+        "kernel": "1",
+        "location": "some-location",
+    }
+
+    stage_module.main(fake_paths, fake_devices, fake_options)
+    assert len(mocked_run.call_args_list) == 1
+    args, kwargs = mocked_run.call_args_list[0]
+    assert len(args) == 1
+    run_argv = args[0]
+    assert "ignition.platform.id=qemu ostree=/ostree/boot.1/fedora-coreos/abcd/0" in run_argv
+    assert kwargs["check"]
+
+
+@patch("subprocess.run")
+def test_zipl_inst_kernel_opts_append(mocked_run, tmp_path, stage_module):
+    make_fake_tree(tmp_path, {
+        "/boot/loader/entries/00_linux.conf": textwrap.dedent("""\
+        title fake-linux
+        linux /vmlinuz
+        initrd /initrd.img
+        options root=/dev/sda1 ro
+        version 6.8
+        """),
+        "/vmlinuz": "fake-vmlinuz",
+        "/initrd.img": "fake-initrd.img",
+    })
+    fake_paths = {
+        "mounts": os.fspath(tmp_path),
+        "devices": "/run/osbuild/dev",
+    }
+    fake_devices = {
+        "disk": {
+            "path": "some-device-path",
+        }
+    }
+    fake_options = {
+        "kernel": "6.8",
+        "location": "some-location",
+        "kernel_opts_append": ["some=more", "opts"],
+    }
+
+    stage_module.main(fake_paths, fake_devices, fake_options)
+    assert len(mocked_run.call_args_list) == 1
+    args, kwargs = mocked_run.call_args_list[0]
+    assert len(args) == 1
+    run_argv = args[0]
+    assert "root=/dev/sda1 ro some=more opts" in run_argv
+    assert kwargs["check"]