image: create installer image types for fedora

This adds the `fedora-image-installer` and
`fedora-image-installer-preview` images.

The image installer type installs anaconda-webui on Fedora >= 38 to use
the new UI. It also writes its setting to
`/usr/share/anaconda/interactive-defaults.ks` as the current
anaconda-webui has not yet been tested in kickstart mode.

To do so manifest.Anaconda was expanded to take a (subset) of options
for a KickstartStage which is will write into interactive-defaults.ks.
And to take a list of additional modules to enable, so we can set up
Anaconda with all default modules.
This commit is contained in:
Simon de Vlieger 2022-10-06 12:01:45 +02:00 committed by Ondřej Budai
parent 9ea58d1486
commit d4d100383e
27 changed files with 531772 additions and 30 deletions

View file

@ -72,6 +72,24 @@ var (
}
// Image Definitions
imageInstallerImgType = imageType{
name: "image-installer",
nameAliases: []string{"fedora-image-installer"},
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
packageSets: map[string]packageSetFunc{
osPkgsKey: bareMetalPackageSet,
installerPkgsKey: imageInstallerPackageSet,
},
bootable: true,
bootISO: true,
rpmOstree: false,
image: imageInstallerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "anaconda-tree", "rootfs-image", "efiboot-tree", "bootiso-tree"},
exports: []string{"bootiso"},
}
iotCommitImgType = imageType{
name: "iot-commit",
nameAliases: []string{"fedora-iot-commit"},
@ -702,8 +720,11 @@ func (t *imageType) checkOptions(customizations *blueprint.Customizations, optio
if options.OSTree.FetchChecksum == "" {
return fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name)
}
}
if t.name == "iot-installer" {
// BootISO's have limited support for customizations.
if t.bootISO {
if t.name == "iot-installer" || t.name == "image-installer" {
allowed := []string{"User", "Group"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
@ -874,6 +895,7 @@ func newDistro(version int) distro.Distro {
iotOCIImgType,
iotCommitImgType,
iotInstallerImgType,
imageInstallerImgType,
)
x86_64.addImageTypes(
&platform.X86{
@ -932,6 +954,7 @@ func newDistro(version int) distro.Distro {
iotCommitImgType,
iotOCIImgType,
iotInstallerImgType,
imageInstallerImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{

View file

@ -148,6 +148,22 @@ func TestFilenameFromType(t *testing.T) {
mimeType: "application/x-iso9660-image",
},
},
{
name: "image-installer",
args: args{"image-installer"},
want: wantResult{
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
},
},
{ // Alias
name: "fedora-image-installer",
args: args{"fedora-image-installer"},
want: wantResult{
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
},
},
{
name: "invalid-output-type",
args: args{"foobar"},
@ -250,6 +266,7 @@ func TestImageType_Name(t *testing.T) {
"iot-installer",
"iot-raw-image",
"oci",
"image-installer",
},
},
{
@ -263,6 +280,7 @@ func TestImageType_Name(t *testing.T) {
"iot-container",
"iot-installer",
"iot-raw-image",
"image-installer",
},
},
}
@ -394,6 +412,8 @@ func TestDistro_ManifestError(t *testing.T) {
assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types")
} else if imgTypeName == "iot-installer" {
assert.EqualError(t, err, fmt.Sprintf("boot ISO image type \"%s\" requires specifying a URL from which to retrieve the OSTree commit", imgTypeName))
} else if imgTypeName == "image-installer" {
assert.EqualError(t, err, fmt.Sprintf("unsupported blueprint customizations found for boot ISO image type \"%s\": (allowed: User, Group)", imgTypeName))
} else {
assert.NoError(t, err)
}
@ -421,6 +441,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"iot-raw-image",
"oci",
"container",
"image-installer",
},
},
{
@ -435,6 +456,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"iot-raw-image",
"oci",
"container",
"image-installer",
},
},
}
@ -528,7 +550,7 @@ func TestDistro_CustomFileSystemManifestError(t *testing.T) {
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, nil, 0)
if imgTypeName == "iot-commit" || imgTypeName == "iot-container" || imgTypeName == "iot-raw-image" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
} else if imgTypeName == "iot-installer" {
} else if imgTypeName == "iot-installer" || imgTypeName == "image-installer" {
continue
} else {
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/etc\"]")
@ -557,7 +579,7 @@ func TestDistro_TestRootMountPoint(t *testing.T) {
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, nil, 0)
if imgTypeName == "iot-commit" || imgTypeName == "iot-container" || imgTypeName == "iot-raw-image" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
} else if imgTypeName == "iot-installer" {
} else if imgTypeName == "iot-installer" || imgTypeName == "image-installer" {
continue
} else {
assert.NoError(t, err)
@ -588,7 +610,7 @@ func TestDistro_CustomFileSystemSubDirectories(t *testing.T) {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, nil, 0)
if strings.HasPrefix(imgTypeName, "iot-") {
if strings.HasPrefix(imgTypeName, "iot-") || strings.HasPrefix(imgTypeName, "image-") {
continue
} else {
assert.NoError(t, err)
@ -627,7 +649,7 @@ func TestDistro_MountpointsWithArbitraryDepthAllowed(t *testing.T) {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, nil, 0)
if strings.HasPrefix(imgTypeName, "iot-") {
if strings.HasPrefix(imgTypeName, "iot-") || strings.HasPrefix(imgTypeName, "image-") {
continue
} else {
assert.NoError(t, err)
@ -661,7 +683,7 @@ func TestDistro_DirtyMountpointsNotAllowed(t *testing.T) {
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, nil, 0)
if strings.HasPrefix(imgTypeName, "iot-") {
if strings.HasPrefix(imgTypeName, "iot-") || strings.HasPrefix(imgTypeName, "image-") {
continue
} else {
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"//\" \"/var//\" \"/var//log/audit/\"]")
@ -693,7 +715,7 @@ func TestDistro_CustomFileSystemPatternMatching(t *testing.T) {
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, nil, 0)
if imgTypeName == "iot-commit" || imgTypeName == "iot-container" || imgTypeName == "iot-raw-image" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
} else if imgTypeName == "iot-installer" {
} else if imgTypeName == "iot-installer" || imgTypeName == "image-installer" {
continue
} else {
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/variable\" \"/variable/log/audit\"]")
@ -722,7 +744,7 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, nil, 0)
if imgTypeName == "iot-commit" || imgTypeName == "iot-container" || imgTypeName == "iot-raw-image" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
} else if imgTypeName == "iot-installer" {
} else if imgTypeName == "iot-installer" || imgTypeName == "image-installer" {
continue
} else {
assert.NoError(t, err)

View file

@ -178,6 +178,34 @@ func containerImage(workload workload.Workload,
return img, nil
}
func imageInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewImageInstaller()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
d := t.arch.distro
img.ISOLabelTempl = d.isolabelTmpl
img.Product = d.product
img.OSName = "fedora"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.Filename = t.Filename()
return img, nil
}
func iotCommitImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,

View file

@ -432,12 +432,14 @@ func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
ps.Append(rpmmd.PackageSet{
Include: []string{
"smc-meera-fonts",
"sil-scheherazade-fonts",
},
})
} else {
ps.Append(rpmmd.PackageSet{
Include: []string{
"rit-meera-new-fonts",
"sil-scheherazade-new-fonts",
},
})
}
@ -487,6 +489,27 @@ func iotInstallerPackageSet(t *imageType) rpmmd.PackageSet {
return anacondaPackageSet(t)
}
func imageInstallerPackageSet(t *imageType) rpmmd.PackageSet {
ps := anacondaPackageSet(t)
releasever := t.Arch().Distro().Releasever()
version, err := strconv.Atoi(releasever)
if err != nil {
panic("cannot convert releasever to int: " + err.Error())
}
// We want to generate a preview image when rawhide is built
if version >= 38 {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"anaconda-webui",
},
})
}
return ps
}
func containerPackageSet(t *imageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
@ -540,3 +563,11 @@ func containerPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",
},
}
}

View file

@ -1043,7 +1043,7 @@ func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec
}
p.AddStage(osbuild.NewUsersStage(usersStageOptions))
p.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(users)))
p.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(users, []string{})))
p.AddStage(osbuild.NewLoraxScriptStage(loraxScriptStageOptions(arch)))
p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, arch, []string{
"anaconda",

View file

@ -1039,7 +1039,7 @@ func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec
}
p.AddStage(osbuild.NewUsersStage(usersStageOptions))
p.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(users)))
p.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(users, []string{})))
p.AddStage(osbuild.NewLoraxScriptStage(loraxScriptStageOptions(arch)))
dso := dracutStageOptions(kernelVer, arch, []string{
"anaconda",

View file

@ -0,0 +1,152 @@
package image
import (
"fmt"
"math/rand"
"strconv"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/users"
"github.com/osbuild/osbuild-composer/internal/workload"
)
type ImageInstaller struct {
Base
Platform platform.Platform
OSCustomizations manifest.OSCustomizations
Environment environment.Environment
Workload workload.Workload
ExtraBasePackages rpmmd.PackageSet
Users []users.User
Groups []users.Group
ISOLabelTempl string
Product string
Variant string
OSName string
OSVersion string
Release string
Filename string
}
func NewImageInstaller() *ImageInstaller {
return &ImageInstaller{
Base: NewBase("image-installer"),
}
}
func (img *ImageInstaller) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
version, err := strconv.Atoi(img.OSVersion)
if err != nil {
panic("cannot convert version to int: " + err.Error())
}
useWebUi := img.OSName == "fedora" && version >= 38
anacondaPipeline := manifest.NewAnaconda(m,
buildPipeline,
img.Platform,
repos,
"kernel",
img.Product,
img.OSVersion)
interactiveDefaults := manifest.NewAnacondaInteractiveDefaults(
"file:///run/install/repo/liveimg.tar",
)
anacondaPipeline.ExtraPackages = img.ExtraBasePackages.Include
anacondaPipeline.ExtraRepos = img.ExtraBasePackages.Repositories
anacondaPipeline.Users = len(img.Users)+len(img.Groups) > 0
anacondaPipeline.Variant = img.Variant
anacondaPipeline.Biosdevname = (img.Platform.GetArch() == platform.ARCH_X86_64)
anacondaPipeline.InteractiveDefaults = interactiveDefaults
if useWebUi {
anacondaPipeline.AdditionalModules = []string{
"org.fedoraproject.Anaconda.Modules.Security",
"org.fedoraproject.Anaconda.Modules.Users",
"org.fedoraproject.Anaconda.Modules.Timezone",
"org.fedoraproject.Anaconda.Modules.Localization",
}
}
anacondaPipeline.Checkpoint()
rootfsPartitionTable := &disk.PartitionTable{
Size: 20 * common.MebiByte,
Partitions: []disk.Partition{
{
Start: 0,
Size: 20 * common.MebiByte,
Payload: &disk.Filesystem{
Type: "vfat",
Mountpoint: "/",
UUID: disk.NewVolIDFromRand(rng),
},
},
},
}
// TODO: replace isoLabelTmpl with more high-level properties
isoLabel := fmt.Sprintf(img.ISOLabelTempl, img.Platform.GetArch())
rootfsImagePipeline := manifest.NewISORootfsImg(m, buildPipeline, anacondaPipeline)
rootfsImagePipeline.Size = 4 * common.GibiByte
bootTreePipeline := manifest.NewEFIBootTree(m, buildPipeline, anacondaPipeline)
bootTreePipeline.Platform = img.Platform
bootTreePipeline.UEFIVendor = img.Platform.GetUEFIVendor()
bootTreePipeline.ISOLabel = isoLabel
if useWebUi {
bootTreePipeline.KernelOpts = []string{"inst.webui", "inst.webui.remote"}
}
osPipeline := manifest.NewOS(m, buildPipeline, img.Platform, repos)
osPipeline.OSCustomizations = img.OSCustomizations
osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload
isoTreePipeline := manifest.NewISOTree(m,
buildPipeline,
anacondaPipeline,
rootfsImagePipeline,
bootTreePipeline,
isoLabel)
isoTreePipeline.PartitionTable = rootfsPartitionTable
isoTreePipeline.Release = img.Release
isoTreePipeline.OSName = img.OSName
isoTreePipeline.Users = img.Users
isoTreePipeline.Groups = img.Groups
isoTreePipeline.OSPipeline = osPipeline
if useWebUi {
isoTreePipeline.KernelOpts = []string{"inst.webui", "inst.webui.remote"}
}
isoPipeline := manifest.NewISO(m, buildPipeline, isoTreePipeline)
isoPipeline.Filename = img.Filename
isoPipeline.ISOLinux = true
artifact := isoPipeline.Export()
return artifact, nil
}

View file

@ -37,6 +37,13 @@ type Anaconda struct {
kernelVer string
product string
version string
// Interactive defaults is a kickstart stage that can be provided, it
// will be written to /usr/share/anaconda/interactive-defaults
InteractiveDefaults *AnacondaInteractiveDefaults
// Additional anaconda modules to enable
AdditionalModules []string
}
// NewAnaconda creates an anaconda pipeline object. repos and packages
@ -184,7 +191,7 @@ func (p *Anaconda) serialize() osbuild.Pipeline {
}
pipeline.AddStage(osbuild.NewUsersStage(usersStageOptions))
pipeline.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(p.Users)))
pipeline.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(p.Users, p.AdditionalModules)))
pipeline.AddStage(osbuild.NewLoraxScriptStage(&osbuild.LoraxScriptStageOptions{
Path: "99-generic/runtime-postinstall.tmpl",
BaseArch: p.platform.GetArch().String(),
@ -202,6 +209,24 @@ func (p *Anaconda) serialize() osbuild.Pipeline {
})))
pipeline.AddStage(osbuild.NewSELinuxConfigStage(&osbuild.SELinuxConfigStageOptions{State: osbuild.SELinuxStatePermissive}))
if p.InteractiveDefaults != nil {
kickstartOptions, err := osbuild.NewKickstartStageOptions(
"/usr/share/anaconda/interactive-defaults.ks",
p.InteractiveDefaults.TarPath,
nil,
nil,
"",
"",
"",
)
if err != nil {
panic("failed to create kickstartstage options for interactive defaults")
}
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
}
return pipeline
}
@ -262,3 +287,15 @@ func dracutStageOptions(kernelVer string, biosdevname bool, additionalModules []
func (p *Anaconda) GetPlatform() platform.Platform {
return p.platform
}
type AnacondaInteractiveDefaults struct {
TarPath string
}
func NewAnacondaInteractiveDefaults(tarPath string) *AnacondaInteractiveDefaults {
i := &AnacondaInteractiveDefaults{
TarPath: tarPath,
}
return i
}

View file

@ -18,6 +18,8 @@ type EFIBootTree struct {
UEFIVendor string
ISOLabel string
KSPath string
KernelOpts []string
}
func NewEFIBootTree(m *Manifest, buildPipeline *Build, anacondaPipeline *Anaconda) *EFIBootTree {
@ -43,6 +45,18 @@ func (p *EFIBootTree) serialize() osbuild.Pipeline {
panic("unsupported architecture")
}
kernelOpts := []string{}
if p.KSPath != "" {
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.ISOLabel, p.KSPath))
} else {
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.stage2=hd:LABEL=%s", p.ISOLabel))
}
if len(p.KernelOpts) > 0 {
kernelOpts = append(kernelOpts, p.KernelOpts...)
}
grubOptions := &osbuild.GrubISOStageOptions{
Product: osbuild.Product{
Name: p.anacondaPipeline.product,
@ -50,7 +64,7 @@ func (p *EFIBootTree) serialize() osbuild.Pipeline {
},
Kernel: osbuild.ISOKernel{
Dir: "/images/pxeboot",
Opts: []string{fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.ISOLabel, p.KSPath)},
Opts: kernelOpts,
},
ISOLabel: p.ISOLabel,
Architectures: architectures,

View file

@ -12,7 +12,8 @@ import (
// An ISOTree represents a tree containing the anaconda installer,
// configuration in terms of a kickstart file, as well as an embedded
// payload to be installed.
// payload to be installed, this payload can either be an ostree
// CommitSpec or OSPipeline for an OS.
type ISOTree struct {
Base
@ -31,7 +32,10 @@ type ISOTree struct {
KSPath string
isoLabel string
OSTree *ostree.CommitSpec
OSPipeline *OS
OSTree *ostree.CommitSpec
KernelOpts []string
}
func NewISOTree(m *Manifest,
@ -61,6 +65,7 @@ func (p *ISOTree) getOSTreeCommits() []ostree.CommitSpec {
if p.OSTree == nil {
return nil
}
return []ostree.CommitSpec{
*p.OSTree,
}
@ -68,17 +73,45 @@ func (p *ISOTree) getOSTreeCommits() []ostree.CommitSpec {
func (p *ISOTree) getBuildPackages() []string {
packages := []string{
"rpm-ostree",
"squashfs-tools",
}
if p.OSTree != nil {
packages = append(packages, "rpm-ostree")
}
if p.OSPipeline != nil {
packages = append(packages, "tar")
}
return packages
}
func (p *ISOTree) serialize() osbuild.Pipeline {
// We need one of two payloads
if p.OSTree == nil && p.OSPipeline == nil {
panic("missing ostree or ospipeline parameters in ISO tree pipeline")
}
// But not both payloads
if p.OSTree != nil && p.OSPipeline != nil {
panic("got both ostree and ospipeline parameters in ISO tree pipeline")
}
pipeline := p.Base.serialize()
ostreeRepoPath := "/ostree/repo"
kernelOpts := fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.isoLabel, p.KSPath)
kernelOpts := []string{}
if p.KSPath != "" {
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.isoLabel, p.KSPath))
} else {
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.stage2=hd:LABEL=%s", p.isoLabel))
}
if len(p.KernelOpts) > 0 {
kernelOpts = append(kernelOpts, p.KernelOpts...)
}
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
Paths: []osbuild.Path{
@ -124,7 +157,7 @@ func (p *ISOTree) serialize() osbuild.Pipeline {
},
Kernel: osbuild.ISOLinuxKernel{
Dir: "/images/pxeboot",
Opts: []string{kernelOpts},
Opts: kernelOpts,
},
}
isoLinuxStage := osbuild.NewISOLinuxStage(isoLinuxOptions, p.anacondaPipeline.Name())
@ -159,21 +192,29 @@ func (p *ISOTree) serialize() osbuild.Pipeline {
copyInputs,
))
if p.OSTree == nil {
panic("missing ostree parameters in ISO tree pipeline")
}
kickstartOptions, err := osbuild.NewKickstartStageOptions(p.KSPath, "", p.Users, p.Groups, makeISORootPath(ostreeRepoPath), p.OSTree.Ref, p.OSName)
if err != nil {
panic("password encryption failed")
if p.OSTree != nil {
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: ostreeRepoPath}))
pipeline.AddStage(osbuild.NewOSTreePullStage(
&osbuild.OSTreePullStageOptions{Repo: ostreeRepoPath},
osbuild.NewOstreePullStageInputs("org.osbuild.source", p.OSTree.Checksum, p.OSTree.Ref),
))
kickstartOptions, err := osbuild.NewKickstartStageOptions(p.KSPath, "", p.Users, p.Groups, makeISORootPath(ostreeRepoPath), p.OSTree.Ref, p.OSName)
if err != nil {
panic("failed to create kickstartstage options")
}
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
}
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: ostreeRepoPath}))
pipeline.AddStage(osbuild.NewOSTreePullStage(
&osbuild.OSTreePullStageOptions{Repo: ostreeRepoPath},
osbuild.NewOstreePullStageInputs("org.osbuild.source", p.OSTree.Checksum, p.OSTree.Ref),
))
if p.OSPipeline != nil {
pipeline.AddStage(osbuild.NewTarStage(&osbuild.TarStageOptions{Filename: "/liveimg.tar"}, p.OSPipeline.name))
// In the case of OSPipeline then the ImageInstaller has already set InteractiveDefaults on the anaconda-tree,
// eliminating the need to set a separate kickstart here.
}
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
pipeline.AddStage(osbuild.NewDiscinfoStage(&osbuild.DiscinfoStageOptions{
BaseArch: p.anacondaPipeline.platform.GetArch().String(),
Release: p.Release,

View file

@ -15,7 +15,7 @@ func NewAnacondaStage(options *AnacondaStageOptions) *Stage {
}
}
func NewAnacondaStageOptions(users bool) *AnacondaStageOptions {
func NewAnacondaStageOptions(users bool, additionalModules []string) *AnacondaStageOptions {
modules := []string{
"org.fedoraproject.Anaconda.Modules.Network",
"org.fedoraproject.Anaconda.Modules.Payloads",
@ -26,6 +26,10 @@ func NewAnacondaStageOptions(users bool) *AnacondaStageOptions {
modules = append(modules, "org.fedoraproject.Anaconda.Modules.Users")
}
if len(additionalModules) > 0 {
modules = append(modules, additionalModules...)
}
return &AnacondaStageOptions{
KickstartModules: modules,
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff