distro: remove rhel84 package
This commit is contained in:
parent
6c7c55825d
commit
fdc6790472
5 changed files with 0 additions and 3752 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,358 +0,0 @@
|
|||
// This file contains common pipelines-related code backported form newer
|
||||
// distro definitions, mainly RHEL-8.6 / 9.0
|
||||
|
||||
package rhel84
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/disk"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
func bootloaderConfigStage(t *imageTypeS2, partitionTable disk.PartitionTable, kernel *blueprint.KernelCustomization, kernelVer string, install, greenboot bool) *osbuild.Stage {
|
||||
if t.arch.name == distro.S390xArchName {
|
||||
return osbuild.NewZiplStage(new(osbuild.ZiplStageOptions))
|
||||
}
|
||||
|
||||
kernelOptions := t.kernelOptions
|
||||
uefi := t.arch.uefi
|
||||
legacy := t.arch.legacy
|
||||
|
||||
options := osbuild.NewGrub2StageOptions(&partitionTable, kernelOptions, kernel, kernelVer, uefi, legacy, "redhat", install)
|
||||
options.Greenboot = greenboot
|
||||
|
||||
return osbuild.NewGRUB2Stage(options)
|
||||
}
|
||||
|
||||
func bootloaderInstStage(filename string, pt *disk.PartitionTable, arch *architecture, kernelVer string, devices *osbuild.Devices, mounts *osbuild.Mounts, disk *osbuild.Device) *osbuild.Stage {
|
||||
platform := arch.legacy
|
||||
if platform != "" {
|
||||
return osbuild.NewGrub2InstStage(osbuild.NewGrub2InstStageOption(filename, pt, platform))
|
||||
}
|
||||
|
||||
if arch.name == distro.S390xArchName {
|
||||
return osbuild.NewZiplInstStage(osbuild.NewZiplInstStageOptions(kernelVer, pt), disk, devices, mounts)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions {
|
||||
options := osbuild.FirewallStageOptions{
|
||||
Ports: firewall.Ports,
|
||||
}
|
||||
|
||||
if firewall.Services != nil {
|
||||
options.EnabledServices = firewall.Services.Enabled
|
||||
options.DisabledServices = firewall.Services.Disabled
|
||||
}
|
||||
|
||||
return &options
|
||||
}
|
||||
|
||||
func liveImagePipeline(inputPipelineName string, outputFilename string, pt *disk.PartitionTable, arch *architecture, kernelVer string) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "image"
|
||||
p.Build = "name:build"
|
||||
|
||||
for _, stage := range osbuild.GenImagePrepareStages(pt, outputFilename, osbuild.PTSfdisk) {
|
||||
p.AddStage(stage)
|
||||
}
|
||||
|
||||
inputName := "root-tree"
|
||||
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, inputPipelineName, outputFilename, pt)
|
||||
copyInputs := osbuild.NewCopyStagePipelineTreeInputs(inputName, inputPipelineName)
|
||||
p.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
|
||||
|
||||
for _, stage := range osbuild.GenImageFinishStages(pt, outputFilename) {
|
||||
p.AddStage(stage)
|
||||
}
|
||||
|
||||
loopback := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: outputFilename})
|
||||
p.AddStage(bootloaderInstStage(outputFilename, pt, arch, kernelVer, copyDevices, copyMounts, loopback))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func tarArchivePipeline(name, inputPipelineName string, tarOptions *osbuild.TarStageOptions) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = name
|
||||
p.Build = "name:build"
|
||||
p.AddStage(osbuild.NewTarStage(tarOptions, osbuild.NewTarStagePipelineTreeInputs(inputPipelineName)))
|
||||
return p
|
||||
}
|
||||
|
||||
func usersFirstBootOptions(usersStageOptions *osbuild.UsersStageOptions) *osbuild.FirstBootStageOptions {
|
||||
cmds := make([]string, 0, 3*len(usersStageOptions.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 name, user := range usersStageOptions.Users {
|
||||
if user.Key != nil {
|
||||
var home string
|
||||
|
||||
if name == "root" {
|
||||
home = roothome
|
||||
} else {
|
||||
home = filepath.Join(varhome, 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", name, 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
|
||||
}
|
||||
|
||||
// osPipelineRhel86 is a backport of the osPipeline from RHEL-86
|
||||
//
|
||||
// This pipeline generator takes distro.ImageConfig instance, which
|
||||
// defines the image default configuration
|
||||
func osPipelineRhel86(t *imageTypeS2,
|
||||
imageConfig *distro.ImageConfig,
|
||||
repos []rpmmd.RepoConfig,
|
||||
packages []rpmmd.PackageSpec,
|
||||
c *blueprint.Customizations,
|
||||
options distro.ImageOptions,
|
||||
pt *disk.PartitionTable) (*osbuild.Pipeline, error) {
|
||||
p := new(osbuild.Pipeline)
|
||||
if t.rpmOstree {
|
||||
p.Name = "ostree-tree"
|
||||
} else {
|
||||
p.Name = "os"
|
||||
}
|
||||
p.Build = "name:build"
|
||||
|
||||
if t.rpmOstree && options.OSTree.Parent != "" && options.OSTree.URL != "" {
|
||||
p.AddStage(osbuild.NewOSTreePasswdStage("org.osbuild.source", options.OSTree.Parent))
|
||||
}
|
||||
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(packages)))
|
||||
|
||||
// If the /boot is on a separate partition, the prefix for the BLS stage must be ""
|
||||
if pt == nil || pt.FindMountable("/boot") == nil {
|
||||
p.AddStage(osbuild.NewFixBLSStage(&osbuild.FixBLSStageOptions{}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewFixBLSStage(&osbuild.FixBLSStageOptions{Prefix: common.StringToPtr("")}))
|
||||
}
|
||||
|
||||
language, keyboard := c.GetPrimaryLocale()
|
||||
if language != nil {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: *language}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: imageConfig.Locale}))
|
||||
}
|
||||
if keyboard != nil {
|
||||
p.AddStage(osbuild.NewKeymapStage(&osbuild.KeymapStageOptions{Keymap: *keyboard}))
|
||||
} else if imageConfig.Keyboard != nil {
|
||||
p.AddStage(osbuild.NewKeymapStage(imageConfig.Keyboard))
|
||||
}
|
||||
|
||||
if hostname := c.GetHostname(); hostname != nil {
|
||||
p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: *hostname}))
|
||||
}
|
||||
|
||||
timezone, ntpServers := c.GetTimezoneSettings()
|
||||
if timezone != nil {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: *timezone}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: imageConfig.Timezone}))
|
||||
}
|
||||
|
||||
if len(ntpServers) > 0 {
|
||||
p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{Timeservers: ntpServers}))
|
||||
} else if imageConfig.TimeSynchronization != nil {
|
||||
p.AddStage(osbuild.NewChronyStage(imageConfig.TimeSynchronization))
|
||||
}
|
||||
|
||||
if !t.bootISO {
|
||||
// don't put users and groups in the payload of an installer
|
||||
// add them via kickstart instead
|
||||
if groups := c.GetGroups(); len(groups) > 0 {
|
||||
p.AddStage(osbuild.NewGroupsStage(osbuild.NewGroupsStageOptions(groups)))
|
||||
}
|
||||
|
||||
if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil {
|
||||
return nil, err
|
||||
} else if userOptions != nil {
|
||||
if t.rpmOstree {
|
||||
// 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
|
||||
userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.AddStage(osbuild.NewUsersStage(userOptionsSansKeys))
|
||||
p.AddStage(osbuild.NewFirstBootStage(usersFirstBootOptions(userOptions)))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewUsersStage(userOptions))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if services := c.GetServices(); services != nil || imageConfig.EnabledServices != nil ||
|
||||
imageConfig.DisabledServices != nil || imageConfig.DefaultTarget != "" {
|
||||
p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(
|
||||
imageConfig.EnabledServices,
|
||||
imageConfig.DisabledServices,
|
||||
services,
|
||||
imageConfig.DefaultTarget,
|
||||
)))
|
||||
}
|
||||
|
||||
var fwStageOptions *osbuild.FirewallStageOptions
|
||||
if firewallCustomization := c.GetFirewall(); firewallCustomization != nil {
|
||||
fwStageOptions = firewallStageOptions(firewallCustomization)
|
||||
}
|
||||
if firewallConfig := imageConfig.Firewall; firewallConfig != nil {
|
||||
// merge the user-provided firewall config with the default one
|
||||
if fwStageOptions != nil {
|
||||
fwStageOptions = &osbuild.FirewallStageOptions{
|
||||
// Prefer the firewall ports and services settings provided
|
||||
// via BP customization.
|
||||
Ports: fwStageOptions.Ports,
|
||||
EnabledServices: fwStageOptions.EnabledServices,
|
||||
DisabledServices: fwStageOptions.DisabledServices,
|
||||
// Default zone can not be set using BP customizations, therefore
|
||||
// default to the one provided in the default image configuration.
|
||||
DefaultZone: firewallConfig.DefaultZone,
|
||||
}
|
||||
} else {
|
||||
fwStageOptions = firewallConfig
|
||||
}
|
||||
}
|
||||
if fwStageOptions != nil {
|
||||
p.AddStage(osbuild.NewFirewallStage(fwStageOptions))
|
||||
}
|
||||
|
||||
for _, sysconfigConfig := range imageConfig.Sysconfig {
|
||||
p.AddStage(osbuild.NewSysconfigStage(sysconfigConfig))
|
||||
}
|
||||
|
||||
if t.arch.distro.isRHEL() {
|
||||
if options.Subscription != nil {
|
||||
commands := []string{
|
||||
fmt.Sprintf("/usr/sbin/subscription-manager register --org=%s --activationkey=%s --serverurl %s --baseurl %s", options.Subscription.Organization, options.Subscription.ActivationKey, options.Subscription.ServerUrl, options.Subscription.BaseUrl),
|
||||
}
|
||||
if options.Subscription.Insights {
|
||||
commands = append(commands, "/usr/bin/insights-client --register")
|
||||
}
|
||||
p.AddStage(osbuild.NewFirstBootStage(&osbuild.FirstBootStageOptions{
|
||||
Commands: commands,
|
||||
WaitForNetwork: true,
|
||||
}))
|
||||
|
||||
if rhsmConfig, exists := imageConfig.RHSMConfig[distro.RHSMConfigWithSubscription]; exists {
|
||||
p.AddStage(osbuild.NewRHSMStage(rhsmConfig))
|
||||
}
|
||||
} else {
|
||||
if rhsmConfig, exists := imageConfig.RHSMConfig[distro.RHSMConfigNoSubscription]; exists {
|
||||
p.AddStage(osbuild.NewRHSMStage(rhsmConfig))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, systemdLogindConfig := range imageConfig.SystemdLogind {
|
||||
p.AddStage(osbuild.NewSystemdLogindStage(systemdLogindConfig))
|
||||
}
|
||||
|
||||
for _, cloudInitConfig := range imageConfig.CloudInit {
|
||||
p.AddStage(osbuild.NewCloudInitStage(cloudInitConfig))
|
||||
}
|
||||
|
||||
for _, modprobeConfig := range imageConfig.Modprobe {
|
||||
p.AddStage(osbuild.NewModprobeStage(modprobeConfig))
|
||||
}
|
||||
|
||||
for _, dracutConfConfig := range imageConfig.DracutConf {
|
||||
p.AddStage(osbuild.NewDracutConfStage(dracutConfConfig))
|
||||
}
|
||||
|
||||
for _, systemdUnitConfig := range imageConfig.SystemdUnit {
|
||||
p.AddStage(osbuild.NewSystemdUnitStage(systemdUnitConfig))
|
||||
}
|
||||
|
||||
if authselectConfig := imageConfig.Authselect; authselectConfig != nil {
|
||||
p.AddStage(osbuild.NewAuthselectStage(authselectConfig))
|
||||
}
|
||||
|
||||
if seLinuxConfig := imageConfig.SELinuxConfig; seLinuxConfig != nil {
|
||||
p.AddStage(osbuild.NewSELinuxConfigStage(seLinuxConfig))
|
||||
}
|
||||
|
||||
if tunedConfig := imageConfig.Tuned; tunedConfig != nil {
|
||||
p.AddStage(osbuild.NewTunedStage(tunedConfig))
|
||||
}
|
||||
|
||||
for _, tmpfilesdConfig := range imageConfig.Tmpfilesd {
|
||||
p.AddStage(osbuild.NewTmpfilesdStage(tmpfilesdConfig))
|
||||
}
|
||||
|
||||
for _, pamLimitsConfConfig := range imageConfig.PamLimitsConf {
|
||||
p.AddStage(osbuild.NewPamLimitsConfStage(pamLimitsConfConfig))
|
||||
}
|
||||
|
||||
for _, sysctldConfig := range imageConfig.Sysctld {
|
||||
p.AddStage(osbuild.NewSysctldStage(sysctldConfig))
|
||||
}
|
||||
|
||||
for _, dnfConfig := range imageConfig.DNFConfig {
|
||||
p.AddStage(osbuild.NewDNFConfigStage(dnfConfig))
|
||||
}
|
||||
|
||||
if sshdConfig := imageConfig.SshdConfig; sshdConfig != nil {
|
||||
p.AddStage((osbuild.NewSshdConfigStage(sshdConfig)))
|
||||
}
|
||||
|
||||
if dnfAutomaticConfig := imageConfig.DNFAutomaticConfig; dnfAutomaticConfig != nil {
|
||||
p.AddStage(osbuild.NewDNFAutomaticConfigStage(dnfAutomaticConfig))
|
||||
}
|
||||
|
||||
for _, yumRepo := range imageConfig.YUMRepos {
|
||||
p.AddStage(osbuild.NewYumReposStage(yumRepo))
|
||||
}
|
||||
|
||||
if udevRules := imageConfig.UdevRules; udevRules != nil {
|
||||
p.AddStage(osbuild.NewUdevRulesStage(udevRules))
|
||||
}
|
||||
|
||||
if pt != nil {
|
||||
p = t.prependKernelCmdlineStage(p, pt)
|
||||
p.AddStage(osbuild.NewFSTabStage(osbuild.NewFSTabStageOptions(pt)))
|
||||
kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packages, c.GetKernel().Name)
|
||||
p.AddStage(bootloaderConfigStage(t, *pt, c.GetKernel(), kernelVer, false, false))
|
||||
}
|
||||
|
||||
p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions()))
|
||||
|
||||
if t.rpmOstree {
|
||||
p.AddStage(osbuild.NewOSTreePrepTreeStage(&osbuild.OSTreePrepTreeStageOptions{
|
||||
EtcGroupMembers: []string{
|
||||
// NOTE: We may want to make this configurable.
|
||||
"wheel", "docker",
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
|
@ -1,683 +0,0 @@
|
|||
package rhel84_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/distro_test_common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/rhel84"
|
||||
)
|
||||
|
||||
type rhelFamilyDistro struct {
|
||||
name string
|
||||
distro distro.Distro
|
||||
}
|
||||
|
||||
var rhelFamilyDistros = []rhelFamilyDistro{
|
||||
{
|
||||
name: "rhel",
|
||||
distro: rhel84.New(),
|
||||
},
|
||||
{
|
||||
name: "centos",
|
||||
distro: rhel84.NewCentos(),
|
||||
},
|
||||
}
|
||||
|
||||
func TestFilenameFromType(t *testing.T) {
|
||||
type args struct {
|
||||
outputFormat string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
want1 string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
args: args{"ami"},
|
||||
want: "image.raw",
|
||||
want1: "application/octet-stream",
|
||||
},
|
||||
{
|
||||
name: "openstack",
|
||||
args: args{"openstack"},
|
||||
want: "disk.qcow2",
|
||||
want1: "application/x-qemu-disk",
|
||||
},
|
||||
{
|
||||
name: "qcow2",
|
||||
args: args{"qcow2"},
|
||||
want: "disk.qcow2",
|
||||
want1: "application/x-qemu-disk",
|
||||
},
|
||||
{
|
||||
name: "tar",
|
||||
args: args{"tar"},
|
||||
want: "root.tar.xz",
|
||||
want1: "application/x-tar",
|
||||
},
|
||||
|
||||
{
|
||||
name: "vhd",
|
||||
args: args{"vhd"},
|
||||
want: "disk.vhd",
|
||||
want1: "application/x-vhd",
|
||||
},
|
||||
{
|
||||
name: "vmdk",
|
||||
args: args{"vmdk"},
|
||||
want: "disk.vmdk",
|
||||
want1: "application/x-vmdk",
|
||||
},
|
||||
{
|
||||
name: "gce",
|
||||
args: args{"gce"},
|
||||
want: "image.tar.gz",
|
||||
want1: "application/gzip",
|
||||
},
|
||||
{
|
||||
name: "gce-rhui",
|
||||
args: args{"gce-rhui"},
|
||||
want: "image.tar.gz",
|
||||
want1: "application/gzip",
|
||||
},
|
||||
{
|
||||
name: "invalid-output-type",
|
||||
args: args{"foobar"},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
dist := dist.distro
|
||||
arch, _ := dist.GetArch("x86_64")
|
||||
imgType, err := arch.GetImageType(tt.args.outputFormat)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Arch.GetImageType() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr {
|
||||
got := imgType.Filename()
|
||||
got1 := imgType.MIMEType()
|
||||
if got != tt.want {
|
||||
t.Errorf("ImageType.Filename() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("ImageType.MIMEType() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_BuildPackages(t *testing.T) {
|
||||
x8664BuildPackages := []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"e2fsprogs",
|
||||
"grub2-efi-x64",
|
||||
"grub2-pc",
|
||||
"policycoreutils",
|
||||
"shim-x64",
|
||||
"systemd",
|
||||
"tar",
|
||||
"qemu-img",
|
||||
"xz",
|
||||
}
|
||||
aarch64BuildPackages := []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"e2fsprogs",
|
||||
"policycoreutils",
|
||||
"qemu-img",
|
||||
"systemd",
|
||||
"tar",
|
||||
"xz",
|
||||
}
|
||||
buildPackages := map[string][]string{
|
||||
"x86_64": x8664BuildPackages,
|
||||
"aarch64": aarch64BuildPackages,
|
||||
"ppc64le": nil,
|
||||
"s390x": nil,
|
||||
}
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
d := dist.distro
|
||||
for _, archLabel := range d.ListArches() {
|
||||
archStruct, err := d.GetArch(archLabel)
|
||||
if assert.NoErrorf(t, err, "d.GetArch(%v) returned err = %v; expected nil", archLabel, err) {
|
||||
continue
|
||||
}
|
||||
for _, itLabel := range archStruct.ListImageTypes() {
|
||||
itStruct, err := archStruct.GetImageType(itLabel)
|
||||
if assert.NoErrorf(t, err, "d.GetArch(%v) returned err = %v; expected nil", archLabel, err) {
|
||||
continue
|
||||
}
|
||||
buildPkgs := itStruct.PackageSets(blueprint.Blueprint{}, distro.ImageOptions{}, nil)["build-packages"]
|
||||
assert.NotNil(t, buildPkgs)
|
||||
assert.Len(t, buildPkgs, 1)
|
||||
assert.ElementsMatch(t, buildPackages[archLabel], buildPkgs[0].Include)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_Name(t *testing.T) {
|
||||
imgMap := []struct {
|
||||
arch string
|
||||
imgNames []string
|
||||
}{
|
||||
{
|
||||
arch: "x86_64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
"rhel-edge-commit",
|
||||
"tar",
|
||||
"vhd",
|
||||
"vmdk",
|
||||
},
|
||||
},
|
||||
{
|
||||
arch: "aarch64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
"rhel-edge-commit",
|
||||
"tar",
|
||||
},
|
||||
},
|
||||
{
|
||||
arch: "ppc64le",
|
||||
imgNames: []string{
|
||||
"qcow2",
|
||||
"tar",
|
||||
},
|
||||
},
|
||||
{
|
||||
arch: "s390x",
|
||||
imgNames: []string{
|
||||
"qcow2",
|
||||
"tar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
for _, mapping := range imgMap {
|
||||
if mapping.arch == distro.S390xArchName && dist.name == "centos" {
|
||||
continue
|
||||
}
|
||||
arch, err := dist.distro.GetArch(mapping.arch)
|
||||
if assert.NoError(t, err) {
|
||||
for _, imgName := range mapping.imgNames {
|
||||
if imgName == "rhel-edge-commit" && dist.name == "centos" {
|
||||
continue
|
||||
}
|
||||
imgType, err := arch.GetImageType(imgName)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equalf(t, imgName, imgType.Name(), "arch: %s", mapping.arch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_Size(t *testing.T) {
|
||||
const gigaByte = 1024 * 1024 * 1024
|
||||
sizeMap := []struct {
|
||||
name string
|
||||
inputSize uint64
|
||||
outputSize uint64
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
inputSize: 6*gigaByte + 1,
|
||||
outputSize: 6*gigaByte + 1,
|
||||
},
|
||||
{
|
||||
name: "ami",
|
||||
inputSize: 0,
|
||||
outputSize: 6 * gigaByte,
|
||||
},
|
||||
{
|
||||
name: "vhd",
|
||||
inputSize: 10 * gigaByte,
|
||||
outputSize: 10 * gigaByte,
|
||||
},
|
||||
{
|
||||
name: "vhd",
|
||||
inputSize: 10*gigaByte - 1,
|
||||
outputSize: 10 * gigaByte,
|
||||
},
|
||||
}
|
||||
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
arch, err := dist.distro.GetArch("x86_64")
|
||||
if assert.NoError(t, err) {
|
||||
for _, mapping := range sizeMap {
|
||||
imgType, err := arch.GetImageType(mapping.name)
|
||||
if assert.NoError(t, err) {
|
||||
size := imgType.Size(mapping.inputSize)
|
||||
assert.Equalf(t, mapping.outputSize, size, "Image type: %s, input size: %d, expected: %d, got: %d",
|
||||
mapping.name, mapping.inputSize, mapping.outputSize, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_BasePackages(t *testing.T) {
|
||||
pkgMaps := []struct {
|
||||
name string
|
||||
basePackages []string
|
||||
bootloaderPackages []string
|
||||
excludedPackages []string
|
||||
bootable bool
|
||||
rhelOnlyBasePackages []string
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
basePackages: []string{
|
||||
"checkpolicy",
|
||||
"chrony",
|
||||
"cloud-init",
|
||||
"cloud-init",
|
||||
"cloud-utils-growpart",
|
||||
"@core",
|
||||
"dhcp-client",
|
||||
"gdisk",
|
||||
"langpacks-en",
|
||||
"net-tools",
|
||||
"NetworkManager",
|
||||
"redhat-release",
|
||||
"redhat-release-eula",
|
||||
"rsync",
|
||||
"selinux-policy-targeted",
|
||||
"tar",
|
||||
"yum-utils",
|
||||
|
||||
// Default from Blueprint
|
||||
"kernel",
|
||||
},
|
||||
bootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"grub2-pc",
|
||||
"grub2-efi-x64",
|
||||
"shim-x64",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"aic94xx-firmware",
|
||||
"alsa-firmware",
|
||||
"alsa-lib",
|
||||
"alsa-tools-firmware",
|
||||
"biosdevname",
|
||||
"dracut-config-rescue",
|
||||
"firewalld",
|
||||
"iprutils",
|
||||
"ivtv-firmware",
|
||||
"iwl1000-firmware",
|
||||
"iwl100-firmware",
|
||||
"iwl105-firmware",
|
||||
"iwl135-firmware",
|
||||
"iwl2000-firmware",
|
||||
"iwl2030-firmware",
|
||||
"iwl3160-firmware",
|
||||
"iwl3945-firmware",
|
||||
"iwl4965-firmware",
|
||||
"iwl5000-firmware",
|
||||
"iwl5150-firmware",
|
||||
"iwl6000-firmware",
|
||||
"iwl6000g2a-firmware",
|
||||
"iwl6000g2b-firmware",
|
||||
"iwl6050-firmware",
|
||||
"iwl7260-firmware",
|
||||
"libertas-sd8686-firmware",
|
||||
"libertas-sd8787-firmware",
|
||||
"libertas-usb8388-firmware",
|
||||
"plymouth",
|
||||
"rng-tools",
|
||||
|
||||
// TODO this cannot be removed, because the kernel (?)
|
||||
// depends on it. The ec2 kickstart force-removes it.
|
||||
// "linux-firmware",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
bootable: true,
|
||||
rhelOnlyBasePackages: []string{
|
||||
"insights-client",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "openstack",
|
||||
basePackages: []string{
|
||||
// Defaults
|
||||
"@Core",
|
||||
"langpacks-en",
|
||||
// From the lorax kickstart
|
||||
"selinux-policy-targeted",
|
||||
"cloud-init",
|
||||
"qemu-guest-agent",
|
||||
"spice-vdagent",
|
||||
|
||||
// Default from Blueprint
|
||||
"kernel",
|
||||
},
|
||||
bootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"grub2-pc",
|
||||
"grub2-efi-x64",
|
||||
"shim-x64",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"rng-tools",
|
||||
},
|
||||
bootable: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
arch, err := dist.distro.GetArch("x86_64")
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, pkgMap := range pkgMaps {
|
||||
imgType, err := arch.GetImageType(pkgMap.name)
|
||||
assert.NoError(t, err)
|
||||
packages := imgType.PackageSets(blueprint.Blueprint{}, distro.ImageOptions{}, nil)["packages"]
|
||||
assert.NotNil(t, packages)
|
||||
assert.Len(t, packages, 1)
|
||||
expectedPackages := append(pkgMap.basePackages, pkgMap.bootloaderPackages...)
|
||||
if dist.name == "rhel" {
|
||||
expectedPackages = append(expectedPackages, pkgMap.rhelOnlyBasePackages...)
|
||||
}
|
||||
assert.ElementsMatchf(
|
||||
t,
|
||||
expectedPackages,
|
||||
packages[0].Include,
|
||||
"image type: %s",
|
||||
pkgMap.name,
|
||||
)
|
||||
assert.Equalf(t, pkgMap.excludedPackages, packages[0].Exclude, "image type: %s", pkgMap.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check that Manifest() function returns an error for unsupported
|
||||
// configurations.
|
||||
func TestDistro_ManifestError(t *testing.T) {
|
||||
// Currently, the only unsupported configuration is OSTree commit types
|
||||
// with Kernel boot options
|
||||
r8distro := rhel84.New()
|
||||
bp := blueprint.Blueprint{
|
||||
Customizations: &blueprint.Customizations{
|
||||
Kernel: &blueprint.KernelCustomization{
|
||||
Append: "debug",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, archName := range r8distro.ListArches() {
|
||||
arch, _ := r8distro.GetArch(archName)
|
||||
for _, imgTypeName := range arch.ListImageTypes() {
|
||||
if archName == distro.S390xArchName && imgTypeName == "tar" {
|
||||
// broken arch-imgType combination; see
|
||||
// https://github.com/osbuild/osbuild-composer/issues/1220
|
||||
continue
|
||||
}
|
||||
imgType, _ := arch.GetImageType(imgTypeName)
|
||||
imgOpts := distro.ImageOptions{
|
||||
Size: imgType.Size(0),
|
||||
}
|
||||
testPackageSpecSets := distro_test_common.GetTestingPackageSpecSets("kernel", arch.Name(), imgType.PayloadPackageSets())
|
||||
_, err := imgType.Manifest(bp.Customizations, imgOpts, nil, testPackageSpecSets, 0)
|
||||
if imgTypeName == "rhel-edge-commit" || imgTypeName == "rhel-edge-container" {
|
||||
assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types")
|
||||
} else if imgTypeName == "rhel-edge-installer" {
|
||||
assert.EqualError(t, err, "boot ISO image type \"rhel-edge-installer\" requires specifying a URL from which to retrieve the OSTree commit")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestArchitecture_ListImageTypes(t *testing.T) {
|
||||
imgMap := []struct {
|
||||
arch string
|
||||
imgNames []string
|
||||
rhelAdditionalImageTypes []string
|
||||
}{
|
||||
{
|
||||
arch: "x86_64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
"tar",
|
||||
"vhd",
|
||||
"vmdk",
|
||||
"gce",
|
||||
"gce-rhui",
|
||||
},
|
||||
rhelAdditionalImageTypes: []string{"rhel-edge-commit", "rhel-edge-container", "rhel-edge-installer"},
|
||||
},
|
||||
{
|
||||
arch: "aarch64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
"tar",
|
||||
},
|
||||
rhelAdditionalImageTypes: []string{"rhel-edge-commit", "rhel-edge-container"},
|
||||
},
|
||||
{
|
||||
arch: "ppc64le",
|
||||
imgNames: []string{
|
||||
"qcow2",
|
||||
"tar",
|
||||
},
|
||||
},
|
||||
{
|
||||
arch: "s390x",
|
||||
imgNames: []string{
|
||||
"qcow2",
|
||||
"tar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
for _, mapping := range imgMap {
|
||||
if mapping.arch == distro.S390xArchName && dist.name == "centos" {
|
||||
continue
|
||||
}
|
||||
arch, err := dist.distro.GetArch(mapping.arch)
|
||||
require.NoError(t, err)
|
||||
imageTypes := arch.ListImageTypes()
|
||||
|
||||
var expectedImageTypes []string
|
||||
expectedImageTypes = append(expectedImageTypes, mapping.imgNames...)
|
||||
if dist.name == "rhel" {
|
||||
expectedImageTypes = append(expectedImageTypes, mapping.rhelAdditionalImageTypes...)
|
||||
}
|
||||
|
||||
require.ElementsMatch(t, expectedImageTypes, imageTypes)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRhel84_ListArches(t *testing.T) {
|
||||
arches := rhel84.New().ListArches()
|
||||
assert.Equal(t, []string{"aarch64", "ppc64le", "s390x", "x86_64"}, arches)
|
||||
}
|
||||
|
||||
func TestCentos_ListArches(t *testing.T) {
|
||||
arches := rhel84.NewCentos().ListArches()
|
||||
assert.Equal(t, []string{"aarch64", "ppc64le", "x86_64"}, arches)
|
||||
}
|
||||
|
||||
func TestRhel84_GetArch(t *testing.T) {
|
||||
arches := []struct {
|
||||
name string
|
||||
errorExpected bool
|
||||
errorExpectedInCentos bool
|
||||
}{
|
||||
{
|
||||
name: "x86_64",
|
||||
},
|
||||
{
|
||||
name: "aarch64",
|
||||
},
|
||||
{
|
||||
name: "ppc64le",
|
||||
},
|
||||
{
|
||||
name: "s390x",
|
||||
errorExpectedInCentos: true,
|
||||
},
|
||||
{
|
||||
name: "foo-arch",
|
||||
errorExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
for _, a := range arches {
|
||||
actualArch, err := dist.distro.GetArch(a.name)
|
||||
if a.errorExpected || (a.errorExpectedInCentos && dist.name == "centos") {
|
||||
assert.Nil(t, actualArch)
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.Equal(t, a.name, actualArch.Name())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRhel84_Name(t *testing.T) {
|
||||
distro := rhel84.New()
|
||||
assert.Equal(t, "rhel-84", distro.Name())
|
||||
}
|
||||
|
||||
func TestCentos_Name(t *testing.T) {
|
||||
distro := rhel84.NewCentos()
|
||||
assert.Equal(t, "centos-8", distro.Name())
|
||||
}
|
||||
|
||||
func TestRhel84_ModulePlatformID(t *testing.T) {
|
||||
distro := rhel84.New()
|
||||
assert.Equal(t, "platform:el8", distro.ModulePlatformID())
|
||||
|
||||
centos := rhel84.NewCentos()
|
||||
assert.Equal(t, "platform:el8", centos.ModulePlatformID())
|
||||
}
|
||||
|
||||
func TestRhel84_KernelOption(t *testing.T) {
|
||||
distro_test_common.TestDistro_KernelOption(t, rhel84.New())
|
||||
}
|
||||
|
||||
func TestDistro_CustomFileSystemManifestError(t *testing.T) {
|
||||
bp := blueprint.Blueprint{
|
||||
Customizations: &blueprint.Customizations{
|
||||
Filesystem: []blueprint.FilesystemCustomization{
|
||||
{
|
||||
MinSize: 1024,
|
||||
Mountpoint: "/boot",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
d := dist.distro
|
||||
for _, archName := range d.ListArches() {
|
||||
arch, _ := d.GetArch(archName)
|
||||
for _, imgTypeName := range arch.ListImageTypes() {
|
||||
if (archName == distro.S390xArchName && imgTypeName == "tar") || imgTypeName == "rhel-edge-installer" {
|
||||
continue
|
||||
}
|
||||
imgType, _ := arch.GetImageType(imgTypeName)
|
||||
imgOpts := distro.ImageOptions{
|
||||
Size: imgType.Size(0),
|
||||
}
|
||||
testPackageSpecSets := distro_test_common.GetTestingPackageSpecSets("kernel", arch.Name(), imgType.PayloadPackageSets())
|
||||
_, err := imgType.Manifest(bp.Customizations, imgOpts, nil, testPackageSpecSets, 0)
|
||||
if imgTypeName == "rhel-edge-commit" || imgTypeName == "rhel-edge-container" {
|
||||
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
|
||||
} else {
|
||||
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/boot\"]")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDistro_TestRootMountPoint(t *testing.T) {
|
||||
bp := blueprint.Blueprint{
|
||||
Customizations: &blueprint.Customizations{
|
||||
Filesystem: []blueprint.FilesystemCustomization{
|
||||
{
|
||||
MinSize: 1024,
|
||||
Mountpoint: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, dist := range rhelFamilyDistros {
|
||||
t.Run(dist.name, func(t *testing.T) {
|
||||
d := dist.distro
|
||||
for _, archName := range d.ListArches() {
|
||||
arch, _ := d.GetArch(archName)
|
||||
for _, imgTypeName := range arch.ListImageTypes() {
|
||||
if (archName == distro.S390xArchName && imgTypeName == "tar") || imgTypeName == "rhel-edge-installer" {
|
||||
continue
|
||||
}
|
||||
imgType, _ := arch.GetImageType(imgTypeName)
|
||||
imgOpts := distro.ImageOptions{
|
||||
Size: imgType.Size(0),
|
||||
}
|
||||
testPackageSpecSets := distro_test_common.GetTestingPackageSpecSets("kernel", arch.Name(), imgType.PayloadPackageSets())
|
||||
_, err := imgType.Manifest(bp.Customizations, imgOpts, nil, testPackageSpecSets, 0)
|
||||
if imgTypeName == "rhel-edge-commit" || imgTypeName == "rhel-edge-container" {
|
||||
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,730 +0,0 @@
|
|||
package rhel84
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/disk"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
|
||||
"github.com/osbuild/osbuild-composer/internal/ostree"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
const (
|
||||
kspath = "/usr/share/anaconda/interactive-defaults.ks"
|
||||
)
|
||||
|
||||
type pipelinesFunc func(t *imageTypeS2, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error)
|
||||
|
||||
type imageTypeS2 struct {
|
||||
arch *architecture
|
||||
name string
|
||||
filename string
|
||||
mimeType string
|
||||
packageSets map[string]rpmmd.PackageSet
|
||||
enabledServices []string
|
||||
disabledServices []string
|
||||
defaultTarget string
|
||||
kernelOptions string
|
||||
bootable bool
|
||||
bootISO bool
|
||||
rpmOstree bool
|
||||
defaultSize uint64
|
||||
buildPipelines []string
|
||||
payloadPipelines []string
|
||||
exports []string
|
||||
partitionTableGenerator func(imageSize uint64, arch distro.Arch, rng *rand.Rand) disk.PartitionTable
|
||||
pipelines pipelinesFunc
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Arch() distro.Arch {
|
||||
return t.arch
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Name() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Filename() string {
|
||||
return t.filename
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) MIMEType() string {
|
||||
return t.mimeType
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) OSTreeRef() string {
|
||||
if t.rpmOstree {
|
||||
return fmt.Sprintf(ostreeRef, t.Arch().Name())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Size(size uint64) uint64 {
|
||||
const MegaByte = 1024 * 1024
|
||||
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
|
||||
if t.name == "vhd" && size%MegaByte != 0 {
|
||||
size = (size/MegaByte + 1) * MegaByte
|
||||
}
|
||||
if size == 0 {
|
||||
size = t.defaultSize
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) PartitionType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Packages(bp blueprint.Blueprint) ([]string, []string) {
|
||||
packages := append(t.packageSets["packages"].Include, bp.GetPackages()...)
|
||||
timezone, _ := bp.Customizations.GetTimezoneSettings()
|
||||
if timezone != nil {
|
||||
packages = append(packages, "chrony")
|
||||
}
|
||||
|
||||
// copy the list of excluded packages from the image type
|
||||
// and subtract any packages found in the blueprint (this
|
||||
// will not handle the issue with dependencies present in
|
||||
// the list of excluded packages, but it will create a
|
||||
// possibility of a workaround at least)
|
||||
excludedPackages := append([]string(nil), t.packageSets["packages"].Exclude...)
|
||||
for _, pkg := range bp.GetPackages() {
|
||||
// removePackage is fine if the package doesn't exist
|
||||
excludedPackages = removePackage(excludedPackages, pkg)
|
||||
}
|
||||
|
||||
return packages, excludedPackages
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) BuildPackages() []string {
|
||||
buildPackages := append(t.arch.distro.buildPackages, t.arch.buildPackages...)
|
||||
if t.rpmOstree {
|
||||
buildPackages = append(buildPackages, "rpm-ostree")
|
||||
}
|
||||
if t.bootISO {
|
||||
buildPackages = append(buildPackages, t.packageSets["build"].Include...)
|
||||
}
|
||||
return buildPackages
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) PackageSets(bp blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig) map[string][]rpmmd.PackageSet {
|
||||
sets := map[string][]rpmmd.PackageSet{
|
||||
"build-packages": {{
|
||||
Include: t.BuildPackages(),
|
||||
Repositories: repos,
|
||||
}},
|
||||
}
|
||||
for name := range t.packageSets {
|
||||
if name == "packages" {
|
||||
// treat base packages separately to combine with blueprint
|
||||
include, exclude := t.Packages(bp)
|
||||
sets[name] = []rpmmd.PackageSet{{
|
||||
Include: include,
|
||||
Exclude: exclude,
|
||||
Repositories: repos,
|
||||
}}
|
||||
continue
|
||||
}
|
||||
pkgSet := t.packageSets[name]
|
||||
pkgSet.Repositories = repos
|
||||
sets[name] = []rpmmd.PackageSet{pkgSet}
|
||||
}
|
||||
return sets
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) BuildPipelines() []string {
|
||||
return t.buildPipelines
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) PayloadPipelines() []string {
|
||||
return t.payloadPipelines
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) PayloadPackageSets() []string {
|
||||
return []string{"packages"}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) PackageSetsChains() map[string][]string {
|
||||
return map[string][]string{}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Exports() []string {
|
||||
return t.exports
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) Manifest(c *blueprint.Customizations,
|
||||
options distro.ImageOptions,
|
||||
repos []rpmmd.RepoConfig,
|
||||
packageSpecSets map[string][]rpmmd.PackageSpec,
|
||||
seed int64) (distro.Manifest, error) {
|
||||
|
||||
if err := t.checkOptions(c, options); err != nil {
|
||||
return distro.Manifest{}, err
|
||||
}
|
||||
|
||||
source := rand.NewSource(seed)
|
||||
// math/rand is good enough in this case
|
||||
/* #nosec G404 */
|
||||
rng := rand.New(source)
|
||||
pipelines, err := t.pipelines(t, c, options, repos, packageSpecSets, rng)
|
||||
if err != nil {
|
||||
return distro.Manifest{}, err
|
||||
}
|
||||
|
||||
// flatten spec sets for sources
|
||||
allPackageSpecs := make([]rpmmd.PackageSpec, 0)
|
||||
for _, specs := range packageSpecSets {
|
||||
allPackageSpecs = append(allPackageSpecs, specs...)
|
||||
}
|
||||
|
||||
var commits []ostree.CommitSource
|
||||
if t.bootISO && options.OSTree.Parent != "" && options.OSTree.URL != "" {
|
||||
commit := ostree.CommitSource{Checksum: options.OSTree.Parent, URL: options.OSTree.URL}
|
||||
commits = []ostree.CommitSource{commit}
|
||||
}
|
||||
return json.Marshal(
|
||||
osbuild.Manifest{
|
||||
Version: "2",
|
||||
Pipelines: pipelines,
|
||||
Sources: osbuild.GenSources(allPackageSpecs, commits, nil),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func edgePipelines(t *imageTypeS2, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
|
||||
pipelines := make([]osbuild.Pipeline, 0)
|
||||
|
||||
pipelines = append(pipelines, *t.buildPipeline(repos, packageSetSpecs["build-packages"]))
|
||||
|
||||
if t.bootISO {
|
||||
var kernelPkg *rpmmd.PackageSpec
|
||||
installerPackages := packageSetSpecs["installer"]
|
||||
for idx := range installerPackages {
|
||||
pkg := installerPackages[idx]
|
||||
if pkg.Name == "kernel" {
|
||||
kernelPkg = &pkg
|
||||
break
|
||||
}
|
||||
}
|
||||
if kernelPkg == nil {
|
||||
panic("kernel package not found in installer package set; this is a programming error")
|
||||
}
|
||||
kernelVer := fmt.Sprintf("%s-%s.%s", kernelPkg.Version, kernelPkg.Release, kernelPkg.Arch)
|
||||
anacondaPipeline, err := t.anacondaTreePipeline(repos, customizations, packageSetSpecs["installer"], options, kernelVer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pipelines = append(pipelines, *anacondaPipeline)
|
||||
pipelines = append(pipelines, *t.bootISOTreePipeline(kernelVer))
|
||||
pipelines = append(pipelines, *t.bootISOPipeline())
|
||||
} else {
|
||||
treePipeline, err := t.ostreeTreePipeline(repos, packageSetSpecs["packages"], customizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pipelines = append(pipelines, *treePipeline)
|
||||
pipelines = append(pipelines, *t.ostreeCommitPipeline(options))
|
||||
pipelines = append(pipelines, *t.containerTreePipeline(repos, packageSetSpecs["container"], options, customizations))
|
||||
pipelines = append(pipelines, *t.containerPipeline())
|
||||
}
|
||||
|
||||
return pipelines, nil
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) buildPipeline(repos []rpmmd.RepoConfig, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "build"
|
||||
p.Runner = "org.osbuild.rhel84"
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(buildPackageSpecs)))
|
||||
p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions()))
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, c *blueprint.Customizations) (*osbuild.Pipeline, error) {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "ostree-tree"
|
||||
p.Build = "name:build"
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(packages)))
|
||||
language, keyboard := c.GetPrimaryLocale()
|
||||
if language != nil {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: *language}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"}))
|
||||
}
|
||||
if keyboard != nil {
|
||||
p.AddStage(osbuild.NewKeymapStage(&osbuild.KeymapStageOptions{Keymap: *keyboard}))
|
||||
}
|
||||
if hostname := c.GetHostname(); hostname != nil {
|
||||
p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: *hostname}))
|
||||
}
|
||||
|
||||
timezone, ntpServers := c.GetTimezoneSettings()
|
||||
if timezone != nil {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: *timezone}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: "America/New_York"}))
|
||||
}
|
||||
|
||||
if len(ntpServers) > 0 {
|
||||
p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{Timeservers: ntpServers}))
|
||||
}
|
||||
|
||||
if groups := c.GetGroups(); len(groups) > 0 {
|
||||
p.AddStage(osbuild.NewGroupsStage(osbuild.NewGroupsStageOptions(groups)))
|
||||
}
|
||||
|
||||
if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil {
|
||||
return nil, err
|
||||
} else if userOptions != nil {
|
||||
// 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
|
||||
userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.AddStage(osbuild.NewUsersStage(userOptionsSansKeys))
|
||||
p.AddStage(osbuild.NewFirstBootStage(t.usersFirstBootOptions(userOptions)))
|
||||
}
|
||||
|
||||
if services := c.GetServices(); services != nil || t.enabledServices != nil || t.disabledServices != nil || t.defaultTarget != "" {
|
||||
p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.enabledServices, t.disabledServices, services, t.defaultTarget)))
|
||||
}
|
||||
|
||||
if firewall := c.GetFirewall(); firewall != nil {
|
||||
p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall)))
|
||||
}
|
||||
|
||||
if !t.bootISO {
|
||||
p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions()))
|
||||
}
|
||||
|
||||
// These are the current defaults for the sysconfig stage. This can be changed to be image type exclusive if different configs are needed.
|
||||
p.AddStage(osbuild.NewSysconfigStage(&osbuild.SysconfigStageOptions{
|
||||
Kernel: &osbuild.SysconfigKernelOptions{
|
||||
UpdateDefault: true,
|
||||
DefaultKernel: "kernel",
|
||||
},
|
||||
Network: &osbuild.SysconfigNetworkOptions{
|
||||
Networking: true,
|
||||
NoZeroConf: true,
|
||||
},
|
||||
}))
|
||||
|
||||
p.AddStage(osbuild.NewOSTreePrepTreeStage(&osbuild.OSTreePrepTreeStageOptions{
|
||||
EtcGroupMembers: []string{
|
||||
// NOTE: We may want to make this configurable.
|
||||
"wheel", "docker",
|
||||
},
|
||||
}))
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) ostreeCommitPipeline(options distro.ImageOptions) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "ostree-commit"
|
||||
p.Build = "name:build"
|
||||
p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/repo"}))
|
||||
|
||||
commitStageInput := new(osbuild.OSTreeCommitStageInput)
|
||||
commitStageInput.Type = "org.osbuild.tree"
|
||||
commitStageInput.Origin = "org.osbuild.pipeline"
|
||||
commitStageInput.References = osbuild.OSTreeCommitStageReferences{"name:ostree-tree"}
|
||||
|
||||
p.AddStage(osbuild.NewOSTreeCommitStage(
|
||||
&osbuild.OSTreeCommitStageOptions{
|
||||
Ref: options.OSTree.Ref,
|
||||
OSVersion: "8.4", // NOTE: Set on image type?
|
||||
Parent: options.OSTree.Parent,
|
||||
},
|
||||
&osbuild.OSTreeCommitStageInputs{Tree: commitStageInput}),
|
||||
)
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "container-tree"
|
||||
p.Build = "name:build"
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(packages)))
|
||||
language, _ := c.GetPrimaryLocale()
|
||||
if language != nil {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: *language}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US"}))
|
||||
}
|
||||
p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/var/www/html/repo"}))
|
||||
|
||||
p.AddStage(osbuild.NewOSTreePullStage(
|
||||
&osbuild.OSTreePullStageOptions{Repo: "/var/www/html/repo"},
|
||||
osbuild.NewOstreePullStageInputs("org.osbuild.pipeline", "name:ostree-commit", options.OSTree.Ref),
|
||||
))
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) containerPipeline() *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
// NOTE(akoutsou) 1to2t: final pipeline should always be named "assembler"
|
||||
p.Name = "assembler"
|
||||
p.Build = "name:build"
|
||||
options := &osbuild.OCIArchiveStageOptions{
|
||||
Architecture: t.arch.Name(),
|
||||
Filename: t.Filename(),
|
||||
Config: &osbuild.OCIArchiveConfig{
|
||||
Cmd: []string{"httpd", "-D", "FOREGROUND"},
|
||||
ExposedPorts: []string{"80"},
|
||||
},
|
||||
}
|
||||
baseInput := new(osbuild.OCIArchiveStageInput)
|
||||
baseInput.Type = "org.osbuild.tree"
|
||||
baseInput.Origin = "org.osbuild.pipeline"
|
||||
baseInput.References = []string{"name:container-tree"}
|
||||
inputs := &osbuild.OCIArchiveStageInputs{Base: baseInput}
|
||||
p.AddStage(osbuild.NewOCIArchiveStage(options, inputs))
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) anacondaTreePipeline(repos []rpmmd.RepoConfig, customizations *blueprint.Customizations, packages []rpmmd.PackageSpec, options distro.ImageOptions, kernelVer string) (*osbuild.Pipeline, error) {
|
||||
ostreeRepoPath := "/ostree/repo"
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "anaconda-tree"
|
||||
p.Build = "name:build"
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(packages)))
|
||||
p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: ostreeRepoPath}))
|
||||
p.AddStage(osbuild.NewOSTreePullStage(
|
||||
&osbuild.OSTreePullStageOptions{Repo: ostreeRepoPath},
|
||||
osbuild.NewOstreePullStageInputs("org.osbuild.source", options.OSTree.Parent, options.OSTree.Ref),
|
||||
))
|
||||
p.AddStage(osbuild.NewBuildstampStage(t.buildStampStageOptions()))
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"}))
|
||||
|
||||
rootPassword := ""
|
||||
rootUser := osbuild.UsersStageOptionsUser{
|
||||
Password: &rootPassword,
|
||||
}
|
||||
|
||||
installUID := 0
|
||||
installGID := 0
|
||||
installHome := "/root"
|
||||
installShell := "/usr/libexec/anaconda/run-anaconda"
|
||||
installPassword := ""
|
||||
installUser := osbuild.UsersStageOptionsUser{
|
||||
UID: &installUID,
|
||||
GID: &installGID,
|
||||
Home: &installHome,
|
||||
Shell: &installShell,
|
||||
Password: &installPassword,
|
||||
}
|
||||
usersStageOptions := &osbuild.UsersStageOptions{
|
||||
Users: map[string]osbuild.UsersStageOptionsUser{
|
||||
"root": rootUser,
|
||||
"install": installUser,
|
||||
},
|
||||
}
|
||||
|
||||
p.AddStage(osbuild.NewUsersStage(usersStageOptions))
|
||||
nUsers := len(customizations.GetUsers())+len(customizations.GetGroups()) > 0
|
||||
p.AddStage(osbuild.NewAnacondaStage(osbuild.NewAnacondaStageOptions(nUsers)))
|
||||
p.AddStage(osbuild.NewLoraxScriptStage(t.loraxScriptStageOptions()))
|
||||
p.AddStage(osbuild.NewDracutStage(t.dracutStageOptions(kernelVer)))
|
||||
kickstartOptions, err := osbuild.NewKickstartStageOptions(kspath, "", customizations.GetUsers(), customizations.GetGroups(), fmt.Sprintf("file://%s", ostreeRepoPath), options.OSTree.Ref, "rhel")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.AddStage(osbuild.NewKickstartStage(kickstartOptions))
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) bootISOTreePipeline(kernelVer string) *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
p.Name = "bootiso-tree"
|
||||
p.Build = "name:build"
|
||||
|
||||
p.AddStage(osbuild.NewBootISOMonoStage(t.bootISOMonoStageOptions(kernelVer), osbuild.NewBootISOMonoStagePipelineTreeInputs("anaconda-tree")))
|
||||
p.AddStage(osbuild.NewDiscinfoStage(t.discinfoStageOptions()))
|
||||
|
||||
return p
|
||||
}
|
||||
func (t *imageTypeS2) bootISOPipeline() *osbuild.Pipeline {
|
||||
p := new(osbuild.Pipeline)
|
||||
// NOTE(akoutsou) 1to2t: final pipeline should always be named "assembler"
|
||||
p.Name = "assembler"
|
||||
p.Build = "name:build"
|
||||
|
||||
p.AddStage(osbuild.NewXorrisofsStage(t.xorrisofsStageOptions(), osbuild.NewXorrisofsStagePipelineTreeInputs("bootiso-tree")))
|
||||
p.AddStage(osbuild.NewImplantisomd5Stage(&osbuild.Implantisomd5StageOptions{Filename: t.Filename()}))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) rpmStageOptions(repos []rpmmd.RepoConfig) *osbuild.RPMStageOptions {
|
||||
var gpgKeys []string
|
||||
for _, repo := range repos {
|
||||
if repo.GPGKey == "" {
|
||||
continue
|
||||
}
|
||||
gpgKeys = append(gpgKeys, repo.GPGKey)
|
||||
}
|
||||
|
||||
return &osbuild.RPMStageOptions{
|
||||
GPGKeys: gpgKeys,
|
||||
Exclude: &osbuild.Exclude{
|
||||
// NOTE: Make configurable?
|
||||
Docs: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) selinuxStageOptions() *osbuild.SELinuxStageOptions {
|
||||
|
||||
options := &osbuild.SELinuxStageOptions{
|
||||
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
|
||||
}
|
||||
if t.bootISO {
|
||||
options.Labels = map[string]string{
|
||||
"/usr/bin/cp": "system_u:object_r:install_exec_t:s0",
|
||||
"/usr/bin/tar": "system_u:object_r:install_exec_t:s0",
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) usersFirstBootOptions(usersStageOptions *osbuild.UsersStageOptions) *osbuild.FirstBootStageOptions {
|
||||
cmds := make([]string, 0, 3*len(usersStageOptions.Users)+1)
|
||||
// workaround for creating authorized_keys file for user
|
||||
varhome := filepath.Join("/var", "home")
|
||||
for name, user := range usersStageOptions.Users {
|
||||
if user.Key != nil {
|
||||
sshdir := filepath.Join(varhome, name, ".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", name, name, sshdir))
|
||||
}
|
||||
}
|
||||
cmds = append(cmds, fmt.Sprintf("restorecon -rvF %s", varhome))
|
||||
options := &osbuild.FirstBootStageOptions{
|
||||
Commands: cmds,
|
||||
WaitForNetwork: false,
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions {
|
||||
options := osbuild.FirewallStageOptions{
|
||||
Ports: firewall.Ports,
|
||||
}
|
||||
|
||||
if firewall.Services != nil {
|
||||
options.EnabledServices = firewall.Services.Enabled
|
||||
options.DisabledServices = firewall.Services.Disabled
|
||||
}
|
||||
|
||||
return &options
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization, target string) *osbuild.SystemdStageOptions {
|
||||
if s != nil {
|
||||
enabledServices = append(enabledServices, s.Enabled...)
|
||||
disabledServices = append(disabledServices, s.Disabled...)
|
||||
}
|
||||
return &osbuild.SystemdStageOptions{
|
||||
EnabledServices: enabledServices,
|
||||
DisabledServices: disabledServices,
|
||||
DefaultTarget: target,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) buildStampStageOptions() *osbuild.BuildstampStageOptions {
|
||||
return &osbuild.BuildstampStageOptions{
|
||||
Arch: t.Arch().Name(),
|
||||
Product: "Red Hat Enterprise Linux",
|
||||
Version: "8.4",
|
||||
Variant: "edge",
|
||||
Final: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) loraxScriptStageOptions() *osbuild.LoraxScriptStageOptions {
|
||||
return &osbuild.LoraxScriptStageOptions{
|
||||
Path: "99-generic/runtime-postinstall.tmpl",
|
||||
BaseArch: t.Arch().Name(),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) dracutStageOptions(kernelVer string) *osbuild.DracutStageOptions {
|
||||
kernel := []string{kernelVer}
|
||||
modules := []string{
|
||||
"bash",
|
||||
"systemd",
|
||||
"fips",
|
||||
"systemd-initrd",
|
||||
"modsign",
|
||||
"nss-softokn",
|
||||
"rdma",
|
||||
"rngd",
|
||||
"i18n",
|
||||
"convertfs",
|
||||
"network-manager",
|
||||
"network",
|
||||
"ifcfg",
|
||||
"url-lib",
|
||||
"drm",
|
||||
"plymouth",
|
||||
"prefixdevname",
|
||||
"prefixdevname-tools",
|
||||
"anaconda",
|
||||
"crypt",
|
||||
"dm",
|
||||
"dmsquash-live",
|
||||
"kernel-modules",
|
||||
"kernel-modules-extra",
|
||||
"kernel-network-modules",
|
||||
"livenet",
|
||||
"lvm",
|
||||
"mdraid",
|
||||
"multipath",
|
||||
"qemu",
|
||||
"qemu-net",
|
||||
"fcoe",
|
||||
"fcoe-uefi",
|
||||
"iscsi",
|
||||
"lunmask",
|
||||
"nfs",
|
||||
"resume",
|
||||
"rootfs-block",
|
||||
"terminfo",
|
||||
"udev-rules",
|
||||
"biosdevname",
|
||||
"dracut-systemd",
|
||||
"pollcdrom",
|
||||
"usrmount",
|
||||
"base",
|
||||
"fs-lib",
|
||||
"img-lib",
|
||||
"shutdown",
|
||||
"uefi-lib",
|
||||
}
|
||||
return &osbuild.DracutStageOptions{
|
||||
Kernel: kernel,
|
||||
Modules: modules,
|
||||
Install: []string{"/.buildstamp"},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) bootISOMonoStageOptions(kernelVer string) *osbuild.BootISOMonoStageOptions {
|
||||
return &osbuild.BootISOMonoStageOptions{
|
||||
Product: osbuild.Product{
|
||||
Name: "Red Hat Enterprise Linux",
|
||||
Version: "8.4",
|
||||
},
|
||||
ISOLabel: fmt.Sprintf("RHEL-8-4-0-BaseOS-%s", t.Arch().Name()),
|
||||
Kernel: kernelVer,
|
||||
EFI: osbuild.EFI{
|
||||
Architectures: []string{
|
||||
"IA32",
|
||||
"X64",
|
||||
},
|
||||
Vendor: "redhat",
|
||||
},
|
||||
ISOLinux: osbuild.ISOLinux{
|
||||
Enabled: true,
|
||||
Debug: false,
|
||||
},
|
||||
Templates: "80-rhel",
|
||||
RootFS: osbuild.RootFS{
|
||||
Size: 4096,
|
||||
Compression: osbuild.FSCompression{
|
||||
Method: "xz",
|
||||
Options: &osbuild.FSCompressionOptions{
|
||||
// TODO: based on image arch
|
||||
BCJ: "x86",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) discinfoStageOptions() *osbuild.DiscinfoStageOptions {
|
||||
return &osbuild.DiscinfoStageOptions{
|
||||
BaseArch: t.Arch().Name(),
|
||||
Release: "202010217.n.0",
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) xorrisofsStageOptions() *osbuild.XorrisofsStageOptions {
|
||||
return &osbuild.XorrisofsStageOptions{
|
||||
Filename: t.Filename(),
|
||||
VolID: fmt.Sprintf("RHEL-8-4-0-BaseOS-%s", t.Arch().Name()),
|
||||
SysID: "LINUX",
|
||||
Boot: &osbuild.XorrisofsBoot{
|
||||
Image: "isolinux/isolinux.bin",
|
||||
Catalog: "isolinux/boot.cat",
|
||||
},
|
||||
EFI: "images/efiboot.img",
|
||||
IsohybridMBR: "/usr/share/syslinux/isohdpfx.bin",
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) checkOptions(customizations *blueprint.Customizations, options distro.ImageOptions) error {
|
||||
if t.bootISO {
|
||||
if options.OSTree.Parent == "" {
|
||||
return fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name)
|
||||
}
|
||||
if t.name == "rhel-edge-installer" {
|
||||
allowed := []string{"User", "Group"}
|
||||
if err := customizations.CheckAllowed(allowed...); err != nil {
|
||||
return fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.rpmOstree {
|
||||
return fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
|
||||
}
|
||||
|
||||
mountpoints := customizations.GetFilesystems()
|
||||
|
||||
if mountpoints != nil && t.rpmOstree {
|
||||
return fmt.Errorf("Custom mountpoints are not supported for ostree types")
|
||||
}
|
||||
|
||||
invalidMountpoints := []string{}
|
||||
for _, m := range mountpoints {
|
||||
if m.Mountpoint != "/" {
|
||||
invalidMountpoints = append(invalidMountpoints, m.Mountpoint)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidMountpoints) > 0 {
|
||||
return fmt.Errorf("The following custom mountpoints are not supported %+q", invalidMountpoints)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) prependKernelCmdlineStage(pipeline *osbuild.Pipeline, pt *disk.PartitionTable) *osbuild.Pipeline {
|
||||
if t.arch.name == distro.S390xArchName {
|
||||
rootFs := pt.FindMountable("/")
|
||||
if rootFs == nil {
|
||||
panic("s390x image must have a root partition, this is a programming error")
|
||||
}
|
||||
kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootFs.GetFSSpec().UUID, t.kernelOptions))
|
||||
pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...)
|
||||
}
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func (t *imageTypeS2) getPartitionTable(options distro.ImageOptions, rng *rand.Rand) (*disk.PartitionTable, error) {
|
||||
basePartitionTable := t.partitionTableGenerator(options.Size, t.Arch(), rng)
|
||||
pt, err := disk.NewPartitionTable(&basePartitionTable, nil, options.Size, false, rng)
|
||||
return pt, err
|
||||
}
|
||||
|
|
@ -1,296 +0,0 @@
|
|||
package rhel84
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
// common GCE image
|
||||
func getGceCommonPackageSet() rpmmd.PackageSet {
|
||||
return rpmmd.PackageSet{
|
||||
Include: []string{
|
||||
"@core",
|
||||
"langpacks-en", // not in Google's KS
|
||||
"acpid",
|
||||
"dhcp-client",
|
||||
"dnf-automatic",
|
||||
"net-tools",
|
||||
//"openssh-server", included in core
|
||||
"python3",
|
||||
"rng-tools",
|
||||
"tar",
|
||||
"vim",
|
||||
|
||||
// GCE guest tools
|
||||
"google-compute-engine",
|
||||
"google-osconfig-agent",
|
||||
"gce-disk-expand",
|
||||
// GCP SDK
|
||||
"google-cloud-sdk",
|
||||
|
||||
// Not explicitly included in GCP kickstart, but present on the image
|
||||
// for time synchronization
|
||||
"chrony",
|
||||
"timedatex",
|
||||
// Detected Platform requirements by Anaconda
|
||||
"qemu-guest-agent",
|
||||
// EFI
|
||||
"grub2-tools-efi",
|
||||
},
|
||||
Exclude: []string{
|
||||
"alsa-utils",
|
||||
"b43-fwcutter",
|
||||
"dmraid",
|
||||
"eject",
|
||||
"gpm",
|
||||
"irqbalance",
|
||||
"microcode_ctl",
|
||||
"smartmontools",
|
||||
"aic94xx-firmware",
|
||||
"atmel-firmware",
|
||||
"b43-openfwwf",
|
||||
"bfa-firmware",
|
||||
"ipw2100-firmware",
|
||||
"ipw2200-firmware",
|
||||
"ivtv-firmware",
|
||||
"iwl100-firmware",
|
||||
"iwl1000-firmware",
|
||||
"iwl3945-firmware",
|
||||
"iwl4965-firmware",
|
||||
"iwl5000-firmware",
|
||||
"iwl5150-firmware",
|
||||
"iwl6000-firmware",
|
||||
"iwl6000g2a-firmware",
|
||||
"iwl6050-firmware",
|
||||
"kernel-firmware",
|
||||
"libertas-usb8388-firmware",
|
||||
"ql2100-firmware",
|
||||
"ql2200-firmware",
|
||||
"ql23xx-firmware",
|
||||
"ql2400-firmware",
|
||||
"ql2500-firmware",
|
||||
"rt61pci-firmware",
|
||||
"rt73usb-firmware",
|
||||
"xorg-x11-drv-ati-firmware",
|
||||
"zd1211-firmware",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GCE BYOS image
|
||||
func getGcePackageSet() rpmmd.PackageSet {
|
||||
return getGceCommonPackageSet()
|
||||
}
|
||||
|
||||
// GCE RHUI image
|
||||
func getGceRhuiPackageSet() rpmmd.PackageSet {
|
||||
return rpmmd.PackageSet{
|
||||
Include: []string{
|
||||
"google-rhui-client-rhel8",
|
||||
},
|
||||
}.Append(getGceCommonPackageSet())
|
||||
}
|
||||
|
||||
// gcePipelinesRhel86 is a slightly modified RHEL-86 version of gcePipelines() function
|
||||
func gcePipelinesRhel86(t *imageTypeS2, imageConfig *distro.ImageConfig, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
|
||||
pipelines := make([]osbuild.Pipeline, 0)
|
||||
pipelines = append(pipelines, *t.buildPipeline(repos, packageSetSpecs["build-packages"]))
|
||||
|
||||
partitionTable, err := t.getPartitionTable(options, rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
treePipeline, err := osPipelineRhel86(t, imageConfig, repos, packageSetSpecs["packages"], customizations, options, partitionTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pipelines = append(pipelines, *treePipeline)
|
||||
|
||||
diskfile := "disk.raw"
|
||||
kernelVer, err := rpmmd.GetVerStrFromPackageSpecList(packageSetSpecs["packages"], customizations.GetKernel().Name)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("kernel package %q not found", customizations.GetKernel().Name))
|
||||
}
|
||||
imagePipeline := liveImagePipeline(treePipeline.Name, diskfile, partitionTable, t.arch, kernelVer)
|
||||
pipelines = append(pipelines, *imagePipeline)
|
||||
|
||||
archivePipeline := tarArchivePipeline("archive", imagePipeline.Name, &osbuild.TarStageOptions{
|
||||
Filename: t.Filename(),
|
||||
Format: osbuild.TarArchiveFormatOldgnu,
|
||||
RootNode: osbuild.TarRootNodeOmit,
|
||||
// import of the image to GCP fails in case the options below are enabled, which is the default
|
||||
ACLs: common.BoolToPtr(false),
|
||||
SELinux: common.BoolToPtr(false),
|
||||
Xattrs: common.BoolToPtr(false),
|
||||
})
|
||||
pipelines = append(pipelines, *archivePipeline)
|
||||
|
||||
return pipelines, nil
|
||||
}
|
||||
|
||||
func getDefaultGceByosImageConfig() *distro.ImageConfig {
|
||||
return &distro.ImageConfig{
|
||||
Timezone: "UTC",
|
||||
TimeSynchronization: &osbuild.ChronyStageOptions{
|
||||
Timeservers: []string{"metadata.google.internal"},
|
||||
},
|
||||
Firewall: &osbuild.FirewallStageOptions{
|
||||
DefaultZone: "trusted",
|
||||
},
|
||||
EnabledServices: []string{
|
||||
"sshd",
|
||||
"rngd",
|
||||
"dnf-automatic.timer",
|
||||
},
|
||||
DisabledServices: []string{
|
||||
"sshd-keygen@",
|
||||
"reboot.target",
|
||||
},
|
||||
DefaultTarget: "multi-user.target",
|
||||
Locale: "en_US.UTF-8",
|
||||
Keyboard: &osbuild.KeymapStageOptions{
|
||||
Keymap: "us",
|
||||
},
|
||||
DNFConfig: []*osbuild.DNFConfigStageOptions{
|
||||
{
|
||||
Config: &osbuild.DNFConfig{
|
||||
Main: &osbuild.DNFConfigMain{
|
||||
IPResolve: "4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DNFAutomaticConfig: &osbuild.DNFAutomaticConfigStageOptions{
|
||||
Config: &osbuild.DNFAutomaticConfig{
|
||||
Commands: &osbuild.DNFAutomaticConfigCommands{
|
||||
ApplyUpdates: common.BoolToPtr(true),
|
||||
UpgradeType: osbuild.DNFAutomaticUpgradeTypeSecurity,
|
||||
},
|
||||
},
|
||||
},
|
||||
YUMRepos: []*osbuild.YumReposStageOptions{
|
||||
{
|
||||
Filename: "google-cloud.repo",
|
||||
Repos: []osbuild.YumRepository{
|
||||
{
|
||||
Id: "google-compute-engine",
|
||||
Name: "Google Compute Engine",
|
||||
BaseURL: []string{"https://packages.cloud.google.com/yum/repos/google-compute-engine-el8-x86_64-stable"},
|
||||
Enabled: common.BoolToPtr(true),
|
||||
GPGCheck: common.BoolToPtr(true),
|
||||
RepoGPGCheck: common.BoolToPtr(false),
|
||||
GPGKey: []string{
|
||||
"https://packages.cloud.google.com/yum/doc/yum-key.gpg",
|
||||
"https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg",
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "google-cloud-sdk",
|
||||
Name: "Google Cloud SDK",
|
||||
BaseURL: []string{"https://packages.cloud.google.com/yum/repos/cloud-sdk-el8-x86_64"},
|
||||
Enabled: common.BoolToPtr(true),
|
||||
GPGCheck: common.BoolToPtr(true),
|
||||
RepoGPGCheck: common.BoolToPtr(false),
|
||||
GPGKey: []string{
|
||||
"https://packages.cloud.google.com/yum/doc/yum-key.gpg",
|
||||
"https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RHSMConfig: map[distro.RHSMSubscriptionStatus]*osbuild.RHSMStageOptions{
|
||||
distro.RHSMConfigNoSubscription: {
|
||||
SubMan: &osbuild.RHSMStageOptionsSubMan{
|
||||
Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{
|
||||
AutoRegistration: common.BoolToPtr(true),
|
||||
},
|
||||
// Don't disable RHSM redhat.repo management on the GCE
|
||||
// image, which is BYOS and does not use RHUI for content.
|
||||
// Otherwise subscribing the system manually after booting
|
||||
// it would result in empty redhat.repo. Without RHUI, such
|
||||
// system would have no way to get Red Hat content, but
|
||||
// enable the repo management manually, which would be very
|
||||
// confusing.
|
||||
},
|
||||
},
|
||||
distro.RHSMConfigWithSubscription: {
|
||||
SubMan: &osbuild.RHSMStageOptionsSubMan{
|
||||
Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{
|
||||
AutoRegistration: common.BoolToPtr(true),
|
||||
},
|
||||
// do not disable the redhat.repo management if the user
|
||||
// explicitly request the system to be subscribed
|
||||
},
|
||||
},
|
||||
},
|
||||
SshdConfig: &osbuild.SshdConfigStageOptions{
|
||||
Config: osbuild.SshdConfigConfig{
|
||||
PasswordAuthentication: common.BoolToPtr(false),
|
||||
ClientAliveInterval: common.IntToPtr(420),
|
||||
PermitRootLogin: osbuild.PermitRootLoginValueNo,
|
||||
},
|
||||
},
|
||||
Sysconfig: []*osbuild.SysconfigStageOptions{
|
||||
{
|
||||
Kernel: &osbuild.SysconfigKernelOptions{
|
||||
DefaultKernel: "kernel-core",
|
||||
UpdateDefault: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Modprobe: []*osbuild.ModprobeStageOptions{
|
||||
{
|
||||
Filename: "blacklist-floppy.conf",
|
||||
Commands: osbuild.ModprobeConfigCmdList{
|
||||
osbuild.NewModprobeConfigCmdBlacklist("floppy"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GCE BYOS image
|
||||
func gceByosPipelines(t *imageTypeS2, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
|
||||
return gcePipelinesRhel86(t, getDefaultGceByosImageConfig(), customizations, options, repos, packageSetSpecs, rng)
|
||||
}
|
||||
|
||||
func getDefaultGceRhuiImageConfig() *distro.ImageConfig {
|
||||
defaultGceRhuiImageConfig := &distro.ImageConfig{
|
||||
RHSMConfig: map[distro.RHSMSubscriptionStatus]*osbuild.RHSMStageOptions{
|
||||
distro.RHSMConfigNoSubscription: {
|
||||
SubMan: &osbuild.RHSMStageOptionsSubMan{
|
||||
Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{
|
||||
AutoRegistration: common.BoolToPtr(true),
|
||||
},
|
||||
Rhsm: &osbuild.SubManConfigRHSMSection{
|
||||
ManageRepos: common.BoolToPtr(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
distro.RHSMConfigWithSubscription: {
|
||||
SubMan: &osbuild.RHSMStageOptionsSubMan{
|
||||
Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{
|
||||
AutoRegistration: common.BoolToPtr(true),
|
||||
},
|
||||
// do not disable the redhat.repo management if the user
|
||||
// explicitly request the system to be subscribed
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
defaultGceRhuiImageConfig = defaultGceRhuiImageConfig.InheritFrom(getDefaultGceByosImageConfig())
|
||||
return defaultGceRhuiImageConfig
|
||||
}
|
||||
|
||||
// GCE RHUI image
|
||||
func gceRhuiPipelines(t *imageTypeS2, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
|
||||
return gcePipelinesRhel86(t, getDefaultGceRhuiImageConfig(), customizations, options, repos, packageSetSpecs, rng)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue