Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions bib/cmd/bootc-image-builder/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,3 @@ func MockOsGetuid(new func() int) (restore func()) {
osGetuid = saved
}
}

func MockOsReadFile(new func(string) ([]byte, error)) (restore func()) {
saved := osReadFile
osReadFile = new
return func() {
osReadFile = saved
}
}
112 changes: 66 additions & 46 deletions bib/cmd/bootc-image-builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,56 @@ func getContainerSize(imgref string) (uint64, error) {
return size, nil
}

func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (manifest.OSBuildManifest, map[string][]rpmmd.RepoConfig, error) {
func reposHaveOnlyHostMappedSecrets(repos []rpmmd.RepoConfig) error {
for _, repo := range repos {
if repo.SSLCACert != "" && !strings.Contains(repo.SSLCACert, "etc/rhsm-host/") {
return fmt.Errorf("unsupported cacert %q: not mapped from host", repo.SSLCACert)
}
if repo.SSLClientKey != "" && !strings.Contains(repo.SSLClientKey, "etc/pki/entitlement-host/") {
return fmt.Errorf("unsupported client key %q: not mapped from host", repo.SSLClientKey)
}
if repo.SSLClientCert != "" && !strings.Contains(repo.SSLClientCert, "etc/pki/entitlement-host/") {
return fmt.Errorf("unsupported client cert %q: not mapped from host", repo.SSLClientCert)
}
}
return nil
}

func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (manifest.OSBuildManifest, error) {
mani, err := Manifest(c)
if err != nil {
return nil, nil, fmt.Errorf("cannot get manifest: %w", err)
return nil, fmt.Errorf("cannot get manifest: %w", err)
}

// depsolve packages
// depsolve packages (only needed for ISO image types)
depsolvedSets := make(map[string]dnfjson.DepsolveResult)
depsolvedRepos := make(map[string][]rpmmd.RepoConfig)
for name, pkgSet := range mani.GetPackageSetChains() {
res, err := solver.Depsolve(pkgSet, 0)
if err != nil {
return nil, nil, fmt.Errorf("cannot depsolve: %w", err)
return nil, fmt.Errorf("cannot depsolve: %w", err)
}

// We depsolve the container with an alterantive
// rootdir - this means the depsolver will assume any
// required secrets in the found rootdir repos must be
// provided via mtls. However in almost all cases in
// our containers this is unnecessary (and a headache)
// because podman maps our host entitlements into the
// container so we can build it with org.osbuild.rhsm
//
// So we double check here that we only have content
// mapped from the host via podman. Then we just
// switch from org.osbuild.mtls to org.osbuild.rhsm
if err := reposHaveOnlyHostMappedSecrets(res.Repos); err != nil {
return nil, err
}
// we can switch from mtls->rhsm as we valided above that
// only host mounted entitlements are used
for idx := range res.Packages {
res.Packages[idx].Secrets = strings.ReplaceAll(res.Packages[idx].Secrets, "org.osbuild.mtls", "org.osbuild.rhsm")
}

depsolvedSets[name] = *res
depsolvedRepos[name] = res.Repos
}
Expand All @@ -146,11 +182,11 @@ func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (
}
specs, err := resolver.Finish()
if err != nil {
return nil, nil, fmt.Errorf("cannot resolve containers: %w", err)
return nil, fmt.Errorf("cannot resolve containers: %w", err)
}
for _, spec := range specs {
if spec.Arch != c.Architecture {
return nil, nil, fmt.Errorf("image found is for unexpected architecture %q (expected %q), if that is intentional, please make sure --target-arch matches", spec.Arch, c.Architecture)
return nil, fmt.Errorf("image found is for unexpected architecture %q (expected %q), if that is intentional, please make sure --target-arch matches", spec.Arch, c.Architecture)
}
}
containerSpecs[plName] = specs
Expand All @@ -162,9 +198,9 @@ func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (
}
mf, err := mani.Serialize(depsolvedSets, containerSpecs, nil, &opts)
if err != nil {
return nil, nil, fmt.Errorf("[ERROR] manifest serialization failed: %s", err.Error())
return nil, fmt.Errorf("[ERROR] manifest serialization failed: %s", err.Error())
}
return mf, depsolvedRepos, nil
return mf, nil
}

func saveManifest(ms manifest.OSBuildManifest, fpath string) (err error) {
Expand Down Expand Up @@ -194,7 +230,7 @@ func saveManifest(ms manifest.OSBuildManifest, fpath string) (err error) {
//
// TODO: provide a podman progress reader to integrate the podman progress
// into our progress.
func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.ProgressBar) ([]byte, *mTLSConfig, error) {
func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.ProgressBar) ([]byte, error) {
cntArch := arch.Current()

imgref := args[0]
Expand All @@ -212,15 +248,15 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
if localStorage {
fmt.Fprintf(os.Stderr, "WARNING: --local is now the default behavior, you can remove it from the command line\n")
} else {
return nil, nil, fmt.Errorf(`--local=false is no longer supported, remove it and make sure to pull the container before running bib:
return nil, fmt.Errorf(`--local=false is no longer supported, remove it and make sure to pull the container before running bib:
sudo podman pull %s`, imgref)
}
}

if targetArch != "" {
target, err := arch.FromString(targetArch)
if err != nil {
return nil, nil, err
return nil, err
}
if target != arch.Current() {
// TODO: detect if binfmt_misc for target arch is
Expand All @@ -230,41 +266,41 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
// binaries inside our bib container
fmt.Fprintf(os.Stderr, "WARNING: target-arch is experimental and needs an installed 'qemu-user' package\n")
if slices.Contains(imgTypes, "iso") {
return nil, nil, fmt.Errorf("cannot build iso for different target arches yet")
return nil, fmt.Errorf("cannot build iso for different target arches yet")
}
cntArch = target
}
}
// TODO: add "target-variant", see https://github.com/osbuild/bootc-image-builder/pull/139/files#r1467591868

if err := setup.ValidateHasContainerStorageMounted(); err != nil {
return nil, nil, fmt.Errorf("could not access container storage, did you forget -v /var/lib/containers/storage:/var/lib/containers/storage? (%w)", err)
return nil, fmt.Errorf("could not access container storage, did you forget -v /var/lib/containers/storage:/var/lib/containers/storage? (%w)", err)
}

imageTypes, err := imagetypes.New(imgTypes...)
if err != nil {
return nil, nil, fmt.Errorf("cannot detect build types %v: %w", imgTypes, err)
return nil, fmt.Errorf("cannot detect build types %v: %w", imgTypes, err)
}

config, err := blueprintload.LoadWithFallback(userConfigFile)
if err != nil {
return nil, nil, fmt.Errorf("cannot read config: %w", err)
return nil, fmt.Errorf("cannot read config: %w", err)
}

pbar.SetPulseMsgf("Manifest generation step")
pbar.Start()

if err := setup.ValidateHasContainerTags(imgref); err != nil {
return nil, nil, err
return nil, err
}

cntSize, err := getContainerSize(imgref)
if err != nil {
return nil, nil, fmt.Errorf("cannot get container size: %w", err)
return nil, fmt.Errorf("cannot get container size: %w", err)
}
container, err := podman_container.New(imgref)
if err != nil {
return nil, nil, err
return nil, err
}
defer func() {
if err := container.Stop(); err != nil {
Expand All @@ -278,17 +314,17 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
} else {
rootfsType, err = container.DefaultRootfsType()
if err != nil {
return nil, nil, fmt.Errorf("cannot get rootfs type for container: %w", err)
return nil, fmt.Errorf("cannot get rootfs type for container: %w", err)
}
if rootfsType == "" {
return nil, nil, fmt.Errorf(`no default root filesystem type specified in container, please use "--rootfs" to set manually`)
return nil, fmt.Errorf(`no default root filesystem type specified in container, please use "--rootfs" to set manually`)
}
}

// Gather some data from the containers distro
sourceinfo, err := osinfo.Load(container.Root())
if err != nil {
return nil, nil, err
return nil, err
}

buildContainer := container
Expand All @@ -305,14 +341,14 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
if buildImgref != "" {
buildContainer, err = podman_container.New(buildImgref)
if err != nil {
return nil, nil, err
return nil, err
}
startedBuildContainer = true

// Gather some data from the containers distro
buildSourceinfo, err = osinfo.Load(buildContainer.Root())
if err != nil {
return nil, nil, err
return nil, err
}
} else {
buildImgref = imgref
Expand All @@ -321,11 +357,11 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
// This is needed just for RHEL and RHSM in most cases, but let's run it every time in case
// the image has some non-standard dnf plugins.
if err := buildContainer.InitDNF(); err != nil {
return nil, nil, err
return nil, err
}
solver, err := buildContainer.NewContainerSolver(rpmCacheRoot, cntArch, sourceinfo)
if err != nil {
return nil, nil, err
return nil, err
}

manifestConfig := &ManifestConfig{
Expand All @@ -342,17 +378,12 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress
UseLibrepo: useLibrepo,
}

manifest, repos, err := makeManifest(manifestConfig, solver, rpmCacheRoot)
if err != nil {
return nil, nil, err
}

mTLS, err := extractTLSKeys(repos)
manifest, err := makeManifest(manifestConfig, solver, rpmCacheRoot)
if err != nil {
return nil, nil, err
return nil, err
}

return manifest, mTLS, nil
return manifest, nil
}

func cmdManifest(cmd *cobra.Command, args []string) error {
Expand All @@ -363,7 +394,7 @@ func cmdManifest(cmd *cobra.Command, args []string) error {
}
defer pbar.Stop()

mf, _, err := manifestFromCobra(cmd, args, pbar)
mf, err := manifestFromCobra(cmd, args, pbar)
if err != nil {
return fmt.Errorf("cannot generate manifest: %w", err)
}
Expand Down Expand Up @@ -458,7 +489,7 @@ func cmdBuild(cmd *cobra.Command, args []string) error {

manifest_fname := fmt.Sprintf("manifest-%s.json", strings.Join(imgTypes, "-"))
pbar.SetMessagef("Generating manifest %s", manifest_fname)
mf, mTLS, err := manifestFromCobra(cmd, args, pbar)
mf, err := manifestFromCobra(cmd, args, pbar)
if err != nil {
return fmt.Errorf("cannot build manifest: %w", err)
}
Expand All @@ -484,17 +515,6 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
osbuildEnv = []string{"OSBUILD_EXPORT_FORCE_NO_PRESERVE_OWNER=1"}
}

if mTLS != nil {
envVars, cleanup, err := prepareOsbuildMTLSConfig(mTLS)
if err != nil {
return fmt.Errorf("failed to prepare osbuild TLS keys: %w", err)
}

defer cleanup()

osbuildEnv = append(osbuildEnv, envVars...)
}

if experimentalflags.Bool("debug-qemu-user") {
osbuildEnv = append(osbuildEnv, "OBSBUILD_EXPERIMENAL=debug-qemu-user")
}
Expand Down
99 changes: 0 additions & 99 deletions bib/cmd/bootc-image-builder/mtls.go

This file was deleted.

Loading
Loading