diff --git a/cmd/gen-manifests/main.go b/cmd/gen-manifests/main.go index cfac52d059..ec14a7258b 100644 --- a/cmd/gen-manifests/main.go +++ b/cmd/gen-manifests/main.go @@ -299,7 +299,8 @@ func makeManifestJob( var depsolvedSets map[string]depsolvednf.DepsolveResult if content["packages"] { - depsolvedSets, err = manifestgen.DefaultDepsolver(cacheDir, os.Stderr, common.Must(manifest.GetPackageSetChains()), distribution, archName) + solver := depsolvednf.NewSolver(distribution.ModulePlatformID(), distribution.Releasever(), archName, distribution.Name(), cacheDir) + depsolvedSets, err = manifestgen.DefaultDepsolve(solver, cacheDir, os.Stderr, common.Must(manifest.GetPackageSetChains()), distribution, archName) if err != nil { err = fmt.Errorf("[%s] depsolve failed: %s", filename, err.Error()) return diff --git a/data/distrodefs/bootc-generic/imagetypes.yaml b/data/distrodefs/bootc-generic/imagetypes.yaml index 189bdc0857..c39516091f 100644 --- a/data/distrodefs/bootc-generic/imagetypes.yaml +++ b/data/distrodefs/bootc-generic/imagetypes.yaml @@ -149,3 +149,19 @@ image_types: exports: ["bootiso"] filename: "install.iso" boot_iso: true + + # this image type is special (in many ways) and all is a bit ugly: + # - we want to get rid of it (here for compat with bib) + # - its "indirect" in the sense that it pulls the RPMs from a + # "real" distro, i.e. if a bootc centos-10 is found it will + # load the imagetypes.yaml for that to load the + # bootc-rpm-installer + anaconda-iso: &anaconda_iso + mime_type: "application/x-iso9660-image" + exports: ["bootiso"] + filename: "install.iso" + boot_iso: true + + # XXX: ideally we would use name_aliases but the loader lib + # does not not fully support this yet + iso: *anaconda_iso diff --git a/pkg/bib/container/solver.go b/pkg/bib/container/solver.go index 540dc03bb2..d51e139fbf 100644 --- a/pkg/bib/container/solver.go +++ b/pkg/bib/container/solver.go @@ -1,6 +1,7 @@ package container import ( + "errors" "fmt" "os" "os/exec" @@ -11,6 +12,8 @@ import ( "github.com/osbuild/images/pkg/depsolvednf" ) +var ErrNoDnf = errors.New("no dnf in container") + func forceSymlink(symlinkPath, target string) error { if output, err := exec.Command("ln", "-sf", target, symlinkPath).CombinedOutput(); err != nil { return fmt.Errorf("cannot run ln: %w, output:\n%s", err, output) @@ -31,6 +34,11 @@ func forceSymlink(symlinkPath, target string) error { // check" without arguments takes around 25s so that is not a great // option). func (c *Container) InitDNF() error { + /* #nosec G204 */ + if err := exec.Command("podman", "exec", c.id, "dnf", "--version").Run(); err != nil { + return ErrNoDnf + } + /* #nosec G204 */ if output, err := exec.Command("podman", "exec", c.id, "dnf", "check", "--duplicates").CombinedOutput(); err != nil { return fmt.Errorf("initializing dnf in %s container failed: %w\noutput:\n%s", c.id, err, string(output)) diff --git a/pkg/bib/container/solver_test.go b/pkg/bib/container/solver_test.go index 44d797273b..f2ff1683a7 100644 --- a/pkg/bib/container/solver_test.go +++ b/pkg/bib/container/solver_test.go @@ -21,6 +21,7 @@ import ( const ( dnfTestingImageRHEL = "registry.access.redhat.com/ubi9:latest" dnfTestingImageCentos = "quay.io/centos/centos:stream9" + dnfTestingImageNoDnf = "alpine:latest" dnfTestingImageFedoraLatest = "registry.fedoraproject.org/fedora:latest" ) @@ -200,3 +201,19 @@ func TestDepsolveDNFWorkWithSubscribedContentNestedContainers(t *testing.T) { // run the test runCmd(t, "podman", "exec", cntID, "/dnftest") } + +func TestDepsolveDNFdetectsMissingDnf(t *testing.T) { + if !hasPodman() { + t.Skip("skipping test: no podman") + } + ensureCanRunDepsolveDNFTests(t) + + cnt, err := container.New(dnfTestingImageNoDnf) + require.NoError(t, err) + defer func() { + assert.NoError(t, cnt.Stop()) + }() + + err = cnt.InitDNF() + require.Equal(t, container.ErrNoDnf, err) +} diff --git a/pkg/distro/bootc/bootc.go b/pkg/distro/bootc/bootc.go index a176ffcf79..fd51fb45be 100644 --- a/pkg/distro/bootc/bootc.go +++ b/pkg/distro/bootc/bootc.go @@ -20,6 +20,7 @@ import ( "github.com/osbuild/images/pkg/customizations/anaconda" "github.com/osbuild/images/pkg/customizations/kickstart" "github.com/osbuild/images/pkg/customizations/users" + "github.com/osbuild/images/pkg/depsolvednf" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro/defs" @@ -32,7 +33,7 @@ import ( "github.com/osbuild/images/pkg/runner" ) -var _ = distro.Distro(&BootcDistro{}) +var _ = distro.CustomDepsolverDistro(&BootcDistro{}) type BootcDistro struct { imgref string @@ -121,6 +122,39 @@ func (d *BootcDistro) OSTreeRef() string { return "" } +func (d *BootcDistro) Depsolver(rpmCacheRoot string, archi arch.Arch) (solver *depsolvednf.Solver, cleanup func() error, err error) { + cnt, err := bibcontainer.New(d.buildImgref) + if err != nil { + return nil, nil, err + } + defer func() { + if err != nil { + err = errors.Join(err, cnt.Stop()) + } + }() + + cleanup = func() error { + return cnt.Stop() + } + if err := cnt.InitDNF(); err != nil { + // Not all bootc container have dnf, so check if it can + // be run here and if not just return nil which will + // ensure the depsolver of the host is used + if errors.Is(err, bibcontainer.ErrNoDnf) { + return nil, cleanup, nil + } + // Return any other errors to the caller, it means + // dnf is installed but not working. + return nil, nil, err + } + solver, err = cnt.NewContainerSolver(rpmCacheRoot, archi, d.buildSourceInfo) + if err != nil { + return nil, nil, err + } + + return solver, cleanup, nil +} + func (d *BootcDistro) ListArches() []string { archs := make([]string, 0, len(d.arches)) for name := range d.arches { @@ -315,13 +349,25 @@ func (t *BootcImageType) Manifest(bp *blueprint.Blueprint, options distro.ImageO } func (t *BootcImageType) manifestWithoutValidation(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { - if t.BootISO { - return t.manifestForISO(bp, options, repos, seedp) + seed, err := cmdutil.SeedArgFor(nil, t.Name(), t.arch.Name(), t.arch.distro.Name()) + if err != nil { + return nil, nil, err + } + //nolint:gosec + rng := rand.New(rand.NewSource(seed)) + + switch { + // XXX: make this a yaml property + case slices.Contains([]string{"iso", "anaconda-iso"}, t.Name()): + return t.manifestForLegacyISO(bp, options, repos, rng) + case t.BootISO: + return t.manifestForISO(bp, options, repos, rng) + default: + return t.manifestForDisk(bp, options, repos, rng) } - return t.manifestForDisk(bp, options, repos, seedp) } -func (t *BootcImageType) manifestForDisk(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { +func (t *BootcImageType) manifestForDisk(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, rng *rand.Rand) (*manifest.Manifest, []string, error) { if t.arch.distro.imgref == "" { return nil, nil, fmt.Errorf("internal error: no base image defined") } @@ -340,12 +386,6 @@ func (t *BootcImageType) manifestForDisk(bp *blueprint.Blueprint, options distro if bp != nil { customizations = bp.Customizations } - seed, err := cmdutil.SeedArgFor(nil, t.Name(), t.arch.Name(), t.arch.distro.Name()) - if err != nil { - return nil, nil, err - } - //nolint:gosec - rng := rand.New(rand.NewSource(seed)) platform := PlatformFor(t.arch.Name(), t.arch.distro.sourceInfo.UEFIVendor) // For the bootc-disk image, the filename is the basename and @@ -412,7 +452,7 @@ func (t *BootcImageType) manifestForDisk(bp *blueprint.Blueprint, options distro return &mf, nil, nil } -func (t *BootcImageType) manifestForISO(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { +func (t *BootcImageType) manifestForISO(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, rng *rand.Rand) (*manifest.Manifest, []string, error) { if t.arch.distro.imgref == "" { return nil, nil, fmt.Errorf("internal error: no base image defined") } @@ -435,12 +475,6 @@ func (t *BootcImageType) manifestForISO(bp *blueprint.Blueprint, options distro. if bp != nil { customizations = bp.Customizations } - seed, err := cmdutil.SeedArgFor(nil, t.Name(), t.arch.Name(), t.arch.distro.Name()) - if err != nil { - return nil, nil, err - } - //nolint:gosec - rng := rand.New(rand.NewSource(seed)) platformi := PlatformFor(t.arch.Name(), t.arch.distro.sourceInfo.UEFIVendor) platformi.ImageFormat = platform.FORMAT_ISO @@ -478,6 +512,7 @@ func (t *BootcImageType) manifestForISO(bp *blueprint.Blueprint, options distro. img.InstallerCustomizations.ISOLabel = LabelForISO(&t.arch.distro.sourceInfo.OSRelease, t.arch.Name()) img.InstallerCustomizations.FIPS = customizations.GetFIPS() + var err error img.Kickstart, err = kickstart.New(customizations) if err != nil { return nil, nil, err @@ -579,6 +614,143 @@ func NewBootcDistro(imgref string, opts *DistroOptions) (*BootcDistro, error) { return newBootcDistroAfterIntrospect(cnt.Arch(), info, imgref, defaultFs, cntSize) } +// newDistroYAMLFrom() returns the distroYAML for the given sourceInfo, +// if no direct match can be found it will it will use the ID_LIKE. +// This should ensure we work on every bootc image that puts a correct +// ID_LIKE= in /etc/os-release +func newDistroYAMLFrom(sourceInfo *osinfo.Info) (*defs.DistroYAML, *distro.ID, error) { + for _, distroID := range append([]string{sourceInfo.OSRelease.ID}, sourceInfo.OSRelease.IDLike...) { + nameVer := fmt.Sprintf("%s-%s", distroID, sourceInfo.OSRelease.VersionID) + id, err := distro.ParseID(nameVer) + if err != nil { + return nil, nil, err + } + distroYAML, err := defs.NewDistroYAML(nameVer) + if err != nil { + return nil, nil, err + } + if distroYAML != nil { + return distroYAML, id, nil + } + } + return nil, nil, fmt.Errorf("cannot load distro definitions for %s-%s or any of %v", sourceInfo.OSRelease.ID, sourceInfo.OSRelease.VersionID, sourceInfo.OSRelease.IDLike) +} + +func (t *BootcImageType) manifestForLegacyISO(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, rng *rand.Rand) (*manifest.Manifest, []string, error) { + archStr := t.arch.Name() + imgref := t.arch.distro.imgref + sourceInfo := t.arch.distro.sourceInfo + + if t.arch.distro.imgref == "" { + return nil, nil, fmt.Errorf("pipeline: no base image defined") + } + distroYAML, id, err := newDistroYAMLFrom(t.arch.distro.sourceInfo) + if err != nil { + return nil, nil, err + } + + // XXX: or "bootc-legacy-installer"? + installerImgTypeName := "bootc-rpm-installer" + imgType, ok := distroYAML.ImageTypes()[installerImgTypeName] + if !ok { + return nil, nil, fmt.Errorf("cannot find image definition for %v", installerImgTypeName) + } + installerPkgSet, ok := imgType.PackageSets(*id, archStr)["installer"] + if !ok { + return nil, nil, fmt.Errorf("cannot find installer package set for %v", installerImgTypeName) + } + installerConfig := imgType.InstallerConfig(*id, archStr) + if installerConfig == nil { + return nil, nil, fmt.Errorf("empty installer config for %s", installerImgTypeName) + } + + containerSource := container.SourceSpec{ + Source: imgref, + Name: imgref, + Local: true, + } + + platformi := PlatformFor(archStr, sourceInfo.UEFIVendor) + platformi.ImageFormat = platform.FORMAT_ISO + + // The ref is not needed and will be removed from the ctor later + // in time + img := image.NewAnacondaContainerInstallerLegacy(platformi, t.Filename(), containerSource, "") + img.ContainerRemoveSignatures = true + img.RootfsCompression = "zstd" + + if archStr == arch.ARCH_X86_64.String() { + img.InstallerCustomizations.ISOBoot = manifest.Grub2ISOBoot + } + + img.InstallerCustomizations.Product = sourceInfo.OSRelease.Name + img.InstallerCustomizations.OSVersion = sourceInfo.OSRelease.VersionID + img.InstallerCustomizations.ISOLabel = LabelForISO(&sourceInfo.OSRelease, archStr) + img.ExtraBasePackages = installerPkgSet + + var customizations *blueprint.Customizations + if bp != nil { + customizations = bp.Customizations + } + img.InstallerCustomizations.FIPS = customizations.GetFIPS() + img.Kickstart, err = kickstart.New(customizations) + if err != nil { + return nil, nil, err + } + img.Kickstart.Path = osbuild.KickstartPathOSBuild + if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" { + img.Kickstart.KernelOptionsAppend = append(img.Kickstart.KernelOptionsAppend, kopts.Append) + } + img.Kickstart.NetworkOnBoot = true + + instCust, err := customizations.GetInstaller() + if err != nil { + return nil, nil, err + } + if instCust != nil && instCust.Modules != nil { + img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, instCust.Modules.Enable...) + img.InstallerCustomizations.DisabledAnacondaModules = append(img.InstallerCustomizations.DisabledAnacondaModules, instCust.Modules.Disable...) + } + img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, + anaconda.ModuleUsers, + anaconda.ModuleServices, + anaconda.ModuleSecurity, + // XXX: get from the imagedefs + anaconda.ModuleNetwork, + anaconda.ModulePayloads, + anaconda.ModuleRuntime, + anaconda.ModuleStorage, + ) + + img.Kickstart.OSTree = &kickstart.OSTree{ + OSName: "default", + } + img.InstallerCustomizations.LoraxTemplates = installerConfig.LoraxTemplates + if installerConfig.LoraxTemplatePackage != nil { + img.InstallerCustomizations.LoraxTemplatePackage = *installerConfig.LoraxTemplatePackage + } + + // see https://github.com/osbuild/bootc-image-builder/issues/733 + img.InstallerCustomizations.ISORootfsType = manifest.SquashfsRootfs + + installRootfsType, err := disk.NewFSType(t.arch.distro.defaultFs) + if err != nil { + return nil, nil, err + } + img.InstallRootfsType = installRootfsType + + mf := manifest.New() + + foundDistro, foundRunner, err := GetDistroAndRunner(sourceInfo.OSRelease) + if err != nil { + return nil, nil, fmt.Errorf("failed to infer distro and runner: %w", err) + } + mf.Distro = foundDistro + + _, err = img.InstantiateManifest(&mf, nil, foundRunner, rng) + return &mf, nil, err +} + func newBootcDistroAfterIntrospect(archStr string, info *osinfo.Info, imgref, defaultFsStr string, cntSize uint64) (*BootcDistro, error) { nameVer := fmt.Sprintf("bootc-%s-%s", info.OSRelease.ID, info.OSRelease.VersionID) id, err := distro.ParseID(nameVer) diff --git a/pkg/distro/distro.go b/pkg/distro/distro.go index 1a2fa0d2e7..9acf733b40 100644 --- a/pkg/distro/distro.go +++ b/pkg/distro/distro.go @@ -4,7 +4,9 @@ import ( "math/rand" "github.com/osbuild/blueprint/pkg/blueprint" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/customizations/subscription" + "github.com/osbuild/images/pkg/depsolvednf" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk/partition" "github.com/osbuild/images/pkg/manifest" @@ -56,6 +58,12 @@ type Distro interface { GetArch(arch string) (Arch, error) } +type CustomDepsolverDistro interface { + Distro + + Depsolver(cacheDir string, archi arch.Arch) (solver *depsolvednf.Solver, cleanup func() error, err error) +} + // An Arch represents a given distribution's support for a given architecture. type Arch interface { // Returns the name of the architecture. diff --git a/pkg/manifestgen/manifestgen.go b/pkg/manifestgen/manifestgen.go index 1b760a090d..ffb2d73a17 100644 --- a/pkg/manifestgen/manifestgen.go +++ b/pkg/manifestgen/manifestgen.go @@ -12,6 +12,8 @@ import ( "strings" "github.com/osbuild/blueprint/pkg/blueprint" + "github.com/osbuild/images/internal/common" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/depsolvednf" "github.com/osbuild/images/pkg/distro" @@ -66,7 +68,7 @@ type Options struct { // Custom "solver" functions, if unset the defaults will be // used. Only needed for specialized use-cases. - Depsolver DepsolveFunc + Depsolve DepsolveFunc ContainerResolver ContainerResolverFunc CommitResolver CommitResolverFunc @@ -80,7 +82,7 @@ type Options struct { type Generator struct { cacheDir string - depsolver DepsolveFunc + depsolve DepsolveFunc containerResolver ContainerResolverFunc commitResolver CommitResolverFunc sbomWriter SBOMWriterFunc @@ -106,7 +108,7 @@ func New(reporegistry *reporegistry.RepoRegistry, opts *Options) (*Generator, er reporegistry: reporegistry, cacheDir: opts.Cachedir, - depsolver: opts.Depsolver, + depsolve: opts.Depsolve, containerResolver: opts.ContainerResolver, commitResolver: opts.CommitResolver, rpmDownloader: opts.RpmDownloader, @@ -117,8 +119,8 @@ func New(reporegistry *reporegistry.RepoRegistry, opts *Options) (*Generator, er overrideRepos: opts.OverrideRepos, useBootstrapContainer: opts.UseBootstrapContainer, } - if mg.depsolver == nil { - mg.depsolver = DefaultDepsolver + if mg.depsolve == nil { + mg.depsolve = DefaultDepsolve } if mg.containerResolver == nil { mg.containerResolver = DefaultContainerResolver @@ -126,6 +128,13 @@ func New(reporegistry *reporegistry.RepoRegistry, opts *Options) (*Generator, er if mg.commitResolver == nil { mg.commitResolver = DefaultCommitResolver } + if mg.cacheDir == "" { + xdgCacheHomeDir, err := xdgCacheHome() + if err != nil { + return nil, err + } + mg.cacheDir = filepath.Join(xdgCacheHomeDir, defaultDepsolveCacheDir) + } return mg, nil } @@ -170,7 +179,25 @@ func (mg *Generator) Generate(bp *blueprint.Blueprint, imgType distro.ImageType, if err != nil { return nil, err } - depsolved, err := mg.depsolver(mg.cacheDir, mg.depsolveWarningsOutput, pkgSetChains, dist, a.Name()) + solver := depsolvednf.NewSolver(dist.ModulePlatformID(), dist.Releasever(), a.Name(), dist.Name(), mg.cacheDir) + if dd, ok := dist.(distro.CustomDepsolverDistro); ok { + // XXX: it would be nice to have access to arch.Arch + // from distro.Arch but we dont so we have to do without. + archi := common.Must(arch.FromString(a.Name())) + customSolver, cleanupFunc, err := dd.Depsolver(mg.cacheDir, archi) + if err != nil { + return nil, err + } + if customSolver != nil { + solver = customSolver + } + defer func() { + if err := cleanupFunc(); err != nil { + fmt.Fprintf(mg.warningsOutput, "WARNING: cleanup failed: %v\n", err) + } + }() + } + depsolved, err := mg.depsolve(solver, mg.cacheDir, mg.depsolveWarningsOutput, pkgSetChains, dist, a.Name()) if err != nil { return nil, err } @@ -240,20 +267,15 @@ func xdgCacheHome() (string, error) { return filepath.Join(home, ".cache"), nil } -// DefaultDepsolver provides a default implementation for depsolving. +// DefaultDepsolve provides a default implementation for depsolving. // It should rarely be necessary to use it directly and will be used // by default by manifestgen (unless overriden) -func DefaultDepsolver(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) { - if cacheDir == "" { - xdgCacheHomeDir, err := xdgCacheHome() - if err != nil { - return nil, err - } - cacheDir = filepath.Join(xdgCacheHomeDir, defaultDepsolveCacheDir) +// +// The customSolver argument can be nil +func DefaultDepsolve(solver *depsolvednf.Solver, cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) { + if solver == nil { + return nil, fmt.Errorf("need a valid solver, got nil") } - - solver := depsolvednf.NewSolver(d.ModulePlatformID(), d.Releasever(), arch, d.Name(), cacheDir) - if depsolveWarningsOutput != nil { solver.Stderr = depsolveWarningsOutput } @@ -321,7 +343,7 @@ func DefaultCommitResolver(commitSources map[string][]ostree.SourceSpec) (map[st } type ( - DepsolveFunc func(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) + DepsolveFunc func(solver *depsolvednf.Solver, cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) ContainerResolverFunc func(containerSources map[string][]container.SourceSpec, archName string) (map[string][]container.Spec, error) diff --git a/pkg/manifestgen/manifestgen_test.go b/pkg/manifestgen/manifestgen_test.go index ad363b26ed..e94c30e461 100644 --- a/pkg/manifestgen/manifestgen_test.go +++ b/pkg/manifestgen/manifestgen_test.go @@ -55,7 +55,7 @@ func TestManifestGeneratorDepsolve(t *testing.T) { } opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, CommitResolver: panicCommitResolver, ContainerResolver: panicContainerResolver, @@ -96,7 +96,7 @@ func TestManifestGeneratorWithOstreeCommit(t *testing.T) { assert.Equal(t, 1, len(res)) opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, CommitResolver: fakeCommitResolver, ContainerResolver: panicContainerResolver, } @@ -127,7 +127,7 @@ func TestManifestGeneratorWithOstreeCommit(t *testing.T) { assert.Contains(t, string(osbuildManifest), expectedSha256) } -func fakeDepsolve(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) { +func fakeDepsolve(solver *depsolvednf.Solver, cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]depsolvednf.DepsolveResult, error) { depsolvedSets := make(map[string]depsolvednf.DepsolveResult) if depsolveWarningsOutput != nil { _, _ = depsolveWarningsOutput.Write([]byte(`fake depsolve output`)) @@ -218,7 +218,7 @@ func TestManifestGeneratorContainers(t *testing.T) { assert.Equal(t, 1, len(res)) opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, CommitResolver: panicCommitResolver, ContainerResolver: fakeContainerResolver, } @@ -253,7 +253,7 @@ func TestManifestGeneratorDepsolveWithSbomWriter(t *testing.T) { generatedSboms := map[string]string{} opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, CommitResolver: panicCommitResolver, ContainerResolver: panicContainerResolver, @@ -295,7 +295,7 @@ func TestManifestGeneratorSeed(t *testing.T) { for _, withCustomSeed := range []bool{false, true} { opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, } if withCustomSeed { customSeed := int64(123) @@ -333,7 +333,7 @@ func TestManifestGeneratorDepsolveOutput(t *testing.T) { var depsolveWarningsOutput bytes.Buffer opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, DepsolveWarningsOutput: &depsolveWarningsOutput, } @@ -361,7 +361,7 @@ func TestManifestGeneratorOverrideRepos(t *testing.T) { for _, withOverrideRepos := range []bool{false, true} { t.Run(fmt.Sprintf("withOverrideRepos: %v", withOverrideRepos), func(t *testing.T) { opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, } if withOverrideRepos { opts.OverrideRepos = []rpmmd.RepoConfig{ @@ -401,7 +401,7 @@ func TestManifestGeneratorUseBootstrapContainer(t *testing.T) { for _, useBootstrapContainer := range []bool{false, true} { t.Run(fmt.Sprintf("useBootstrapContainer: %v", useBootstrapContainer), func(t *testing.T) { opts := &manifestgen.Options{ - Depsolver: fakeDepsolve, + Depsolve: fakeDepsolve, ContainerResolver: fakeContainerResolver, UseBootstrapContainer: useBootstrapContainer, } diff --git a/test/bootc-fake-containers.yaml b/test/bootc-fake-containers.yaml index c406864e87..04884a0dd3 100644 --- a/test/bootc-fake-containers.yaml +++ b/test/bootc-fake-containers.yaml @@ -40,7 +40,7 @@ containers: os_release: id: "build-test-os" - # test ISO installer + # test bootc based ISO installer - <<: *default_fake_container image_types: ["bootc-installer"] arch: x86_64 @@ -49,3 +49,44 @@ containers: image_types: ["bootc-installer"] arch: aarch64 payload_container_ref: "payload-container-fake-ref" + + # test rpm based ISO installer + - <<: *default_fake_container + image_types: ["anaconda-iso"] + arch: x86_64 + info: + <<: *default_info + os_release: + # we need a "real" distro here as the packages will + # be selected from the distros + # imagetypes.yaml:bootc-rpm-installer + name: "RHEL 10" + id: "rhel" + versionid: "10.1" + - <<: *default_fake_container + image_types: ["anaconda-iso"] + arch: x86_64 + info: + <<: *default_info + os_release: + name: "Centos 9" + id: "centos" + versionid: "9" + - <<: *default_fake_container + image_types: ["anaconda-iso"] + arch: x86_64 + info: + <<: *default_info + os_release: + name: "Fedora 43" + id: "fedora" + versionid: "43" + - <<: *default_fake_container + image_types: ["anaconda-iso"] + arch: x86_64 + info: + <<: *default_info + os_release: + name: "Fedora 42" + id: "fedora" + versionid: "42" diff --git a/test/data/manifest-checksums/bootc_centos_9-x86_64-anaconda_iso-empty b/test/data/manifest-checksums/bootc_centos_9-x86_64-anaconda_iso-empty new file mode 100644 index 0000000000..4ba71d3448 --- /dev/null +++ b/test/data/manifest-checksums/bootc_centos_9-x86_64-anaconda_iso-empty @@ -0,0 +1 @@ +df04e2d96faf93fdfa68a29f5e80945f7d2d7f84 diff --git a/test/data/manifest-checksums/bootc_fedora_42-x86_64-anaconda_iso-empty b/test/data/manifest-checksums/bootc_fedora_42-x86_64-anaconda_iso-empty new file mode 100644 index 0000000000..a972f78ff8 --- /dev/null +++ b/test/data/manifest-checksums/bootc_fedora_42-x86_64-anaconda_iso-empty @@ -0,0 +1 @@ +85951658efd54e0afd1cad0199583b241d76cfef diff --git a/test/data/manifest-checksums/bootc_fedora_43-x86_64-anaconda_iso-empty b/test/data/manifest-checksums/bootc_fedora_43-x86_64-anaconda_iso-empty new file mode 100644 index 0000000000..595ed1330f --- /dev/null +++ b/test/data/manifest-checksums/bootc_fedora_43-x86_64-anaconda_iso-empty @@ -0,0 +1 @@ +b7653845d09fe19e23236046ee22992889596911 diff --git a/test/data/manifest-checksums/bootc_rhel_10.1-x86_64-anaconda_iso-empty b/test/data/manifest-checksums/bootc_rhel_10.1-x86_64-anaconda_iso-empty new file mode 100644 index 0000000000..6ccf3d02f2 --- /dev/null +++ b/test/data/manifest-checksums/bootc_rhel_10.1-x86_64-anaconda_iso-empty @@ -0,0 +1 @@ +9bb33e9355d4b7f85e2b703a23397d7261cecee9