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:
parent
9ea58d1486
commit
d4d100383e
27 changed files with 531772 additions and 30 deletions
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
152
internal/image/image_installer.go
Normal file
152
internal/image/image_installer.go
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
31512
test/data/manifests/fedora_35-aarch64-image_installer-boot.json
Normal file
31512
test/data/manifests/fedora_35-aarch64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
32074
test/data/manifests/fedora_35-x86_64-image_installer-boot.json
Normal file
32074
test/data/manifests/fedora_35-x86_64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
33135
test/data/manifests/fedora_36-aarch64-image_installer-boot.json
Normal file
33135
test/data/manifests/fedora_36-aarch64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
33811
test/data/manifests/fedora_36-x86_64-image_installer-boot.json
Normal file
33811
test/data/manifests/fedora_36-x86_64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
33583
test/data/manifests/fedora_37-aarch64-image_installer-boot.json
Normal file
33583
test/data/manifests/fedora_37-aarch64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
34280
test/data/manifests/fedora_37-x86_64-image_installer-boot.json
Normal file
34280
test/data/manifests/fedora_37-x86_64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
33270
test/data/manifests/fedora_38-aarch64-image_installer-boot.json
Normal file
33270
test/data/manifests/fedora_38-aarch64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
33910
test/data/manifests/fedora_38-x86_64-image_installer-boot.json
Normal file
33910
test/data/manifests/fedora_38-x86_64-image_installer-boot.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue