go.mod: update osbuild/images to v0.151.0
tag v0.149.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.149.0 ---------------- * Update dependencies 2025-05-25 (osbuild/images#1560) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * Update osbuild dependency commit ID to latest (osbuild/images#1522) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * Update snapshots to 20250515 (osbuild/images#1524) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * `vagrant-libvirt` implementation (HMS-6116) (osbuild/images#1548) * Author: Simon de Vlieger, Reviewers: Achilleas Koutsou, Tomáš Hozza * fedora: tweaks after all imageTypes are YAML (osbuild/images#1518) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * gha: do not break gobump output (osbuild/images#1561) * Author: Lukáš Zapletal, Reviewers: Simon de Vlieger, Tomáš Hozza * repositories: AlmaLinux 10 (osbuild/images#1567) * Author: Simon de Vlieger, Reviewers: Achilleas Koutsou, Lukáš Zapletal, Neal Gompa (ニール・ゴンパ) * vagrant: image config for default vagrant user (HMS-6116) (osbuild/images#1565) * Author: Simon de Vlieger, Reviewers: Achilleas Koutsou, Michael Vogt — Somewhere on the Internet, 2025-05-27 --- tag v0.150.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.150.0 ---------------- * Replace hardcoded kickstart %post scripts with new stage options and bootc switch with custom kickstart content (HMS-6051) (osbuild/images#1527) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza * test: install yamllint for tests (osbuild/images#1572) * Author: Achilleas Koutsou, Reviewers: Lukáš Zapletal, Simon de Vlieger, Tomáš Hozza — Somewhere on the Internet, 2025-06-02 --- tag v0.151.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.151.0 ---------------- * Introduce new Azure CVM image type (HMS-5636) (osbuild/images#1318) * Author: Achilleas Koutsou, Reviewers: Nobody * Many: support using string with unit for byte-sized partitioning fields in YAML distro definitions (osbuild/images#1579) * Author: Tomáš Hozza, Reviewers: Achilleas Koutsou, Brian C. Lane * Update osbuild dependency commit ID to latest (osbuild/images#1587) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Tomáš Hozza * Update snapshots to 20250601 (osbuild/images#1573) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Lukáš Zapletal * bootc: Make installed rootfs configurable (osbuild/images#1555) * Author: Mbarak Bujra, Reviewers: Michael Vogt, Tomáš Hozza * distro: create new ImageConfig.DNFConfig (osbuild/images#1583) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * distro: make "fedora" a "generic" distro (osbuild/images#1563) * Author: Michael Vogt, Reviewers: Nobody * image: If using a separate build container, copy bootc customization to it (osbuild/images#1571) * Author: Alexander Larsson, Reviewers: Achilleas Koutsou, Tomáš Hozza * manifest/ostree: explicitly include shadow-utils (osbuild/images#1585) * Author: Simon de Vlieger, Reviewers: Achilleas Koutsou, Michael Vogt * osbuild/tar: explicit compression (HMS-8573, HMS-6116) (osbuild/images#1581) * Author: Simon de Vlieger, Reviewers: Achilleas Koutsou, Tomáš Hozza * tests: bump fedora versions to 41 (osbuild/images#1438) * Author: Lukáš Zapletal, Reviewers: Brian C. Lane, Michael Vogt — Somewhere on the Internet, 2025-06-09 ---
This commit is contained in:
parent
cedc351bbd
commit
deccaf9548
82 changed files with 2844 additions and 1175 deletions
238
vendor/github.com/osbuild/images/pkg/distro/generic/distro.go
generated
vendored
Normal file
238
vendor/github.com/osbuild/images/pkg/distro/generic/distro.go
generated
vendored
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
package generic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"text/template"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/pkg/distro"
|
||||
"github.com/osbuild/images/pkg/distro/defs"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
)
|
||||
|
||||
const (
|
||||
// package set names
|
||||
|
||||
// main/common os image package set name
|
||||
osPkgsKey = "os"
|
||||
|
||||
// container package set name
|
||||
containerPkgsKey = "container"
|
||||
|
||||
// installer package set name
|
||||
installerPkgsKey = "installer"
|
||||
|
||||
// blueprint package set name
|
||||
blueprintPkgsKey = "blueprint"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDistroNotFound = errors.New("distribution not found")
|
||||
)
|
||||
|
||||
// distribution implements the distro.Distro interface
|
||||
var _ = distro.Distro(&distribution{})
|
||||
|
||||
type distribution struct {
|
||||
defs.DistroYAML
|
||||
|
||||
arches map[string]*architecture
|
||||
// XXX: move into defs.DistroYAML? the downside of doing this
|
||||
// is that we would have to duplicate the default image config
|
||||
// accross the centos/alma/rhel distros.yaml, otherwise we
|
||||
// just load it from the imagetypes file/dir and it is natually
|
||||
// "in-sync"
|
||||
defaultImageConfig *distro.ImageConfig
|
||||
}
|
||||
|
||||
func (d *distribution) getISOLabelFunc(isoLabel string) isoLabelFunc {
|
||||
return func(t *imageType) string {
|
||||
type inputs struct {
|
||||
Product string
|
||||
OsVersion string
|
||||
Arch string
|
||||
ImgTypeLabel string
|
||||
}
|
||||
templ := common.Must(template.New("iso-label").Parse(d.DistroYAML.ISOLabelTmpl))
|
||||
var buf bytes.Buffer
|
||||
err := templ.Execute(&buf, inputs{
|
||||
Product: t.Arch().Distro().Product(),
|
||||
OsVersion: t.Arch().Distro().OsVersion(),
|
||||
Arch: t.Arch().Name(),
|
||||
ImgTypeLabel: isoLabel,
|
||||
})
|
||||
if err != nil {
|
||||
// XXX: cleanup isoLabelFunc to allow error
|
||||
panic(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func newDistro(nameVer string) (distro.Distro, error) {
|
||||
distroYAML, err := defs.Distro(nameVer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if distroYAML == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rd := &distribution{
|
||||
DistroYAML: *distroYAML,
|
||||
|
||||
defaultImageConfig: common.Must(defs.DistroImageConfig(nameVer)),
|
||||
arches: make(map[string]*architecture),
|
||||
}
|
||||
|
||||
its, err := defs.ImageTypes(rd.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, imgTypeYAML := range its {
|
||||
// use as marker for images that are not converted to
|
||||
// YAML yet
|
||||
if imgTypeYAML.Filename == "" {
|
||||
continue
|
||||
}
|
||||
for _, pl := range imgTypeYAML.Platforms {
|
||||
ar, ok := rd.arches[pl.Arch.String()]
|
||||
if !ok {
|
||||
ar = newArchitecture(rd, pl.Arch.String())
|
||||
rd.arches[pl.Arch.String()] = ar
|
||||
}
|
||||
it := newImageTypeFrom(rd, ar, imgTypeYAML)
|
||||
if err := ar.addImageType(&pl, it); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rd, nil
|
||||
}
|
||||
|
||||
func (d *distribution) Name() string {
|
||||
return d.DistroYAML.Name
|
||||
}
|
||||
|
||||
func (d *distribution) Codename() string {
|
||||
return d.DistroYAML.Codename
|
||||
}
|
||||
|
||||
func (d *distribution) Releasever() string {
|
||||
return d.DistroYAML.ReleaseVersion
|
||||
}
|
||||
|
||||
func (d *distribution) OsVersion() string {
|
||||
return d.DistroYAML.OsVersion
|
||||
}
|
||||
|
||||
func (d *distribution) Product() string {
|
||||
return d.DistroYAML.Product
|
||||
}
|
||||
|
||||
func (d *distribution) ModulePlatformID() string {
|
||||
return d.DistroYAML.ModulePlatformID
|
||||
}
|
||||
|
||||
func (d *distribution) OSTreeRef() string {
|
||||
return d.DistroYAML.OSTreeRefTmpl
|
||||
}
|
||||
|
||||
func (d *distribution) ListArches() []string {
|
||||
archNames := make([]string, 0, len(d.arches))
|
||||
for name := range d.arches {
|
||||
archNames = append(archNames, name)
|
||||
}
|
||||
sort.Strings(archNames)
|
||||
return archNames
|
||||
}
|
||||
|
||||
func (d *distribution) GetArch(name string) (distro.Arch, error) {
|
||||
arch, exists := d.arches[name]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("invalid architecture: %v", name)
|
||||
}
|
||||
return arch, nil
|
||||
}
|
||||
|
||||
// architecture implements the distro.Arch interface
|
||||
var _ = distro.Arch(&architecture{})
|
||||
|
||||
type architecture struct {
|
||||
distro *distribution
|
||||
name string
|
||||
imageTypes map[string]distro.ImageType
|
||||
imageTypeAliases map[string]string
|
||||
}
|
||||
|
||||
func newArchitecture(rd *distribution, name string) *architecture {
|
||||
return &architecture{
|
||||
distro: rd,
|
||||
name: name,
|
||||
imageTypes: make(map[string]distro.ImageType),
|
||||
imageTypeAliases: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *architecture) Name() string {
|
||||
return a.name
|
||||
}
|
||||
|
||||
func (a *architecture) ListImageTypes() []string {
|
||||
itNames := make([]string, 0, len(a.imageTypes))
|
||||
for name := range a.imageTypes {
|
||||
itNames = append(itNames, name)
|
||||
}
|
||||
sort.Strings(itNames)
|
||||
return itNames
|
||||
}
|
||||
|
||||
func (a *architecture) GetImageType(name string) (distro.ImageType, error) {
|
||||
t, exists := a.imageTypes[name]
|
||||
if !exists {
|
||||
aliasForName, exists := a.imageTypeAliases[name]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("invalid image type: %v", name)
|
||||
}
|
||||
t, exists = a.imageTypes[aliasForName]
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("image type '%s' is an alias to a non-existing image type '%s'", name, aliasForName))
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (a *architecture) addImageType(platform platform.Platform, it imageType) error {
|
||||
it.arch = a
|
||||
it.platform = platform
|
||||
a.imageTypes[it.Name()] = &it
|
||||
for _, alias := range it.ImageTypeYAML.NameAliases {
|
||||
if a.imageTypeAliases == nil {
|
||||
a.imageTypeAliases = map[string]string{}
|
||||
}
|
||||
if existingAliasFor, exists := a.imageTypeAliases[alias]; exists {
|
||||
return fmt.Errorf("image type alias '%s' for '%s' is already defined for another image type '%s'", alias, it.Name(), existingAliasFor)
|
||||
}
|
||||
a.imageTypeAliases[alias] = it.Name()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *architecture) Distro() distro.Distro {
|
||||
return a.distro
|
||||
}
|
||||
|
||||
func DistroFactory(idStr string) distro.Distro {
|
||||
distro, err := newDistro(idStr)
|
||||
if errors.Is(err, ErrDistroNotFound) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return distro
|
||||
}
|
||||
48
vendor/github.com/osbuild/images/pkg/distro/generic/imagedefs.go
generated
vendored
Normal file
48
vendor/github.com/osbuild/images/pkg/distro/generic/imagedefs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package generic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/pkg/distro/defs"
|
||||
)
|
||||
|
||||
func newImageTypeFrom(d *distribution, ar *architecture, imgYAML defs.ImageTypeYAML) imageType {
|
||||
typName := imgYAML.Name()
|
||||
it := imageType{
|
||||
ImageTypeYAML: imgYAML,
|
||||
isoLabel: d.getISOLabelFunc(imgYAML.ISOLabel),
|
||||
}
|
||||
it.defaultImageConfig = common.Must(defs.ImageConfig(d.Name(), ar.name, typName))
|
||||
it.defaultInstallerConfig = common.Must(defs.InstallerConfig(d.Name(), ar.name, typName))
|
||||
|
||||
switch imgYAML.Image {
|
||||
case "disk":
|
||||
it.image = diskImage
|
||||
case "container":
|
||||
it.image = containerImage
|
||||
case "image_installer":
|
||||
it.image = imageInstallerImage
|
||||
case "live_installer":
|
||||
it.image = liveInstallerImage
|
||||
case "bootable_container":
|
||||
it.image = bootableContainerImage
|
||||
case "iot":
|
||||
it.image = iotImage
|
||||
case "iot_commit":
|
||||
it.image = iotCommitImage
|
||||
case "iot_container":
|
||||
it.image = iotContainerImage
|
||||
case "iot_installer":
|
||||
it.image = iotInstallerImage
|
||||
case "iot_simplified_installer":
|
||||
it.image = iotSimplifiedInstallerImage
|
||||
case "tar":
|
||||
it.image = tarImage
|
||||
default:
|
||||
err := fmt.Errorf("unknown image func: %v for %v", imgYAML.Image, imgYAML.Name())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return it
|
||||
}
|
||||
977
vendor/github.com/osbuild/images/pkg/distro/generic/images.go
generated
vendored
Normal file
977
vendor/github.com/osbuild/images/pkg/distro/generic/images.go
generated
vendored
Normal file
|
|
@ -0,0 +1,977 @@
|
|||
package generic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/osbuild/images/internal/workload"
|
||||
"github.com/osbuild/images/pkg/arch"
|
||||
"github.com/osbuild/images/pkg/blueprint"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/customizations/anaconda"
|
||||
"github.com/osbuild/images/pkg/customizations/bootc"
|
||||
"github.com/osbuild/images/pkg/customizations/fdo"
|
||||
"github.com/osbuild/images/pkg/customizations/fsnode"
|
||||
"github.com/osbuild/images/pkg/customizations/ignition"
|
||||
"github.com/osbuild/images/pkg/customizations/kickstart"
|
||||
"github.com/osbuild/images/pkg/customizations/oscap"
|
||||
"github.com/osbuild/images/pkg/customizations/users"
|
||||
"github.com/osbuild/images/pkg/distro"
|
||||
"github.com/osbuild/images/pkg/image"
|
||||
"github.com/osbuild/images/pkg/manifest"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []container.SourceSpec, c *blueprint.Customizations) (manifest.OSCustomizations, error) {
|
||||
imageConfig := t.getDefaultImageConfig()
|
||||
|
||||
osc := manifest.OSCustomizations{}
|
||||
|
||||
if t.ImageTypeYAML.Bootable || t.ImageTypeYAML.RPMOSTree {
|
||||
osc.KernelName = c.GetKernel().Name
|
||||
|
||||
var kernelOptions []string
|
||||
// XXX: keep in sync with the identical copy in rhel/images.go
|
||||
if t.defaultImageConfig != nil && len(t.defaultImageConfig.KernelOptions) > 0 {
|
||||
kernelOptions = append(kernelOptions, t.defaultImageConfig.KernelOptions...)
|
||||
}
|
||||
if bpKernel := c.GetKernel(); bpKernel.Append != "" {
|
||||
kernelOptions = append(kernelOptions, bpKernel.Append)
|
||||
}
|
||||
osc.KernelOptionsAppend = kernelOptions
|
||||
}
|
||||
|
||||
osc.FIPS = c.GetFIPS()
|
||||
|
||||
osc.BasePackages = osPackageSet.Include
|
||||
osc.ExcludeBasePackages = osPackageSet.Exclude
|
||||
osc.ExtraBaseRepos = osPackageSet.Repositories
|
||||
|
||||
osc.Containers = containers
|
||||
|
||||
osc.GPGKeyFiles = imageConfig.GPGKeyFiles
|
||||
if rpm := c.GetRPM(); rpm != nil && rpm.ImportKeys != nil {
|
||||
osc.GPGKeyFiles = append(osc.GPGKeyFiles, rpm.ImportKeys.Files...)
|
||||
}
|
||||
|
||||
if imageConfig.ExcludeDocs != nil {
|
||||
osc.ExcludeDocs = *imageConfig.ExcludeDocs
|
||||
}
|
||||
|
||||
if !t.ImageTypeYAML.BootISO {
|
||||
// don't put users and groups in the payload of an installer
|
||||
// add them via kickstart instead
|
||||
osc.Groups = users.GroupsFromBP(c.GetGroups())
|
||||
|
||||
osc.Users = users.UsersFromBP(c.GetUsers())
|
||||
osc.Users = append(osc.Users, imageConfig.Users...)
|
||||
}
|
||||
|
||||
osc.EnabledServices = imageConfig.EnabledServices
|
||||
osc.DisabledServices = imageConfig.DisabledServices
|
||||
osc.MaskedServices = imageConfig.MaskedServices
|
||||
if imageConfig.DefaultTarget != nil {
|
||||
osc.DefaultTarget = *imageConfig.DefaultTarget
|
||||
}
|
||||
|
||||
if fw := c.GetFirewall(); fw != nil {
|
||||
options := osbuild.FirewallStageOptions{
|
||||
Ports: fw.Ports,
|
||||
}
|
||||
|
||||
if fw.Services != nil {
|
||||
options.EnabledServices = fw.Services.Enabled
|
||||
options.DisabledServices = fw.Services.Disabled
|
||||
}
|
||||
osc.Firewall = &options
|
||||
}
|
||||
|
||||
language, keyboard := c.GetPrimaryLocale()
|
||||
if language != nil {
|
||||
osc.Language = *language
|
||||
} else if imageConfig.Locale != nil {
|
||||
osc.Language = *imageConfig.Locale
|
||||
}
|
||||
if keyboard != nil {
|
||||
osc.Keyboard = keyboard
|
||||
} else if imageConfig.Keyboard != nil {
|
||||
osc.Keyboard = &imageConfig.Keyboard.Keymap
|
||||
}
|
||||
|
||||
if hostname := c.GetHostname(); hostname != nil {
|
||||
osc.Hostname = *hostname
|
||||
} else if imageConfig.Hostname != nil {
|
||||
osc.Hostname = *imageConfig.Hostname
|
||||
}
|
||||
|
||||
if imageConfig.InstallWeakDeps != nil {
|
||||
osc.InstallWeakDeps = *imageConfig.InstallWeakDeps
|
||||
}
|
||||
|
||||
timezone, ntpServers := c.GetTimezoneSettings()
|
||||
if timezone != nil {
|
||||
osc.Timezone = *timezone
|
||||
} else if imageConfig.Timezone != nil {
|
||||
osc.Timezone = *imageConfig.Timezone
|
||||
}
|
||||
|
||||
if len(ntpServers) > 0 {
|
||||
chronyServers := make([]osbuild.ChronyConfigServer, 0, len(ntpServers))
|
||||
for _, server := range ntpServers {
|
||||
chronyServers = append(chronyServers, osbuild.ChronyConfigServer{Hostname: server})
|
||||
}
|
||||
osc.ChronyConfig = &osbuild.ChronyStageOptions{
|
||||
Servers: chronyServers,
|
||||
}
|
||||
} else if imageConfig.TimeSynchronization != nil {
|
||||
osc.ChronyConfig = imageConfig.TimeSynchronization
|
||||
}
|
||||
|
||||
// Relabel the tree, unless the `NoSElinux` flag is explicitly set to `true`
|
||||
if imageConfig.NoSElinux == nil || imageConfig.NoSElinux != nil && !*imageConfig.NoSElinux {
|
||||
osc.SElinux = "targeted"
|
||||
}
|
||||
|
||||
var err error
|
||||
osc.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(c.GetDirectories())
|
||||
if err != nil {
|
||||
// In theory this should never happen, because the blueprint directory customizations
|
||||
// should have been validated before this point.
|
||||
panic(fmt.Sprintf("failed to convert directory customizations to fs node directories: %v", err))
|
||||
}
|
||||
|
||||
osc.Files, err = blueprint.FileCustomizationsToFsNodeFiles(c.GetFiles())
|
||||
if err != nil {
|
||||
// In theory this should never happen, because the blueprint file customizations
|
||||
// should have been validated before this point.
|
||||
panic(fmt.Sprintf("failed to convert file customizations to fs node files: %v", err))
|
||||
}
|
||||
|
||||
// OSTree commits do not include data in `/var` since that is tied to the
|
||||
// deployment, rather than the commit. Therefore the containers need to be
|
||||
// stored in a different location, like `/usr/share`, and the container
|
||||
// storage engine configured accordingly.
|
||||
if t.ImageTypeYAML.RPMOSTree && len(containers) > 0 {
|
||||
storagePath := "/usr/share/containers/storage"
|
||||
osc.ContainersStorage = &storagePath
|
||||
}
|
||||
|
||||
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
|
||||
osc.ContainersStorage = containerStorage.StoragePath
|
||||
}
|
||||
|
||||
customRepos, err := c.GetRepositories()
|
||||
if err != nil {
|
||||
// This shouldn't happen and since the repos
|
||||
// should have already been validated
|
||||
panic(fmt.Sprintf("failed to get custom repos: %v", err))
|
||||
}
|
||||
|
||||
// This function returns a map of filename and corresponding yum repos
|
||||
// and a list of fs node files for the inline gpg keys so we can save
|
||||
// them to disk. This step also swaps the inline gpg key with the path
|
||||
// to the file in the os file tree
|
||||
yumRepos, gpgKeyFiles, err := blueprint.RepoCustomizationsToRepoConfigAndGPGKeyFiles(customRepos)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to convert inline gpgkeys to fs node files: %v", err))
|
||||
}
|
||||
|
||||
// add the gpg key files to the list of files to be added to the tree
|
||||
if len(gpgKeyFiles) > 0 {
|
||||
osc.Files = append(osc.Files, gpgKeyFiles...)
|
||||
}
|
||||
|
||||
for filename, repos := range yumRepos {
|
||||
osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos))
|
||||
}
|
||||
|
||||
if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil {
|
||||
if t.ImageTypeYAML.RPMOSTree {
|
||||
panic("unexpected oscap options for ostree image type")
|
||||
}
|
||||
|
||||
oscapDataNode, err := fsnode.NewDirectory(oscap.DataDir, nil, nil, nil, true)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unexpected error creating required OpenSCAP directory: %s", oscap.DataDir))
|
||||
}
|
||||
osc.Directories = append(osc.Directories, oscapDataNode)
|
||||
|
||||
remediationConfig, err := oscap.NewConfigs(*oscapConfig, imageConfig.DefaultOSCAPDatastream)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error creating OpenSCAP configs: %w", err))
|
||||
}
|
||||
|
||||
osc.OpenSCAPRemediationConfig = remediationConfig
|
||||
}
|
||||
|
||||
osc.ShellInit = imageConfig.ShellInit
|
||||
|
||||
osc.Grub2Config = imageConfig.Grub2Config
|
||||
osc.Sysconfig = imageConfig.SysconfigStageOptions()
|
||||
osc.SystemdLogind = imageConfig.SystemdLogind
|
||||
osc.CloudInit = imageConfig.CloudInit
|
||||
osc.Modprobe = imageConfig.Modprobe
|
||||
osc.DracutConf = imageConfig.DracutConf
|
||||
osc.SystemdDropin = imageConfig.SystemdDropin
|
||||
osc.SystemdUnit = imageConfig.SystemdUnit
|
||||
osc.Authselect = imageConfig.Authselect
|
||||
osc.SELinuxConfig = imageConfig.SELinuxConfig
|
||||
osc.Tuned = imageConfig.Tuned
|
||||
osc.Tmpfilesd = imageConfig.Tmpfilesd
|
||||
osc.PamLimitsConf = imageConfig.PamLimitsConf
|
||||
osc.Sysctld = imageConfig.Sysctld
|
||||
osc.DNFConfig = imageConfig.DNFConfigOptions(t.arch.distro.OsVersion())
|
||||
osc.SshdConfig = imageConfig.SshdConfig
|
||||
osc.AuthConfig = imageConfig.Authconfig
|
||||
osc.PwQuality = imageConfig.PwQuality
|
||||
osc.WSLConfig = imageConfig.WSLConfStageOptions()
|
||||
osc.NetworkManager = imageConfig.NetworkManager
|
||||
|
||||
osc.Files = append(osc.Files, imageConfig.Files...)
|
||||
osc.Directories = append(osc.Directories, imageConfig.Directories...)
|
||||
|
||||
ca, err := c.GetCACerts()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unexpected error checking CA certs: %v", err))
|
||||
}
|
||||
if ca != nil {
|
||||
osc.CACerts = ca.PEMCerts
|
||||
}
|
||||
|
||||
if imageConfig.MachineIdUninitialized != nil {
|
||||
osc.MachineIdUninitialized = *imageConfig.MachineIdUninitialized
|
||||
}
|
||||
|
||||
if imageConfig.MountUnits != nil {
|
||||
osc.MountUnits = *imageConfig.MountUnits
|
||||
}
|
||||
|
||||
return osc, nil
|
||||
}
|
||||
|
||||
func ostreeDeploymentCustomizations(
|
||||
t *imageType,
|
||||
c *blueprint.Customizations) (manifest.OSTreeDeploymentCustomizations, error) {
|
||||
|
||||
if !t.ImageTypeYAML.RPMOSTree || !t.ImageTypeYAML.Bootable {
|
||||
return manifest.OSTreeDeploymentCustomizations{}, fmt.Errorf("ostree deployment customizations are only supported for bootable rpm-ostree images")
|
||||
}
|
||||
|
||||
imageConfig := t.getDefaultImageConfig()
|
||||
deploymentConf := manifest.OSTreeDeploymentCustomizations{}
|
||||
|
||||
var kernelOptions []string
|
||||
if len(t.defaultImageConfig.KernelOptions) > 0 {
|
||||
kernelOptions = append(kernelOptions, t.defaultImageConfig.KernelOptions...)
|
||||
}
|
||||
if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" {
|
||||
kernelOptions = append(kernelOptions, bpKernel.Append)
|
||||
}
|
||||
|
||||
if imageConfig.IgnitionPlatform != nil {
|
||||
deploymentConf.IgnitionPlatform = *imageConfig.IgnitionPlatform
|
||||
}
|
||||
|
||||
switch deploymentConf.IgnitionPlatform {
|
||||
case "metal":
|
||||
if bpIgnition := c.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
|
||||
kernelOptions = append(kernelOptions, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
|
||||
}
|
||||
}
|
||||
deploymentConf.KernelOptionsAppend = kernelOptions
|
||||
|
||||
deploymentConf.FIPS = c.GetFIPS()
|
||||
|
||||
deploymentConf.Users = users.UsersFromBP(c.GetUsers())
|
||||
deploymentConf.Groups = users.GroupsFromBP(c.GetGroups())
|
||||
|
||||
var err error
|
||||
deploymentConf.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(c.GetDirectories())
|
||||
if err != nil {
|
||||
return manifest.OSTreeDeploymentCustomizations{}, err
|
||||
}
|
||||
deploymentConf.Files, err = blueprint.FileCustomizationsToFsNodeFiles(c.GetFiles())
|
||||
if err != nil {
|
||||
return manifest.OSTreeDeploymentCustomizations{}, err
|
||||
}
|
||||
|
||||
language, keyboard := c.GetPrimaryLocale()
|
||||
if language != nil {
|
||||
deploymentConf.Locale = *language
|
||||
} else if imageConfig.Locale != nil {
|
||||
deploymentConf.Locale = *imageConfig.Locale
|
||||
}
|
||||
if keyboard != nil {
|
||||
deploymentConf.Keyboard = *keyboard
|
||||
} else if imageConfig.Keyboard != nil {
|
||||
deploymentConf.Keyboard = imageConfig.Keyboard.Keymap
|
||||
}
|
||||
|
||||
if imageConfig.OSTreeConfSysrootReadOnly != nil {
|
||||
deploymentConf.SysrootReadOnly = *imageConfig.OSTreeConfSysrootReadOnly
|
||||
}
|
||||
|
||||
if imageConfig.LockRootUser != nil {
|
||||
deploymentConf.LockRoot = *imageConfig.LockRootUser
|
||||
}
|
||||
|
||||
for _, fs := range c.GetFilesystems() {
|
||||
deploymentConf.CustomFileSystems = append(deploymentConf.CustomFileSystems, fs.Mountpoint)
|
||||
}
|
||||
|
||||
return deploymentConf, nil
|
||||
}
|
||||
|
||||
// IMAGES
|
||||
|
||||
func diskImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
img := image.NewDiskImage()
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
img.Compression = t.ImageTypeYAML.Compression
|
||||
if bp.Minimal {
|
||||
// Disable weak dependencies if the 'minimal' option is enabled
|
||||
img.OSCustomizations.InstallWeakDeps = false
|
||||
}
|
||||
// TODO: move generation into LiveImage
|
||||
pt, err := t.getPartitionTable(bp.Customizations, options, rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.PartitionTable = pt
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func tarImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
img := image.NewArchive()
|
||||
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func containerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
img := image.NewBaseContainer()
|
||||
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func liveInstallerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
img := image.NewAnacondaLiveInstaller()
|
||||
|
||||
img.Platform = t.platform
|
||||
img.Workload = workload
|
||||
img.ExtraBasePackages = packageSets[installerPkgsKey]
|
||||
|
||||
d := t.arch.distro
|
||||
|
||||
img.Product = d.Product()
|
||||
img.Variant = "Workstation"
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.Release = fmt.Sprintf("%s %s", d.DistroYAML.Product, d.OsVersion())
|
||||
img.Preview = d.DistroYAML.Preview
|
||||
|
||||
var err error
|
||||
img.ISOLabel, err = t.ISOLabel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
// Enable grub2 BIOS iso on x86_64 only
|
||||
if img.Platform.GetArch() == arch.ARCH_X86_64 {
|
||||
img.ISOBoot = manifest.Grub2ISOBoot
|
||||
}
|
||||
|
||||
if locale := t.getDefaultImageConfig().Locale; locale != nil {
|
||||
img.Locale = *locale
|
||||
}
|
||||
|
||||
installerConfig, err := t.getDefaultInstallerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if installerConfig != nil {
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
|
||||
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
|
||||
if installerConfig.SquashfsRootfs != nil && *installerConfig.SquashfsRootfs {
|
||||
img.RootfsType = manifest.SquashfsRootfs
|
||||
}
|
||||
}
|
||||
|
||||
imgConfig := t.getDefaultImageConfig()
|
||||
if imgConfig != nil && imgConfig.IsoRootfsType != nil {
|
||||
img.RootfsType = *imgConfig.IsoRootfsType
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func imageInstallerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
customizations := bp.Customizations
|
||||
|
||||
img := image.NewAnacondaTarInstaller()
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Kickstart, err = kickstart.New(customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.Kickstart.Language = &img.OSCustomizations.Language
|
||||
img.Kickstart.Keyboard = img.OSCustomizations.Keyboard
|
||||
img.Kickstart.Timezone = &img.OSCustomizations.Timezone
|
||||
|
||||
if img.Kickstart.Unattended {
|
||||
// NOTE: this is not supported right now because the
|
||||
// image-installer on Fedora isn't working when unattended.
|
||||
// These options are probably necessary but could change.
|
||||
// Unattended/non-interactive installations are better set to text
|
||||
// time since they might be running headless and a UI is
|
||||
// unnecessary.
|
||||
img.AdditionalKernelOpts = []string{"inst.text", "inst.noninteractive"}
|
||||
}
|
||||
|
||||
instCust, err := customizations.GetInstaller()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if instCust != nil && instCust.Modules != nil {
|
||||
img.AdditionalAnacondaModules = append(img.AdditionalAnacondaModules, instCust.Modules.Enable...)
|
||||
img.DisabledAnacondaModules = append(img.DisabledAnacondaModules, instCust.Modules.Disable...)
|
||||
}
|
||||
img.AdditionalAnacondaModules = append(img.AdditionalAnacondaModules, anaconda.ModuleUsers)
|
||||
|
||||
img.Platform = t.platform
|
||||
img.Workload = workload
|
||||
|
||||
img.ExtraBasePackages = packageSets[installerPkgsKey]
|
||||
|
||||
installerConfig, err := t.getDefaultInstallerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if installerConfig != nil {
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
|
||||
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
|
||||
if installerConfig.SquashfsRootfs != nil && *installerConfig.SquashfsRootfs {
|
||||
img.RootfsType = manifest.SquashfsRootfs
|
||||
}
|
||||
}
|
||||
|
||||
d := t.arch.distro
|
||||
|
||||
img.Product = d.DistroYAML.Product
|
||||
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.Release = fmt.Sprintf("%s %s", d.DistroYAML.Product, d.OsVersion())
|
||||
img.Variant = t.Variant
|
||||
img.Preview = d.DistroYAML.Preview
|
||||
|
||||
img.ISOLabel, err = t.ISOLabel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
img.RootfsCompression = "xz" // This also triggers using the bcj filter
|
||||
imgConfig := t.getDefaultImageConfig()
|
||||
if imgConfig != nil && imgConfig.IsoRootfsType != nil {
|
||||
img.RootfsType = *imgConfig.IsoRootfsType
|
||||
}
|
||||
|
||||
// Enable grub2 BIOS iso on x86_64 only
|
||||
if img.Platform.GetArch() == arch.ARCH_X86_64 {
|
||||
img.ISOBoot = manifest.Grub2ISOBoot
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func iotCommitImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
|
||||
img := image.NewOSTreeArchive(commitRef)
|
||||
|
||||
d := t.arch.distro
|
||||
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// see https://github.com/ostreedev/ostree/issues/2840
|
||||
img.OSCustomizations.Presets = []osbuild.Preset{
|
||||
{
|
||||
Name: "ignition-firstboot-complete.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
{
|
||||
Name: "coreos-ignition-write-issues.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
{
|
||||
Name: "fdo-client-linuxapp.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
}
|
||||
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
img.OSTreeParent = parentCommit
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.Filename = t.Filename()
|
||||
img.InstallWeakDeps = false
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func bootableContainerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
|
||||
img := image.NewOSTreeArchive(commitRef)
|
||||
|
||||
d := t.arch.distro
|
||||
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
img.OSTreeParent = parentCommit
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.Filename = t.Filename()
|
||||
img.InstallWeakDeps = false
|
||||
img.BootContainer = true
|
||||
id, err := distro.ParseID(d.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.BootcConfig = &bootc.Config{
|
||||
Filename: fmt.Sprintf("20-%s.toml", id.Name),
|
||||
RootFilesystemType: "ext4",
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func iotContainerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
|
||||
img := image.NewOSTreeContainer(commitRef)
|
||||
d := t.arch.distro
|
||||
img.Platform = t.platform
|
||||
|
||||
var err error
|
||||
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// see https://github.com/ostreedev/ostree/issues/2840
|
||||
img.OSCustomizations.Presets = []osbuild.Preset{
|
||||
{
|
||||
Name: "ignition-firstboot-complete.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
{
|
||||
Name: "coreos-ignition-write-issues.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
{
|
||||
Name: "fdo-client-linuxapp.service",
|
||||
State: osbuild.StateEnable,
|
||||
},
|
||||
}
|
||||
|
||||
img.ContainerLanguage = img.OSCustomizations.Language
|
||||
img.Environment = &t.ImageTypeYAML.Environment
|
||||
img.Workload = workload
|
||||
img.OSTreeParent = parentCommit
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.ExtraContainerPackages = packageSets[containerPkgsKey]
|
||||
img.Filename = t.Filename()
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func iotInstallerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
d := t.arch.distro
|
||||
|
||||
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
|
||||
}
|
||||
|
||||
img := image.NewAnacondaOSTreeInstaller(commit)
|
||||
|
||||
customizations := bp.Customizations
|
||||
img.FIPS = customizations.GetFIPS()
|
||||
img.Platform = t.platform
|
||||
img.ExtraBasePackages = packageSets[installerPkgsKey]
|
||||
|
||||
img.Kickstart, err = kickstart.New(customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.Kickstart.OSTree = &kickstart.OSTree{
|
||||
OSName: t.OSTree.Name,
|
||||
Remote: t.OSTree.Remote,
|
||||
}
|
||||
img.Kickstart.Path = osbuild.KickstartPathOSBuild
|
||||
img.Kickstart.Language, img.Kickstart.Keyboard = customizations.GetPrimaryLocale()
|
||||
// ignore ntp servers - we don't currently support setting these in the
|
||||
// kickstart though kickstart does support setting them
|
||||
img.Kickstart.Timezone, _ = customizations.GetTimezoneSettings()
|
||||
|
||||
instCust, err := customizations.GetInstaller()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if instCust != nil && instCust.Modules != nil {
|
||||
img.AdditionalAnacondaModules = append(img.AdditionalAnacondaModules, instCust.Modules.Enable...)
|
||||
img.DisabledAnacondaModules = append(img.DisabledAnacondaModules, instCust.Modules.Disable...)
|
||||
}
|
||||
|
||||
img.AdditionalAnacondaModules = append(img.AdditionalAnacondaModules, []string{
|
||||
anaconda.ModuleTimezone,
|
||||
anaconda.ModuleLocalization,
|
||||
anaconda.ModuleUsers,
|
||||
}...)
|
||||
|
||||
installerConfig, err := t.getDefaultInstallerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if installerConfig != nil {
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
|
||||
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
|
||||
if installerConfig.SquashfsRootfs != nil && *installerConfig.SquashfsRootfs {
|
||||
img.RootfsType = manifest.SquashfsRootfs
|
||||
}
|
||||
}
|
||||
|
||||
// On Fedora anaconda needs dbus-broker, but isn't added when dracut runs.
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, "dbus-broker")
|
||||
|
||||
img.Product = d.DistroYAML.Product
|
||||
img.Variant = "IoT"
|
||||
img.OSVersion = d.OsVersion()
|
||||
img.Release = fmt.Sprintf("%s %s", d.DistroYAML.Product, d.OsVersion())
|
||||
img.Preview = d.DistroYAML.Preview
|
||||
|
||||
img.ISOLabel, err = t.ISOLabel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img.Filename = t.Filename()
|
||||
|
||||
img.RootfsCompression = "xz" // This also triggers using the bcj filter
|
||||
imgConfig := t.getDefaultImageConfig()
|
||||
if imgConfig != nil && imgConfig.IsoRootfsType != nil {
|
||||
img.RootfsType = *imgConfig.IsoRootfsType
|
||||
}
|
||||
|
||||
// Enable grub2 BIOS iso on x86_64 only
|
||||
if img.Platform.GetArch() == arch.ARCH_X86_64 {
|
||||
img.ISOBoot = manifest.Grub2ISOBoot
|
||||
}
|
||||
|
||||
if locale := t.getDefaultImageConfig().Locale; locale != nil {
|
||||
img.Locale = *locale
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func iotImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
|
||||
}
|
||||
img := image.NewOSTreeDiskImageFromCommit(commit)
|
||||
|
||||
customizations := bp.Customizations
|
||||
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.OSTreeDeploymentCustomizations = deploymentConfig
|
||||
|
||||
img.Platform = t.platform
|
||||
img.Workload = workload
|
||||
|
||||
img.Remote = ostree.Remote{
|
||||
Name: t.OSTree.Remote,
|
||||
}
|
||||
img.OSName = t.OSTree.Remote
|
||||
|
||||
// TODO: move generation into LiveImage
|
||||
pt, err := t.getPartitionTable(customizations, options, rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.PartitionTable = pt
|
||||
|
||||
img.Filename = t.Filename()
|
||||
img.Compression = t.ImageTypeYAML.Compression
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func iotSimplifiedInstallerImage(workload workload.Workload,
|
||||
t *imageType,
|
||||
bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
packageSets map[string]rpmmd.PackageSet,
|
||||
containers []container.SourceSpec,
|
||||
rng *rand.Rand) (image.ImageKind, error) {
|
||||
|
||||
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
|
||||
}
|
||||
rawImg := image.NewOSTreeDiskImageFromCommit(commit)
|
||||
|
||||
customizations := bp.Customizations
|
||||
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawImg.OSTreeDeploymentCustomizations = deploymentConfig
|
||||
|
||||
rawImg.Platform = t.platform
|
||||
rawImg.Workload = workload
|
||||
rawImg.Remote = ostree.Remote{
|
||||
Name: t.OSTree.Remote,
|
||||
}
|
||||
rawImg.OSName = t.OSTree.Name
|
||||
|
||||
// TODO: move generation into LiveImage
|
||||
pt, err := t.getPartitionTable(customizations, options, rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawImg.PartitionTable = pt
|
||||
|
||||
rawImg.Filename = t.Filename()
|
||||
|
||||
img := image.NewOSTreeSimplifiedInstaller(rawImg, customizations.InstallationDevice)
|
||||
img.ExtraBasePackages = packageSets[installerPkgsKey]
|
||||
// img.Workload = workload
|
||||
img.Platform = t.platform
|
||||
img.Filename = t.Filename()
|
||||
if bpFDO := customizations.GetFDO(); bpFDO != nil {
|
||||
img.FDO = fdo.FromBP(*bpFDO)
|
||||
}
|
||||
// ignition configs from blueprint
|
||||
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil {
|
||||
if bpIgnition.Embedded != nil {
|
||||
var err error
|
||||
img.IgnitionEmbedded, err = ignition.EmbeddedOptionsFromBP(*bpIgnition.Embedded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
installerConfig, err := t.getDefaultInstallerConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if installerConfig != nil {
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
|
||||
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
|
||||
}
|
||||
|
||||
img.AdditionalDracutModules = append(img.AdditionalDracutModules, "dbus-broker")
|
||||
|
||||
d := t.arch.distro
|
||||
img.Product = d.DistroYAML.Product
|
||||
img.Variant = "IoT"
|
||||
img.OSName = t.OSTree.Name
|
||||
img.OSVersion = d.OsVersion()
|
||||
|
||||
img.ISOLabel, err = t.ISOLabel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// Create an ostree SourceSpec to define an ostree parent commit using the user
|
||||
// options and the default ref for the image type. Additionally returns the
|
||||
// ref to be used for the new commit to be created.
|
||||
func makeOSTreeParentCommit(options *ostree.ImageOptions, defaultRef string) (*ostree.SourceSpec, string) {
|
||||
commitRef := defaultRef
|
||||
if options == nil {
|
||||
// nothing to do
|
||||
return nil, commitRef
|
||||
}
|
||||
if options.ImageRef != "" {
|
||||
// user option overrides default commit ref
|
||||
commitRef = options.ImageRef
|
||||
}
|
||||
|
||||
var parentCommit *ostree.SourceSpec
|
||||
if options.URL == "" {
|
||||
// no parent
|
||||
return nil, commitRef
|
||||
}
|
||||
|
||||
// ostree URL specified: set source spec for parent commit
|
||||
parentRef := options.ParentRef
|
||||
if parentRef == "" {
|
||||
// parent ref not set: use image ref
|
||||
parentRef = commitRef
|
||||
|
||||
}
|
||||
parentCommit = &ostree.SourceSpec{
|
||||
URL: options.URL,
|
||||
Ref: parentRef,
|
||||
RHSM: options.RHSM,
|
||||
}
|
||||
return parentCommit, commitRef
|
||||
}
|
||||
|
||||
// Create an ostree SourceSpec to define an ostree payload using the user options and the default ref for the image type.
|
||||
func makeOSTreePayloadCommit(options *ostree.ImageOptions, defaultRef string) (ostree.SourceSpec, error) {
|
||||
if options == nil || options.URL == "" {
|
||||
// this should be caught by checkOptions() in distro, but it's good
|
||||
// to guard against it here as well
|
||||
return ostree.SourceSpec{}, fmt.Errorf("ostree commit URL required")
|
||||
}
|
||||
|
||||
commitRef := defaultRef
|
||||
if options.ImageRef != "" {
|
||||
// user option overrides default commit ref
|
||||
commitRef = options.ImageRef
|
||||
}
|
||||
|
||||
return ostree.SourceSpec{
|
||||
URL: options.URL,
|
||||
Ref: commitRef,
|
||||
RHSM: options.RHSM,
|
||||
}, nil
|
||||
}
|
||||
515
vendor/github.com/osbuild/images/pkg/distro/generic/imagetype.go
generated
vendored
Normal file
515
vendor/github.com/osbuild/images/pkg/distro/generic/imagetype.go
generated
vendored
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
package generic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"slices"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/internal/workload"
|
||||
"github.com/osbuild/images/pkg/arch"
|
||||
"github.com/osbuild/images/pkg/blueprint"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/customizations/oscap"
|
||||
"github.com/osbuild/images/pkg/datasizes"
|
||||
"github.com/osbuild/images/pkg/disk"
|
||||
"github.com/osbuild/images/pkg/distro"
|
||||
"github.com/osbuild/images/pkg/distro/defs"
|
||||
"github.com/osbuild/images/pkg/experimentalflags"
|
||||
"github.com/osbuild/images/pkg/image"
|
||||
"github.com/osbuild/images/pkg/manifest"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/policies"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
type imageFunc func(workload workload.Workload, t *imageType, bp *blueprint.Blueprint, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error)
|
||||
|
||||
type isoLabelFunc func(t *imageType) string
|
||||
|
||||
// imageType implements the distro.ImageType interface
|
||||
var _ = distro.ImageType(&imageType{})
|
||||
|
||||
type imageType struct {
|
||||
defs.ImageTypeYAML
|
||||
|
||||
arch *architecture
|
||||
platform platform.Platform
|
||||
|
||||
// XXX: make definable via YAML
|
||||
workload workload.Workload
|
||||
// XXX: make member function ImageTypeYAML
|
||||
defaultImageConfig *distro.ImageConfig
|
||||
defaultInstallerConfig *distro.InstallerConfig
|
||||
|
||||
image imageFunc
|
||||
isoLabel isoLabelFunc
|
||||
}
|
||||
|
||||
func (t *imageType) Name() string {
|
||||
return t.ImageTypeYAML.Name()
|
||||
}
|
||||
|
||||
func (t *imageType) Arch() distro.Arch {
|
||||
return t.arch
|
||||
}
|
||||
|
||||
func (t *imageType) Filename() string {
|
||||
return t.ImageTypeYAML.Filename
|
||||
}
|
||||
|
||||
func (t *imageType) MIMEType() string {
|
||||
return t.ImageTypeYAML.MimeType
|
||||
}
|
||||
|
||||
func (t *imageType) OSTreeRef() string {
|
||||
d := t.arch.distro
|
||||
if t.ImageTypeYAML.RPMOSTree {
|
||||
return fmt.Sprintf(d.OSTreeRef(), t.arch.Name())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *imageType) ISOLabel() (string, error) {
|
||||
if !t.ImageTypeYAML.BootISO {
|
||||
return "", fmt.Errorf("image type %q is not an ISO", t.Name())
|
||||
}
|
||||
|
||||
if t.isoLabel != nil {
|
||||
return t.isoLabel(t), nil
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (t *imageType) Size(size uint64) uint64 {
|
||||
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
|
||||
if t.ImageTypeYAML.Name() == "vhd" && size%datasizes.MebiByte != 0 {
|
||||
size = (size/datasizes.MebiByte + 1) * datasizes.MebiByte
|
||||
}
|
||||
if size == 0 {
|
||||
size = t.ImageTypeYAML.DefaultSize
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (t *imageType) BuildPipelines() []string {
|
||||
return t.ImageTypeYAML.BuildPipelines
|
||||
}
|
||||
|
||||
func (t *imageType) PayloadPipelines() []string {
|
||||
return t.ImageTypeYAML.PayloadPipelines
|
||||
}
|
||||
|
||||
func (t *imageType) PayloadPackageSets() []string {
|
||||
return []string{blueprintPkgsKey}
|
||||
}
|
||||
|
||||
func (t *imageType) Exports() []string {
|
||||
if len(t.ImageTypeYAML.Exports) > 0 {
|
||||
return t.ImageTypeYAML.Exports
|
||||
}
|
||||
return []string{"assembler"}
|
||||
}
|
||||
|
||||
func (t *imageType) BootMode() platform.BootMode {
|
||||
if t.platform.GetUEFIVendor() != "" && t.platform.GetBIOSPlatform() != "" {
|
||||
return platform.BOOT_HYBRID
|
||||
} else if t.platform.GetUEFIVendor() != "" {
|
||||
return platform.BOOT_UEFI
|
||||
} else if t.platform.GetBIOSPlatform() != "" || t.platform.GetZiplSupport() {
|
||||
return platform.BOOT_LEGACY
|
||||
}
|
||||
return platform.BOOT_NONE
|
||||
}
|
||||
|
||||
func (t *imageType) BasePartitionTable() (*disk.PartitionTable, error) {
|
||||
return defs.PartitionTable(t)
|
||||
}
|
||||
|
||||
func (t *imageType) getPartitionTable(customizations *blueprint.Customizations, options distro.ImageOptions, rng *rand.Rand) (*disk.PartitionTable, error) {
|
||||
basePartitionTable, err := t.BasePartitionTable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imageSize := t.Size(options.Size)
|
||||
partitioning, err := customizations.GetPartitioning()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if partitioning != nil {
|
||||
// Use the new custom partition table to create a PT fully based on the user's customizations.
|
||||
// This overrides FilesystemCustomizations, but we should never have both defined.
|
||||
if options.Size > 0 {
|
||||
// user specified a size on the command line, so let's override the
|
||||
// customization with the calculated/rounded imageSize
|
||||
partitioning.MinSize = imageSize
|
||||
}
|
||||
|
||||
partOptions := &disk.CustomPartitionTableOptions{
|
||||
PartitionTableType: basePartitionTable.Type, // PT type is not customizable, it is determined by the base PT for an image type or architecture
|
||||
BootMode: t.BootMode(),
|
||||
DefaultFSType: t.arch.distro.DefaultFSType,
|
||||
RequiredMinSizes: t.ImageTypeYAML.RequiredPartitionSizes,
|
||||
Architecture: t.platform.GetArch(),
|
||||
}
|
||||
return disk.NewCustomPartitionTable(partitioning, partOptions, rng)
|
||||
}
|
||||
|
||||
partitioningMode := options.PartitioningMode
|
||||
if t.ImageTypeYAML.RPMOSTree {
|
||||
// IoT supports only LVM, force it.
|
||||
// Raw is not supported, return an error if it is requested
|
||||
// TODO Need a central location for logic like this
|
||||
if partitioningMode == disk.RawPartitioningMode {
|
||||
return nil, fmt.Errorf("partitioning mode raw not supported for %s on %s", t.Name(), t.arch.Name())
|
||||
}
|
||||
partitioningMode = disk.AutoLVMPartitioningMode
|
||||
}
|
||||
|
||||
mountpoints := customizations.GetFilesystems()
|
||||
return disk.NewPartitionTable(basePartitionTable, mountpoints, imageSize, partitioningMode, t.platform.GetArch(), t.ImageTypeYAML.RequiredPartitionSizes, rng)
|
||||
}
|
||||
|
||||
func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
|
||||
// ensure that image always returns non-nil default config
|
||||
imageConfig := t.defaultImageConfig
|
||||
if imageConfig == nil {
|
||||
imageConfig = &distro.ImageConfig{}
|
||||
}
|
||||
return imageConfig.InheritFrom(t.arch.distro.defaultImageConfig)
|
||||
|
||||
}
|
||||
|
||||
func (t *imageType) getDefaultInstallerConfig() (*distro.InstallerConfig, error) {
|
||||
if !t.ImageTypeYAML.BootISO {
|
||||
return nil, fmt.Errorf("image type %q is not an ISO", t.Name())
|
||||
}
|
||||
|
||||
return t.defaultInstallerConfig, nil
|
||||
}
|
||||
|
||||
func (t *imageType) PartitionType() disk.PartitionTableType {
|
||||
basePartitionTable, err := t.BasePartitionTable()
|
||||
if errors.Is(err, defs.ErrNoPartitionTableForImgType) {
|
||||
return disk.PT_NONE
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return basePartitionTable.Type
|
||||
}
|
||||
|
||||
func (t *imageType) Manifest(bp *blueprint.Blueprint,
|
||||
options distro.ImageOptions,
|
||||
repos []rpmmd.RepoConfig,
|
||||
seedp *int64) (*manifest.Manifest, []string, error) {
|
||||
seed := distro.SeedFrom(seedp)
|
||||
|
||||
warnings, err := t.checkOptions(bp, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// merge package sets that appear in the image type with the package sets
|
||||
// of the same name from the distro and arch
|
||||
staticPackageSets := make(map[string]rpmmd.PackageSet)
|
||||
|
||||
// don't add any static packages if Minimal was selected
|
||||
if !bp.Minimal {
|
||||
pkgSets, err := defs.PackageSets(t)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for name, pkgSet := range pkgSets {
|
||||
staticPackageSets[name] = pkgSet
|
||||
}
|
||||
}
|
||||
|
||||
// amend with repository information and collect payload repos
|
||||
payloadRepos := make([]rpmmd.RepoConfig, 0)
|
||||
for _, repo := range repos {
|
||||
if len(repo.PackageSets) > 0 {
|
||||
// only apply the repo to the listed package sets
|
||||
for _, psName := range repo.PackageSets {
|
||||
if slices.Contains(t.PayloadPackageSets(), psName) {
|
||||
payloadRepos = append(payloadRepos, repo)
|
||||
}
|
||||
ps := staticPackageSets[psName]
|
||||
ps.Repositories = append(ps.Repositories, repo)
|
||||
staticPackageSets[psName] = ps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w := t.workload
|
||||
if w == nil {
|
||||
// XXX: this needs to get duplicaed in exactly the same
|
||||
// way in rhel/imagetype.go
|
||||
workloadRepos := payloadRepos
|
||||
customRepos, err := bp.Customizations.GetRepositories()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
installFromRepos := blueprint.RepoCustomizationsInstallFromOnly(customRepos)
|
||||
workloadRepos = append(workloadRepos, installFromRepos...)
|
||||
|
||||
cw := &workload.Custom{
|
||||
BaseWorkload: workload.BaseWorkload{
|
||||
Repos: workloadRepos,
|
||||
},
|
||||
Packages: bp.GetPackagesEx(false),
|
||||
EnabledModules: bp.GetEnabledModules(),
|
||||
}
|
||||
if services := bp.Customizations.GetServices(); services != nil {
|
||||
cw.Services = services.Enabled
|
||||
cw.DisabledServices = services.Disabled
|
||||
cw.MaskedServices = services.Masked
|
||||
}
|
||||
w = cw
|
||||
}
|
||||
|
||||
if experimentalflags.Bool("no-fstab") {
|
||||
if t.defaultImageConfig == nil {
|
||||
t.defaultImageConfig = &distro.ImageConfig{
|
||||
MountUnits: common.ToPtr(true),
|
||||
}
|
||||
} else {
|
||||
t.defaultImageConfig.MountUnits = common.ToPtr(true)
|
||||
}
|
||||
}
|
||||
|
||||
containerSources := make([]container.SourceSpec, len(bp.Containers))
|
||||
for idx, cont := range bp.Containers {
|
||||
containerSources[idx] = container.SourceSpec{
|
||||
Source: cont.Source,
|
||||
Name: cont.Name,
|
||||
TLSVerify: cont.TLSVerify,
|
||||
Local: cont.LocalStorage,
|
||||
}
|
||||
}
|
||||
|
||||
source := rand.NewSource(seed)
|
||||
// math/rand is good enough in this case
|
||||
/* #nosec G404 */
|
||||
rng := rand.New(source)
|
||||
|
||||
img, err := t.image(w, t, bp, options, staticPackageSets, containerSources, rng)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mf := manifest.New()
|
||||
mf.Distro = manifest.DISTRO_FEDORA
|
||||
if options.UseBootstrapContainer {
|
||||
mf.DistroBootstrapRef = bootstrapContainerFor(t)
|
||||
}
|
||||
_, err = img.InstantiateManifest(&mf, repos, &t.arch.distro.DistroYAML.Runner, rng)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &mf, warnings, err
|
||||
}
|
||||
|
||||
// checkOptions checks the validity and compatibility of options and customizations for the image type.
|
||||
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
|
||||
func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
|
||||
customizations := bp.Customizations
|
||||
|
||||
var warnings []string
|
||||
|
||||
if !t.ImageTypeYAML.RPMOSTree && options.OSTree != nil {
|
||||
return warnings, fmt.Errorf("OSTree is not supported for %q", t.Name())
|
||||
}
|
||||
|
||||
// we do not support embedding containers on ostree-derived images, only on commits themselves
|
||||
if len(bp.Containers) > 0 && t.ImageTypeYAML.RPMOSTree && (t.Name() != "iot-commit" && t.Name() != "iot-container") {
|
||||
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.Name(), t.arch.distro.Name())
|
||||
}
|
||||
|
||||
if options.OSTree != nil {
|
||||
if err := options.OSTree.Validate(); err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
}
|
||||
|
||||
if t.ImageTypeYAML.BootISO && t.ImageTypeYAML.RPMOSTree {
|
||||
// ostree-based ISOs require a URL from which to pull a payload commit
|
||||
if options.OSTree == nil || options.OSTree.URL == "" {
|
||||
return warnings, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if t.Name() == "iot-raw-xz" || t.Name() == "iot-qcow2" {
|
||||
allowed := []string{"User", "Group", "Directories", "Files", "Services", "FIPS"}
|
||||
if err := customizations.CheckAllowed(allowed...); err != nil {
|
||||
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
|
||||
}
|
||||
// TODO: consider additional checks, such as those in "edge-simplified-installer" in RHEL distros
|
||||
}
|
||||
|
||||
// BootISOs have limited support for customizations.
|
||||
// TODO: Support kernel name selection for image-installer
|
||||
if t.ImageTypeYAML.BootISO {
|
||||
if t.Name() == "iot-simplified-installer" {
|
||||
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS"}
|
||||
if err := customizations.CheckAllowed(allowed...); err != nil {
|
||||
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
|
||||
}
|
||||
if customizations.GetInstallationDevice() == "" {
|
||||
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.Name())
|
||||
}
|
||||
|
||||
// FDO is optional, but when specified has some restrictions
|
||||
if customizations.GetFDO() != nil {
|
||||
if customizations.GetFDO().ManufacturingServerURL == "" {
|
||||
return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to when using FDO", t.Name())
|
||||
}
|
||||
var diunSet int
|
||||
if customizations.GetFDO().DiunPubKeyHash != "" {
|
||||
diunSet++
|
||||
}
|
||||
if customizations.GetFDO().DiunPubKeyInsecure != "" {
|
||||
diunSet++
|
||||
}
|
||||
if customizations.GetFDO().DiunPubKeyRootCerts != "" {
|
||||
diunSet++
|
||||
}
|
||||
if diunSet != 1 {
|
||||
return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to when using FDO", t.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// ignition is optional, we might be using FDO
|
||||
if customizations.GetIgnition() != nil {
|
||||
if customizations.GetIgnition().Embedded != nil && customizations.GetIgnition().FirstBoot != nil {
|
||||
return warnings, fmt.Errorf("both ignition embedded and firstboot configurations found")
|
||||
}
|
||||
if customizations.GetIgnition().FirstBoot != nil && customizations.GetIgnition().FirstBoot.ProvisioningURL == "" {
|
||||
return warnings, fmt.Errorf("ignition.firstboot requires a provisioning url")
|
||||
}
|
||||
}
|
||||
} else if t.Name() == "iot-installer" || t.Name() == "minimal-installer" {
|
||||
// "Installer" is actually not allowed for image-installer right now, but this is checked at the end
|
||||
allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"}
|
||||
if err := customizations.CheckAllowed(allowed...); err != nil {
|
||||
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
|
||||
}
|
||||
} else if t.Name() == "workstation-live-installer" {
|
||||
allowed := []string{"Installer"}
|
||||
if err := customizations.CheckAllowed(allowed...); err != nil {
|
||||
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.ImageTypeYAML.RPMOSTree {
|
||||
return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
|
||||
}
|
||||
|
||||
mountpoints := customizations.GetFilesystems()
|
||||
partitioning, err := customizations.GetPartitioning()
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
if (len(mountpoints) > 0 || partitioning != nil) && t.ImageTypeYAML.RPMOSTree {
|
||||
return warnings, fmt.Errorf("Custom mountpoints and partitioning are not supported for ostree types")
|
||||
}
|
||||
if len(mountpoints) > 0 && partitioning != nil {
|
||||
return warnings, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)")
|
||||
}
|
||||
|
||||
if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
if err := partitioning.ValidateLayoutConstraints(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if osc := customizations.GetOpenSCAP(); osc != nil {
|
||||
supported := oscap.IsProfileAllowed(osc.ProfileID, t.arch.distro.DistroYAML.OscapProfilesAllowList)
|
||||
if !supported {
|
||||
return warnings, fmt.Errorf("OpenSCAP unsupported profile: %s", osc.ProfileID)
|
||||
}
|
||||
if t.ImageTypeYAML.RPMOSTree {
|
||||
return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types")
|
||||
}
|
||||
if osc.ProfileID == "" {
|
||||
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
|
||||
}
|
||||
}
|
||||
|
||||
// Check Directory/File Customizations are valid
|
||||
dc := customizations.GetDirectories()
|
||||
fc := customizations.GetFiles()
|
||||
|
||||
err = blueprint.ValidateDirFileCustomizations(dc, fc)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
dcp := policies.CustomDirectoriesPolicies
|
||||
fcp := policies.CustomFilesPolicies
|
||||
|
||||
if t.ImageTypeYAML.RPMOSTree {
|
||||
dcp = policies.OstreeCustomDirectoriesPolicies
|
||||
fcp = policies.OstreeCustomFilesPolicies
|
||||
}
|
||||
|
||||
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
// check if repository customizations are valid
|
||||
_, err = customizations.GetRepositories()
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
|
||||
warnings = append(warnings, fmt.Sprintln(common.FIPSEnabledImageWarning))
|
||||
}
|
||||
|
||||
instCust, err := customizations.GetInstaller()
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
if instCust != nil {
|
||||
// only supported by the Anaconda installer
|
||||
if slices.Index([]string{"iot-installer"}, t.Name()) == -1 {
|
||||
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name())
|
||||
}
|
||||
|
||||
// NOTE: the image type check is redundant with the check above, but
|
||||
// let's keep it explicit in case one of the two changes.
|
||||
// The kickstart contents is incompatible with the users and groups
|
||||
// customization only for the iot-installer.
|
||||
if t.Name() == "iot-installer" &&
|
||||
instCust.Kickstart != nil &&
|
||||
len(instCust.Kickstart.Contents) > 0 &&
|
||||
(customizations.GetUsers() != nil || customizations.GetGroups() != nil) {
|
||||
return warnings, fmt.Errorf("iot-installer installer.kickstart.contents are not supported in combination with users or groups")
|
||||
}
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func bootstrapContainerFor(t *imageType) string {
|
||||
a := common.Must(arch.FromString(t.arch.name))
|
||||
return t.arch.distro.DistroYAML.BootstrapContainers[a]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue