diff --git a/cmd/image-builder/main.go b/cmd/image-builder/main.go index 4a12c1cd..31391ebc 100644 --- a/cmd/image-builder/main.go +++ b/cmd/image-builder/main.go @@ -215,6 +215,10 @@ func cmdManifestWrapper(pbar progress.ProgressBar, cmd *cobra.Command, args []st if err != nil { return nil, err } + bootcInstallerPayloadRef, err := cmd.Flags().GetString("bootc-installer-payload-ref") + if err != nil { + return nil, err + } // XXX: remove once https://github.com/osbuild/images/pull/1797 // and https://github.com/osbuild/bootc-image-builder/pull/1014 // are merged @@ -284,16 +288,17 @@ func cmdManifestWrapper(pbar progress.ProgressBar, cmd *cobra.Command, args []st } opts := &manifestOptions{ - OutputDir: outputDir, - OutputFilename: outputFilename, - BlueprintPath: blueprintPath, - Ostree: ostreeImgOpts, - BootcRef: bootcRef, - RpmDownloader: rpmDownloader, - WithSBOM: withSBOM, - IgnoreWarnings: ignoreWarnings, - CustomSeed: customSeed, - Subscription: subscription, + OutputDir: outputDir, + OutputFilename: outputFilename, + BlueprintPath: blueprintPath, + Ostree: ostreeImgOpts, + BootcRef: bootcRef, + BootcInstallerPayloadRef: bootcInstallerPayloadRef, + RpmDownloader: rpmDownloader, + WithSBOM: withSBOM, + IgnoreWarnings: ignoreWarnings, + CustomSeed: customSeed, + Subscription: subscription, ForceRepos: forceRepos, } @@ -532,6 +537,7 @@ operating systems like Fedora, CentOS and RHEL with easy customizations support. manifestCmd.Flags().String("ostree-url", "", `OSTREE url`) manifestCmd.Flags().String("bootc-ref", "", `bootc container ref`) manifestCmd.Flags().String("bootc-build-ref", "", `bootc build container ref`) + manifestCmd.Flags().String("bootc-installer-payload-ref", "", `bootc installer payload ref`) manifestCmd.Flags().Bool("use-librepo", true, `use librepo to download packages (disable if you use old versions of osbuild)`) manifestCmd.Flags().Bool("with-sbom", false, `export SPDX SBOM document`) manifestCmd.Flags().Bool("ignore-warnings", false, `ignore warnings during manifest generation`) diff --git a/cmd/image-builder/manifest.go b/cmd/image-builder/manifest.go index cdd5f04d..b70b9bbc 100644 --- a/cmd/image-builder/manifest.go +++ b/cmd/image-builder/manifest.go @@ -20,16 +20,17 @@ import ( ) type manifestOptions struct { - OutputDir string - OutputFilename string - BlueprintPath string - Ostree *ostree.ImageOptions - BootcRef string - Subscription *subscription.ImageOptions - RpmDownloader osbuild.RpmDownloader - WithSBOM bool - IgnoreWarnings bool - CustomSeed *int64 + OutputDir string + OutputFilename string + BlueprintPath string + Ostree *ostree.ImageOptions + BootcRef string + BootcInstallerPayloadRef string + Subscription *subscription.ImageOptions + RpmDownloader osbuild.RpmDownloader + WithSBOM bool + IgnoreWarnings bool + CustomSeed *int64 ForceRepos []string UseBootstrapContainer bool @@ -102,6 +103,9 @@ func generateManifest(dataDir string, extraRepos []string, img *imagefilter.Resu Facts: &facts.ImageOptions{APIType: facts.IBCLI_APITYPE}, OSTree: opts.Ostree, Subscription: opts.Subscription, + Bootc: &distro.BootcImageOptions{ + InstallerPayloadRef: opts.BootcInstallerPayloadRef, + }, } mf, err := mg.Generate(bp, img.ImgType, imgOpts) diff --git a/go.mod b/go.mod index 144cfcaa..9921b21e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gobwas/glob v0.2.3 github.com/mattn/go-isatty v0.0.20 github.com/osbuild/blueprint v1.16.0 - github.com/osbuild/images v0.206.0 + github.com/osbuild/images v0.210.0 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.11.1 golang.org/x/sys v0.35.0 diff --git a/go.sum b/go.sum index cd534f90..9f2ea11d 100644 --- a/go.sum +++ b/go.sum @@ -245,8 +245,8 @@ github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplU github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U= github.com/osbuild/blueprint v1.16.0 h1:f/kHih+xpeJ1v7wtIfzdHPZTsiXsqKeDQ1+rrue6298= github.com/osbuild/blueprint v1.16.0/go.mod h1:HPlJzkEl7q5g8hzaGksUk7ifFAy9QFw9LmzhuFOAVm4= -github.com/osbuild/images v0.206.0 h1:F9G6dnqrURRUcWE2eWIPQLzHutSCT0OyWMcITK28uCQ= -github.com/osbuild/images v0.206.0/go.mod h1:iF6bTLzBtyp9l27fexsD5AzwHEn9+bXF5Jr4HHQecmI= +github.com/osbuild/images v0.210.0 h1:I1OFYl/9mtOMQccRv3YBxWr14uJDG+CwTgmy4kYISpU= +github.com/osbuild/images v0.210.0/go.mod h1:tZqcrs3eNUA0VPs1h3YCnbnpAskVVfo36CIi2USSfDs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/image-builder.spec b/image-builder.spec index 38b476b1..059e5fed 100644 --- a/image-builder.spec +++ b/image-builder.spec @@ -3,7 +3,7 @@ # required. So if this needs backport to places where there is no # recent osbuild available we could simply make --use-librepo false # and go back to 129. -%global min_osbuild_version 160 +%global min_osbuild_version 163 %global goipath github.com/osbuild/image-builder-cli diff --git a/test/test_manifest.py b/test/test_manifest.py index 6326bd53..cd2a3af5 100644 --- a/test/test_manifest.py +++ b/test/test_manifest.py @@ -1,12 +1,16 @@ import json import os import platform +import re import subprocess import pytest # put common podman run args in once place -podman_run = ["podman", "run", "--rm", "--privileged"] +podman_run = [ + "podman", "run", "--rm", "--privileged", + "-v", "/var/lib/containers/storage:/var/lib/containers/storage", +] @pytest.mark.skipif(os.getuid() != 0, reason="needs root") @@ -69,6 +73,7 @@ def test_manifest_bootc_build_container(build_container): bootc_ref = "quay.io/centos-bootc/centos-bootc:stream9" bootc_build_container_ref = "quay.io/centos-bootc/centos-bootc:stream10" subprocess.check_call(["podman", "pull", bootc_ref]) + subprocess.check_call(["podman", "pull", bootc_build_container_ref]) output = subprocess.check_output(podman_run + [ build_container, @@ -94,3 +99,51 @@ def test_manifest_bootc_build_container(build_container): cnt_deploy = [st for st in img_pipeline["stages"] if st["type"] == "org.osbuild.bootc.install-to-filesystem"][0] assert cnt_deploy["options"]["target-imgref"] == "quay.io/centos-bootc/centos-bootc:stream9" + + +def test_container_manifest_bootc_iso_smoke(build_container): + # Note that this is not a realistic ref, a generic bootc + # image does not contain anaconda so this won't produce a + # working installer. For the purpose of the test to validate + # that we get a manifest with the right refs its good enough. + bootc_ref = "quay.io/centos-bootc/centos-bootc:stream9" + bootc_payload_ref = "quay.io/centos-bootc/centos-bootc:stream10" + subprocess.check_call(["podman", "pull", bootc_ref]) + subprocess.check_call(["podman", "pull", bootc_payload_ref]) + output = subprocess.check_output(podman_run + [ + build_container, + "manifest", + "bootc-installer", + "--bootc-ref", bootc_ref, + "--bootc-installer-payload-ref", bootc_payload_ref + ], text=True) + manifest = json.loads(output) + assert len(manifest["sources"]["org.osbuild.containers-storage"]["items"]) == 2 + assert bootc_ref in output + assert bootc_payload_ref in output + # build pipeline uses bootc-ref + pipeline = [p for p in manifest["pipelines"] + if p["name"] == "build"][0] + cnt_deploy = [st for st in pipeline["stages"] + if st["type"] == "org.osbuild.container-deploy"][0] + refs = cnt_deploy["inputs"]["images"]["references"] + assert refs.popitem()[1]["name"] == bootc_ref + # anaconda-tree uses bootc-ref too + pipeline = [p for p in manifest["pipelines"] + if p["name"] == "anaconda-tree"][0] + cnt_deploy = [st for st in pipeline["stages"] + if st["type"] == "org.osbuild.container-deploy"][0] + refs = cnt_deploy["inputs"]["images"]["references"] + assert refs.popitem()[1]["name"] == bootc_ref + # the payload container is centos10 + pipeline = [p for p in manifest["pipelines"] + if p["name"] == "bootiso-tree"][0] + skopeo_stage = [st for st in pipeline["stages"] + if st["type"] == "org.osbuild.skopeo"][0] + refs = skopeo_stage["inputs"]["images"]["references"] + assert refs.popitem()[1]["name"] == bootc_payload_ref + kickstart_stage = [st for st in pipeline["stages"] + if st["type"] == "org.osbuild.kickstart"][0] + assert re.match( + f'bootc switch .* registry {bootc_payload_ref}', + kickstart_stage["options"]["%post"][0]["commands"][0])