split: replace internal packages with images library
Remove all the internal package that are now in the github.com/osbuild/images package and vendor it. A new function in internal/blueprint/ converts from an osbuild-composer blueprint to an images blueprint. This is necessary for keeping the blueprint implementation in both packages. In the future, the images package will change the blueprint (and most likely rename it) and it will only be part of the osbuild-composer internals and interface. The Convert() function will be responsible for converting the blueprint into the new configuration object.
This commit is contained in:
parent
d59199670f
commit
0e4a9e586f
446 changed files with 5690 additions and 13312 deletions
394
vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer.go
generated
vendored
Normal file
394
vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/osbuild/images/internal/fsnode"
|
||||
"github.com/osbuild/images/internal/users"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
type AnacondaInstallerType int
|
||||
|
||||
const (
|
||||
AnacondaInstallerTypeLive AnacondaInstallerType = iota + 1
|
||||
AnacondaInstallerTypePayload
|
||||
)
|
||||
|
||||
// An Anaconda represents the installer tree as found on an ISO this can be either
|
||||
// a payload installer or a live installer depending on `Type`.
|
||||
type AnacondaInstaller struct {
|
||||
Base
|
||||
|
||||
// The type of the Anaconda installer tree to prepare, this can be either
|
||||
// a 'live' or a 'payload' and it controls which stages are added to the
|
||||
// manifest.
|
||||
Type AnacondaInstallerType
|
||||
|
||||
// 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
|
||||
AdditionalAnacondaModules []string
|
||||
|
||||
// Additional dracut modules and drivers to enable
|
||||
AdditionalDracutModules []string
|
||||
AdditionalDrivers []string
|
||||
|
||||
Files []*fsnode.File
|
||||
}
|
||||
|
||||
func NewAnacondaInstaller(m *Manifest,
|
||||
installerType AnacondaInstallerType,
|
||||
buildPipeline *Build,
|
||||
platform platform.Platform,
|
||||
repos []rpmmd.RepoConfig,
|
||||
kernelName,
|
||||
product,
|
||||
version string) *AnacondaInstaller {
|
||||
name := "anaconda-tree"
|
||||
p := &AnacondaInstaller{
|
||||
Base: NewBase(m, name, buildPipeline),
|
||||
Type: installerType,
|
||||
platform: platform,
|
||||
repos: filterRepos(repos, name),
|
||||
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 *AnacondaInstaller) 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 *AnacondaInstaller) getBuildPackages(Distro) []string {
|
||||
packages := p.anacondaBootPackageSet()
|
||||
packages = append(packages,
|
||||
"rpm",
|
||||
"lorax-templates-generic",
|
||||
)
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *AnacondaInstaller) getPackageSetChain(Distro) []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 *AnacondaInstaller) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *AnacondaInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec) {
|
||||
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 *AnacondaInstaller) serializeEnd() {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.kernelVer = ""
|
||||
p.packageSpecs = nil
|
||||
}
|
||||
|
||||
func (p *AnacondaInstaller) serialize() osbuild.Pipeline {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serialization not started")
|
||||
}
|
||||
|
||||
// Let's do a bunch of sanity checks that are dependent on the installer type
|
||||
// being serialized
|
||||
if p.Type == AnacondaInstallerTypeLive {
|
||||
if len(p.Users) != 0 || len(p.Groups) != 0 {
|
||||
panic("anaconda installer type payload does not support users and groups customization")
|
||||
}
|
||||
|
||||
if p.InteractiveDefaults != nil {
|
||||
panic("anaconda installer type payload does not support interactive defaults")
|
||||
}
|
||||
} else if p.Type == AnacondaInstallerTypePayload {
|
||||
} else {
|
||||
panic("invalid anaconda installer type")
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
var usersStageOptions *osbuild.UsersStageOptions
|
||||
|
||||
if p.Type == AnacondaInstallerTypePayload {
|
||||
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,
|
||||
},
|
||||
}
|
||||
} else if p.Type == AnacondaInstallerTypeLive {
|
||||
usersStageOptions = &osbuild.UsersStageOptions{
|
||||
Users: map[string]osbuild.UsersStageOptionsUser{
|
||||
"root": rootUser,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewUsersStage(usersStageOptions))
|
||||
|
||||
if p.Type == AnacondaInstallerTypeLive {
|
||||
systemdStageOptions := &osbuild.SystemdStageOptions{
|
||||
EnabledServices: []string{
|
||||
"livesys.service",
|
||||
"livesys-late.service",
|
||||
},
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewSystemdStage(systemdStageOptions))
|
||||
|
||||
livesysMode := os.FileMode(int(0644))
|
||||
livesysFile, err := fsnode.NewFile("/etc/sysconfig/livesys", &livesysMode, "root", "root", []byte("livesys_session=\"gnome\""))
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
p.Files = []*fsnode.File{livesysFile}
|
||||
|
||||
pipeline.AddStages(osbuild.GenFileNodesStages(p.Files)...)
|
||||
}
|
||||
|
||||
if p.Type == AnacondaInstallerTypePayload {
|
||||
pipeline.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(p.AdditionalAnacondaModules)))
|
||||
pipeline.AddStage(osbuild.NewLoraxScriptStage(&osbuild.LoraxScriptStageOptions{
|
||||
Path: "99-generic/runtime-postinstall.tmpl",
|
||||
BaseArch: p.platform.GetArch().String(),
|
||||
}))
|
||||
}
|
||||
|
||||
dracutModules := append(
|
||||
p.AdditionalDracutModules,
|
||||
"anaconda",
|
||||
"rdma",
|
||||
"rngd",
|
||||
"multipath",
|
||||
"fcoe",
|
||||
"fcoe-uefi",
|
||||
"iscsi",
|
||||
"lunmask",
|
||||
"nfs",
|
||||
)
|
||||
dracutOptions := dracutStageOptions(p.kernelVer, p.Biosdevname, dracutModules)
|
||||
dracutOptions.AddDrivers = p.AdditionalDrivers
|
||||
pipeline.AddStage(osbuild.NewDracutStage(dracutOptions))
|
||||
pipeline.AddStage(osbuild.NewSELinuxConfigStage(&osbuild.SELinuxConfigStageOptions{State: osbuild.SELinuxStatePermissive}))
|
||||
|
||||
if p.Type == AnacondaInstallerTypePayload {
|
||||
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 *AnacondaInstaller) GetPlatform() platform.Platform {
|
||||
return p.platform
|
||||
}
|
||||
|
||||
type AnacondaInteractiveDefaults struct {
|
||||
TarPath string
|
||||
}
|
||||
|
||||
func NewAnacondaInteractiveDefaults(tarPath string) *AnacondaInteractiveDefaults {
|
||||
i := &AnacondaInteractiveDefaults{
|
||||
TarPath: tarPath,
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (p *AnacondaInstaller) getInline() []string {
|
||||
inlineData := []string{}
|
||||
|
||||
// inline data for custom files
|
||||
for _, file := range p.Files {
|
||||
inlineData = append(inlineData, string(file.Data()))
|
||||
}
|
||||
|
||||
return inlineData
|
||||
}
|
||||
316
vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go
generated
vendored
Normal file
316
vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/osbuild/images/internal/users"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/disk"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
// An AnacondaInstallerISOTree represents a tree containing the anaconda installer,
|
||||
// configuration in terms of a kickstart file, as well as an embedded
|
||||
// payload to be installed, this payload can either be an ostree
|
||||
// CommitSpec or OSPipeline for an OS.
|
||||
type AnacondaInstallerISOTree struct {
|
||||
Base
|
||||
|
||||
// TODO: review optional and mandatory fields and their meaning
|
||||
OSName string
|
||||
Release string
|
||||
Users []users.User
|
||||
Groups []users.Group
|
||||
|
||||
PartitionTable *disk.PartitionTable
|
||||
|
||||
anacondaPipeline *AnacondaInstaller
|
||||
rootfsPipeline *ISORootfsImg
|
||||
bootTreePipeline *EFIBootTree
|
||||
|
||||
// The location of the kickstart file, if it will be added to the
|
||||
// bootiso-tree.
|
||||
// Otherwise, it should be defined in the interactive defaults of the
|
||||
// Anaconda pipeline.
|
||||
KSPath string
|
||||
|
||||
// The path where the payload (tarball or ostree repo) will be stored.
|
||||
PayloadPath string
|
||||
|
||||
isoLabel string
|
||||
|
||||
SquashfsCompression string
|
||||
|
||||
OSPipeline *OS
|
||||
OSTreeCommitSource *ostree.SourceSpec
|
||||
|
||||
ostreeCommitSpec *ostree.CommitSpec
|
||||
|
||||
KernelOpts []string
|
||||
|
||||
// Enable ISOLinux stage
|
||||
ISOLinux bool
|
||||
}
|
||||
|
||||
func NewAnacondaInstallerISOTree(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
anacondaPipeline *AnacondaInstaller,
|
||||
rootfsPipeline *ISORootfsImg,
|
||||
bootTreePipeline *EFIBootTree,
|
||||
isoLabel string) *AnacondaInstallerISOTree {
|
||||
|
||||
p := &AnacondaInstallerISOTree{
|
||||
Base: NewBase(m, "bootiso-tree", buildPipeline),
|
||||
anacondaPipeline: anacondaPipeline,
|
||||
rootfsPipeline: rootfsPipeline,
|
||||
bootTreePipeline: bootTreePipeline,
|
||||
isoLabel: isoLabel,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
if anacondaPipeline.Base.manifest != m {
|
||||
panic("anaconda pipeline from different manifest")
|
||||
}
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) getOSTreeCommitSources() []ostree.SourceSpec {
|
||||
if p.OSTreeCommitSource == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []ostree.SourceSpec{
|
||||
*p.OSTreeCommitSource,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) getOSTreeCommits() []ostree.CommitSpec {
|
||||
if p.ostreeCommitSpec == nil {
|
||||
return nil
|
||||
}
|
||||
return []ostree.CommitSpec{*p.ostreeCommitSpec}
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) getBuildPackages(_ Distro) []string {
|
||||
packages := []string{
|
||||
"squashfs-tools",
|
||||
}
|
||||
|
||||
if p.OSTreeCommitSource != nil {
|
||||
packages = append(packages, "rpm-ostree")
|
||||
}
|
||||
|
||||
if p.OSPipeline != nil {
|
||||
packages = append(packages, "tar")
|
||||
}
|
||||
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) serializeStart(_ []rpmmd.PackageSpec, _ []container.Spec, commits []ostree.CommitSpec) {
|
||||
if len(commits) == 0 {
|
||||
// nothing to do
|
||||
return
|
||||
}
|
||||
|
||||
if len(commits) > 1 {
|
||||
panic("pipeline supports at most one ostree commit")
|
||||
}
|
||||
|
||||
p.ostreeCommitSpec = &commits[0]
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) serializeEnd() {
|
||||
p.ostreeCommitSpec = nil
|
||||
}
|
||||
|
||||
func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline {
|
||||
// If the anaconda pipeline is a payload then we need one of two payload types
|
||||
if p.anacondaPipeline.Type == AnacondaInstallerTypePayload {
|
||||
if p.ostreeCommitSpec == nil && p.OSPipeline == nil {
|
||||
panic("missing ostree or ospipeline parameters in ISO tree pipeline")
|
||||
}
|
||||
|
||||
// But not both payloads
|
||||
if p.ostreeCommitSpec != nil && p.OSPipeline != nil {
|
||||
panic("got both ostree and ospipeline parameters in ISO tree pipeline")
|
||||
}
|
||||
}
|
||||
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
kernelOpts := []string{}
|
||||
|
||||
if p.anacondaPipeline.Type == AnacondaInstallerTypePayload {
|
||||
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.stage2=hd:LABEL=%s", p.isoLabel))
|
||||
if p.KSPath != "" {
|
||||
kernelOpts = append(kernelOpts, fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.isoLabel, p.KSPath))
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.KernelOpts) > 0 {
|
||||
kernelOpts = append(kernelOpts, p.KernelOpts...)
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
||||
Paths: []osbuild.MkdirStagePath{
|
||||
{
|
||||
Path: "images",
|
||||
},
|
||||
{
|
||||
Path: "images/pxeboot",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
if p.anacondaPipeline.Type == AnacondaInstallerTypeLive {
|
||||
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
||||
Paths: []osbuild.MkdirStagePath{
|
||||
{
|
||||
Path: "LiveOS",
|
||||
},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
inputName := "tree"
|
||||
copyStageOptions := &osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/boot/vmlinuz-%s", inputName, p.anacondaPipeline.kernelVer),
|
||||
To: "tree:///images/pxeboot/vmlinuz",
|
||||
},
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/boot/initramfs-%s.img", inputName, p.anacondaPipeline.kernelVer),
|
||||
To: "tree:///images/pxeboot/initrd.img",
|
||||
},
|
||||
},
|
||||
}
|
||||
copyStageInputs := osbuild.NewPipelineTreeInputs(inputName, p.anacondaPipeline.Name())
|
||||
copyStage := osbuild.NewCopyStageSimple(copyStageOptions, copyStageInputs)
|
||||
pipeline.AddStage(copyStage)
|
||||
|
||||
var squashfsOptions osbuild.SquashfsStageOptions
|
||||
|
||||
if p.anacondaPipeline.Type == AnacondaInstallerTypePayload {
|
||||
squashfsOptions = osbuild.SquashfsStageOptions{
|
||||
Filename: "images/install.img",
|
||||
}
|
||||
} else if p.anacondaPipeline.Type == AnacondaInstallerTypeLive {
|
||||
squashfsOptions = osbuild.SquashfsStageOptions{
|
||||
Filename: "LiveOS/squashfs.img",
|
||||
}
|
||||
}
|
||||
|
||||
if p.SquashfsCompression != "" {
|
||||
squashfsOptions.Compression.Method = p.SquashfsCompression
|
||||
} else {
|
||||
// default to xz if not specified
|
||||
squashfsOptions.Compression.Method = "xz"
|
||||
}
|
||||
|
||||
if squashfsOptions.Compression.Method == "xz" {
|
||||
squashfsOptions.Compression.Options = &osbuild.FSCompressionOptions{
|
||||
BCJ: osbuild.BCJOption(p.anacondaPipeline.platform.GetArch().String()),
|
||||
}
|
||||
}
|
||||
|
||||
squashfsStage := osbuild.NewSquashfsStage(&squashfsOptions, p.rootfsPipeline.Name())
|
||||
pipeline.AddStage(squashfsStage)
|
||||
|
||||
if p.ISOLinux {
|
||||
isoLinuxOptions := &osbuild.ISOLinuxStageOptions{
|
||||
Product: osbuild.ISOLinuxProduct{
|
||||
Name: p.anacondaPipeline.product,
|
||||
Version: p.anacondaPipeline.version,
|
||||
},
|
||||
Kernel: osbuild.ISOLinuxKernel{
|
||||
Dir: "/images/pxeboot",
|
||||
Opts: kernelOpts,
|
||||
},
|
||||
}
|
||||
|
||||
isoLinuxStage := osbuild.NewISOLinuxStage(isoLinuxOptions, p.anacondaPipeline.Name())
|
||||
pipeline.AddStage(isoLinuxStage)
|
||||
}
|
||||
|
||||
filename := "images/efiboot.img"
|
||||
pipeline.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{
|
||||
Filename: filename,
|
||||
Size: fmt.Sprintf("%d", p.PartitionTable.Size),
|
||||
}))
|
||||
|
||||
efibootDevice := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: filename})
|
||||
for _, stage := range osbuild.GenMkfsStages(p.PartitionTable, efibootDevice) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
inputName = "root-tree"
|
||||
copyInputs := osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
||||
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.bootTreePipeline.Name(), filename, p.PartitionTable)
|
||||
pipeline.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
|
||||
|
||||
copyInputs = osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
||||
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
||||
&osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/EFI", inputName),
|
||||
To: "tree:///",
|
||||
},
|
||||
},
|
||||
},
|
||||
copyInputs,
|
||||
))
|
||||
|
||||
if p.ostreeCommitSpec != nil {
|
||||
// Set up the payload ostree repo
|
||||
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: p.PayloadPath}))
|
||||
pipeline.AddStage(osbuild.NewOSTreePullStage(
|
||||
&osbuild.OSTreePullStageOptions{Repo: p.PayloadPath},
|
||||
osbuild.NewOstreePullStageInputs("org.osbuild.source", p.ostreeCommitSpec.Checksum, p.ostreeCommitSpec.Ref),
|
||||
))
|
||||
|
||||
// Configure the kickstart file with the payload and any user options
|
||||
kickstartOptions, err := osbuild.NewKickstartStageOptions(p.KSPath, "", p.Users, p.Groups, makeISORootPath(p.PayloadPath), p.ostreeCommitSpec.Ref, p.OSName)
|
||||
|
||||
if err != nil {
|
||||
panic("failed to create kickstartstage options")
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
|
||||
}
|
||||
|
||||
if p.OSPipeline != nil {
|
||||
// Create the payload tarball
|
||||
pipeline.AddStage(osbuild.NewTarStage(&osbuild.TarStageOptions{Filename: p.PayloadPath}, p.OSPipeline.name))
|
||||
|
||||
// If the KSPath is set, we need to add the kickstart stage to this (bootiso-tree) pipeline.
|
||||
// If it's not specified here, it should have been added to the InteractiveDefaults in the anaconda-tree.
|
||||
if p.KSPath != "" {
|
||||
kickstartOptions, err := osbuild.NewKickstartStageOptions(p.KSPath, makeISORootPath(p.PayloadPath), p.Users, p.Groups, "", "", p.OSName)
|
||||
if err != nil {
|
||||
panic("failed to create kickstartstage options")
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewDiscinfoStage(&osbuild.DiscinfoStageOptions{
|
||||
BaseArch: p.anacondaPipeline.platform.GetArch().String(),
|
||||
Release: p.Release,
|
||||
}))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
// makeISORootPath return a path that can be used to address files and folders
|
||||
// in the root of the iso
|
||||
func makeISORootPath(p string) string {
|
||||
fullpath := path.Join("/run/install/repo", p)
|
||||
return fmt.Sprintf("file://%s", fullpath)
|
||||
}
|
||||
116
vendor/github.com/osbuild/images/pkg/manifest/build.go
generated
vendored
Normal file
116
vendor/github.com/osbuild/images/pkg/manifest/build.go
generated
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
"github.com/osbuild/images/pkg/runner"
|
||||
)
|
||||
|
||||
// A Build represents the build environment for other pipelines. As a
|
||||
// general rule, tools required to build pipelines are used from the build
|
||||
// environment, rather than from the pipeline itself. Without a specified
|
||||
// build environment, the build host's root filesystem would be used, which
|
||||
// is not predictable nor reproducible. For the purposes of building the
|
||||
// build pipeline, we do use the build host's filesystem, this means we should
|
||||
// make minimal assumptions about what's available there.
|
||||
type Build struct {
|
||||
Base
|
||||
|
||||
runner runner.Runner
|
||||
dependents []Pipeline
|
||||
repos []rpmmd.RepoConfig
|
||||
packageSpecs []rpmmd.PackageSpec
|
||||
}
|
||||
|
||||
// NewBuild creates a new build pipeline from the repositories in repos
|
||||
// and the specified packages.
|
||||
func NewBuild(m *Manifest, runner runner.Runner, repos []rpmmd.RepoConfig) *Build {
|
||||
name := "build"
|
||||
pipeline := &Build{
|
||||
Base: NewBase(m, name, nil),
|
||||
runner: runner,
|
||||
dependents: make([]Pipeline, 0),
|
||||
repos: filterRepos(repos, name),
|
||||
}
|
||||
m.addPipeline(pipeline)
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *Build) addDependent(dep Pipeline) {
|
||||
p.dependents = append(p.dependents, dep)
|
||||
}
|
||||
|
||||
func (p *Build) getPackageSetChain(distro Distro) []rpmmd.PackageSet {
|
||||
// TODO: make the /usr/bin/cp dependency conditional
|
||||
// TODO: make the /usr/bin/xz dependency conditional
|
||||
packages := []string{
|
||||
"selinux-policy-targeted", // needed to build the build pipeline
|
||||
"coreutils", // /usr/bin/cp - used all over
|
||||
"xz", // usage unclear
|
||||
}
|
||||
|
||||
packages = append(packages, p.runner.GetBuildPackages()...)
|
||||
|
||||
for _, pipeline := range p.dependents {
|
||||
packages = append(packages, pipeline.getBuildPackages(distro)...)
|
||||
}
|
||||
|
||||
return []rpmmd.PackageSet{
|
||||
{
|
||||
Include: packages,
|
||||
Repositories: p.repos,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Build) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *Build) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec) {
|
||||
if len(p.packageSpecs) > 0 {
|
||||
panic("double call to serializeStart()")
|
||||
}
|
||||
p.packageSpecs = packages
|
||||
}
|
||||
|
||||
func (p *Build) serializeEnd() {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.packageSpecs = nil
|
||||
}
|
||||
|
||||
func (p *Build) serialize() osbuild.Pipeline {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serialization not started")
|
||||
}
|
||||
pipeline := p.Base.serialize()
|
||||
pipeline.Runner = p.runner.String()
|
||||
|
||||
pipeline.AddStage(osbuild.NewRPMStage(osbuild.NewRPMStageOptions(p.repos), osbuild.NewRpmStageSourceFilesInputs(p.packageSpecs)))
|
||||
pipeline.AddStage(osbuild.NewSELinuxStage(&osbuild.SELinuxStageOptions{
|
||||
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
|
||||
Labels: p.getSELinuxLabels(),
|
||||
},
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
// Returns a map of paths to labels for the SELinux stage based on specific
|
||||
// packages found in the pipeline.
|
||||
func (p *Build) getSELinuxLabels() map[string]string {
|
||||
labels := make(map[string]string)
|
||||
for _, pkg := range p.getPackageSpecs() {
|
||||
switch pkg.Name {
|
||||
case "coreutils":
|
||||
labels["/usr/bin/cp"] = "system_u:object_r:install_exec_t:s0"
|
||||
case "tar":
|
||||
labels["/usr/bin/tar"] = "system_u:object_r:install_exec_t:s0"
|
||||
}
|
||||
}
|
||||
return labels
|
||||
}
|
||||
170
vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go
generated
vendored
Normal file
170
vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/internal/users"
|
||||
"github.com/osbuild/images/pkg/disk"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
type CoreOSISOTree struct {
|
||||
Base
|
||||
|
||||
// TODO: review optional and mandatory fields and their meaning
|
||||
OSName string
|
||||
Release string
|
||||
Users []users.User
|
||||
Groups []users.Group
|
||||
|
||||
PartitionTable *disk.PartitionTable
|
||||
|
||||
payloadPipeline *XZ
|
||||
coiPipeline *CoreOSInstaller
|
||||
bootTreePipeline *EFIBootTree
|
||||
|
||||
// The path where the payload (tarball or ostree repo) will be stored.
|
||||
PayloadPath string
|
||||
|
||||
isoLabel string
|
||||
|
||||
// Enable ISOLinux stage
|
||||
ISOLinux bool
|
||||
|
||||
KernelOpts []string
|
||||
}
|
||||
|
||||
func NewCoreOSISOTree(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
payloadPipeline *XZ,
|
||||
coiPipeline *CoreOSInstaller,
|
||||
bootTreePipeline *EFIBootTree,
|
||||
isoLabel string) *CoreOSISOTree {
|
||||
|
||||
p := &CoreOSISOTree{
|
||||
Base: NewBase(m, "bootiso-tree", buildPipeline),
|
||||
payloadPipeline: payloadPipeline,
|
||||
coiPipeline: coiPipeline,
|
||||
bootTreePipeline: bootTreePipeline,
|
||||
isoLabel: isoLabel,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
if coiPipeline.Base.manifest != m {
|
||||
panic("anaconda pipeline from different manifest")
|
||||
}
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *CoreOSISOTree) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
||||
&osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://file/%s", p.payloadPipeline.Filename),
|
||||
To: fmt.Sprintf("tree://%s", p.PayloadPath),
|
||||
},
|
||||
},
|
||||
},
|
||||
osbuild.NewXzStageInputs(osbuild.NewFilesInputPipelineObjectRef(p.payloadPipeline.Name(), p.payloadPipeline.Filename, nil)),
|
||||
))
|
||||
|
||||
if p.coiPipeline.Ignition != nil {
|
||||
filename := ""
|
||||
copyInput := ""
|
||||
// These specific filenames in the root of the ISO are expected by
|
||||
// coreos-installer-dracut during installation
|
||||
if p.coiPipeline.Ignition.Config != "" {
|
||||
filename = "ignition_config"
|
||||
copyInput = p.coiPipeline.Ignition.Config
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
||||
&osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://inlinefile/sha256:%x", sha256.Sum256([]byte(copyInput))),
|
||||
To: fmt.Sprintf("tree:///%s", filename),
|
||||
},
|
||||
},
|
||||
},
|
||||
osbuild.NewIgnitionInlineInput(copyInput)))
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
||||
Paths: []osbuild.MkdirStagePath{
|
||||
{
|
||||
Path: "images",
|
||||
},
|
||||
{
|
||||
Path: "images/pxeboot",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
filename := "images/efiboot.img"
|
||||
pipeline.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{
|
||||
Filename: filename,
|
||||
Size: fmt.Sprintf("%d", p.PartitionTable.Size),
|
||||
}))
|
||||
|
||||
efibootDevice := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: filename})
|
||||
for _, stage := range osbuild.GenMkfsStages(p.PartitionTable, efibootDevice) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
inputName := "root-tree"
|
||||
copyInputs := osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
||||
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.bootTreePipeline.Name(), filename, p.PartitionTable)
|
||||
pipeline.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
|
||||
|
||||
inputName = "tree"
|
||||
copyStageOptions := &osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/boot/vmlinuz-%s", inputName, p.coiPipeline.kernelVer),
|
||||
To: "tree:///images/pxeboot/vmlinuz",
|
||||
},
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/boot/initramfs-%s.img", inputName, p.coiPipeline.kernelVer),
|
||||
To: "tree:///images/pxeboot/initrd.img",
|
||||
},
|
||||
},
|
||||
}
|
||||
copyStageInputs := osbuild.NewPipelineTreeInputs(inputName, p.coiPipeline.Name())
|
||||
copyStage := osbuild.NewCopyStageSimple(copyStageOptions, copyStageInputs)
|
||||
pipeline.AddStage(copyStage)
|
||||
|
||||
if p.ISOLinux {
|
||||
isoLinuxOptions := &osbuild.ISOLinuxStageOptions{
|
||||
Product: osbuild.ISOLinuxProduct{
|
||||
Name: p.coiPipeline.product,
|
||||
Version: p.coiPipeline.version,
|
||||
},
|
||||
Kernel: osbuild.ISOLinuxKernel{
|
||||
Dir: "/images/pxeboot",
|
||||
Opts: p.KernelOpts,
|
||||
},
|
||||
}
|
||||
|
||||
isoLinuxStage := osbuild.NewISOLinuxStage(isoLinuxOptions, p.coiPipeline.Name())
|
||||
pipeline.AddStage(isoLinuxStage)
|
||||
}
|
||||
|
||||
copyInputs = osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
||||
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
||||
&osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/EFI", inputName),
|
||||
To: "tree:///",
|
||||
},
|
||||
},
|
||||
},
|
||||
copyInputs,
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
72
vendor/github.com/osbuild/images/pkg/manifest/commit.go
generated
vendored
Normal file
72
vendor/github.com/osbuild/images/pkg/manifest/commit.go
generated
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// OSTreeCommit represents an ostree with one commit.
|
||||
type OSTreeCommit struct {
|
||||
Base
|
||||
OSVersion string
|
||||
|
||||
treePipeline *OS
|
||||
ref string
|
||||
}
|
||||
|
||||
// NewOSTreeCommit creates a new OSTree commit pipeline. The
|
||||
// treePipeline is the tree representing the content of the commit.
|
||||
// ref is the ref to create the commit under.
|
||||
func NewOSTreeCommit(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
treePipeline *OS,
|
||||
ref string) *OSTreeCommit {
|
||||
p := &OSTreeCommit{
|
||||
Base: NewBase(m, "ostree-commit", buildPipeline),
|
||||
treePipeline: treePipeline,
|
||||
ref: ref,
|
||||
}
|
||||
if treePipeline.Base.manifest != m {
|
||||
panic("tree pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OSTreeCommit) getBuildPackages(Distro) []string {
|
||||
packages := []string{
|
||||
"rpm-ostree",
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *OSTreeCommit) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
if p.treePipeline.OSTreeRef == "" {
|
||||
panic("tree is not ostree")
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/repo"}))
|
||||
|
||||
var parentID string
|
||||
treeCommits := p.treePipeline.getOSTreeCommits()
|
||||
if len(treeCommits) > 0 {
|
||||
if len(treeCommits) > 1 {
|
||||
panic("multiple ostree commit specs found; this is a programming error")
|
||||
}
|
||||
parentCommit := &treeCommits[0]
|
||||
parentID = parentCommit.Checksum
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreeCommitStage(
|
||||
&osbuild.OSTreeCommitStageOptions{
|
||||
Ref: p.ref,
|
||||
OSVersion: p.OSVersion,
|
||||
Parent: parentID,
|
||||
},
|
||||
p.treePipeline.Name()),
|
||||
)
|
||||
|
||||
return pipeline
|
||||
}
|
||||
153
vendor/github.com/osbuild/images/pkg/manifest/commit_server_tree.go
generated
vendored
Normal file
153
vendor/github.com/osbuild/images/pkg/manifest/commit_server_tree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
// An OSTreeCommitServer contains an nginx server serving
|
||||
// an embedded ostree commit.
|
||||
type OSTreeCommitServer 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
|
||||
// TODO: should this be configurable?
|
||||
Language string
|
||||
|
||||
platform platform.Platform
|
||||
repos []rpmmd.RepoConfig
|
||||
packageSpecs []rpmmd.PackageSpec
|
||||
commitPipeline *OSTreeCommit
|
||||
nginxConfigPath string
|
||||
listenPort string
|
||||
}
|
||||
|
||||
// NewOSTreeCommitServer creates a new pipeline. The content
|
||||
// is built from repos and packages, which must contain nginx. commitPipeline
|
||||
// is a pipeline producing an ostree commit to be served. nginxConfigPath
|
||||
// is the path to the main nginx config file and listenPort is the port
|
||||
// nginx will be listening on.
|
||||
func NewOSTreeCommitServer(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
platform platform.Platform,
|
||||
repos []rpmmd.RepoConfig,
|
||||
commitPipeline *OSTreeCommit,
|
||||
nginxConfigPath,
|
||||
listenPort string) *OSTreeCommitServer {
|
||||
name := "container-tree"
|
||||
p := &OSTreeCommitServer{
|
||||
Base: NewBase(m, name, buildPipeline),
|
||||
platform: platform,
|
||||
repos: filterRepos(repos, name),
|
||||
commitPipeline: commitPipeline,
|
||||
nginxConfigPath: nginxConfigPath,
|
||||
listenPort: listenPort,
|
||||
Language: "en_US",
|
||||
}
|
||||
if commitPipeline.Base.manifest != m {
|
||||
panic("commit pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) getPackageSetChain(Distro) []rpmmd.PackageSet {
|
||||
// FIXME: container package is defined here
|
||||
packages := []string{"nginx"}
|
||||
return []rpmmd.PackageSet{
|
||||
{
|
||||
Include: append(packages, p.ExtraPackages...),
|
||||
Repositories: append(p.repos, p.ExtraRepos...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) getBuildPackages(Distro) []string {
|
||||
packages := []string{
|
||||
"rpm",
|
||||
"rpm-ostree",
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec) {
|
||||
if len(p.packageSpecs) > 0 {
|
||||
panic("double call to serializeStart()")
|
||||
}
|
||||
p.packageSpecs = packages
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) serializeEnd() {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.packageSpecs = nil
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) 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.NewLocaleStage(&osbuild.LocaleStageOptions{Language: p.Language}))
|
||||
|
||||
htmlRoot := "/usr/share/nginx/html"
|
||||
repoPath := filepath.Join(htmlRoot, "repo")
|
||||
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: repoPath}))
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreePullStage(
|
||||
&osbuild.OSTreePullStageOptions{Repo: repoPath},
|
||||
osbuild.NewOstreePullStageInputs("org.osbuild.pipeline", "name:"+p.commitPipeline.Name(), p.commitPipeline.ref),
|
||||
))
|
||||
|
||||
// make nginx log and lib directories world writeable, otherwise nginx can't start in
|
||||
// an unprivileged container
|
||||
pipeline.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/log/nginx", "a+rwX", true)))
|
||||
pipeline.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/lib/nginx", "a+rwX", true)))
|
||||
|
||||
pipeline.AddStage(osbuild.NewNginxConfigStage(nginxConfigStageOptions(p.nginxConfigPath, htmlRoot, p.listenPort)))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func nginxConfigStageOptions(path, htmlRoot, listen string) *osbuild.NginxConfigStageOptions {
|
||||
// configure nginx to work in an unprivileged container
|
||||
cfg := &osbuild.NginxConfig{
|
||||
Listen: listen,
|
||||
Root: htmlRoot,
|
||||
Daemon: common.ToPtr(false),
|
||||
PID: "/tmp/nginx.pid",
|
||||
}
|
||||
return &osbuild.NginxConfigStageOptions{
|
||||
Path: path,
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func chmodStageOptions(path, mode string, recursive bool) *osbuild.ChmodStageOptions {
|
||||
return &osbuild.ChmodStageOptions{
|
||||
Items: map[string]osbuild.ChmodStagePathOptions{
|
||||
path: {Mode: mode, Recursive: recursive},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OSTreeCommitServer) GetPlatform() platform.Platform {
|
||||
return p.platform
|
||||
}
|
||||
189
vendor/github.com/osbuild/images/pkg/manifest/coreos_installer.go
generated
vendored
Normal file
189
vendor/github.com/osbuild/images/pkg/manifest/coreos_installer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/internal/fdo"
|
||||
"github.com/osbuild/images/internal/ignition"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
type CoreOSInstaller 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
|
||||
|
||||
platform platform.Platform
|
||||
repos []rpmmd.RepoConfig
|
||||
packageSpecs []rpmmd.PackageSpec
|
||||
kernelName string
|
||||
kernelVer string
|
||||
product string
|
||||
version string
|
||||
Variant string
|
||||
|
||||
// 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
|
||||
|
||||
FDO *fdo.Options
|
||||
|
||||
// For the coreos-installer we only have EmbeddedOptions for ignition
|
||||
Ignition *ignition.EmbeddedOptions
|
||||
|
||||
AdditionalDracutModules []string
|
||||
}
|
||||
|
||||
// NewCoreOSInstaller creates an CoreOS installer pipeline object.
|
||||
func NewCoreOSInstaller(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
platform platform.Platform,
|
||||
repos []rpmmd.RepoConfig,
|
||||
kernelName,
|
||||
product,
|
||||
version string) *CoreOSInstaller {
|
||||
name := "coi-tree"
|
||||
p := &CoreOSInstaller{
|
||||
Base: NewBase(m, name, buildPipeline),
|
||||
platform: platform,
|
||||
repos: filterRepos(repos, name),
|
||||
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 *CoreOSInstaller) getBootPackages() []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 *CoreOSInstaller) getBuildPackages(Distro) []string {
|
||||
packages := p.getBootPackages()
|
||||
packages = append(packages,
|
||||
"rpm",
|
||||
"lorax-templates-generic",
|
||||
)
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) getPackageSetChain(Distro) []rpmmd.PackageSet {
|
||||
packages := p.getBootPackages()
|
||||
return []rpmmd.PackageSet{
|
||||
{
|
||||
Include: append(packages, p.ExtraPackages...),
|
||||
Repositories: append(p.repos, p.ExtraRepos...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) serializeStart(packages []rpmmd.PackageSpec, _ []container.Spec, _ []ostree.CommitSpec) {
|
||||
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 *CoreOSInstaller) getInline() []string {
|
||||
inlineData := []string{}
|
||||
// inline data for FDO cert
|
||||
if p.FDO != nil && p.FDO.DiunPubKeyRootCerts != "" {
|
||||
inlineData = append(inlineData, p.FDO.DiunPubKeyRootCerts)
|
||||
}
|
||||
// inline data for ignition embedded (url or data)
|
||||
if p.Ignition != nil {
|
||||
if p.Ignition.Config != "" {
|
||||
inlineData = append(inlineData, p.Ignition.Config)
|
||||
}
|
||||
}
|
||||
return inlineData
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) serializeEnd() {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.kernelVer = ""
|
||||
p.packageSpecs = nil
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) serialize() osbuild.Pipeline {
|
||||
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: "C.UTF-8"}))
|
||||
|
||||
dracutModules := append(
|
||||
p.AdditionalDracutModules,
|
||||
"coreos-installer",
|
||||
"fdo",
|
||||
)
|
||||
|
||||
dracutStageOptions := dracutStageOptions(p.kernelVer, p.Biosdevname, dracutModules)
|
||||
if p.FDO != nil && p.FDO.DiunPubKeyRootCerts != "" {
|
||||
pipeline.AddStage(osbuild.NewFDOStageForRootCerts(p.FDO.DiunPubKeyRootCerts))
|
||||
dracutStageOptions.Install = []string{"/fdo_diun_pub_key_root_certs.pem"}
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewDracutStage(dracutStageOptions))
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *CoreOSInstaller) GetPlatform() platform.Platform {
|
||||
return p.platform
|
||||
}
|
||||
62
vendor/github.com/osbuild/images/pkg/manifest/efi_boot_tree.go
generated
vendored
Normal file
62
vendor/github.com/osbuild/images/pkg/manifest/efi_boot_tree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
)
|
||||
|
||||
type EFIBootTree struct {
|
||||
Base
|
||||
|
||||
Platform platform.Platform
|
||||
|
||||
product string
|
||||
version string
|
||||
|
||||
UEFIVendor string
|
||||
ISOLabel string
|
||||
|
||||
KernelOpts []string
|
||||
}
|
||||
|
||||
func NewEFIBootTree(m *Manifest, buildPipeline *Build, product, version string) *EFIBootTree {
|
||||
p := &EFIBootTree{
|
||||
Base: NewBase(m, "efiboot-tree", buildPipeline),
|
||||
product: product,
|
||||
version: version,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *EFIBootTree) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
arch := p.Platform.GetArch().String()
|
||||
var architectures []string
|
||||
if arch == platform.ARCH_X86_64.String() {
|
||||
architectures = []string{"X64"}
|
||||
} else if arch == platform.ARCH_AARCH64.String() {
|
||||
architectures = []string{"AA64"}
|
||||
} else {
|
||||
panic("unsupported architecture")
|
||||
}
|
||||
|
||||
grubOptions := &osbuild.GrubISOStageOptions{
|
||||
Product: osbuild.Product{
|
||||
Name: p.product,
|
||||
Version: p.version,
|
||||
},
|
||||
Kernel: osbuild.ISOKernel{
|
||||
Dir: "/images/pxeboot",
|
||||
Opts: p.KernelOpts,
|
||||
},
|
||||
ISOLabel: p.ISOLabel,
|
||||
Architectures: architectures,
|
||||
Vendor: p.UEFIVendor,
|
||||
}
|
||||
grub2Stage := osbuild.NewGrubISOStage(grubOptions)
|
||||
pipeline.AddStage(grub2Stage)
|
||||
return pipeline
|
||||
}
|
||||
98
vendor/github.com/osbuild/images/pkg/manifest/empty.go
generated
vendored
Normal file
98
vendor/github.com/osbuild/images/pkg/manifest/empty.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
// A ContentTest can be used to define content sources without generating
|
||||
// pipelines. It is useful for testing but not much else.
|
||||
type ContentTest struct {
|
||||
Base
|
||||
|
||||
// content sources
|
||||
packageSets []rpmmd.PackageSet
|
||||
containers []container.SourceSpec
|
||||
commits []ostree.SourceSpec
|
||||
|
||||
// resolved content
|
||||
packageSpecs []rpmmd.PackageSpec
|
||||
containerSpecs []container.Spec
|
||||
commitSpecs []ostree.CommitSpec
|
||||
|
||||
// serialization flag
|
||||
serializing bool
|
||||
}
|
||||
|
||||
// NewContentTest creates a new ContentTest pipeline with a given name and
|
||||
// content sources.
|
||||
func NewContentTest(m *Manifest, name string, packageSets []rpmmd.PackageSet, containers []container.SourceSpec, commits []ostree.SourceSpec) *ContentTest {
|
||||
pipeline := &ContentTest{
|
||||
Base: NewBase(m, name, nil),
|
||||
packageSets: packageSets,
|
||||
containers: containers,
|
||||
commits: commits,
|
||||
}
|
||||
m.addPipeline(pipeline)
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *ContentTest) getPackageSetChain(Distro) []rpmmd.PackageSet {
|
||||
return p.packageSets
|
||||
}
|
||||
|
||||
func (p *ContentTest) getContainerSources() []container.SourceSpec {
|
||||
return p.containers
|
||||
}
|
||||
|
||||
func (p *ContentTest) getOSTreeCommitSources() []ostree.SourceSpec {
|
||||
return p.commits
|
||||
}
|
||||
|
||||
func (p *ContentTest) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *ContentTest) getContainerSpecs() []container.Spec {
|
||||
return p.containerSpecs
|
||||
}
|
||||
|
||||
func (p *ContentTest) getOSTreeCommits() []ostree.CommitSpec {
|
||||
return p.commitSpecs
|
||||
}
|
||||
|
||||
func (p *ContentTest) serializeStart(pkgs []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec) {
|
||||
if p.serializing {
|
||||
panic("double call to serializeStart()")
|
||||
}
|
||||
p.packageSpecs = pkgs
|
||||
p.containerSpecs = containers
|
||||
p.commitSpecs = commits
|
||||
|
||||
p.serializing = true
|
||||
}
|
||||
|
||||
func (p *ContentTest) serializeEnd() {
|
||||
if !p.serializing {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.packageSpecs = nil
|
||||
p.containerSpecs = nil
|
||||
p.commitSpecs = nil
|
||||
|
||||
p.serializing = false
|
||||
}
|
||||
|
||||
func (p *ContentTest) serialize() osbuild.Pipeline {
|
||||
if !p.serializing {
|
||||
panic("serialization not started")
|
||||
}
|
||||
|
||||
// no stages
|
||||
|
||||
return osbuild.Pipeline{
|
||||
Name: p.name,
|
||||
}
|
||||
}
|
||||
75
vendor/github.com/osbuild/images/pkg/manifest/iso.go
generated
vendored
Normal file
75
vendor/github.com/osbuild/images/pkg/manifest/iso.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// An ISO represents a bootable ISO file created from an
|
||||
// an existing ISOTreePipeline.
|
||||
type ISO struct {
|
||||
Base
|
||||
ISOLinux bool
|
||||
Filename string
|
||||
|
||||
treePipeline Pipeline
|
||||
isoLabel string
|
||||
}
|
||||
|
||||
func NewISO(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
treePipeline Pipeline,
|
||||
isoLabel string) *ISO {
|
||||
p := &ISO{
|
||||
Base: NewBase(m, "bootiso", buildPipeline),
|
||||
treePipeline: treePipeline,
|
||||
Filename: "image.iso",
|
||||
isoLabel: isoLabel,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *ISO) getBuildPackages(Distro) []string {
|
||||
return []string{
|
||||
"isomd5sum",
|
||||
"xorriso",
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ISO) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewXorrisofsStage(xorrisofsStageOptions(p.Filename, p.isoLabel, p.ISOLinux), p.treePipeline.Name()))
|
||||
pipeline.AddStage(osbuild.NewImplantisomd5Stage(&osbuild.Implantisomd5StageOptions{Filename: p.Filename}))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func xorrisofsStageOptions(filename, isolabel string, isolinux bool) *osbuild.XorrisofsStageOptions {
|
||||
options := &osbuild.XorrisofsStageOptions{
|
||||
Filename: filename,
|
||||
VolID: isolabel,
|
||||
SysID: "LINUX",
|
||||
EFI: "images/efiboot.img",
|
||||
ISOLevel: 3,
|
||||
}
|
||||
|
||||
if isolinux {
|
||||
options.Boot = &osbuild.XorrisofsBoot{
|
||||
Image: "isolinux/isolinux.bin",
|
||||
Catalog: "isolinux/boot.cat",
|
||||
}
|
||||
|
||||
options.IsohybridMBR = "/usr/share/syslinux/isohdpfx.bin"
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (p *ISO) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-iso9660-image"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
71
vendor/github.com/osbuild/images/pkg/manifest/iso_rootfs.go
generated
vendored
Normal file
71
vendor/github.com/osbuild/images/pkg/manifest/iso_rootfs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
type ISORootfsImg struct {
|
||||
Base
|
||||
|
||||
Size uint64
|
||||
|
||||
installerPipeline Pipeline
|
||||
}
|
||||
|
||||
func NewISORootfsImg(m *Manifest, buildPipeline *Build, installerPipeline Pipeline) *ISORootfsImg {
|
||||
p := &ISORootfsImg{
|
||||
Base: NewBase(m, "rootfs-image", buildPipeline),
|
||||
installerPipeline: installerPipeline,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *ISORootfsImg) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
||||
Paths: []osbuild.MkdirStagePath{
|
||||
{
|
||||
Path: "LiveOS",
|
||||
},
|
||||
},
|
||||
}))
|
||||
pipeline.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{
|
||||
Filename: "LiveOS/rootfs.img",
|
||||
Size: fmt.Sprintf("%d", p.Size),
|
||||
}))
|
||||
|
||||
mkfsStageOptions := &osbuild.MkfsExt4StageOptions{
|
||||
UUID: "2fe99653-f7ff-44fd-bea8-fa70107524fb",
|
||||
Label: "Anaconda",
|
||||
}
|
||||
lodevice := osbuild.NewLoopbackDevice(
|
||||
&osbuild.LoopbackDeviceOptions{
|
||||
Filename: "LiveOS/rootfs.img",
|
||||
},
|
||||
)
|
||||
|
||||
devName := "device"
|
||||
devices := osbuild.Devices{devName: *lodevice}
|
||||
mkfsStage := osbuild.NewMkfsExt4Stage(mkfsStageOptions, devices)
|
||||
pipeline.AddStage(mkfsStage)
|
||||
|
||||
inputName := "tree"
|
||||
copyStageOptions := &osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
{
|
||||
From: fmt.Sprintf("input://%s/", inputName),
|
||||
To: fmt.Sprintf("mount://%s/", devName),
|
||||
},
|
||||
},
|
||||
}
|
||||
copyStageInputs := osbuild.NewPipelineTreeInputs(inputName, p.installerPipeline.Name())
|
||||
copyStageMounts := &osbuild.Mounts{*osbuild.NewExt4Mount(devName, devName, "/")}
|
||||
copyStage := osbuild.NewCopyStage(copyStageOptions, copyStageInputs, &devices, copyStageMounts)
|
||||
pipeline.AddStage(copyStage)
|
||||
return pipeline
|
||||
}
|
||||
199
vendor/github.com/osbuild/images/pkg/manifest/manifest.go
generated
vendored
Normal file
199
vendor/github.com/osbuild/images/pkg/manifest/manifest.go
generated
vendored
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
// Package manifest is used to define an osbuild manifest as a series of
|
||||
// pipelines with content. Typically, a Manifest is created using
|
||||
// manifest.New() and pipelines are defined and added to it using the pipeline
|
||||
// constructors (e.g., NewBuild()) with the manifest as the first argument. The
|
||||
// pipelines are added in the order they are called.
|
||||
//
|
||||
// The package implements a standard set of osbuild pipelines. A pipeline
|
||||
// conceptually represents a named filesystem tree, optionally generated
|
||||
// in a provided build root (represented by another pipeline). All inputs
|
||||
// to a pipeline must be explicitly specified, either in terms of another
|
||||
// pipeline, in terms of content addressable inputs or in terms of static
|
||||
// parameters to the inherited Pipeline structs.
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
type Arch uint64
|
||||
|
||||
const (
|
||||
ARCH_X86_64 Arch = iota
|
||||
ARCH_AARCH64
|
||||
ARCH_S390X
|
||||
ARCH_PPC64LE
|
||||
)
|
||||
|
||||
type Distro uint64
|
||||
|
||||
const (
|
||||
DISTRO_NULL = iota
|
||||
DISTRO_EL9
|
||||
DISTRO_EL8
|
||||
DISTRO_EL7
|
||||
DISTRO_FEDORA
|
||||
)
|
||||
|
||||
// An OSBuildManifest is an opaque JSON object, which is a valid input to osbuild
|
||||
type OSBuildManifest []byte
|
||||
|
||||
func (m OSBuildManifest) MarshalJSON() ([]byte, error) {
|
||||
return json.RawMessage(m).MarshalJSON()
|
||||
}
|
||||
|
||||
func (m *OSBuildManifest) UnmarshalJSON(payload []byte) error {
|
||||
var raw json.RawMessage
|
||||
err := (&raw).UnmarshalJSON(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = OSBuildManifest(raw)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Manifest represents a manifest initialised with all the information required
|
||||
// to generate the pipelines but no content. The content type sources
|
||||
// (PackageSetChains, ContainerSourceSpecs, OSTreeSourceSpecs) must be
|
||||
// retrieved through their corresponding Getters and resolved before
|
||||
// serializing.
|
||||
type Manifest struct {
|
||||
|
||||
// pipelines describe the build process for an image.
|
||||
pipelines []Pipeline
|
||||
|
||||
// Distro defines the distribution of the image that this manifest will
|
||||
// generate. It is used for determining package names that differ between
|
||||
// different distributions and version.
|
||||
Distro Distro
|
||||
}
|
||||
|
||||
func New() Manifest {
|
||||
return Manifest{
|
||||
pipelines: make([]Pipeline, 0),
|
||||
Distro: DISTRO_NULL,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manifest) addPipeline(p Pipeline) {
|
||||
for _, pipeline := range m.pipelines {
|
||||
if pipeline.Name() == p.Name() {
|
||||
panic("duplicate pipeline name in manifest")
|
||||
}
|
||||
}
|
||||
m.pipelines = append(m.pipelines, p)
|
||||
}
|
||||
|
||||
type PackageSelector func([]rpmmd.PackageSet) []rpmmd.PackageSet
|
||||
|
||||
func (m Manifest) GetPackageSetChains() map[string][]rpmmd.PackageSet {
|
||||
chains := make(map[string][]rpmmd.PackageSet)
|
||||
|
||||
for _, pipeline := range m.pipelines {
|
||||
if chain := pipeline.getPackageSetChain(m.Distro); chain != nil {
|
||||
chains[pipeline.Name()] = chain
|
||||
}
|
||||
}
|
||||
|
||||
return chains
|
||||
}
|
||||
|
||||
func (m Manifest) GetContainerSourceSpecs() map[string][]container.SourceSpec {
|
||||
// Containers should only appear in the payload pipeline.
|
||||
// Let's iterate over all pipelines to avoid assuming pipeline names, but
|
||||
// return all the specs as a single slice.
|
||||
containerSpecs := make(map[string][]container.SourceSpec)
|
||||
for _, pipeline := range m.pipelines {
|
||||
if containers := pipeline.getContainerSources(); len(containers) > 0 {
|
||||
containerSpecs[pipeline.Name()] = containers
|
||||
}
|
||||
}
|
||||
return containerSpecs
|
||||
}
|
||||
|
||||
func (m Manifest) GetOSTreeSourceSpecs() map[string][]ostree.SourceSpec {
|
||||
// OSTree commits should only appear in one pipeline.
|
||||
// Let's iterate over all pipelines to avoid assuming pipeline names, but
|
||||
// return all the specs as a single slice if there are multiple.
|
||||
ostreeSpecs := make(map[string][]ostree.SourceSpec)
|
||||
for _, pipeline := range m.pipelines {
|
||||
if commits := pipeline.getOSTreeCommitSources(); len(commits) > 0 {
|
||||
ostreeSpecs[pipeline.Name()] = commits
|
||||
}
|
||||
}
|
||||
return ostreeSpecs
|
||||
}
|
||||
|
||||
func (m Manifest) Serialize(packageSets map[string][]rpmmd.PackageSpec, containerSpecs map[string][]container.Spec, ostreeCommits map[string][]ostree.CommitSpec) (OSBuildManifest, error) {
|
||||
pipelines := make([]osbuild.Pipeline, 0)
|
||||
packages := make([]rpmmd.PackageSpec, 0)
|
||||
commits := make([]ostree.CommitSpec, 0)
|
||||
inline := make([]string, 0)
|
||||
containers := make([]container.Spec, 0)
|
||||
for _, pipeline := range m.pipelines {
|
||||
pipeline.serializeStart(packageSets[pipeline.Name()], containerSpecs[pipeline.Name()], ostreeCommits[pipeline.Name()])
|
||||
}
|
||||
for _, pipeline := range m.pipelines {
|
||||
commits = append(commits, pipeline.getOSTreeCommits()...)
|
||||
pipelines = append(pipelines, pipeline.serialize())
|
||||
packages = append(packages, packageSets[pipeline.Name()]...)
|
||||
inline = append(inline, pipeline.getInline()...)
|
||||
containers = append(containers, pipeline.getContainerSpecs()...)
|
||||
}
|
||||
for _, pipeline := range m.pipelines {
|
||||
pipeline.serializeEnd()
|
||||
}
|
||||
|
||||
return json.Marshal(
|
||||
osbuild.Manifest{
|
||||
Version: "2",
|
||||
Pipelines: pipelines,
|
||||
Sources: osbuild.GenSources(packages, commits, inline, containers),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (m Manifest) GetCheckpoints() []string {
|
||||
checkpoints := []string{}
|
||||
for _, p := range m.pipelines {
|
||||
if p.getCheckpoint() {
|
||||
checkpoints = append(checkpoints, p.Name())
|
||||
}
|
||||
}
|
||||
return checkpoints
|
||||
}
|
||||
|
||||
func (m Manifest) GetExports() []string {
|
||||
exports := []string{}
|
||||
for _, p := range m.pipelines {
|
||||
if p.getExport() {
|
||||
exports = append(exports, p.Name())
|
||||
}
|
||||
}
|
||||
return exports
|
||||
}
|
||||
|
||||
// filterRepos returns a list of repositories that specify the given pipeline
|
||||
// name in their PackageSets list in addition to any global repositories
|
||||
// (global repositories are ones that do not specify any PackageSets).
|
||||
func filterRepos(repos []rpmmd.RepoConfig, plName string) []rpmmd.RepoConfig {
|
||||
filtered := make([]rpmmd.RepoConfig, 0, len(repos))
|
||||
for _, repo := range repos {
|
||||
if len(repo.PackageSets) == 0 {
|
||||
filtered = append(filtered, repo)
|
||||
continue
|
||||
}
|
||||
for _, ps := range repo.PackageSets {
|
||||
if ps == plName {
|
||||
filtered = append(filtered, repo)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
61
vendor/github.com/osbuild/images/pkg/manifest/oci_container.go
generated
vendored
Normal file
61
vendor/github.com/osbuild/images/pkg/manifest/oci_container.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// An OCIContainer represents an OCI container, containing a filesystem
|
||||
// tree created by another Pipeline.
|
||||
type OCIContainer struct {
|
||||
Base
|
||||
Filename string
|
||||
Cmd []string
|
||||
ExposedPorts []string
|
||||
|
||||
treePipeline Tree
|
||||
}
|
||||
|
||||
func NewOCIContainer(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
treePipeline Tree) *OCIContainer {
|
||||
p := &OCIContainer{
|
||||
Base: NewBase(m, "container", buildPipeline),
|
||||
treePipeline: treePipeline,
|
||||
Filename: "oci-archive.tar",
|
||||
}
|
||||
if treePipeline.GetManifest() != m {
|
||||
panic("tree pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OCIContainer) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
options := &osbuild.OCIArchiveStageOptions{
|
||||
Architecture: p.treePipeline.GetPlatform().GetArch().String(),
|
||||
Filename: p.Filename,
|
||||
Config: &osbuild.OCIArchiveConfig{
|
||||
Cmd: p.Cmd,
|
||||
ExposedPorts: p.ExposedPorts,
|
||||
},
|
||||
}
|
||||
baseInput := osbuild.NewTreeInput("name:" + p.treePipeline.Name())
|
||||
inputs := &osbuild.OCIArchiveStageInputs{Base: baseInput}
|
||||
pipeline.AddStage(osbuild.NewOCIArchiveStage(options, inputs))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *OCIContainer) getBuildPackages(Distro) []string {
|
||||
return []string{"tar"}
|
||||
}
|
||||
|
||||
func (p *OCIContainer) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-tar"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
786
vendor/github.com/osbuild/images/pkg/manifest/os.go
generated
vendored
Normal file
786
vendor/github.com/osbuild/images/pkg/manifest/os.go
generated
vendored
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/internal/environment"
|
||||
"github.com/osbuild/images/internal/fsnode"
|
||||
"github.com/osbuild/images/internal/shell"
|
||||
"github.com/osbuild/images/internal/users"
|
||||
"github.com/osbuild/images/internal/workload"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/disk"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rhsm/facts"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
"github.com/osbuild/images/pkg/subscription"
|
||||
)
|
||||
|
||||
// OSCustomizations encapsulates all configuration applied to the base
|
||||
// operating system independently of where and how it is integrated and what
|
||||
// workload it is running.
|
||||
// TODO: move out kernel/bootloader/cloud-init/... to other
|
||||
//
|
||||
// abstractions, this should ideally only contain things that
|
||||
// can always be applied.
|
||||
type OSCustomizations struct {
|
||||
|
||||
// Packages to install in addition to the ones required by the
|
||||
// pipeline.
|
||||
ExtraBasePackages []string
|
||||
|
||||
// Packages to exclude from the base package set. This is useful in
|
||||
// case of weak dependencies, comps groups, or where multiple packages
|
||||
// can satisfy a dependency. Must not conflict with the included base
|
||||
// package set.
|
||||
ExcludeBasePackages []string
|
||||
|
||||
// Additional repos to install the base packages from.
|
||||
ExtraBaseRepos []rpmmd.RepoConfig
|
||||
|
||||
// Containers to embed in the image (source specification)
|
||||
// TODO: move to workload
|
||||
Containers []container.SourceSpec
|
||||
|
||||
// KernelName indicates that a kernel is installed, and names the kernel
|
||||
// package.
|
||||
KernelName string
|
||||
|
||||
// KernelOptionsAppend are appended to the kernel commandline
|
||||
KernelOptionsAppend []string
|
||||
|
||||
// KernelOptionsBootloader controls whether kernel command line options
|
||||
// should be specified in the bootloader grubenv configuration. Otherwise
|
||||
// they are specified in /etc/kernel/cmdline (default).
|
||||
//
|
||||
// NB: The kernel options need to be still specified in /etc/default/grub
|
||||
// under the GRUB_CMDLINE_LINUX variable. The reason is that it is used by
|
||||
// the 10_linux script executed by grub2-mkconfig to override the kernel
|
||||
// options in /etc/kernel/cmdline if the file has older timestamp than
|
||||
// /etc/default/grub.
|
||||
//
|
||||
// This should only be used for RHEL 8 and CentOS 8 images that use grub
|
||||
// (non s390x). Newer releases (9+) should keep this disabled.
|
||||
KernelOptionsBootloader bool
|
||||
|
||||
GPGKeyFiles []string
|
||||
Language string
|
||||
Keyboard *string
|
||||
X11KeymapLayouts []string
|
||||
Hostname string
|
||||
Timezone string
|
||||
EnabledServices []string
|
||||
DisabledServices []string
|
||||
DefaultTarget string
|
||||
|
||||
// SELinux policy, when set it enables the labeling of the tree with the
|
||||
// selected profile
|
||||
SElinux string
|
||||
|
||||
SELinuxForceRelabel *bool
|
||||
|
||||
// Do not install documentation
|
||||
ExcludeDocs bool
|
||||
|
||||
Groups []users.Group
|
||||
Users []users.User
|
||||
|
||||
ShellInit []shell.InitFile
|
||||
|
||||
// TODO: drop osbuild types from the API
|
||||
Firewall *osbuild.FirewallStageOptions
|
||||
Grub2Config *osbuild.GRUB2Config
|
||||
Sysconfig []*osbuild.SysconfigStageOptions
|
||||
SystemdLogind []*osbuild.SystemdLogindStageOptions
|
||||
CloudInit []*osbuild.CloudInitStageOptions
|
||||
Modprobe []*osbuild.ModprobeStageOptions
|
||||
DracutConf []*osbuild.DracutConfStageOptions
|
||||
SystemdUnit []*osbuild.SystemdUnitStageOptions
|
||||
Authselect *osbuild.AuthselectStageOptions
|
||||
SELinuxConfig *osbuild.SELinuxConfigStageOptions
|
||||
Tuned *osbuild.TunedStageOptions
|
||||
Tmpfilesd []*osbuild.TmpfilesdStageOptions
|
||||
PamLimitsConf []*osbuild.PamLimitsConfStageOptions
|
||||
Sysctld []*osbuild.SysctldStageOptions
|
||||
DNFConfig []*osbuild.DNFConfigStageOptions
|
||||
DNFAutomaticConfig *osbuild.DNFAutomaticConfigStageOptions
|
||||
YUMConfig *osbuild.YumConfigStageOptions
|
||||
YUMRepos []*osbuild.YumReposStageOptions
|
||||
SshdConfig *osbuild.SshdConfigStageOptions
|
||||
GCPGuestAgentConfig *osbuild.GcpGuestAgentConfigOptions
|
||||
AuthConfig *osbuild.AuthconfigStageOptions
|
||||
PwQuality *osbuild.PwqualityConfStageOptions
|
||||
OpenSCAPConfig *osbuild.OscapRemediationStageOptions
|
||||
NTPServers []osbuild.ChronyConfigServer
|
||||
WAAgentConfig *osbuild.WAAgentConfStageOptions
|
||||
UdevRules *osbuild.UdevRulesStageOptions
|
||||
LeapSecTZ *string
|
||||
FactAPIType *facts.APIType
|
||||
|
||||
Subscription *subscription.ImageOptions
|
||||
RHSMConfig map[subscription.RHSMStatus]*osbuild.RHSMStageOptions
|
||||
|
||||
// Custom directories and files to create in the image
|
||||
Directories []*fsnode.Directory
|
||||
Files []*fsnode.File
|
||||
}
|
||||
|
||||
// OS represents the filesystem tree of the target image. This roughly
|
||||
// corresponds to the root filesystem once an instance of the image is running.
|
||||
type OS struct {
|
||||
Base
|
||||
// Customizations to apply to the base OS
|
||||
OSCustomizations
|
||||
// Environment the system will run in
|
||||
Environment environment.Environment
|
||||
// Workload to install on top of the base system
|
||||
Workload workload.Workload
|
||||
// Ref of ostree commit (optional). If empty the tree cannot be in an ostree commit
|
||||
OSTreeRef string
|
||||
// OSTreeParent source spec (optional). If nil the new commit (if
|
||||
// applicable) will have no parent
|
||||
OSTreeParent *ostree.SourceSpec
|
||||
// Partition table, if nil the tree cannot be put on a partitioned disk
|
||||
PartitionTable *disk.PartitionTable
|
||||
|
||||
// content-related fields
|
||||
repos []rpmmd.RepoConfig
|
||||
packageSpecs []rpmmd.PackageSpec
|
||||
containerSpecs []container.Spec
|
||||
ostreeParentSpec *ostree.CommitSpec
|
||||
|
||||
platform platform.Platform
|
||||
kernelVer string
|
||||
|
||||
// NoBLS configures the image bootloader with traditional menu entries
|
||||
// instead of BLS. Required for legacy systems like RHEL 7.
|
||||
NoBLS bool
|
||||
OSProduct string
|
||||
OSVersion string
|
||||
OSNick string
|
||||
}
|
||||
|
||||
// NewOS creates a new OS pipeline. build is the build pipeline to use for
|
||||
// building the OS pipeline. platform is the target platform for the final
|
||||
// image. repos are the repositories to install RPMs from.
|
||||
func NewOS(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
platform platform.Platform,
|
||||
repos []rpmmd.RepoConfig) *OS {
|
||||
name := "os"
|
||||
p := &OS{
|
||||
Base: NewBase(m, name, buildPipeline),
|
||||
repos: filterRepos(repos, name),
|
||||
platform: platform,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OS) getPackageSetChain(Distro) []rpmmd.PackageSet {
|
||||
packages := p.platform.GetPackages()
|
||||
|
||||
if p.KernelName != "" {
|
||||
packages = append(packages, p.KernelName)
|
||||
}
|
||||
|
||||
// If we have a logical volume we need to include the lvm2 package.
|
||||
// OSTree-based images (commit and container) aren't bootable images and
|
||||
// don't have partition tables.
|
||||
if p.PartitionTable != nil && p.OSTreeRef == "" {
|
||||
packages = append(packages, p.PartitionTable.GetBuildPackages()...)
|
||||
}
|
||||
|
||||
if p.Environment != nil {
|
||||
packages = append(packages, p.Environment.GetPackages()...)
|
||||
}
|
||||
|
||||
if len(p.NTPServers) > 0 {
|
||||
packages = append(packages, "chrony")
|
||||
}
|
||||
|
||||
if p.SElinux != "" {
|
||||
packages = append(packages, fmt.Sprintf("selinux-policy-%s", p.SElinux))
|
||||
}
|
||||
|
||||
if p.OpenSCAPConfig != nil {
|
||||
packages = append(packages, "openscap-scanner", "scap-security-guide")
|
||||
}
|
||||
|
||||
// Make sure the right packages are included for subscriptions
|
||||
// rhc always uses insights, and depends on subscription-manager
|
||||
// non-rhc uses subscription-manager and optionally includes Insights
|
||||
if p.Subscription != nil {
|
||||
packages = append(packages, "subscription-manager")
|
||||
if p.Subscription.Rhc {
|
||||
packages = append(packages, "rhc", "insights-client", "rhc-worker-playbook")
|
||||
} else if p.Subscription.Insights {
|
||||
packages = append(packages, "insights-client")
|
||||
}
|
||||
}
|
||||
|
||||
osRepos := append(p.repos, p.ExtraBaseRepos...)
|
||||
chain := []rpmmd.PackageSet{
|
||||
{
|
||||
Include: append(packages, p.ExtraBasePackages...),
|
||||
Exclude: p.ExcludeBasePackages,
|
||||
Repositories: osRepos,
|
||||
},
|
||||
}
|
||||
|
||||
if p.Workload != nil {
|
||||
workloadPackages := p.Workload.GetPackages()
|
||||
if len(workloadPackages) > 0 {
|
||||
chain = append(chain, rpmmd.PackageSet{
|
||||
Include: workloadPackages,
|
||||
Repositories: append(osRepos, p.Workload.GetRepos()...),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func (p *OS) getContainerSources() []container.SourceSpec {
|
||||
return p.OSCustomizations.Containers
|
||||
}
|
||||
|
||||
func (p *OS) getBuildPackages(distro Distro) []string {
|
||||
packages := p.platform.GetBuildPackages()
|
||||
if p.PartitionTable != nil {
|
||||
packages = append(packages, p.PartitionTable.GetBuildPackages()...)
|
||||
}
|
||||
packages = append(packages, "rpm")
|
||||
if p.OSTreeRef != "" {
|
||||
packages = append(packages, "rpm-ostree")
|
||||
}
|
||||
if p.SElinux != "" {
|
||||
packages = append(packages, "policycoreutils", fmt.Sprintf("selinux-policy-%s", p.SElinux))
|
||||
}
|
||||
if len(p.CloudInit) > 0 {
|
||||
switch distro {
|
||||
case DISTRO_EL7:
|
||||
packages = append(packages, "python3-PyYAML")
|
||||
default:
|
||||
packages = append(packages, "python3-pyyaml")
|
||||
}
|
||||
}
|
||||
if len(p.DNFConfig) > 0 || len(p.RHSMConfig) > 0 {
|
||||
packages = append(packages, "python3-iniparse")
|
||||
}
|
||||
|
||||
if len(p.OSCustomizations.Containers) > 0 {
|
||||
if p.OSTreeRef != "" {
|
||||
switch distro {
|
||||
case DISTRO_EL8:
|
||||
packages = append(packages, "python3-pytoml")
|
||||
default:
|
||||
packages = append(packages, "python3-toml")
|
||||
}
|
||||
}
|
||||
packages = append(packages, "skopeo")
|
||||
}
|
||||
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *OS) getOSTreeCommitSources() []ostree.SourceSpec {
|
||||
if p.OSTreeParent == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []ostree.SourceSpec{
|
||||
*p.OSTreeParent,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OS) getOSTreeCommits() []ostree.CommitSpec {
|
||||
if p.ostreeParentSpec == nil {
|
||||
return nil
|
||||
}
|
||||
return []ostree.CommitSpec{*p.ostreeParentSpec}
|
||||
}
|
||||
|
||||
func (p *OS) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return p.packageSpecs
|
||||
}
|
||||
|
||||
func (p *OS) getContainerSpecs() []container.Spec {
|
||||
return p.containerSpecs
|
||||
}
|
||||
|
||||
func (p *OS) serializeStart(packages []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec) {
|
||||
if len(p.packageSpecs) > 0 {
|
||||
panic("double call to serializeStart()")
|
||||
}
|
||||
|
||||
p.packageSpecs = packages
|
||||
p.containerSpecs = containers
|
||||
if len(commits) > 0 {
|
||||
if len(commits) > 1 {
|
||||
panic("pipeline supports at most one ostree commit")
|
||||
}
|
||||
p.ostreeParentSpec = &commits[0]
|
||||
}
|
||||
|
||||
if p.KernelName != "" {
|
||||
p.kernelVer = rpmmd.GetVerStrFromPackageSpecListPanic(p.packageSpecs, p.KernelName)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OS) serializeEnd() {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
p.kernelVer = ""
|
||||
p.packageSpecs = nil
|
||||
p.containerSpecs = nil
|
||||
p.ostreeParentSpec = nil
|
||||
}
|
||||
|
||||
func (p *OS) serialize() osbuild.Pipeline {
|
||||
if len(p.packageSpecs) == 0 {
|
||||
panic("serialization not started")
|
||||
}
|
||||
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
if p.ostreeParentSpec != nil {
|
||||
pipeline.AddStage(osbuild.NewOSTreePasswdStage("org.osbuild.source", p.ostreeParentSpec.Checksum))
|
||||
}
|
||||
|
||||
// collect all repos for this pipeline to create the repository options
|
||||
allRepos := append(p.repos, p.ExtraBaseRepos...)
|
||||
if p.Workload != nil {
|
||||
allRepos = append(allRepos, p.Workload.GetRepos()...)
|
||||
}
|
||||
rpmOptions := osbuild.NewRPMStageOptions(allRepos)
|
||||
if p.ExcludeDocs {
|
||||
if rpmOptions.Exclude == nil {
|
||||
rpmOptions.Exclude = &osbuild.Exclude{}
|
||||
}
|
||||
rpmOptions.Exclude.Docs = true
|
||||
}
|
||||
rpmOptions.GPGKeysFromTree = p.GPGKeyFiles
|
||||
if p.OSTreeRef != "" {
|
||||
rpmOptions.OSTreeBooted = common.ToPtr(true)
|
||||
rpmOptions.DBPath = "/usr/share/rpm"
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewRPMStage(rpmOptions, osbuild.NewRpmStageSourceFilesInputs(p.packageSpecs)))
|
||||
|
||||
if !p.NoBLS {
|
||||
// If the /boot is on a separate partition, the prefix for the BLS stage must be ""
|
||||
if p.PartitionTable == nil || p.PartitionTable.FindMountable("/boot") == nil {
|
||||
pipeline.AddStage(osbuild.NewFixBLSStage(&osbuild.FixBLSStageOptions{}))
|
||||
} else {
|
||||
pipeline.AddStage(osbuild.NewFixBLSStage(&osbuild.FixBLSStageOptions{Prefix: common.ToPtr("")}))
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.containerSpecs) > 0 {
|
||||
images := osbuild.NewContainersInputForSources(p.containerSpecs)
|
||||
|
||||
var storagePath string
|
||||
|
||||
// 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 p.OSTreeRef != "" {
|
||||
storagePath = "/usr/share/containers/storage"
|
||||
storageConf := "/etc/containers/storage.conf"
|
||||
|
||||
containerStoreOpts := osbuild.NewContainerStorageOptions(storageConf, storagePath)
|
||||
pipeline.AddStage(osbuild.NewContainersStorageConfStage(containerStoreOpts))
|
||||
}
|
||||
|
||||
manifests := osbuild.NewFilesInputForManifestLists(p.containerSpecs)
|
||||
skopeo := osbuild.NewSkopeoStage(storagePath, images, manifests)
|
||||
pipeline.AddStage(skopeo)
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: p.Language}))
|
||||
|
||||
if p.Keyboard != nil {
|
||||
keymapOptions := &osbuild.KeymapStageOptions{Keymap: *p.Keyboard}
|
||||
if len(p.X11KeymapLayouts) > 0 {
|
||||
keymapOptions.X11Keymap = &osbuild.X11KeymapOptions{Layouts: p.X11KeymapLayouts}
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewKeymapStage(keymapOptions))
|
||||
}
|
||||
|
||||
if p.Hostname != "" {
|
||||
pipeline.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: p.Hostname}))
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: p.Timezone}))
|
||||
|
||||
if len(p.NTPServers) > 0 {
|
||||
chronyOptions := &osbuild.ChronyStageOptions{Servers: p.NTPServers}
|
||||
if p.LeapSecTZ != nil {
|
||||
chronyOptions.LeapsecTz = p.LeapSecTZ
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewChronyStage(chronyOptions))
|
||||
}
|
||||
|
||||
if len(p.Groups) > 0 {
|
||||
pipeline.AddStage(osbuild.GenGroupsStage(p.Groups))
|
||||
}
|
||||
|
||||
if len(p.Users) > 0 {
|
||||
if p.OSTreeRef != "" {
|
||||
// for ostree, writing the key during user creation is
|
||||
// redundant and can cause issues so create users without keys
|
||||
// and write them on first boot
|
||||
usersStageSansKeys, err := osbuild.GenUsersStage(p.Users, true)
|
||||
if err != nil {
|
||||
// TODO: move encryption into weldr
|
||||
panic("password encryption failed")
|
||||
}
|
||||
pipeline.AddStage(usersStageSansKeys)
|
||||
pipeline.AddStage(osbuild.NewFirstBootStage(usersFirstBootOptions(p.Users)))
|
||||
} else {
|
||||
usersStage, err := osbuild.GenUsersStage(p.Users, false)
|
||||
if err != nil {
|
||||
// TODO: move encryption into weldr
|
||||
panic("password encryption failed")
|
||||
}
|
||||
pipeline.AddStage(usersStage)
|
||||
}
|
||||
}
|
||||
|
||||
if p.Firewall != nil {
|
||||
pipeline.AddStage(osbuild.NewFirewallStage(p.Firewall))
|
||||
}
|
||||
|
||||
for _, sysconfigConfig := range p.Sysconfig {
|
||||
pipeline.AddStage(osbuild.NewSysconfigStage(sysconfigConfig))
|
||||
}
|
||||
|
||||
for _, systemdLogindConfig := range p.SystemdLogind {
|
||||
pipeline.AddStage(osbuild.NewSystemdLogindStage(systemdLogindConfig))
|
||||
}
|
||||
|
||||
for _, cloudInitConfig := range p.CloudInit {
|
||||
pipeline.AddStage(osbuild.NewCloudInitStage(cloudInitConfig))
|
||||
}
|
||||
|
||||
for _, modprobeConfig := range p.Modprobe {
|
||||
pipeline.AddStage(osbuild.NewModprobeStage(modprobeConfig))
|
||||
}
|
||||
|
||||
for _, dracutConfConfig := range p.DracutConf {
|
||||
pipeline.AddStage(osbuild.NewDracutConfStage(dracutConfConfig))
|
||||
}
|
||||
|
||||
for _, systemdUnitConfig := range p.SystemdUnit {
|
||||
pipeline.AddStage(osbuild.NewSystemdUnitStage(systemdUnitConfig))
|
||||
}
|
||||
|
||||
if p.Authselect != nil {
|
||||
pipeline.AddStage(osbuild.NewAuthselectStage(p.Authselect))
|
||||
}
|
||||
|
||||
if p.SELinuxConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewSELinuxConfigStage(p.SELinuxConfig))
|
||||
}
|
||||
|
||||
if p.Tuned != nil {
|
||||
pipeline.AddStage(osbuild.NewTunedStage(p.Tuned))
|
||||
}
|
||||
|
||||
for _, tmpfilesdConfig := range p.Tmpfilesd {
|
||||
pipeline.AddStage(osbuild.NewTmpfilesdStage(tmpfilesdConfig))
|
||||
}
|
||||
|
||||
for _, pamLimitsConfConfig := range p.PamLimitsConf {
|
||||
pipeline.AddStage(osbuild.NewPamLimitsConfStage(pamLimitsConfConfig))
|
||||
}
|
||||
|
||||
for _, sysctldConfig := range p.Sysctld {
|
||||
pipeline.AddStage(osbuild.NewSysctldStage(sysctldConfig))
|
||||
}
|
||||
|
||||
for _, dnfConfig := range p.DNFConfig {
|
||||
pipeline.AddStage(osbuild.NewDNFConfigStage(dnfConfig))
|
||||
}
|
||||
|
||||
if p.DNFAutomaticConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewDNFAutomaticConfigStage(p.DNFAutomaticConfig))
|
||||
}
|
||||
|
||||
for _, yumRepo := range p.YUMRepos {
|
||||
pipeline.AddStage(osbuild.NewYumReposStage(yumRepo))
|
||||
}
|
||||
|
||||
if p.YUMConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewYumConfigStage(p.YUMConfig))
|
||||
}
|
||||
|
||||
if p.GCPGuestAgentConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewGcpGuestAgentConfigStage(p.GCPGuestAgentConfig))
|
||||
}
|
||||
|
||||
if p.SshdConfig != nil {
|
||||
pipeline.AddStage((osbuild.NewSshdConfigStage(p.SshdConfig)))
|
||||
}
|
||||
|
||||
if p.AuthConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewAuthconfigStage(p.AuthConfig))
|
||||
}
|
||||
|
||||
if p.PwQuality != nil {
|
||||
pipeline.AddStage(osbuild.NewPwqualityConfStage(p.PwQuality))
|
||||
}
|
||||
|
||||
// If subscription settings are included there are 3 possible setups:
|
||||
// - Register the system with rhc and enable Insights
|
||||
// - Register with subscription-manager, no Insights or rhc
|
||||
// - Register with subscription-manager and enable Insights, no rhc
|
||||
if p.Subscription != nil {
|
||||
var commands []string
|
||||
if p.Subscription.Rhc {
|
||||
// Use rhc for registration instead of subscription manager
|
||||
commands = []string{fmt.Sprintf("/usr/bin/rhc connect -o=%s -a=%s --server %s", p.Subscription.Organization, p.Subscription.ActivationKey, p.Subscription.ServerUrl)}
|
||||
// insights-client creates the .gnupg directory during boot process, and is labeled incorrectly
|
||||
commands = append(commands, "restorecon -R /root/.gnupg")
|
||||
// execute the rhc post install script as the selinuxenabled check doesn't work in the buildroot container
|
||||
commands = append(commands, "/usr/sbin/semanage permissive --add rhcd_t")
|
||||
} else {
|
||||
commands = []string{fmt.Sprintf("/usr/sbin/subscription-manager register --org=%s --activationkey=%s --serverurl %s --baseurl %s", p.Subscription.Organization, p.Subscription.ActivationKey, p.Subscription.ServerUrl, p.Subscription.BaseUrl)}
|
||||
|
||||
// Insights is optional when using subscription-manager
|
||||
if p.Subscription.Insights {
|
||||
commands = append(commands, "/usr/bin/insights-client --register")
|
||||
// insights-client creates the .gnupg directory during boot process, and is labeled incorrectly
|
||||
commands = append(commands, "restorecon -R /root/.gnupg")
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewFirstBootStage(&osbuild.FirstBootStageOptions{
|
||||
Commands: commands,
|
||||
WaitForNetwork: true,
|
||||
}))
|
||||
|
||||
if rhsmConfig, exists := p.RHSMConfig[subscription.RHSMConfigWithSubscription]; exists {
|
||||
pipeline.AddStage(osbuild.NewRHSMStage(rhsmConfig))
|
||||
}
|
||||
} else {
|
||||
if rhsmConfig, exists := p.RHSMConfig[subscription.RHSMConfigNoSubscription]; exists {
|
||||
pipeline.AddStage(osbuild.NewRHSMStage(rhsmConfig))
|
||||
}
|
||||
}
|
||||
|
||||
if waConfig := p.WAAgentConfig; waConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewWAAgentConfStage(waConfig))
|
||||
}
|
||||
|
||||
if udevRules := p.UdevRules; udevRules != nil {
|
||||
pipeline.AddStage(osbuild.NewUdevRulesStage(udevRules))
|
||||
}
|
||||
|
||||
if pt := p.PartitionTable; pt != nil {
|
||||
kernelOptions := osbuild.GenImageKernelOptions(p.PartitionTable)
|
||||
kernelOptions = append(kernelOptions, p.KernelOptionsAppend...)
|
||||
if !p.KernelOptionsBootloader {
|
||||
pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt)
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewFSTabStage(osbuild.NewFSTabStageOptions(pt)))
|
||||
|
||||
var bootloader *osbuild.Stage
|
||||
switch p.platform.GetArch() {
|
||||
case platform.ARCH_S390X:
|
||||
bootloader = osbuild.NewZiplStage(new(osbuild.ZiplStageOptions))
|
||||
default:
|
||||
if p.NoBLS {
|
||||
// BLS entries not supported: use grub2.legacy
|
||||
id := "76a22bf4-f153-4541-b6c7-0332c0dfaeac"
|
||||
product := osbuild.GRUB2Product{
|
||||
Name: p.OSProduct,
|
||||
Version: p.OSVersion,
|
||||
Nick: p.OSNick,
|
||||
}
|
||||
|
||||
_, err := rpmmd.GetVerStrFromPackageSpecList(p.packageSpecs, "dracut-config-rescue")
|
||||
hasRescue := err == nil
|
||||
bootloader = osbuild.NewGrub2LegacyStage(
|
||||
osbuild.NewGrub2LegacyStageOptions(
|
||||
p.Grub2Config,
|
||||
p.PartitionTable,
|
||||
kernelOptions,
|
||||
p.platform.GetBIOSPlatform(),
|
||||
p.platform.GetUEFIVendor(),
|
||||
osbuild.MakeGrub2MenuEntries(id, p.kernelVer, product, hasRescue),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
options := osbuild.NewGrub2StageOptionsUnified(pt,
|
||||
strings.Join(kernelOptions, " "),
|
||||
p.kernelVer,
|
||||
p.platform.GetUEFIVendor() != "",
|
||||
p.platform.GetBIOSPlatform(),
|
||||
p.platform.GetUEFIVendor(), false)
|
||||
if cfg := p.Grub2Config; cfg != nil {
|
||||
// TODO: don't store Grub2Config in OSPipeline, making the overrides unnecessary
|
||||
// grub2.Config.Default is owned and set by `NewGrub2StageOptionsUnified`
|
||||
// and thus we need to preserve it
|
||||
if options.Config != nil {
|
||||
cfg.Default = options.Config.Default
|
||||
}
|
||||
|
||||
options.Config = cfg
|
||||
}
|
||||
if p.KernelOptionsBootloader {
|
||||
options.WriteCmdLine = nil
|
||||
if options.UEFI != nil {
|
||||
options.UEFI.Unified = false
|
||||
}
|
||||
}
|
||||
bootloader = osbuild.NewGRUB2Stage(options)
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.AddStage(bootloader)
|
||||
}
|
||||
|
||||
if p.OpenSCAPConfig != nil {
|
||||
pipeline.AddStage(osbuild.NewOscapRemediationStage(p.OpenSCAPConfig))
|
||||
}
|
||||
|
||||
if p.FactAPIType != nil {
|
||||
pipeline.AddStage(osbuild.NewRHSMFactsStage(&osbuild.RHSMFactsStageOptions{
|
||||
Facts: osbuild.RHSMFacts{
|
||||
ApiType: p.FactAPIType.String(),
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
if p.OSTreeRef != "" {
|
||||
pipeline.AddStage(osbuild.NewSystemdJournaldStage(
|
||||
&osbuild.SystemdJournaldStageOptions{
|
||||
Filename: "10-persistent.conf",
|
||||
Config: osbuild.SystemdJournaldConfigDropin{
|
||||
Journal: osbuild.SystemdJournaldConfigJournalSection{
|
||||
Storage: osbuild.StoragePresistent,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
// First create custom directories, because some of the custom files may depend on them
|
||||
if len(p.Directories) > 0 {
|
||||
pipeline.AddStages(osbuild.GenDirectoryNodesStages(p.Directories)...)
|
||||
}
|
||||
|
||||
if len(p.Files) > 0 {
|
||||
pipeline.AddStages(osbuild.GenFileNodesStages(p.Files)...)
|
||||
}
|
||||
|
||||
enabledServices := []string{}
|
||||
disabledServices := []string{}
|
||||
enabledServices = append(enabledServices, p.EnabledServices...)
|
||||
disabledServices = append(disabledServices, p.DisabledServices...)
|
||||
if p.Environment != nil {
|
||||
enabledServices = append(enabledServices, p.Environment.GetServices()...)
|
||||
}
|
||||
if p.Workload != nil {
|
||||
enabledServices = append(enabledServices, p.Workload.GetServices()...)
|
||||
disabledServices = append(disabledServices, p.Workload.GetDisabledServices()...)
|
||||
}
|
||||
if len(enabledServices) != 0 ||
|
||||
len(disabledServices) != 0 || p.DefaultTarget != "" {
|
||||
pipeline.AddStage(osbuild.NewSystemdStage(&osbuild.SystemdStageOptions{
|
||||
EnabledServices: enabledServices,
|
||||
DisabledServices: disabledServices,
|
||||
DefaultTarget: p.DefaultTarget,
|
||||
}))
|
||||
}
|
||||
if len(p.ShellInit) > 0 {
|
||||
pipeline.AddStage(osbuild.GenShellInitStage(p.ShellInit))
|
||||
}
|
||||
|
||||
if p.SElinux != "" {
|
||||
pipeline.AddStage(osbuild.NewSELinuxStage(&osbuild.SELinuxStageOptions{
|
||||
FileContexts: fmt.Sprintf("etc/selinux/%s/contexts/files/file_contexts", p.SElinux),
|
||||
ForceAutorelabel: p.SELinuxForceRelabel,
|
||||
}))
|
||||
}
|
||||
|
||||
if p.OSTreeRef != "" {
|
||||
pipeline.AddStage(osbuild.NewOSTreePrepTreeStage(&osbuild.OSTreePrepTreeStageOptions{
|
||||
EtcGroupMembers: []string{
|
||||
// NOTE: We may want to make this configurable.
|
||||
"wheel", "docker",
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func prependKernelCmdlineStage(pipeline osbuild.Pipeline, kernelOptions string, pt *disk.PartitionTable) osbuild.Pipeline {
|
||||
rootFs := pt.FindMountable("/")
|
||||
if rootFs == nil {
|
||||
panic("root filesystem must be defined for kernel-cmdline stage, this is a programming error")
|
||||
}
|
||||
rootFsUUID := rootFs.GetFSSpec().UUID
|
||||
kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootFsUUID, kernelOptions))
|
||||
pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...)
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func usersFirstBootOptions(users []users.User) *osbuild.FirstBootStageOptions {
|
||||
cmds := make([]string, 0, 3*len(users)+2)
|
||||
// workaround for creating authorized_keys file for user
|
||||
// need to special case the root user, which has its home in a different place
|
||||
varhome := filepath.Join("/var", "home")
|
||||
roothome := filepath.Join("/var", "roothome")
|
||||
|
||||
for _, user := range users {
|
||||
if user.Key != nil {
|
||||
var home string
|
||||
|
||||
if user.Name == "root" {
|
||||
home = roothome
|
||||
} else {
|
||||
home = filepath.Join(varhome, user.Name)
|
||||
}
|
||||
|
||||
sshdir := filepath.Join(home, ".ssh")
|
||||
|
||||
cmds = append(cmds, fmt.Sprintf("mkdir -p %s", sshdir))
|
||||
cmds = append(cmds, fmt.Sprintf("sh -c 'echo %q >> %q'", *user.Key, filepath.Join(sshdir, "authorized_keys")))
|
||||
cmds = append(cmds, fmt.Sprintf("chown %s:%s -Rc %s", user.Name, user.Name, sshdir))
|
||||
}
|
||||
}
|
||||
cmds = append(cmds, fmt.Sprintf("restorecon -rvF %s", varhome))
|
||||
cmds = append(cmds, fmt.Sprintf("restorecon -rvF %s", roothome))
|
||||
|
||||
options := &osbuild.FirstBootStageOptions{
|
||||
Commands: cmds,
|
||||
WaitForNetwork: false,
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (p *OS) GetPlatform() platform.Platform {
|
||||
return p.platform
|
||||
}
|
||||
|
||||
func (p *OS) getInline() []string {
|
||||
inlineData := []string{}
|
||||
|
||||
// inline data for custom files
|
||||
for _, file := range p.Files {
|
||||
inlineData = append(inlineData, string(file.Data()))
|
||||
}
|
||||
|
||||
return inlineData
|
||||
}
|
||||
348
vendor/github.com/osbuild/images/pkg/manifest/ostree_deployment.go
generated
vendored
Normal file
348
vendor/github.com/osbuild/images/pkg/manifest/ostree_deployment.go
generated
vendored
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/images/internal/common"
|
||||
"github.com/osbuild/images/internal/fsnode"
|
||||
"github.com/osbuild/images/internal/users"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/disk"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
// OSTreeDeployment represents the filesystem tree of a target image based
|
||||
// on a deployed ostree commit.
|
||||
type OSTreeDeployment struct {
|
||||
Base
|
||||
|
||||
Remote ostree.Remote
|
||||
|
||||
OSVersion string
|
||||
|
||||
commitSource ostree.SourceSpec
|
||||
ostreeSpecs []ostree.CommitSpec
|
||||
|
||||
SysrootReadOnly bool
|
||||
|
||||
osName string
|
||||
|
||||
KernelOptionsAppend []string
|
||||
Keyboard string
|
||||
Locale string
|
||||
|
||||
Users []users.User
|
||||
Groups []users.Group
|
||||
|
||||
platform platform.Platform
|
||||
|
||||
PartitionTable *disk.PartitionTable
|
||||
|
||||
// Whether ignition is in use or not
|
||||
ignition bool
|
||||
|
||||
Directories []*fsnode.Directory
|
||||
Files []*fsnode.File
|
||||
|
||||
EnabledServices []string
|
||||
DisabledServices []string
|
||||
}
|
||||
|
||||
// NewOSTreeDeployment creates a pipeline for an ostree deployment from a
|
||||
// commit.
|
||||
func NewOSTreeDeployment(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
commit ostree.SourceSpec,
|
||||
osName string,
|
||||
ignition bool,
|
||||
platform platform.Platform) *OSTreeDeployment {
|
||||
|
||||
p := &OSTreeDeployment{
|
||||
Base: NewBase(m, "ostree-deployment", buildPipeline),
|
||||
commitSource: commit,
|
||||
osName: osName,
|
||||
platform: platform,
|
||||
ignition: ignition,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) getBuildPackages(Distro) []string {
|
||||
packages := []string{
|
||||
"rpm-ostree",
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) getOSTreeCommits() []ostree.CommitSpec {
|
||||
return p.ostreeSpecs
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) getOSTreeCommitSources() []ostree.SourceSpec {
|
||||
return []ostree.SourceSpec{
|
||||
p.commitSource,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) serializeStart(packages []rpmmd.PackageSpec, containers []container.Spec, commits []ostree.CommitSpec) {
|
||||
if len(p.ostreeSpecs) > 0 {
|
||||
panic("double call to serializeStart()")
|
||||
}
|
||||
|
||||
if len(commits) != 1 {
|
||||
panic("pipeline requires exactly one ostree commit")
|
||||
}
|
||||
|
||||
p.ostreeSpecs = commits
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) serializeEnd() {
|
||||
if len(p.ostreeSpecs) == 0 {
|
||||
panic("serializeEnd() call when serialization not in progress")
|
||||
}
|
||||
|
||||
p.ostreeSpecs = nil
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) serialize() osbuild.Pipeline {
|
||||
if len(p.ostreeSpecs) == 0 {
|
||||
panic("serialization not started")
|
||||
}
|
||||
if len(p.ostreeSpecs) > 1 {
|
||||
panic("multiple ostree commit specs found; this is a programming error")
|
||||
}
|
||||
commit := p.ostreeSpecs[0]
|
||||
|
||||
const repoPath = "/ostree/repo"
|
||||
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.OSTreeInitFsStage())
|
||||
pipeline.AddStage(osbuild.NewOSTreePullStage(
|
||||
&osbuild.OSTreePullStageOptions{Repo: repoPath, Remote: p.Remote.Name},
|
||||
osbuild.NewOstreePullStageInputs("org.osbuild.source", commit.Checksum, commit.Ref),
|
||||
))
|
||||
pipeline.AddStage(osbuild.NewOSTreeOsInitStage(
|
||||
&osbuild.OSTreeOsInitStageOptions{
|
||||
OSName: p.osName,
|
||||
},
|
||||
))
|
||||
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
||||
Paths: []osbuild.MkdirStagePath{
|
||||
{
|
||||
Path: "/boot/efi",
|
||||
Mode: common.ToPtr(os.FileMode(0700)),
|
||||
},
|
||||
},
|
||||
}))
|
||||
kernelOpts := osbuild.GenImageKernelOptions(p.PartitionTable)
|
||||
kernelOpts = append(kernelOpts, p.KernelOptionsAppend...)
|
||||
|
||||
if p.ignition {
|
||||
kernelOpts = append(kernelOpts,
|
||||
"coreos.no_persist_ip", // users cannot add connections as we don't have a live iso, this prevents connections to bleed into the system from the ign initrd
|
||||
"ignition.platform.id=metal",
|
||||
"$ignition_firstboot",
|
||||
)
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreeDeployStage(
|
||||
&osbuild.OSTreeDeployStageOptions{
|
||||
OsName: p.osName,
|
||||
Ref: commit.Ref,
|
||||
Remote: p.Remote.Name,
|
||||
Mounts: []string{"/boot", "/boot/efi"},
|
||||
Rootfs: osbuild.Rootfs{
|
||||
Label: "root",
|
||||
},
|
||||
KernelOpts: kernelOpts,
|
||||
},
|
||||
))
|
||||
|
||||
remoteURL := p.Remote.URL
|
||||
if remoteURL == "" {
|
||||
// if the remote URL for the image is not specified, use the source commit URL
|
||||
remoteURL = commit.URL
|
||||
}
|
||||
pipeline.AddStage(osbuild.NewOSTreeRemotesStage(
|
||||
&osbuild.OSTreeRemotesStageOptions{
|
||||
Repo: "/ostree/repo",
|
||||
Remotes: []osbuild.OSTreeRemote{
|
||||
{
|
||||
Name: p.Remote.Name,
|
||||
URL: remoteURL,
|
||||
ContentURL: p.Remote.ContentURL,
|
||||
GPGKeyPaths: p.Remote.GPGKeyPaths,
|
||||
},
|
||||
},
|
||||
},
|
||||
))
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreeFillvarStage(
|
||||
&osbuild.OSTreeFillvarStageOptions{
|
||||
Deployment: osbuild.OSTreeDeployment{
|
||||
OSName: p.osName,
|
||||
Ref: commit.Ref,
|
||||
},
|
||||
},
|
||||
))
|
||||
|
||||
configStage := osbuild.NewOSTreeConfigStage(
|
||||
&osbuild.OSTreeConfigStageOptions{
|
||||
Repo: repoPath,
|
||||
Config: &osbuild.OSTreeConfig{
|
||||
Sysroot: &osbuild.SysrootOptions{
|
||||
ReadOnly: &p.SysrootReadOnly,
|
||||
Bootloader: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
configStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(configStage)
|
||||
|
||||
fstabOptions := osbuild.NewFSTabStageOptions(p.PartitionTable)
|
||||
fstabStage := osbuild.NewFSTabStage(fstabOptions)
|
||||
fstabStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(fstabStage)
|
||||
|
||||
if len(p.Users) > 0 {
|
||||
usersStage, err := osbuild.GenUsersStage(p.Users, false)
|
||||
if err != nil {
|
||||
panic("password encryption failed")
|
||||
}
|
||||
usersStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(usersStage)
|
||||
}
|
||||
|
||||
if len(p.Groups) > 0 {
|
||||
grpStage := osbuild.GenGroupsStage(p.Groups)
|
||||
grpStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(grpStage)
|
||||
}
|
||||
|
||||
if p.ignition {
|
||||
pipeline.AddStage(osbuild.NewIgnitionStage(&osbuild.IgnitionStageOptions{
|
||||
// This is a workaround to make the systemd believe it's firstboot when ignition runs on real firstboot.
|
||||
// Right now, since we ship /etc/machine-id, systemd thinks it's not firstboot and ignition depends on it
|
||||
// to run on the real firstboot to enable services from presets.
|
||||
// Since this only applies to artifacts with ignition and changing machineid-compat at commit creation time may
|
||||
// have undesiderable effect, we're doing it here as a stopgap. We may revisit this in the future.
|
||||
Network: []string{
|
||||
"systemd.firstboot=off",
|
||||
"systemd.condition-first-boot=true",
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
// if no root password is set, lock the root account
|
||||
hasRoot := false
|
||||
for _, user := range p.Users {
|
||||
if user.Name == "root" {
|
||||
hasRoot = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasRoot {
|
||||
userOptions := &osbuild.UsersStageOptions{
|
||||
Users: map[string]osbuild.UsersStageOptionsUser{
|
||||
"root": {
|
||||
Password: common.ToPtr("!locked"), // this is treated as crypted and locks/disables the password
|
||||
},
|
||||
},
|
||||
}
|
||||
rootLockStage := osbuild.NewUsersStage(userOptions)
|
||||
rootLockStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(rootLockStage)
|
||||
}
|
||||
|
||||
if p.Keyboard != "" {
|
||||
options := &osbuild.KeymapStageOptions{
|
||||
Keymap: p.Keyboard,
|
||||
}
|
||||
keymapStage := osbuild.NewKeymapStage(options)
|
||||
keymapStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(keymapStage)
|
||||
}
|
||||
|
||||
if p.Locale != "" {
|
||||
options := &osbuild.LocaleStageOptions{
|
||||
Language: p.Locale,
|
||||
}
|
||||
localeStage := osbuild.NewLocaleStage(options)
|
||||
localeStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(localeStage)
|
||||
}
|
||||
|
||||
grubOptions := osbuild.NewGrub2StageOptionsUnified(p.PartitionTable,
|
||||
strings.Join(kernelOpts, " "),
|
||||
"",
|
||||
p.platform.GetUEFIVendor() != "",
|
||||
p.platform.GetBIOSPlatform(),
|
||||
p.platform.GetUEFIVendor(), true)
|
||||
grubOptions.Greenboot = true
|
||||
grubOptions.Ignition = p.ignition
|
||||
grubOptions.Config = &osbuild.GRUB2Config{
|
||||
Default: "saved",
|
||||
Timeout: 1,
|
||||
TerminalOutput: []string{"console"},
|
||||
}
|
||||
bootloader := osbuild.NewGRUB2Stage(grubOptions)
|
||||
bootloader.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(bootloader)
|
||||
|
||||
// First create custom directories, because some of the files may depend on them
|
||||
if len(p.Directories) > 0 {
|
||||
dirStages := osbuild.GenDirectoryNodesStages(p.Directories)
|
||||
for _, stage := range dirStages {
|
||||
stage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
}
|
||||
pipeline.AddStages(dirStages...)
|
||||
}
|
||||
|
||||
if len(p.Files) > 0 {
|
||||
fileStages := osbuild.GenFileNodesStages(p.Files)
|
||||
for _, stage := range fileStages {
|
||||
stage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
}
|
||||
pipeline.AddStages(fileStages...)
|
||||
}
|
||||
|
||||
if len(p.EnabledServices) != 0 || len(p.DisabledServices) != 0 {
|
||||
systemdStage := osbuild.NewSystemdStage(&osbuild.SystemdStageOptions{
|
||||
EnabledServices: p.EnabledServices,
|
||||
DisabledServices: p.DisabledServices,
|
||||
})
|
||||
systemdStage.MountOSTree(p.osName, commit.Ref, 0)
|
||||
pipeline.AddStage(systemdStage)
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewOSTreeSelinuxStage(
|
||||
&osbuild.OSTreeSelinuxStageOptions{
|
||||
Deployment: osbuild.OSTreeDeployment{
|
||||
OSName: p.osName,
|
||||
Ref: commit.Ref,
|
||||
},
|
||||
},
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *OSTreeDeployment) getInline() []string {
|
||||
inlineData := []string{}
|
||||
|
||||
// inline data for custom files
|
||||
for _, file := range p.Files {
|
||||
inlineData = append(inlineData, string(file.Data()))
|
||||
}
|
||||
|
||||
return inlineData
|
||||
}
|
||||
57
vendor/github.com/osbuild/images/pkg/manifest/ovf.go
generated
vendored
Normal file
57
vendor/github.com/osbuild/images/pkg/manifest/ovf.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// A OVF copies a vmdk image to it's own tree and generates an OVF descriptor
|
||||
type OVF struct {
|
||||
Base
|
||||
|
||||
imgPipeline *VMDK
|
||||
}
|
||||
|
||||
// NewOVF creates a new OVF pipeline. imgPipeline is the pipeline producing the vmdk image.
|
||||
func NewOVF(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
imgPipeline *VMDK) *OVF {
|
||||
p := &OVF{
|
||||
Base: NewBase(m, "ovf", buildPipeline),
|
||||
imgPipeline: imgPipeline,
|
||||
}
|
||||
if imgPipeline.Base.manifest != m {
|
||||
panic("live image pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *OVF) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
inputName := "vmdk-tree"
|
||||
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
||||
&osbuild.CopyStageOptions{
|
||||
Paths: []osbuild.CopyStagePath{
|
||||
osbuild.CopyStagePath{
|
||||
From: fmt.Sprintf("input://%s/%s", inputName, p.imgPipeline.Export().Filename()),
|
||||
To: "tree:///",
|
||||
},
|
||||
},
|
||||
},
|
||||
osbuild.NewPipelineTreeInputs(inputName, p.imgPipeline.Name()),
|
||||
))
|
||||
|
||||
pipeline.AddStage(osbuild.NewOVFStage(&osbuild.OVFStageOptions{
|
||||
Vmdk: p.imgPipeline.Filename,
|
||||
}))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *OVF) getBuildPackages(Distro) []string {
|
||||
return []string{"qemu-img"}
|
||||
}
|
||||
183
vendor/github.com/osbuild/images/pkg/manifest/pipeline.go
generated
vendored
Normal file
183
vendor/github.com/osbuild/images/pkg/manifest/pipeline.go
generated
vendored
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/container"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
)
|
||||
|
||||
// Pipeline serializes to a series of stages that modify a file system tree
|
||||
// when used as input to osbuild. Different Pipelines serialize to different
|
||||
// sequences of stages depending on their type and configuration.
|
||||
type Pipeline interface {
|
||||
|
||||
// Name of the pipeline.
|
||||
Name() string
|
||||
|
||||
// Checkpoint this pipeline when osbuild is called.
|
||||
Checkpoint()
|
||||
|
||||
// Export this tree of this pipeline as an artifact when osbuild is called.
|
||||
Export() *artifact.Artifact
|
||||
|
||||
getCheckpoint() bool
|
||||
|
||||
getExport() bool
|
||||
|
||||
// getBuildPackages returns the list of packages required for the pipeline
|
||||
// at build time.
|
||||
getBuildPackages(Distro) []string
|
||||
// getPackageSetChain returns the list of package names to be required by
|
||||
// the pipeline. Each set should be depsolved sequentially to resolve
|
||||
// dependencies and full package specs. See the dnfjson package for more
|
||||
// details.
|
||||
getPackageSetChain(Distro) []rpmmd.PackageSet
|
||||
// getContainerSources returns the list of containers sources to be resolved and
|
||||
// embedded by the pipeline. Each source should be resolved to its full
|
||||
// Spec. See the container package for more details.
|
||||
getContainerSources() []container.SourceSpec
|
||||
// getOSTreeCommitSources returns the list of ostree commit sources to be
|
||||
// resolved and added to the pipeline. Each source should be resolved to
|
||||
// its full Spec. See the ostree package for more details.
|
||||
getOSTreeCommitSources() []ostree.SourceSpec
|
||||
|
||||
serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec)
|
||||
serializeEnd()
|
||||
serialize() osbuild.Pipeline
|
||||
|
||||
// getPackageSpecs returns the list of specifications for packages that
|
||||
// will be installed to the pipeline tree.
|
||||
getPackageSpecs() []rpmmd.PackageSpec
|
||||
// getContainerSpecs returns the list of specifications for the containers
|
||||
// that will be installed to the pipeline tree.
|
||||
getContainerSpecs() []container.Spec
|
||||
// getOSTreeCommits returns the list of specifications for the commits
|
||||
// required by the pipeline.
|
||||
getOSTreeCommits() []ostree.CommitSpec
|
||||
// getInline returns the list of inlined data content that will be used to
|
||||
// embed files in the pipeline tree.
|
||||
getInline() []string
|
||||
}
|
||||
|
||||
// A Base represents the core functionality shared between each of the pipeline
|
||||
// implementations, and the Base struct must be embedded in each of them.
|
||||
type Base struct {
|
||||
manifest *Manifest
|
||||
name string
|
||||
build *Build
|
||||
checkpoint bool
|
||||
export bool
|
||||
}
|
||||
|
||||
// Name returns the name of the pipeline. The name must be unique for a given manifest.
|
||||
// Pipeline names are used to refer to pipelines either as dependencies between pipelines
|
||||
// or for exporting them.
|
||||
func (p Base) Name() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
func (p *Base) Checkpoint() {
|
||||
p.checkpoint = true
|
||||
}
|
||||
|
||||
func (p Base) getCheckpoint() bool {
|
||||
return p.checkpoint
|
||||
}
|
||||
|
||||
func (p *Base) Export() *artifact.Artifact {
|
||||
panic("can't export pipeline")
|
||||
}
|
||||
|
||||
func (p Base) getExport() bool {
|
||||
return p.export
|
||||
}
|
||||
|
||||
func (p Base) GetManifest() *Manifest {
|
||||
return p.manifest
|
||||
}
|
||||
|
||||
func (p Base) getBuildPackages(Distro) []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (p Base) getPackageSetChain(Distro) []rpmmd.PackageSet {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p Base) getContainerSources() []container.SourceSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p Base) getOSTreeCommitSources() []ostree.SourceSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p Base) getPackageSpecs() []rpmmd.PackageSpec {
|
||||
return []rpmmd.PackageSpec{}
|
||||
}
|
||||
|
||||
func (p Base) getOSTreeCommits() []ostree.CommitSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p Base) getContainerSpecs() []container.Spec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p Base) getInline() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// NewBase returns a generic Pipeline object. The name is mandatory, immutable and must
|
||||
// be unique among all the pipelines used in a manifest, which is currently not enforced.
|
||||
// The build argument is a pipeline representing a build root in which the rest of the
|
||||
// pipeline is built. In order to ensure reproducibility a build pipeline must always be
|
||||
// provided, except for int he build pipeline itself. When a build pipeline is not provided
|
||||
// the build host's filesystem is used as the build root. The runner specifies how to use this
|
||||
// pipeline as a build pipeline, by naming the distro it contains. When the host system is used
|
||||
// as a build root, then the necessary runner is autodetected.
|
||||
func NewBase(m *Manifest, name string, build *Build) Base {
|
||||
p := Base{
|
||||
manifest: m,
|
||||
name: name,
|
||||
build: build,
|
||||
}
|
||||
if build != nil {
|
||||
if build.Base.manifest != m {
|
||||
panic("build pipeline from a different manifest")
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// serializeStart must be called exactly once before each call
|
||||
// to serialize().
|
||||
func (p Base) serializeStart([]rpmmd.PackageSpec, []container.Spec, []ostree.CommitSpec) {
|
||||
}
|
||||
|
||||
// serializeEnd must be called exactly once after each call to
|
||||
// serialize().
|
||||
func (p Base) serializeEnd() {
|
||||
}
|
||||
|
||||
// Serialize turns a given pipeline into an osbuild.Pipeline object. This object is
|
||||
// meant to be treated as opaque and not to be modified further outside of the pipeline
|
||||
// package.
|
||||
func (p Base) serialize() osbuild.Pipeline {
|
||||
pipeline := osbuild.Pipeline{
|
||||
Name: p.name,
|
||||
}
|
||||
if p.build != nil {
|
||||
pipeline.Build = "name:" + p.build.Name()
|
||||
}
|
||||
return pipeline
|
||||
}
|
||||
|
||||
type Tree interface {
|
||||
Name() string
|
||||
GetManifest() *Manifest
|
||||
GetPlatform() platform.Platform
|
||||
}
|
||||
59
vendor/github.com/osbuild/images/pkg/manifest/qcow2.go
generated
vendored
Normal file
59
vendor/github.com/osbuild/images/pkg/manifest/qcow2.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// A QCOW2 turns a raw image file into qcow2 image.
|
||||
type QCOW2 struct {
|
||||
Base
|
||||
Filename string
|
||||
Compat string
|
||||
|
||||
imgPipeline *RawImage
|
||||
}
|
||||
|
||||
// NewQCOW2 createsa new QCOW2 pipeline. imgPipeline is the pipeline producing the
|
||||
// raw image. The pipeline name is the name of the new pipeline. Filename is the name
|
||||
// of the produced qcow2 image.
|
||||
func NewQCOW2(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
imgPipeline *RawImage) *QCOW2 {
|
||||
p := &QCOW2{
|
||||
Base: NewBase(m, "qcow2", buildPipeline),
|
||||
imgPipeline: imgPipeline,
|
||||
Filename: "image.qcow2",
|
||||
}
|
||||
if imgPipeline.Base.manifest != m {
|
||||
panic("live image pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *QCOW2) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewQEMUStage(
|
||||
osbuild.NewQEMUStageOptions(p.Filename,
|
||||
osbuild.QEMUFormatQCOW2,
|
||||
osbuild.QCOW2Options{
|
||||
Compat: p.Compat,
|
||||
}),
|
||||
osbuild.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename),
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *QCOW2) getBuildPackages(Distro) []string {
|
||||
return []string{"qemu-img"}
|
||||
}
|
||||
|
||||
func (p *QCOW2) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-qemu-disk"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
80
vendor/github.com/osbuild/images/pkg/manifest/raw.go
generated
vendored
Normal file
80
vendor/github.com/osbuild/images/pkg/manifest/raw.go
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
)
|
||||
|
||||
// A RawImage represents a raw image file which can be booted in a
|
||||
// hypervisor. It is created from an existing OSPipeline.
|
||||
type RawImage struct {
|
||||
Base
|
||||
treePipeline *OS
|
||||
Filename string
|
||||
PartTool osbuild.PartTool
|
||||
}
|
||||
|
||||
func NewRawImage(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
treePipeline *OS) *RawImage {
|
||||
p := &RawImage{
|
||||
Base: NewBase(m, "image", buildPipeline),
|
||||
treePipeline: treePipeline,
|
||||
Filename: "disk.img",
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
if treePipeline.Base.manifest != m {
|
||||
panic("tree pipeline from different manifest")
|
||||
}
|
||||
p.PartTool = osbuild.PTSfdisk // default; can be changed after initialisation
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *RawImage) getBuildPackages(d Distro) []string {
|
||||
pkgs := p.treePipeline.getBuildPackages(d)
|
||||
if p.PartTool == osbuild.PTSgdisk {
|
||||
pkgs = append(pkgs, "gdisk")
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func (p *RawImage) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pt := p.treePipeline.PartitionTable
|
||||
if pt == nil {
|
||||
panic("no partition table in live image")
|
||||
}
|
||||
|
||||
for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename, p.PartTool) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
inputName := "root-tree"
|
||||
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, pt)
|
||||
copyInputs := osbuild.NewPipelineTreeInputs(inputName, p.treePipeline.Name())
|
||||
pipeline.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
|
||||
|
||||
for _, stage := range osbuild.GenImageFinishStages(pt, p.Filename) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
switch p.treePipeline.platform.GetArch() {
|
||||
case platform.ARCH_S390X:
|
||||
loopback := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: p.Filename})
|
||||
pipeline.AddStage(osbuild.NewZiplInstStage(osbuild.NewZiplInstStageOptions(p.treePipeline.kernelVer, pt), loopback, copyDevices, copyMounts))
|
||||
default:
|
||||
if grubLegacy := p.treePipeline.platform.GetBIOSPlatform(); grubLegacy != "" {
|
||||
pipeline.AddStage(osbuild.NewGrub2InstStage(osbuild.NewGrub2InstStageOption(p.Filename, pt, grubLegacy)))
|
||||
}
|
||||
}
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *RawImage) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
return artifact.New(p.Name(), p.Filename, nil)
|
||||
}
|
||||
108
vendor/github.com/osbuild/images/pkg/manifest/raw_ostree.go
generated
vendored
Normal file
108
vendor/github.com/osbuild/images/pkg/manifest/raw_ostree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/platform"
|
||||
)
|
||||
|
||||
// A RawOSTreeImage represents a raw ostree image file which can be booted in a
|
||||
// hypervisor. It is created from an existing OSTreeDeployment.
|
||||
type RawOSTreeImage struct {
|
||||
Base
|
||||
treePipeline *OSTreeDeployment
|
||||
Filename string
|
||||
platform platform.Platform
|
||||
}
|
||||
|
||||
func NewRawOStreeImage(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
platform platform.Platform,
|
||||
treePipeline *OSTreeDeployment) *RawOSTreeImage {
|
||||
p := &RawOSTreeImage{
|
||||
Base: NewBase(m, "image", buildPipeline),
|
||||
treePipeline: treePipeline,
|
||||
Filename: "disk.img",
|
||||
platform: platform,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
if treePipeline.Base.manifest != m {
|
||||
panic("tree pipeline from different manifest")
|
||||
}
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *RawOSTreeImage) getBuildPackages(Distro) []string {
|
||||
packages := p.platform.GetBuildPackages()
|
||||
packages = append(packages, p.platform.GetPackages()...)
|
||||
packages = append(packages, p.treePipeline.PartitionTable.GetBuildPackages()...)
|
||||
packages = append(packages,
|
||||
"rpm-ostree",
|
||||
|
||||
// these should be defined on the platform
|
||||
"dracut-config-generic",
|
||||
"efibootmgr",
|
||||
)
|
||||
return packages
|
||||
}
|
||||
|
||||
func (p *RawOSTreeImage) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pt := p.treePipeline.PartitionTable
|
||||
if pt == nil {
|
||||
panic("no partition table in live image")
|
||||
}
|
||||
|
||||
for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename, osbuild.PTSfdisk) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
inputName := "root-tree"
|
||||
treeCopyOptions, treeCopyDevices, treeCopyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, pt)
|
||||
treeCopyInputs := osbuild.NewPipelineTreeInputs(inputName, p.treePipeline.Name())
|
||||
|
||||
pipeline.AddStage(osbuild.NewCopyStage(treeCopyOptions, treeCopyInputs, treeCopyDevices, treeCopyMounts))
|
||||
|
||||
bootFiles := p.platform.GetBootFiles()
|
||||
if len(bootFiles) > 0 {
|
||||
// we ignore the bootcopyoptions as they contain a full tree copy instead we make our own, we *do* still want all the other
|
||||
// information such as mountpoints and devices
|
||||
_, bootCopyDevices, bootCopyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, pt)
|
||||
bootCopyOptions := &osbuild.CopyStageOptions{}
|
||||
|
||||
commit := p.treePipeline.ostreeSpecs[0]
|
||||
commitChecksum := commit.Checksum
|
||||
|
||||
bootCopyInputs := osbuild.OSTreeCheckoutInputs{
|
||||
"ostree-tree": *osbuild.NewOSTreeCheckoutInput("org.osbuild.source", commitChecksum),
|
||||
}
|
||||
|
||||
for _, paths := range bootFiles {
|
||||
bootCopyOptions.Paths = append(bootCopyOptions.Paths, osbuild.CopyStagePath{
|
||||
From: fmt.Sprintf("input://ostree-tree/%s%s", commitChecksum, paths[0]),
|
||||
To: fmt.Sprintf("mount://root%s", paths[1]),
|
||||
})
|
||||
}
|
||||
|
||||
pipeline.AddStage(osbuild.NewCopyStage(bootCopyOptions, bootCopyInputs, bootCopyDevices, bootCopyMounts))
|
||||
}
|
||||
|
||||
for _, stage := range osbuild.GenImageFinishStages(pt, p.Filename) {
|
||||
pipeline.AddStage(stage)
|
||||
}
|
||||
|
||||
if grubLegacy := p.treePipeline.platform.GetBIOSPlatform(); grubLegacy != "" {
|
||||
pipeline.AddStage(osbuild.NewGrub2InstStage(osbuild.NewGrub2InstStageOption(p.Filename, pt, grubLegacy)))
|
||||
}
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *RawOSTreeImage) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
return artifact.New(p.Name(), p.Filename, nil)
|
||||
}
|
||||
64
vendor/github.com/osbuild/images/pkg/manifest/tar.go
generated
vendored
Normal file
64
vendor/github.com/osbuild/images/pkg/manifest/tar.go
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// A Tar represents the contents of another pipeline in a tar file
|
||||
type Tar struct {
|
||||
Base
|
||||
Filename string
|
||||
|
||||
Format osbuild.TarArchiveFormat
|
||||
RootNode osbuild.TarRootNode
|
||||
ACLs *bool
|
||||
SELinux *bool
|
||||
Xattrs *bool
|
||||
|
||||
inputPipeline Pipeline
|
||||
}
|
||||
|
||||
// NewTar creates a new TarPipeline. The inputPipeline represents the
|
||||
// filesystem tree which will be the contents of the tar file. The pipelinename
|
||||
// is the name of the pipeline. The filename is the name of the output tar file.
|
||||
func NewTar(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
inputPipeline Pipeline,
|
||||
pipelinename string) *Tar {
|
||||
p := &Tar{
|
||||
Base: NewBase(m, pipelinename, buildPipeline),
|
||||
inputPipeline: inputPipeline,
|
||||
Filename: "image.tar",
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Tar) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
tarOptions := &osbuild.TarStageOptions{
|
||||
Filename: p.Filename,
|
||||
Format: p.Format,
|
||||
ACLs: p.ACLs,
|
||||
SELinux: p.SELinux,
|
||||
Xattrs: p.Xattrs,
|
||||
RootNode: p.RootNode,
|
||||
}
|
||||
tarStage := osbuild.NewTarStage(tarOptions, p.inputPipeline.Name())
|
||||
pipeline.AddStage(tarStage)
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *Tar) getBuildPackages(Distro) []string {
|
||||
return []string{"tar"}
|
||||
}
|
||||
|
||||
func (p *Tar) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-tar"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
55
vendor/github.com/osbuild/images/pkg/manifest/vmdk.go
generated
vendored
Normal file
55
vendor/github.com/osbuild/images/pkg/manifest/vmdk.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// A VMDK turns a raw image file into vmdk image.
|
||||
type VMDK struct {
|
||||
Base
|
||||
Filename string
|
||||
|
||||
imgPipeline *RawImage
|
||||
}
|
||||
|
||||
// NewVMDK creates a new VMDK pipeline. imgPipeline is the pipeline producing the
|
||||
// raw image. Filename is the name of the produced image.
|
||||
func NewVMDK(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
imgPipeline *RawImage) *VMDK {
|
||||
p := &VMDK{
|
||||
Base: NewBase(m, "vmdk", buildPipeline),
|
||||
imgPipeline: imgPipeline,
|
||||
Filename: "image.vmdk",
|
||||
}
|
||||
if imgPipeline.Base.manifest != m {
|
||||
panic("live image pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *VMDK) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewQEMUStage(
|
||||
osbuild.NewQEMUStageOptions(p.Filename, osbuild.QEMUFormatVMDK, osbuild.VMDKOptions{
|
||||
Subformat: osbuild.VMDKSubformatStreamOptimized,
|
||||
}),
|
||||
osbuild.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename),
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *VMDK) getBuildPackages(Distro) []string {
|
||||
return []string{"qemu-img"}
|
||||
}
|
||||
|
||||
func (p *VMDK) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-vmdk"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
58
vendor/github.com/osbuild/images/pkg/manifest/vpc.go
generated
vendored
Normal file
58
vendor/github.com/osbuild/images/pkg/manifest/vpc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// A VPC turns a raw image file into qemu-based image format, such as qcow2.
|
||||
type VPC struct {
|
||||
Base
|
||||
Filename string
|
||||
|
||||
ForceSize *bool
|
||||
|
||||
imgPipeline *RawImage
|
||||
}
|
||||
|
||||
// NewVPC createsa new Qemu pipeline. imgPipeline is the pipeline producing the
|
||||
// raw image. The pipeline name is the name of the new pipeline. Filename is the name
|
||||
// of the produced image.
|
||||
func NewVPC(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
imgPipeline *RawImage) *VPC {
|
||||
p := &VPC{
|
||||
Base: NewBase(m, "vpc", buildPipeline),
|
||||
imgPipeline: imgPipeline,
|
||||
Filename: "image.vhd",
|
||||
}
|
||||
if imgPipeline.Base.manifest != m {
|
||||
panic("live image pipeline from different manifest")
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *VPC) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
formatOptions := osbuild.VPCOptions{ForceSize: p.ForceSize}
|
||||
|
||||
pipeline.AddStage(osbuild.NewQEMUStage(
|
||||
osbuild.NewQEMUStageOptions(p.Filename, osbuild.QEMUFormatVPC, formatOptions),
|
||||
osbuild.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename),
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *VPC) getBuildPackages(Distro) []string {
|
||||
return []string{"qemu-img"}
|
||||
}
|
||||
|
||||
func (p *VPC) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/x-vhd"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
50
vendor/github.com/osbuild/images/pkg/manifest/xz.go
generated
vendored
Normal file
50
vendor/github.com/osbuild/images/pkg/manifest/xz.go
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/osbuild/images/pkg/artifact"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
)
|
||||
|
||||
// The XZ pipeline compresses a raw image file using xz.
|
||||
type XZ struct {
|
||||
Base
|
||||
Filename string
|
||||
|
||||
imgPipeline Pipeline
|
||||
}
|
||||
|
||||
// NewXZ creates a new XZ pipeline. imgPipeline is the pipeline producing the
|
||||
// raw image that will be xz compressed.
|
||||
func NewXZ(m *Manifest,
|
||||
buildPipeline *Build,
|
||||
imgPipeline Pipeline) *XZ {
|
||||
p := &XZ{
|
||||
Base: NewBase(m, "xz", buildPipeline),
|
||||
Filename: "image.xz",
|
||||
imgPipeline: imgPipeline,
|
||||
}
|
||||
buildPipeline.addDependent(p)
|
||||
m.addPipeline(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *XZ) serialize() osbuild.Pipeline {
|
||||
pipeline := p.Base.serialize()
|
||||
|
||||
pipeline.AddStage(osbuild.NewXzStage(
|
||||
osbuild.NewXzStageOptions(p.Filename),
|
||||
osbuild.NewXzStageInputs(osbuild.NewFilesInputPipelineObjectRef(p.imgPipeline.Name(), p.imgPipeline.Export().Filename(), nil)),
|
||||
))
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (p *XZ) getBuildPackages(Distro) []string {
|
||||
return []string{"xz"}
|
||||
}
|
||||
|
||||
func (p *XZ) Export() *artifact.Artifact {
|
||||
p.Base.export = true
|
||||
mimeType := "application/xz"
|
||||
return artifact.New(p.Name(), p.Filename, &mimeType)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue