Skip to content

Commit a8f92c6

Browse files
committed
bib: add support for --type bootc-installer
This commit adds support for the new `bootc-installer` image type that will take a bootc container and create an ISO out of it. It also adds a new `--installer-payload-ref` option so that the user can specify a different payload container to install. See osbuild/images#1906 for details. This is the equivalent of osbuild/image-builder-cli#341 for bootc-image-builder and allows us to build these kinds of images with bib now too.
1 parent 58099b5 commit a8f92c6

File tree

5 files changed

+62
-21
lines changed

5 files changed

+62
-21
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Flags:
133133
--progress string type of progress bar to use (e.g. verbose,term) (default "auto")
134134
--rootfs string Root filesystem type. If not given, the default configured in the source container image is used.
135135
--target-arch string build for the given target architecture (experimental)
136-
--type stringArray image types to build [ami, anaconda-iso, gce, iso, qcow2, raw, vhd, vmdk] (default [qcow2])
136+
--type stringArray image types to build [ami, anaconda-iso, bootc-installer, gce, iso, qcow2, raw, vhd, vmdk] (default [qcow2])
137137
--version version for bootc-image-builder
138138

139139
Global Flags:
@@ -172,7 +172,8 @@ The following image types are currently available via the `--type` argument:
172172
| `ami` | [Amazon Machine Image](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) |
173173
| `qcow2` **(default)** | [QEMU](https://www.qemu.org/) |
174174
| `vmdk` | [VMDK](https://en.wikipedia.org/wiki/VMDK) usable in vSphere, among others |
175-
| `anaconda-iso` | An unattended Anaconda installer that installs to the first disk found. |
175+
| `bootc-installer` | An installer ISO image based on the specified bootc container image. |
176+
| `anaconda-iso` | (legacy) an unattended Anaconda installer that installs to the first disk found build from RPMs. |
176177
| `raw` | Unformatted [raw disk](https://en.wikipedia.org/wiki/Rawdisk). |
177178
| `vhd` | [vhd](https://en.wikipedia.org/wiki/VHD_(file_format)) usable in Virtual PC, among others |
178179
| `gce` | [GCE](https://cloud.google.com/compute/docs/images#custom_images) |

bib/cmd/bootc-image-builder/main.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/osbuild/images/pkg/bib/blueprintload"
2626
"github.com/osbuild/images/pkg/cloud"
2727
"github.com/osbuild/images/pkg/cloud/awscloud"
28+
"github.com/osbuild/images/pkg/distro"
2829
"github.com/osbuild/images/pkg/distro/bootc"
2930
"github.com/osbuild/images/pkg/experimentalflags"
3031
"github.com/osbuild/images/pkg/manifest"
@@ -93,6 +94,7 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
9394
targetArch, _ := cmd.Flags().GetString("target-arch")
9495
rootFs, _ := cmd.Flags().GetString("rootfs")
9596
buildImgref, _ := cmd.Flags().GetString("build-container")
97+
installerPayloadRef, _ := cmd.Flags().GetString("installer-payload-ref")
9698
useLibrepo, _ := cmd.Flags().GetBool("use-librepo")
9799

98100
// If --local was given, warn in the case of --local or --local=true (true is the default), error in the case of --local=false
@@ -153,21 +155,21 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
153155
if imageTypes.Legacy() {
154156
return manifestFromCobraForLegacyISO(imgref, buildImgref, imgType, rootFs, rpmCacheRoot, config, useLibrepo, cntArch)
155157
}
156-
return manifestFromCobraForDisk(imgref, buildImgref, imgType, rootFs, rpmCacheRoot, config, useLibrepo, cntArch)
158+
return manifestFromCobraForDisk(imgref, buildImgref, installerPayloadRef, imgType, rootFs, rpmCacheRoot, config, useLibrepo, cntArch)
157159
}
158160

159-
func manifestFromCobraForDisk(imgref, buildImgref, imgTypeStr, rootFs, rpmCacheRoot string, config *blueprint.Blueprint, useLibrepo bool, cntArch arch.Arch) ([]byte, *mTLSConfig, error) {
160-
distro, err := bootc.NewBootcDistro(imgref)
161+
func manifestFromCobraForDisk(imgref, buildImgref, installerPayloadRef, imgTypeStr, rootFs, rpmCacheRoot string, config *blueprint.Blueprint, useLibrepo bool, cntArch arch.Arch) ([]byte, *mTLSConfig, error) {
162+
distri, err := bootc.NewBootcDistro(imgref)
161163
if err != nil {
162164
return nil, nil, err
163165
}
164-
if err := distro.SetBuildContainer(buildImgref); err != nil {
166+
if err := distri.SetBuildContainer(buildImgref); err != nil {
165167
return nil, nil, err
166168
}
167-
if err := distro.SetDefaultFs(rootFs); err != nil {
169+
if err := distri.SetDefaultFs(rootFs); err != nil {
168170
return nil, nil, err
169171
}
170-
archi, err := distro.GetArch(cntArch.String())
172+
archi, err := distri.GetArch(cntArch.String())
171173
if err != nil {
172174
return nil, nil, err
173175
}
@@ -193,7 +195,12 @@ func manifestFromCobraForDisk(imgref, buildImgref, imgTypeStr, rootFs, rpmCacheR
193195
if err != nil {
194196
return nil, nil, err
195197
}
196-
manifest, err := mg.Generate(config, imgType, nil)
198+
imgOpts := &distro.ImageOptions{
199+
Bootc: &distro.BootcImageOptions{
200+
InstallerPayloadRef: installerPayloadRef,
201+
},
202+
}
203+
manifest, err := mg.Generate(config, imgType, imgOpts)
197204
if err != nil {
198205
return nil, nil, err
199206
}
@@ -504,6 +511,9 @@ func buildCobraCmdline() (*cobra.Command, error) {
504511
manifestCmd.Flags().String("rpmmd", "/rpmmd", "rpm metadata cache directory")
505512
manifestCmd.Flags().String("target-arch", "", "build for the given target architecture (experimental)")
506513
manifestCmd.Flags().String("build-container", "", "Use a custom container for the image build")
514+
// XXX: add --bootc-installer-payload-ref as alias to make it
515+
// cmdline compatible with ibcli(?)
516+
manifestCmd.Flags().String("installer-payload-ref", "", "bootc installer payload ref")
507517
manifestCmd.Flags().StringArray("type", []string{"qcow2"}, fmt.Sprintf("image types to build [%s]", imagetypes.Available()))
508518
manifestCmd.Flags().Bool("local", true, "DEPRECATED: --local is now the default behavior, make sure to pull the container image before running bootc-image-builder")
509519
if err := manifestCmd.Flags().MarkHidden("local"); err != nil {

bib/internal/imagetypes/imagetypes.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ var supportedImageTypes = map[string]imageType{
1717
// XXX: ideally we would look how to consolidate all
1818
// knownledge about disk based image types into the images
1919
// library
20-
"ami": imageType{Export: "image"},
21-
"qcow2": imageType{Export: "qcow2"},
22-
"raw": imageType{Export: "image"},
23-
"vmdk": imageType{Export: "vmdk"},
24-
"vhd": imageType{Export: "vpc"},
25-
"gce": imageType{Export: "gce"},
26-
"ova": imageType{Export: "archive"},
20+
"ami": imageType{Export: "image"},
21+
"qcow2": imageType{Export: "qcow2"},
22+
"raw": imageType{Export: "image"},
23+
"vmdk": imageType{Export: "vmdk"},
24+
"vhd": imageType{Export: "vpc"},
25+
"gce": imageType{Export: "gce"},
26+
"ova": imageType{Export: "archive"},
27+
"bootc-installer": imageType{Export: "bootiso", ISO: true},
2728
// the iso image types are RPM based and legacy/deprecated
2829
"anaconda-iso": imageType{Export: "bootiso", ISO: true, Legacy: true},
2930
"iso": imageType{Export: "bootiso", ISO: true, Legacy: true},

bib/internal/imagetypes/imagetypes_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,25 @@ func TestImageTypes(t *testing.T) {
5757
imageTypes: []string{"vmdk", "anaconda-iso"},
5858
expectedErr: errors.New("cannot mix ISO/disk images in request [vmdk anaconda-iso]"),
5959
},
60-
"bad-mix-part-2": {
60+
"bad-mix-2": {
61+
imageTypes: []string{"vmdk", "bootc-installer"},
62+
expectedErr: errors.New("cannot mix ISO/disk images in request [vmdk bootc-installer]"),
63+
},
64+
"bad-mix-3": {
6165
imageTypes: []string{"ami", "iso"},
6266
expectedErr: errors.New("cannot mix ISO/disk images in request [ami iso]"),
6367
},
6468
"bad-image-type": {
6569
imageTypes: []string{"bad"},
66-
expectedErr: errors.New(`unsupported image type "bad", valid types are ami, anaconda-iso, gce, iso, ova, qcow2, raw, vhd, vmdk`),
70+
expectedErr: errors.New(`unsupported image type "bad", valid types are ami, anaconda-iso, bootc-installer, gce, iso, ova, qcow2, raw, vhd, vmdk`),
6771
},
6872
"bad-in-good": {
6973
imageTypes: []string{"ami", "raw", "vmdk", "qcow2", "something-else-what-is-this"},
70-
expectedErr: errors.New(`unsupported image type "something-else-what-is-this", valid types are ami, anaconda-iso, gce, iso, ova, qcow2, raw, vhd, vmdk`),
74+
expectedErr: errors.New(`unsupported image type "something-else-what-is-this", valid types are ami, anaconda-iso, bootc-installer, gce, iso, ova, qcow2, raw, vhd, vmdk`),
7175
},
7276
"all-bad": {
7377
imageTypes: []string{"bad1", "bad2", "bad3", "bad4", "bad5", "bad42"},
74-
expectedErr: errors.New(`unsupported image type "bad1", valid types are ami, anaconda-iso, gce, iso, ova, qcow2, raw, vhd, vmdk`),
78+
expectedErr: errors.New(`unsupported image type "bad1", valid types are ami, anaconda-iso, bootc-installer, gce, iso, ova, qcow2, raw, vhd, vmdk`),
7579
},
7680
}
7781

test/test_manifest.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_manifest_smoke(build_container, tc):
5353

5454

5555
@pytest.mark.parametrize("tc", gen_testcases("anaconda-iso"))
56-
def test_iso_manifest_smoke(build_container, tc):
56+
def test_rpm_iso_manifest_smoke(build_container, tc):
5757
testutil.pull_container(tc.container_ref, tc.target_arch)
5858

5959
output = subprocess.check_output([
@@ -71,6 +71,31 @@ def test_iso_manifest_smoke(build_container, tc):
7171
assert [pipeline["name"] for pipeline in manifest["pipelines"]] == expected_pipeline_names
7272

7373

74+
def test_bootc_iso_manifest_smoke(build_container):
75+
container_ref = "quay.io/centos-bootc/centos-bootc:stream9"
76+
# Note that this is not a realistic ref, a generic bootc
77+
# image does not contain anaconda so this won't produce a
78+
# working installer. For the purpose of the test to validate
79+
# that we get a manifest with the right refs its good enough.
80+
installer_payload_ref = "quay.io/centos-bootc/centos-bootc:stream10"
81+
testutil.pull_container(container_ref)
82+
testutil.pull_container(installer_payload_ref)
83+
84+
output = subprocess.check_output([
85+
*testutil.podman_run_common,
86+
build_container,
87+
"manifest",
88+
"--type=bootc-installer",
89+
f"{container_ref}",
90+
f"--installer-payload-ref={installer_payload_ref}",
91+
])
92+
manifest = json.loads(output)
93+
# just some basic validation
94+
expected_pipeline_names = ["build", "anaconda-tree", "efiboot-tree", "bootiso-tree", "bootiso"]
95+
assert manifest["version"] == "2"
96+
assert [pipeline["name"] for pipeline in manifest["pipelines"]] == expected_pipeline_names
97+
98+
7499
@pytest.mark.parametrize("tc", gen_testcases("manifest"))
75100
def test_manifest_disksize(tmp_path, build_container, tc):
76101
testutil.pull_container(tc.container_ref, tc.target_arch)

0 commit comments

Comments
 (0)