Unconditionally enable the users module in Anaconda. The module serves two purposes: - It will create a user that's defined in the blueprint by adding the user creation stage in the kickstart file. - It allows users to create user accounts interactively during installation.
305 lines
7.4 KiB
Go
305 lines
7.4 KiB
Go
package manifest
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/osbuild/osbuild-composer/internal/osbuild"
|
|
"github.com/osbuild/osbuild-composer/internal/platform"
|
|
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
|
"github.com/osbuild/osbuild-composer/internal/users"
|
|
)
|
|
|
|
// An Anaconda represents the installer tree as found on an ISO.
|
|
type Anaconda struct {
|
|
Base
|
|
|
|
// Packages to install in addition to the ones required by the
|
|
// pipeline.
|
|
ExtraPackages []string
|
|
|
|
// Extra repositories to install packages from
|
|
ExtraRepos []rpmmd.RepoConfig
|
|
|
|
// Users and Groups to create during installation.
|
|
// If empty, then the user can interactively create users at install time.
|
|
Users []users.User
|
|
Groups []users.Group
|
|
|
|
// Biosdevname indicates whether or not biosdevname should be used to
|
|
// name network devices when booting the installer. This may affect
|
|
// the naming of network devices on the target system.
|
|
Biosdevname bool
|
|
|
|
// Variant is the variant of the product being installed, if applicable.
|
|
Variant string
|
|
|
|
platform platform.Platform
|
|
repos []rpmmd.RepoConfig
|
|
packageSpecs []rpmmd.PackageSpec
|
|
kernelName string
|
|
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
|
|
// indicate the content to build the installer from, which is distinct from the
|
|
// packages the installer will install on the target system. kernelName is the
|
|
// name of the kernel package the intsaller will use. arch is the supported
|
|
// architecture. Product and version refers to the product the installer is the
|
|
// installer for.
|
|
func NewAnaconda(m *Manifest,
|
|
buildPipeline *Build,
|
|
platform platform.Platform,
|
|
repos []rpmmd.RepoConfig,
|
|
kernelName,
|
|
product,
|
|
version string) *Anaconda {
|
|
p := &Anaconda{
|
|
Base: NewBase(m, "anaconda-tree", buildPipeline),
|
|
platform: platform,
|
|
repos: repos,
|
|
kernelName: kernelName,
|
|
product: product,
|
|
version: version,
|
|
}
|
|
buildPipeline.addDependent(p)
|
|
m.addPipeline(p)
|
|
return p
|
|
}
|
|
|
|
// TODO: refactor - what is required to boot and what to build, and
|
|
// do they all belong in this pipeline?
|
|
func (p *Anaconda) anacondaBootPackageSet() []string {
|
|
packages := []string{
|
|
"grub2-tools",
|
|
"grub2-tools-extra",
|
|
"grub2-tools-minimal",
|
|
"efibootmgr",
|
|
}
|
|
|
|
switch p.platform.GetArch() {
|
|
case platform.ARCH_X86_64:
|
|
packages = append(packages,
|
|
"grub2-efi-x64",
|
|
"grub2-efi-x64-cdboot",
|
|
"grub2-pc",
|
|
"grub2-pc-modules",
|
|
"shim-x64",
|
|
"syslinux",
|
|
"syslinux-nonlinux",
|
|
)
|
|
case platform.ARCH_AARCH64:
|
|
packages = append(packages,
|
|
"grub2-efi-aa64-cdboot",
|
|
"grub2-efi-aa64",
|
|
"shim-aa64",
|
|
)
|
|
default:
|
|
panic(fmt.Sprintf("unsupported arch: %s", p.platform.GetArch()))
|
|
}
|
|
|
|
return packages
|
|
}
|
|
|
|
func (p *Anaconda) getBuildPackages() []string {
|
|
packages := p.anacondaBootPackageSet()
|
|
packages = append(packages,
|
|
"rpm",
|
|
"lorax-templates-generic",
|
|
)
|
|
return packages
|
|
}
|
|
|
|
func (p *Anaconda) getPackageSetChain() []rpmmd.PackageSet {
|
|
packages := p.anacondaBootPackageSet()
|
|
if p.Biosdevname {
|
|
packages = append(packages, "biosdevname")
|
|
}
|
|
return []rpmmd.PackageSet{
|
|
{
|
|
Include: append(packages, p.ExtraPackages...),
|
|
Repositories: append(p.repos, p.ExtraRepos...),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (p *Anaconda) getPackageSpecs() []rpmmd.PackageSpec {
|
|
return p.packageSpecs
|
|
}
|
|
|
|
func (p *Anaconda) serializeStart(packages []rpmmd.PackageSpec) {
|
|
if len(p.packageSpecs) > 0 {
|
|
panic("double call to serializeStart()")
|
|
}
|
|
p.packageSpecs = packages
|
|
if p.kernelName != "" {
|
|
p.kernelVer = rpmmd.GetVerStrFromPackageSpecListPanic(p.packageSpecs, p.kernelName)
|
|
}
|
|
}
|
|
|
|
func (p *Anaconda) serializeEnd() {
|
|
if len(p.packageSpecs) == 0 {
|
|
panic("serializeEnd() call when serialization not in progress")
|
|
}
|
|
p.kernelVer = ""
|
|
p.packageSpecs = nil
|
|
}
|
|
|
|
func (p *Anaconda) serialize() osbuild.Pipeline {
|
|
if len(p.packageSpecs) == 0 {
|
|
panic("serialization not started")
|
|
}
|
|
pipeline := p.Base.serialize()
|
|
|
|
pipeline.AddStage(osbuild.NewRPMStage(osbuild.NewRPMStageOptions(p.repos), osbuild.NewRpmStageSourceFilesInputs(p.packageSpecs)))
|
|
pipeline.AddStage(osbuild.NewBuildstampStage(&osbuild.BuildstampStageOptions{
|
|
Arch: p.platform.GetArch().String(),
|
|
Product: p.product,
|
|
Variant: p.Variant,
|
|
Version: p.version,
|
|
Final: true,
|
|
}))
|
|
pipeline.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"}))
|
|
|
|
rootPassword := ""
|
|
rootUser := osbuild.UsersStageOptionsUser{
|
|
Password: &rootPassword,
|
|
}
|
|
|
|
installUID := 0
|
|
installGID := 0
|
|
installHome := "/root"
|
|
installShell := "/usr/libexec/anaconda/run-anaconda"
|
|
installPassword := ""
|
|
installUser := osbuild.UsersStageOptionsUser{
|
|
UID: &installUID,
|
|
GID: &installGID,
|
|
Home: &installHome,
|
|
Shell: &installShell,
|
|
Password: &installPassword,
|
|
}
|
|
usersStageOptions := &osbuild.UsersStageOptions{
|
|
Users: map[string]osbuild.UsersStageOptionsUser{
|
|
"root": rootUser,
|
|
"install": installUser,
|
|
},
|
|
}
|
|
|
|
pipeline.AddStage(osbuild.NewUsersStage(usersStageOptions))
|
|
// always enable users module in anaconda
|
|
pipeline.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(true, p.AdditionalModules)))
|
|
pipeline.AddStage(osbuild.NewLoraxScriptStage(&osbuild.LoraxScriptStageOptions{
|
|
Path: "99-generic/runtime-postinstall.tmpl",
|
|
BaseArch: p.platform.GetArch().String(),
|
|
}))
|
|
pipeline.AddStage(osbuild.NewDracutStage(dracutStageOptions(p.kernelVer, p.Biosdevname, []string{
|
|
"anaconda",
|
|
"rdma",
|
|
"rngd",
|
|
"multipath",
|
|
"fcoe",
|
|
"fcoe-uefi",
|
|
"iscsi",
|
|
"lunmask",
|
|
"nfs",
|
|
})))
|
|
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,
|
|
p.Users,
|
|
p.Groups,
|
|
"",
|
|
"",
|
|
"",
|
|
)
|
|
|
|
if err != nil {
|
|
panic("failed to create kickstartstage options for interactive defaults")
|
|
}
|
|
|
|
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
|
|
}
|
|
|
|
return pipeline
|
|
}
|
|
|
|
func dracutStageOptions(kernelVer string, biosdevname bool, additionalModules []string) *osbuild.DracutStageOptions {
|
|
kernel := []string{kernelVer}
|
|
modules := []string{
|
|
"bash",
|
|
"systemd",
|
|
"fips",
|
|
"systemd-initrd",
|
|
"modsign",
|
|
"nss-softokn",
|
|
"i18n",
|
|
"convertfs",
|
|
"network-manager",
|
|
"network",
|
|
"ifcfg",
|
|
"url-lib",
|
|
"drm",
|
|
"plymouth",
|
|
"crypt",
|
|
"dm",
|
|
"dmsquash-live",
|
|
"kernel-modules",
|
|
"kernel-modules-extra",
|
|
"kernel-network-modules",
|
|
"livenet",
|
|
"lvm",
|
|
"mdraid",
|
|
"qemu",
|
|
"qemu-net",
|
|
"resume",
|
|
"rootfs-block",
|
|
"terminfo",
|
|
"udev-rules",
|
|
"dracut-systemd",
|
|
"pollcdrom",
|
|
"usrmount",
|
|
"base",
|
|
"fs-lib",
|
|
"img-lib",
|
|
"shutdown",
|
|
"uefi-lib",
|
|
}
|
|
|
|
if biosdevname {
|
|
modules = append(modules, "biosdevname")
|
|
}
|
|
|
|
modules = append(modules, additionalModules...)
|
|
return &osbuild.DracutStageOptions{
|
|
Kernel: kernel,
|
|
Modules: modules,
|
|
Install: []string{"/.buildstamp"},
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|