image: introduce image kinds for Fedora

Implement all of Fedora in terms of this new abstraction. What used to be the
manifest functions (and before that the pipeline functions) are now the image
functions, whose purpose is to instantiate the right image kind structs from the
image type definitions we currently have in the distro definition.
This commit is contained in:
Tom Gundersen 2022-07-10 15:40:38 +01:00 committed by Christian Kellner
parent 5a15608c89
commit 0f5846326c
8 changed files with 654 additions and 497 deletions

View file

@ -12,6 +12,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/image"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
@ -81,7 +82,7 @@ var (
EnabledServices: iotServices,
},
rpmOstree: true,
manifest: iotCommitManifest,
image: iotCommitImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "commit-archive"},
exports: []string{"commit-archive"},
@ -103,7 +104,7 @@ var (
},
rpmOstree: true,
bootISO: false,
manifest: iotContainerManifest,
image: iotContainerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-tree", "ostree-commit", "container-tree", "container"},
exports: []string{"container"},
@ -123,7 +124,7 @@ var (
},
rpmOstree: true,
bootISO: true,
manifest: iotInstallerManifest,
image: iotInstallerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"anaconda-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
@ -148,7 +149,7 @@ var (
kernelOptions: defaultKernelOptions,
bootable: true,
defaultSize: 2 * GigaByte,
manifest: qcow2Manifest,
image: liveImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
@ -176,7 +177,7 @@ var (
kernelOptions: defaultKernelOptions,
bootable: true,
defaultSize: 2 * GigaByte,
manifest: vhdManifest,
image: liveImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc"},
exports: []string{"vpc"},
@ -203,7 +204,7 @@ var (
kernelOptions: defaultKernelOptions,
bootable: true,
defaultSize: 2 * GigaByte,
manifest: vmdkManifest,
image: liveImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vmdk"},
exports: []string{"vmdk"},
@ -229,7 +230,7 @@ var (
kernelOptions: defaultKernelOptions,
bootable: true,
defaultSize: 2 * GigaByte,
manifest: openstackManifest,
image: liveImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
@ -252,7 +253,7 @@ var (
kernelOptions: defaultKernelOptions,
bootable: true,
defaultSize: 6 * GigaByte,
manifest: ec2Manifest,
image: liveImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image"},
exports: []string{"image"},
@ -273,7 +274,7 @@ var (
Locale: "C.UTF-8",
Timezone: "Etc/UTC",
},
manifest: containerManifest,
image: containerImage,
bootable: false,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "container"},
@ -287,7 +288,6 @@ type distribution struct {
osVersion string
releaseVersion string
modulePlatformID string
vendor string
ostreeRefTmpl string
isolabelTmpl string
runner runner.Runner
@ -309,7 +309,6 @@ var distroMap = map[string]distribution{
osVersion: "35",
releaseVersion: "35",
modulePlatformID: "platform:f35",
vendor: "fedora",
ostreeRefTmpl: "fedora/35/%s/iot",
isolabelTmpl: "Fedora-35-BaseOS-%s",
runner: &runner.Fedora{Version: 35},
@ -321,7 +320,6 @@ var distroMap = map[string]distribution{
osVersion: "36",
releaseVersion: "36",
modulePlatformID: "platform:f36",
vendor: "fedora",
ostreeRefTmpl: "fedora/36/%s/iot",
isolabelTmpl: "Fedora-36-BaseOS-%s",
runner: &runner.Fedora{Version: 36},
@ -439,7 +437,7 @@ func (a *architecture) Distro() distro.Distro {
return a.distro
}
type manifestFunc func(m *manifest.Manifest, workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSets map[string]rpmmd.PackageSet, rng *rand.Rand) error
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, rng *rand.Rand) (image.ImageKind, error)
type packageSetFunc func(t *imageType) rpmmd.PackageSet
@ -458,7 +456,7 @@ type imageType struct {
buildPipelines []string
payloadPipelines []string
exports []string
manifest manifestFunc
image imageFunc
// bootISO: installable ISO
bootISO bool
@ -631,13 +629,16 @@ func (t *imageType) initializeManifest(bp *blueprint.Blueprint,
/* #nosec G404 */
rng := rand.New(source)
manifest := manifest.New()
err := t.manifest(&manifest, w, t, bp.Customizations, options, repos, packageSets, rng)
img, err := t.image(w, t, bp.Customizations, options, packageSets, rng)
if err != nil {
return nil, err
}
return &manifest, nil
manifest := manifest.New()
_, err = img.InstantiateManifest(&manifest, repos, t.arch.distro.runner, rng)
if err != nil {
return nil, err
}
return &manifest, err
}
func (t *imageType) Manifest(customizations *blueprint.Customizations,
@ -745,16 +746,50 @@ func newDistro(distroName string) distro.Distro {
&platform.X86{
BIOS: true,
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
openstackImgType,
vhdImgType,
vmdkImgType,
ociImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
},
vhdImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
vmdkImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
amiImgType,
)
@ -790,12 +825,32 @@ func newDistro(distroName string) distro.Distro {
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
amiImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
openstackImgType,
ociImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: "fedora",
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{},
containerImgType,

View file

@ -0,0 +1,257 @@
package fedora
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/image"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/workload"
)
// HELPERS
func osCustomizations(
t *imageType,
osPackageSet rpmmd.PackageSet,
c *blueprint.Customizations) manifest.OSCustomizations {
imageConfig := t.getDefaultImageConfig()
osc := manifest.OSCustomizations{}
if t.bootable || t.rpmOstree {
osc.KernelName = c.GetKernel().Name
var kernelOptions []string
if t.kernelOptions != "" {
kernelOptions = append(kernelOptions, t.kernelOptions)
}
if bpKernel := c.GetKernel(); bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append)
}
osc.KernelOptionsAppend = kernelOptions
}
osc.ExtraBasePackages = osPackageSet.Include
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
osc.GPGKeyFiles = imageConfig.GPGKeyFiles
osc.ExcludeDocs = imageConfig.ExcludeDocs
if !t.bootISO {
// don't put users and groups in the payload of an installer
// add them via kickstart instead
osc.Groups = c.GetGroups()
osc.Users = c.GetUsers()
}
osc.EnabledServices = imageConfig.EnabledServices
osc.DisabledServices = imageConfig.DisabledServices
osc.DefaultTarget = imageConfig.DefaultTarget
osc.Firewall = c.GetFirewall()
language, keyboard := c.GetPrimaryLocale()
if language != nil {
osc.Language = *language
} else {
osc.Language = imageConfig.Locale
}
if keyboard != nil {
osc.Keyboard = keyboard
} else if imageConfig.Keyboard != nil {
osc.Keyboard = &imageConfig.Keyboard.Keymap
}
if hostname := c.GetHostname(); hostname != nil {
osc.Hostname = *hostname
} else {
osc.Hostname = "localhost.localdomain"
}
timezone, ntpServers := c.GetTimezoneSettings()
if timezone != nil {
osc.Timezone = *timezone
} else {
osc.Timezone = imageConfig.Timezone
}
if len(ntpServers) > 0 {
osc.NTPServers = ntpServers
} else if imageConfig.TimeSynchronization != nil {
osc.NTPServers = imageConfig.TimeSynchronization.Timeservers
}
if !imageConfig.NoSElinux {
osc.SElinux = "targeted"
}
osc.Grub2Config = imageConfig.Grub2Config
osc.Sysconfig = imageConfig.Sysconfig
osc.SystemdLogind = imageConfig.SystemdLogind
osc.CloudInit = imageConfig.CloudInit
osc.Modprobe = imageConfig.Modprobe
osc.DracutConf = imageConfig.DracutConf
osc.SystemdUnit = imageConfig.SystemdUnit
osc.Authselect = imageConfig.Authselect
osc.SELinuxConfig = imageConfig.SELinuxConfig
osc.Tuned = imageConfig.Tuned
osc.Tmpfilesd = imageConfig.Tmpfilesd
osc.PamLimitsConf = imageConfig.PamLimitsConf
osc.Sysctld = imageConfig.Sysctld
osc.DNFConfig = imageConfig.DNFConfig
osc.SshdConfig = imageConfig.SshdConfig
osc.AuthConfig = imageConfig.Authconfig
osc.PwQuality = imageConfig.PwQuality
return osc
}
// IMAGES
func liveImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewLiveImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.Environment = t.environment
img.Workload = workload
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
img.PartitionTable = pt
img.Filename = t.Filename()
return img, nil
}
func containerImage(workload workload.Workload,
t *imageType,
c *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewBaseContainer()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], c)
img.Environment = t.environment
img.Workload = workload
img.Filename = t.Filename()
return img, nil
}
func iotCommitImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeArchive()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.Environment = t.environment
img.Workload = workload
var parent *manifest.OSTreeParent
if options.OSTree.Parent != "" && options.OSTree.URL != "" {
parent = &manifest.OSTreeParent{
Checksum: options.OSTree.Parent,
URL: options.OSTree.URL,
}
}
img.OSTreeParent = manifest.OSTree{
Parent: parent,
}
img.OSTreeRef = options.OSTree.Ref
img.OSVersion = t.arch.distro.osVersion
img.Filename = t.Filename()
return img, nil
}
func iotContainerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeContainer()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.ContainerLanguage = img.OSCustomizations.Language
img.Environment = t.environment
img.Workload = workload
var parent *manifest.OSTreeParent
if options.OSTree.Parent != "" && options.OSTree.URL != "" {
parent = &manifest.OSTreeParent{
Checksum: options.OSTree.Parent,
URL: options.OSTree.URL,
}
}
img.OSTreeParent = manifest.OSTree{
Parent: parent,
}
img.OSTreeRef = options.OSTree.Ref
img.OSVersion = t.arch.distro.osVersion
img.ExtraContainerPackages = packageSets[containerPkgsKey]
img.Filename = t.Filename()
return img, nil
}
func iotInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) (image.ImageKind, error) {
d := t.arch.distro
img := image.NewOSTreeInstaller()
img.Platform = t.platform
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = customizations.GetUsers()
img.Groups = customizations.GetGroups()
img.ISOLabelTempl = d.isolabelTmpl
img.Product = d.product
img.Variant = "IoT"
img.OSName = "fedora"
img.OSVersion = d.osVersion
img.Release = "202010217.n.0" // ???
img.OSTreeURL = options.OSTree.URL
img.OSTreeRef = options.OSTree.Ref
img.OSTreeCommit = options.OSTree.Parent
img.Filename = t.Filename()
return img, nil
}

View file

@ -1,475 +0,0 @@
package fedora
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/workload"
)
func qcow2Manifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return err
}
imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline)
qcow2Pipeline := manifest.NewQCOW2(m, buildPipeline, imagePipeline)
qcow2Pipeline.Filename = t.filename
qcow2Pipeline.Compat = "1.1"
return nil
}
func vhdManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return err
}
imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline)
p := manifest.NewVPC(m, buildPipeline, imagePipeline)
p.Filename = t.filename
return nil
}
func vmdkManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return err
}
imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline)
p := manifest.NewVMDK(m, buildPipeline, imagePipeline)
p.Filename = t.filename
return nil
}
func openstackManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return err
}
imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline)
p := manifest.NewQCOW2(m, buildPipeline, imagePipeline)
p.Filename = t.filename
return nil
}
func ec2CommonManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand,
diskfile string) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return nil
}
p := manifest.NewRawImage(m, buildPipeline, treePipeline)
p.Filename = diskfile
return nil
}
// ec2Manifest returns a manifest which produce uncompressed EC2 images which are expected to use RHSM for content
func ec2Manifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
return ec2CommonManifest(m, workload, t, customizations, options, repos, packageSets, rng, t.Filename())
}
func iotInstallerManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
d := t.arch.distro
ksUsers := len(customizations.GetUsers())+len(customizations.GetGroups()) > 0
anacondaTreePipeline := anacondaTreePipeline(m,
buildPipeline,
t.platform,
repos,
packageSets[installerPkgsKey],
d.product,
d.osVersion,
"IoT",
ksUsers)
isoTreePipeline := bootISOTreePipeline(m, buildPipeline, anacondaTreePipeline, options, d.vendor, d.isolabelTmpl, customizations.GetUsers(), customizations.GetGroups())
bootISOPipeline(m, buildPipeline, isoTreePipeline, t.Filename(), false)
return nil
}
func iotCorePipelines(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet) (*manifest.Build,
*manifest.OSTreeCommit,
error) {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, nil)
if err != nil {
return nil, nil, err
}
commitPipeline := ostreeCommitPipeline(m, buildPipeline, treePipeline, options, t.arch.distro.osVersion)
return buildPipeline, commitPipeline, nil
}
func iotCommitManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline, commitPipeline, err := iotCorePipelines(m, workload, t, customizations, options, repos, packageSets)
if err != nil {
return err
}
p := manifest.NewTar(m, buildPipeline, &commitPipeline.Base, "commit-archive")
p.Filename = t.Filename()
return nil
}
func iotContainerManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline, commitPipeline, err := iotCorePipelines(m, workload, t, customizations, options, repos, packageSets)
if err != nil {
return err
}
nginxConfigPath := "/etc/nginx.conf"
httpPort := "8080"
containerTreePipeline := containerTreePipeline(m,
buildPipeline,
commitPipeline,
t.platform,
repos,
packageSets[containerPkgsKey],
options,
customizations,
nginxConfigPath,
httpPort)
containerPipeline(m, buildPipeline, containerTreePipeline, t, nginxConfigPath, httpPort)
return nil
}
func containerManifest(m *manifest.Manifest,
workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSets map[string]rpmmd.PackageSet,
rng *rand.Rand) error {
buildPipeline := manifest.NewBuild(m, t.arch.distro.runner, repos)
treePipeline, err := osPipeline(m, buildPipeline, workload, t, repos, packageSets[osPkgsKey], customizations, options, rng)
if err != nil {
return err
}
ociPipeline := manifest.NewOCIContainer(m, buildPipeline, treePipeline)
ociPipeline.Filename = t.Filename()
return nil
}
func osPipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
workload workload.Workload,
t *imageType,
repos []rpmmd.RepoConfig,
osPackageSet rpmmd.PackageSet,
c *blueprint.Customizations,
options distro.ImageOptions,
rng *rand.Rand) (*manifest.OS, error) {
pl := manifest.NewOS(m, buildPipeline, t.platform, repos)
pl.Environment = t.environment
pl.Workload = workload
pl.OSCustomizations = osCustomizations(t, repos, osPackageSet, c, options)
if t.bootable {
var err error
pt, err := t.getPartitionTable(c.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
pl.PartitionTable = pt
}
if t.rpmOstree {
var parent *manifest.OSTreeParent
if options.OSTree.Parent != "" && options.OSTree.URL != "" {
parent = &manifest.OSTreeParent{
Checksum: options.OSTree.Parent,
URL: options.OSTree.URL,
}
}
pl.OSTree = &manifest.OSTree{
Parent: parent,
}
}
return pl, nil
}
func osCustomizations(
t *imageType,
repos []rpmmd.RepoConfig,
osPackageSet rpmmd.PackageSet,
c *blueprint.Customizations,
options distro.ImageOptions) manifest.OSCustomizations {
imageConfig := t.getDefaultImageConfig()
osc := manifest.OSCustomizations{}
if t.bootable || t.rpmOstree {
osc.KernelName = c.GetKernel().Name
var kernelOptions []string
if t.kernelOptions != "" {
kernelOptions = append(kernelOptions, t.kernelOptions)
}
if bpKernel := c.GetKernel(); bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append)
}
osc.KernelOptionsAppend = kernelOptions
}
osc.ExtraBasePackages = osPackageSet.Include
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
osc.GPGKeyFiles = imageConfig.GPGKeyFiles
osc.ExcludeDocs = imageConfig.ExcludeDocs
if !t.bootISO {
// don't put users and groups in the payload of an installer
// add them via kickstart instead
osc.Groups = c.GetGroups()
osc.Users = c.GetUsers()
}
osc.EnabledServices = imageConfig.EnabledServices
osc.DisabledServices = imageConfig.DisabledServices
osc.DefaultTarget = imageConfig.DefaultTarget
osc.Firewall = c.GetFirewall()
language, keyboard := c.GetPrimaryLocale()
if language != nil {
osc.Language = *language
} else {
osc.Language = imageConfig.Locale
}
if keyboard != nil {
osc.Keyboard = keyboard
} else if imageConfig.Keyboard != nil {
osc.Keyboard = &imageConfig.Keyboard.Keymap
}
if hostname := c.GetHostname(); hostname != nil {
osc.Hostname = *hostname
} else {
osc.Hostname = "localhost.localdomain"
}
timezone, ntpServers := c.GetTimezoneSettings()
if timezone != nil {
osc.Timezone = *timezone
} else {
osc.Timezone = imageConfig.Timezone
}
if len(ntpServers) > 0 {
osc.NTPServers = ntpServers
} else if imageConfig.TimeSynchronization != nil {
osc.NTPServers = imageConfig.TimeSynchronization.Timeservers
}
if !imageConfig.NoSElinux {
osc.SElinux = "targeted"
}
osc.Grub2Config = imageConfig.Grub2Config
osc.Sysconfig = imageConfig.Sysconfig
osc.SystemdLogind = imageConfig.SystemdLogind
osc.CloudInit = imageConfig.CloudInit
osc.Modprobe = imageConfig.Modprobe
osc.DracutConf = imageConfig.DracutConf
osc.SystemdUnit = imageConfig.SystemdUnit
osc.Authselect = imageConfig.Authselect
osc.SELinuxConfig = imageConfig.SELinuxConfig
osc.Tuned = imageConfig.Tuned
osc.Tmpfilesd = imageConfig.Tmpfilesd
osc.PamLimitsConf = imageConfig.PamLimitsConf
osc.Sysctld = imageConfig.Sysctld
osc.DNFConfig = imageConfig.DNFConfig
osc.SshdConfig = imageConfig.SshdConfig
osc.AuthConfig = imageConfig.Authconfig
osc.PwQuality = imageConfig.PwQuality
return osc
}
func ostreeCommitPipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
treePipeline *manifest.OS,
options distro.ImageOptions,
osVersion string) *manifest.OSTreeCommit {
p := manifest.NewOSTreeCommit(m, buildPipeline, treePipeline, options.OSTree.Ref)
p.OSVersion = osVersion
return p
}
func containerTreePipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
commitPipeline *manifest.OSTreeCommit,
platform platform.Platform,
repos []rpmmd.RepoConfig,
containerPackageSet rpmmd.PackageSet,
options distro.ImageOptions,
c *blueprint.Customizations,
nginxConfigPath,
listenPort string) *manifest.OSTreeCommitServer {
p := manifest.NewOSTreeCommitServer(m, buildPipeline, platform, repos, commitPipeline, nginxConfigPath, listenPort)
p.ExtraPackages = containerPackageSet.Include
p.ExtraRepos = containerPackageSet.Repositories
language, _ := c.GetPrimaryLocale()
if language != nil {
p.Language = *language
}
return p
}
func containerPipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
treePipeline manifest.Tree,
t *imageType,
nginxConfigPath,
listenPort string) *manifest.OCIContainer {
p := manifest.NewOCIContainer(m, buildPipeline, treePipeline)
p.Filename = t.Filename()
p.Cmd = []string{"nginx", "-c", nginxConfigPath}
p.ExposedPorts = []string{listenPort}
return p
}
func anacondaTreePipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
pf platform.Platform,
repos []rpmmd.RepoConfig,
installerPackageSet rpmmd.PackageSet,
product, osVersion, variant string,
users bool) *manifest.Anaconda {
p := manifest.NewAnaconda(m, buildPipeline, pf, repos, "kernel", product, osVersion)
p.ExtraPackages = installerPackageSet.Include
p.ExtraRepos = installerPackageSet.Repositories
p.Users = users
p.Variant = variant
p.Biosdevname = (pf.GetArch() == platform.ARCH_X86_64)
return p
}
func bootISOTreePipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
anacondaPipeline *manifest.Anaconda,
options distro.ImageOptions,
vendor,
isoLabelTempl string,
users []blueprint.UserCustomization,
groups []blueprint.GroupCustomization) *manifest.ISOTree {
p := manifest.NewISOTree(m, buildPipeline, anacondaPipeline, options.OSTree.Parent, options.OSTree.URL, options.OSTree.Ref, isoLabelTempl)
p.Release = "202010217.n.0"
p.OSName = "fedora"
p.UEFIVendor = vendor
p.Users = users
p.Groups = groups
return p
}
func bootISOPipeline(m *manifest.Manifest,
buildPipeline *manifest.Build,
treePipeline *manifest.ISOTree,
filename string,
isolinux bool) *manifest.ISO {
p := manifest.NewISO(m, buildPipeline, treePipeline)
p.ISOLinux = isolinux
p.Filename = filename
return p
}

View file

@ -0,0 +1,47 @@
package image
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/workload"
)
type BaseContainer struct {
Base
Platform platform.Platform
OSCustomizations manifest.OSCustomizations
Environment environment.Environment
Workload workload.Workload
Filename string
}
func NewBaseContainer() *BaseContainer {
return &BaseContainer{
Base: NewBase("base-container"),
}
}
func (img *BaseContainer) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
osPipeline := manifest.NewOS(m, buildPipeline, img.Platform, repos)
osPipeline.OSCustomizations = img.OSCustomizations
osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload
ociPipeline := manifest.NewOCIContainer(m, buildPipeline, osPipeline)
ociPipeline.Filename = img.Filename
artifact := ociPipeline.Export()
return artifact, nil
}

70
internal/image/live.go Normal file
View file

@ -0,0 +1,70 @@
package image
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/workload"
)
type LiveImage struct {
Base
Platform platform.Platform
PartitionTable *disk.PartitionTable
OSCustomizations manifest.OSCustomizations
Environment environment.Environment
Workload workload.Workload
Filename string
}
func NewLiveImage() *LiveImage {
return &LiveImage{
Base: NewBase("live-image"),
}
}
func (img *LiveImage) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
osPipeline := manifest.NewOS(m, buildPipeline, img.Platform, repos)
osPipeline.PartitionTable = img.PartitionTable
osPipeline.OSCustomizations = img.OSCustomizations
osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload
imagePipeline := manifest.NewRawImage(m, buildPipeline, osPipeline)
var artifact *artifact.Artifact
switch img.Platform.GetImageFormat() {
case platform.FORMAT_RAW:
imagePipeline.Filename = img.Filename
artifact = imagePipeline.Export()
case platform.FORMAT_QCOW2:
qcow2Pipeline := manifest.NewQCOW2(m, buildPipeline, imagePipeline)
qcow2Pipeline.Filename = img.Filename
qcow2Pipeline.Compat = img.Platform.GetQCOW2Compat()
artifact = qcow2Pipeline.Export()
case platform.FORMAT_VHD:
vpcPipeline := manifest.NewVPC(m, buildPipeline, imagePipeline)
vpcPipeline.Filename = img.Filename
artifact = vpcPipeline.Export()
case platform.FORMAT_VMDK:
vmdkPipeline := manifest.NewVMDK(m, buildPipeline, imagePipeline)
vmdkPipeline.Filename = img.Filename
artifact = vmdkPipeline.Export()
default:
panic("invalid image format for image kind")
}
return artifact, nil
}

View file

@ -0,0 +1,54 @@
package image
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/workload"
)
type OSTreeArchive struct {
Base
Platform platform.Platform
OSCustomizations manifest.OSCustomizations
Environment environment.Environment
Workload workload.Workload
OSTreeParent manifest.OSTree
OSTreeRef string
OSVersion string
Filename string
}
func NewOSTreeArchive() *OSTreeArchive {
return &OSTreeArchive{
Base: NewBase("ostree-archive"),
}
}
func (img *OSTreeArchive) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
osPipeline := manifest.NewOS(m, buildPipeline, img.Platform, repos)
osPipeline.OSCustomizations = img.OSCustomizations
osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload
osPipeline.OSTree = &img.OSTreeParent
ostreeCommitPipeline := manifest.NewOSTreeCommit(m, buildPipeline, osPipeline, img.OSTreeRef)
ostreeCommitPipeline.OSVersion = img.OSVersion
tarPipeline := manifest.NewTar(m, buildPipeline, &ostreeCommitPipeline.Base, "commit-archive")
tarPipeline.Filename = img.Filename
artifact := tarPipeline.Export()
return artifact, nil
}

View file

@ -0,0 +1,70 @@
package image
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/environment"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/workload"
)
type OSTreeContainer struct {
Base
Platform platform.Platform
OSCustomizations manifest.OSCustomizations
Environment environment.Environment
Workload workload.Workload
OSTreeParent manifest.OSTree
OSTreeRef string // TODO: merge into the above
OSVersion string
ExtraContainerPackages rpmmd.PackageSet
ContainerLanguage string
Filename string
}
func NewOSTreeContainer() *OSTreeContainer {
return &OSTreeContainer{
Base: NewBase("ostree-container"),
}
}
func (img *OSTreeContainer) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
osPipeline := manifest.NewOS(m, buildPipeline, img.Platform, repos)
osPipeline.OSCustomizations = img.OSCustomizations
osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload
osPipeline.OSTree = &img.OSTreeParent
commitPipeline := manifest.NewOSTreeCommit(m, buildPipeline, osPipeline, img.OSTreeRef)
commitPipeline.OSVersion = img.OSVersion
nginxConfigPath := "/etc/nginx.conf"
listenPort := "8080"
serverPipeline := manifest.NewOSTreeCommitServer(m,
buildPipeline,
img.Platform,
repos,
commitPipeline,
nginxConfigPath,
listenPort)
serverPipeline.Language = img.ContainerLanguage
containerPipeline := manifest.NewOCIContainer(m, buildPipeline, serverPipeline)
containerPipeline.Cmd = []string{"nginx", "-c", nginxConfigPath}
containerPipeline.ExposedPorts = []string{listenPort}
containerPipeline.Filename = img.Filename
artifact := containerPipeline.Export()
return artifact, nil
}

View file

@ -0,0 +1,79 @@
package image
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/artifact"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
)
type OSTreeInstaller struct {
Base
Platform platform.Platform
ExtraBasePackages rpmmd.PackageSet
Users []blueprint.UserCustomization
Groups []blueprint.GroupCustomization
ISOLabelTempl string
Product string
Variant string
OSName string
OSVersion string
Release string
OSTreeURL string
OSTreeRef string
OSTreeCommit string
Filename string
}
func NewOSTreeInstaller() *OSTreeInstaller {
return &OSTreeInstaller{
Base: NewBase("ostree-installer"),
}
}
func (img *OSTreeInstaller) InstantiateManifest(m *manifest.Manifest,
repos []rpmmd.RepoConfig,
runner runner.Runner,
rng *rand.Rand) (*artifact.Artifact, error) {
buildPipeline := manifest.NewBuild(m, runner, repos)
buildPipeline.Checkpoint()
anacondaPipeline := manifest.NewAnaconda(m,
buildPipeline,
img.Platform,
repos, "kernel",
img.Product,
img.OSVersion)
anacondaPipeline.ExtraPackages = img.ExtraBasePackages.Include
anacondaPipeline.ExtraRepos = img.ExtraBasePackages.Repositories
anacondaPipeline.Users = len(img.Users)+len(img.Groups) > 0
anacondaPipeline.Variant = img.Variant
anacondaPipeline.Biosdevname = (img.Platform.GetArch() == platform.ARCH_X86_64)
anacondaPipeline.Checkpoint()
isoTreePipeline := manifest.NewISOTree(m,
buildPipeline,
anacondaPipeline,
img.OSTreeCommit,
img.OSTreeURL,
img.OSTreeRef,
img.ISOLabelTempl)
isoTreePipeline.Release = img.Release
isoTreePipeline.OSName = img.OSName
isoTreePipeline.UEFIVendor = img.Platform.GetUEFIVendor()
isoTreePipeline.Users = img.Users
isoTreePipeline.Groups = img.Groups
isoPipeline := manifest.NewISO(m, buildPipeline, isoTreePipeline)
isoPipeline.Filename = img.Filename
artifact := isoPipeline.Export()
return artifact, nil
}