diff --git a/plugin/builder/image_builder.py b/plugin/builder/image_builder.py index bc59c40..f88aef1 100644 --- a/plugin/builder/image_builder.py +++ b/plugin/builder/image_builder.py @@ -443,6 +443,35 @@ def handler( if ostree_parent: cmd.extend(["--ostree-parent", ostree_parent]) + # If bootc information is available pass it on to the command + bootc = self.opts.get("bootc") + if bootc: + # Various containers can be used during the build. `ref` is the contents of + # the main artifact. `build-ref` is a custom buildroot. `installer-payload-ref` + # is applicable to (some) installer image types that contain an embedded + # container. + for ref in ["ref", "build-ref", "installer-payload-ref"]: + bootc_ref = bootc.get(ref) + if bootc_ref: + cmd.extend(["--bootc-ref", bootc_ref]) + + # We need to pull the container into local storage, this + # requires the podman executable to be available in our buildroot + exit_code = broot.mock( + ["--cwd", broot.tmpdir(within=True), "--chroot", "--", + "podman", "pull", bootc_ref] + ) + + if exit_code != 0: + raise koji.GenericError(f"`podman` failed to pull container {ref}: {bootc_ref}") + + # image-builder tries to determine the root filesystem to use based + # on container metadata and/or contents, for some containers this isnt' + # available so there's an option to set it explicitly + bootc_default_fs = bootc.get("default-fs") + if bootc_default_fs: + cmd.extend(["--bootc-defaultfs", bootc_default_fs]) + # If a seed is set, set it seed = opts.get("seed", None) if seed is not None: diff --git a/plugin/cli/image_builder.py b/plugin/cli/image_builder.py index c6e0645..20a3a49 100644 --- a/plugin/cli/image_builder.py +++ b/plugin/cli/image_builder.py @@ -59,6 +59,34 @@ def handle_image_builder_build(gopts, session, args): help="URL to the OSTree repo for OSTree commit image types", ) + parser.add_option( + "--bootc-ref", + type=str, + dest="bootc_ref", + help="Ref to the bootable container for bootc image types", + ) + + parser.add_option( + "--bootc-build-ref", + type=str, + dest="bootc_build_ref", + help="Ref to the bootable container build root container for bootc image types", + ) + + parser.add_option( + "--bootc-installer-payload-ref", + type=str, + dest="bootc_installer_payload_ref", + help="Ref to the bootable container installer payload container for bootc image types", + ) + + parser.add_option( + "--bootc-default-fs", + type=str, + dest="bootc_default_fs", + help="Set the default root filesystem to use when not defined in the container", + ) + parser.add_option( "--release", help="Override release of the output, otherwise determined based on 'target' and 'name'", @@ -107,6 +135,20 @@ def handle_image_builder_build(gopts, session, args): if opts.ostree_url: ostree["url"] = opts.ostree_url + bootc = {} + + if opts.bootc_ref: + bootc["ref"] = opts.bootc_ref + + if opts.bootc_build_ref: + bootc["build-ref"] = opts.bootc_build_ref + + if opts.bootc_installer_payload_ref: + bootc["build-ref"] = opts.bootc_installer_payload_ref + + if opts.bootc_default_fs: + bootc["default-fs"] = opts.bootc_default_fs + task_opts = { "scratch": opts.scratch, } @@ -114,6 +156,9 @@ def handle_image_builder_build(gopts, session, args): if ostree: task_opts["ostree"] = ostree + if bootc: + task_opts["bootc"] = bootc + if opts.repo: task_opts["repos"] = opts.repo diff --git a/plugin/hub/image_builder.py b/plugin/hub/image_builder.py index 544321e..2efe2ce 100644 --- a/plugin/hub/image_builder.py +++ b/plugin/hub/image_builder.py @@ -47,6 +47,17 @@ "url": {"type": "string"}, }, }, + "bootc": { + "title": "bootc specific options", + "type": "object", + "additionalProperties": False, + "properties": { + "ref": {"type": "string"}, + "build-ref": {"type": "string"}, + "installer-payload-ref": {"type": "string"}, + "default-fs": {"type": "string"}, + }, + }, "options": { "title": "Optional arguments", "type": "object", @@ -75,6 +86,11 @@ "$ref": "#/definitions/ostree", "descriptions": "Additional ostree options", }, + "bootc": { + "type": "object", + "$ref": "#/definitions/bootc", + "descriptions": "Additional bootc options", + }, "blueprint": { "type": "object", "description": "Blueprint", diff --git a/test/unit/test_builder.py b/test/unit/test_builder.py index 4accda4..f0c2ea7 100644 --- a/test/unit/test_builder.py +++ b/test/unit/test_builder.py @@ -306,4 +306,78 @@ def test_build_arch_task_seed(koji_mock_kojid): ], ] +def test_build_arch_task_bootc(koji_mock_kojid): + import plugin.builder.image_builder as builder + + t = builder.ImageBuilderBuildArchTask() + + t.id = None + t.session = None + t.options = MockOptions(topurl="/") + t.workdir = None + t.handler( + "Fedora-bootc", + "42", + "1", + "x86_64", + ["qcow2"], + {"build_tag": "f42-build", "build_tag_name": "f42-build"}, + {"extra": {"mock.new_chroot": 0}}, + {"id": 1}, + { + "bootc": { + "ref": "quay.io/centos-bootc/centos-bootc:stream9", + "build-ref": "quay.io/centos-bootc/centos-bootc:stream10", + "default-fs": "ext4", + } + }, + ) + + assert koji_mock_kojid.buildroot.mock_calls == [ + [ + "--cwd", + str(koji_mock_kojid.buildroot._tmpdir), + "--chroot", + "--", + "podman", + "pull", + "quay.io/centos-bootc/centos-bootc:stream9", + ], + [ + "--cwd", + str(koji_mock_kojid.buildroot._tmpdir), + "--chroot", + "--", + "podman", + "pull", + "quay.io/centos-bootc/centos-bootc:stream10", + ], + [ + "--cwd", + str(koji_mock_kojid.buildroot._tmpdir), + "--chroot", + "--", + "sh", + str(koji_mock_kojid.buildroot._tmpdir) + "/mock-wrap", + "image-builder", + "-v", + "build", + "--use-librepo=false", + "--force-repo", + "//repos/f42-build/1/$arch", + "--with-sbom", + "--with-manifest", + "--bootc-ref", + "quay.io/centos-bootc/centos-bootc:stream9", + "--bootc-build-ref", + "quay.io/centos-bootc/centos-bootc:stream10", + "--bootc-defaultfs", + "ext4", + "--output-dir", + "/builddir/output", + "--output-name", + "Fedora-bootc-42-1.x86_64", + "qcow2", + ], + ]