distro: add rhel-8.1 support
Images can be built for rhel 8.1. The pipeline generation and distro tests are based off of the rhel 8.2 ones. Repository information as been added for rhel 8.1. The repo urls are internal ones and will only work if the user is on the Red Hat vpn.
This commit is contained in:
parent
0dcd16aa36
commit
2a3a5b318b
5 changed files with 1006 additions and 0 deletions
|
|
@ -247,6 +247,7 @@ const (
|
|||
Fedora30 Distribution = iota
|
||||
Fedora31
|
||||
Fedora32
|
||||
RHEL81
|
||||
RHEL82
|
||||
)
|
||||
|
||||
|
|
@ -258,6 +259,7 @@ func getDistributionMapping() map[string]int {
|
|||
"fedora-30": int(Fedora30),
|
||||
"fedora-31": int(Fedora31),
|
||||
"fedora-32": int(Fedora32),
|
||||
"rhel-8.1": int(RHEL81),
|
||||
"rhel-8.2": int(RHEL82),
|
||||
}
|
||||
return mapping
|
||||
|
|
@ -269,6 +271,7 @@ func (dist *Distribution) ModulePlatformID() (string, error) {
|
|||
Fedora30: "platform:f30",
|
||||
Fedora31: "platform:f31",
|
||||
Fedora32: "platform:f32",
|
||||
RHEL81: "platform:el8",
|
||||
RHEL82: "platform:el8",
|
||||
}
|
||||
id, exists := mapping[*dist]
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/osbuild/osbuild-composer/internal/distro/fedora30"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora31"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora32"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/rhel81"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/rhel82"
|
||||
)
|
||||
|
||||
|
|
@ -96,6 +97,11 @@ func NewRegistry(confPaths []string) *Registry {
|
|||
panic("Attempt to register Fedora 32 failed")
|
||||
}
|
||||
distros.register(f32)
|
||||
el81 := rhel81.New(confPaths)
|
||||
if el81 == nil {
|
||||
panic("Attempt to register RHEL 8.1 failed")
|
||||
}
|
||||
distros.register(el81)
|
||||
el82 := rhel82.New(confPaths)
|
||||
if el82 == nil {
|
||||
panic("Attempt to register RHEL 8.2 failed")
|
||||
|
|
|
|||
858
internal/distro/rhel81/distro.go
Normal file
858
internal/distro/rhel81/distro.go
Normal file
|
|
@ -0,0 +1,858 @@
|
|||
package rhel81
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/osbuild"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/crypt"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
type RHEL81 struct {
|
||||
arches map[string]arch
|
||||
outputs map[string]output
|
||||
buildPackages []string
|
||||
}
|
||||
|
||||
type arch struct {
|
||||
Name string
|
||||
BootloaderPackages []string
|
||||
BuildPackages []string
|
||||
UEFI bool
|
||||
Repositories []rpmmd.RepoConfig
|
||||
}
|
||||
|
||||
type output struct {
|
||||
Name string
|
||||
MimeType string
|
||||
Packages []string
|
||||
ExcludedPackages []string
|
||||
EnabledServices []string
|
||||
DisabledServices []string
|
||||
Bootable bool
|
||||
DefaultTarget string
|
||||
KernelOptions string
|
||||
DefaultSize uint64
|
||||
Assembler func(uefi bool, size uint64) *osbuild.Assembler
|
||||
}
|
||||
|
||||
const Distro = common.RHEL81
|
||||
const ModulePlatformID = "platform:el8"
|
||||
|
||||
func New(confPaths []string) *RHEL81 {
|
||||
const GigaByte = 1024 * 1024 * 1024
|
||||
|
||||
r := RHEL81{
|
||||
arches: map[string]arch{},
|
||||
outputs: map[string]output{},
|
||||
buildPackages: []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"dracut-config-generic",
|
||||
"e2fsprogs",
|
||||
"glibc",
|
||||
"policycoreutils",
|
||||
"python36",
|
||||
"qemu-img",
|
||||
"systemd",
|
||||
"tar",
|
||||
"xfsprogs",
|
||||
},
|
||||
}
|
||||
|
||||
repoMap, err := rpmmd.LoadRepositories(confPaths, r.Name())
|
||||
if err != nil {
|
||||
log.Printf("Could not load repository data for %s: %s", r.Name(), err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
repos, exists := repoMap["x86_64"]
|
||||
if !exists {
|
||||
log.Printf("Could not load architecture-specific repository data for x86_64 (%s): %s", r.Name(), err.Error())
|
||||
} else {
|
||||
r.arches["x86_64"] = arch{
|
||||
Name: "x86_64",
|
||||
BootloaderPackages: []string{
|
||||
"grub2-pc",
|
||||
},
|
||||
BuildPackages: []string{
|
||||
"grub2-pc",
|
||||
},
|
||||
Repositories: repos,
|
||||
}
|
||||
}
|
||||
|
||||
repos, exists = repoMap["aarch64"]
|
||||
if !exists {
|
||||
log.Printf("Could not load architecture-specific repository data for aarch64 (%s): %s", r.Name(), err.Error())
|
||||
} else {
|
||||
r.arches["aarch64"] = arch{
|
||||
Name: "aarch64",
|
||||
BootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"efibootmgr",
|
||||
"grub2-efi-aa64",
|
||||
"grub2-tools",
|
||||
"shim-aa64",
|
||||
},
|
||||
UEFI: true,
|
||||
Repositories: repos,
|
||||
}
|
||||
}
|
||||
|
||||
r.outputs["ami"] = output{
|
||||
Name: "image.raw.xz",
|
||||
MimeType: "application/octet-stream",
|
||||
Packages: []string{
|
||||
"checkpolicy",
|
||||
"chrony",
|
||||
"cloud-init",
|
||||
"cloud-init",
|
||||
"cloud-utils-growpart",
|
||||
"@core",
|
||||
"dhcp-client",
|
||||
"dracut-config-generic",
|
||||
"gdisk",
|
||||
"insights-client",
|
||||
"kernel",
|
||||
"langpacks-en",
|
||||
"net-tools",
|
||||
"NetworkManager",
|
||||
"redhat-release",
|
||||
"redhat-release-eula",
|
||||
"rng-tools",
|
||||
"rsync",
|
||||
"selinux-policy-targeted",
|
||||
"tar",
|
||||
"yum-utils",
|
||||
|
||||
// TODO this doesn't exist in BaseOS or AppStream
|
||||
// "rh-amazon-rhui-client",
|
||||
},
|
||||
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",
|
||||
|
||||
// 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",
|
||||
},
|
||||
DefaultTarget: "multi-user.target",
|
||||
Bootable: true,
|
||||
KernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
|
||||
DefaultSize: 6 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
r.outputs["ext4-filesystem"] = output{
|
||||
Name: "filesystem.img",
|
||||
MimeType: "application/octet-stream",
|
||||
Packages: []string{
|
||||
"policycoreutils",
|
||||
"selinux-policy-targeted",
|
||||
"kernel",
|
||||
"firewalld",
|
||||
"chrony",
|
||||
"dracut-config-generic",
|
||||
"langpacks-en",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
Bootable: false,
|
||||
KernelOptions: "ro net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) },
|
||||
}
|
||||
|
||||
r.outputs["partitioned-disk"] = output{
|
||||
Name: "disk.img",
|
||||
MimeType: "application/octet-stream",
|
||||
Packages: []string{
|
||||
"@core",
|
||||
"chrony",
|
||||
"dracut-config-generic",
|
||||
"firewalld",
|
||||
"kernel",
|
||||
"langpacks-en",
|
||||
"selinux-policy-targeted",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
Bootable: true,
|
||||
KernelOptions: "ro net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("raw", "disk.img", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
r.outputs["qcow2"] = output{
|
||||
Name: "disk.qcow2",
|
||||
MimeType: "application/x-qemu-disk",
|
||||
Packages: []string{
|
||||
"@core",
|
||||
"chrony",
|
||||
"dnf",
|
||||
"kernel",
|
||||
"yum",
|
||||
"nfs-utils",
|
||||
"dnf-utils",
|
||||
"cloud-init",
|
||||
"python3-jsonschema",
|
||||
"qemu-guest-agent",
|
||||
"cloud-utils-growpart",
|
||||
"dracut-config-generic",
|
||||
"dracut-norescue",
|
||||
"tar",
|
||||
"tcpdump",
|
||||
"rsync",
|
||||
"dnf-plugin-spacewalk",
|
||||
"rhn-client-tools",
|
||||
"rhnlib",
|
||||
"rhnsd",
|
||||
"rhn-setup",
|
||||
"NetworkManager",
|
||||
"dhcp-client",
|
||||
"cockpit-ws",
|
||||
"cockpit-system",
|
||||
"subscription-manager-cockpit",
|
||||
"redhat-release",
|
||||
"redhat-release-eula",
|
||||
"rng-tools",
|
||||
"insights-client",
|
||||
// TODO: rh-amazon-rhui-client
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"aic94xx-firmware",
|
||||
"alsa-firmware",
|
||||
"alsa-lib",
|
||||
"alsa-tools-firmware",
|
||||
"firewalld",
|
||||
"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",
|
||||
"langpacks-*",
|
||||
"langpacks-en",
|
||||
"biosdevname",
|
||||
"plymouth",
|
||||
"iprutils",
|
||||
"langpacks-en",
|
||||
"fedora-release",
|
||||
"fedora-repos",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
Bootable: true,
|
||||
KernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
r.outputs["openstack"] = output{
|
||||
Name: "disk.qcow2",
|
||||
MimeType: "application/x-qemu-disk",
|
||||
Packages: []string{
|
||||
// Defaults
|
||||
"@Core",
|
||||
"langpacks-en",
|
||||
|
||||
// Don't run dracut in host-only mode, in order to pull in
|
||||
// the hv_vmbus, hv_netvsc and hv_storvsc modules into the initrd.
|
||||
"dracut-config-generic",
|
||||
|
||||
// From the lorax kickstart
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"cloud-init",
|
||||
"qemu-guest-agent",
|
||||
"spice-vdagent",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
},
|
||||
Bootable: true,
|
||||
KernelOptions: "ro net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
r.outputs["tar"] = output{
|
||||
Name: "root.tar.xz",
|
||||
MimeType: "application/x-tar",
|
||||
Packages: []string{
|
||||
"policycoreutils",
|
||||
"selinux-policy-targeted",
|
||||
"kernel",
|
||||
"firewalld",
|
||||
"chrony",
|
||||
"dracut-config-generic",
|
||||
"langpacks-en",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
Bootable: false,
|
||||
KernelOptions: "ro net.ifnames=0",
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") },
|
||||
}
|
||||
|
||||
r.outputs["vhd"] = output{
|
||||
Name: "disk.vhd",
|
||||
MimeType: "application/x-vhd",
|
||||
Packages: []string{
|
||||
// Defaults
|
||||
"@Core",
|
||||
"langpacks-en",
|
||||
|
||||
// Don't run dracut in host-only mode, in order to pull in
|
||||
// the hv_vmbus, hv_netvsc and hv_storvsc modules into the initrd.
|
||||
"dracut-config-generic",
|
||||
|
||||
// From the lorax kickstart
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"chrony",
|
||||
"WALinuxAgent",
|
||||
"python3",
|
||||
"net-tools",
|
||||
"cloud-init",
|
||||
"cloud-utils-growpart",
|
||||
"gdisk",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
EnabledServices: []string{
|
||||
"sshd",
|
||||
"waagent",
|
||||
},
|
||||
DefaultTarget: "multi-user.target",
|
||||
Bootable: true,
|
||||
KernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("vpc", "disk.vhd", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
r.outputs["vmdk"] = output{
|
||||
Name: "disk.vmdk",
|
||||
MimeType: "application/x-vmdk",
|
||||
Packages: []string{
|
||||
"@core",
|
||||
"chrony",
|
||||
"dracut-config-generic",
|
||||
"firewalld",
|
||||
"kernel",
|
||||
"langpacks-en",
|
||||
"open-vm-tools",
|
||||
"selinux-policy-targeted",
|
||||
},
|
||||
ExcludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
|
||||
// TODO setfiles failes because of usr/sbin/timedatex. Exlude until
|
||||
// https://errata.devel.redhat.com/advisory/47339 lands
|
||||
"timedatex",
|
||||
},
|
||||
Bootable: true,
|
||||
KernelOptions: "ro net.ifnames=0",
|
||||
DefaultSize: 2 * GigaByte,
|
||||
Assembler: func(uefi bool, size uint64) *osbuild.Assembler {
|
||||
return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size)
|
||||
},
|
||||
}
|
||||
|
||||
return &r
|
||||
}
|
||||
|
||||
func (r *RHEL81) Name() string {
|
||||
name, exists := Distro.ToString()
|
||||
if !exists {
|
||||
panic("Fatal error, hardcoded distro value in rhel81 package is not valid!")
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (r *RHEL81) Distribution() common.Distribution {
|
||||
return Distro
|
||||
}
|
||||
|
||||
func (r *RHEL81) ModulePlatformID() string {
|
||||
return ModulePlatformID
|
||||
}
|
||||
|
||||
func (r *RHEL81) Repositories(arch string) []rpmmd.RepoConfig {
|
||||
return r.arches[arch].Repositories
|
||||
}
|
||||
|
||||
func (r *RHEL81) ListOutputFormats() []string {
|
||||
formats := make([]string, 0, len(r.outputs))
|
||||
for name := range r.outputs {
|
||||
formats = append(formats, name)
|
||||
}
|
||||
sort.Strings(formats)
|
||||
return formats
|
||||
}
|
||||
|
||||
func (r *RHEL81) FilenameFromType(outputFormat string) (string, string, error) {
|
||||
if output, exists := r.outputs[outputFormat]; exists {
|
||||
return output.Name, output.MimeType, nil
|
||||
}
|
||||
return "", "", errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
func (r *RHEL81) GetSizeForOutputType(outputFormat string, size uint64) uint64 {
|
||||
const MegaByte = 1024 * 1024
|
||||
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
|
||||
if outputFormat == "vhd" && size%MegaByte != 0 {
|
||||
size = (size/MegaByte + 1) * MegaByte
|
||||
}
|
||||
if size == 0 {
|
||||
size = r.outputs[outputFormat].DefaultSize
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (r *RHEL81) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) {
|
||||
output, exists := r.outputs[outputFormat]
|
||||
if !exists {
|
||||
return nil, nil, errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
packages := output.Packages
|
||||
if output.Bootable {
|
||||
arch, exists := r.arches[outputArchitecture]
|
||||
if !exists {
|
||||
return nil, nil, errors.New("invalid architecture: " + outputArchitecture)
|
||||
}
|
||||
|
||||
packages = append(packages, arch.BootloaderPackages...)
|
||||
}
|
||||
|
||||
return packages, output.ExcludedPackages, nil
|
||||
}
|
||||
|
||||
func (r *RHEL81) BuildPackages(outputArchitecture string) ([]string, error) {
|
||||
arch, exists := r.arches[outputArchitecture]
|
||||
if !exists {
|
||||
return nil, errors.New("invalid architecture: " + outputArchitecture)
|
||||
}
|
||||
|
||||
return append(r.buildPackages, arch.BuildPackages...), nil
|
||||
}
|
||||
|
||||
func (r *RHEL81) Pipeline(b *blueprint.Blueprint, additionalRepos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, checksums map[string]string, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) {
|
||||
output, exists := r.outputs[outputFormat]
|
||||
if !exists {
|
||||
return nil, errors.New("invalid output format: " + outputFormat)
|
||||
}
|
||||
|
||||
arch, exists := r.arches[outputArchitecture]
|
||||
if !exists {
|
||||
return nil, errors.New("invalid architecture: " + outputArchitecture)
|
||||
}
|
||||
|
||||
p := &osbuild.Pipeline{}
|
||||
p.SetBuild(r.buildPipeline(arch, checksums), "org.osbuild.rhel81")
|
||||
|
||||
packages, excludedPackages, err := r.BasePackages(outputFormat, outputArchitecture)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packages = append(packages, b.GetPackages()...)
|
||||
p.AddStage(osbuild.NewDNFStage(r.dnfStageOptions(arch, additionalRepos, checksums, packages, excludedPackages)))
|
||||
p.AddStage(osbuild.NewFixBLSStage())
|
||||
|
||||
if output.Bootable {
|
||||
p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI)))
|
||||
}
|
||||
|
||||
kernelOptions := output.KernelOptions
|
||||
if kernel := b.GetKernel(); kernel != nil {
|
||||
kernelOptions += " " + kernel.Append
|
||||
}
|
||||
p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(kernelOptions, arch.UEFI)))
|
||||
|
||||
// TODO support setting all languages and install corresponding langpack-* package
|
||||
language, keyboard := b.GetPrimaryLocale()
|
||||
|
||||
if language != nil {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{*language}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{"en_US"}))
|
||||
}
|
||||
|
||||
if keyboard != nil {
|
||||
p.AddStage(osbuild.NewKeymapStage(&osbuild.KeymapStageOptions{*keyboard}))
|
||||
}
|
||||
|
||||
if hostname := b.GetHostname(); hostname != nil {
|
||||
p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{*hostname}))
|
||||
}
|
||||
|
||||
timezone, ntpServers := b.GetTimezoneSettings()
|
||||
|
||||
// TODO install chrony when this is set?
|
||||
if timezone != nil {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{*timezone}))
|
||||
}
|
||||
|
||||
if len(ntpServers) > 0 {
|
||||
p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{ntpServers}))
|
||||
}
|
||||
|
||||
if users := b.GetUsers(); len(users) > 0 {
|
||||
options, err := r.userStageOptions(users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.AddStage(osbuild.NewUsersStage(options))
|
||||
}
|
||||
|
||||
if groups := b.GetGroups(); len(groups) > 0 {
|
||||
p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups)))
|
||||
}
|
||||
|
||||
if services := b.GetServices(); services != nil || output.EnabledServices != nil {
|
||||
p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services, output.DefaultTarget)))
|
||||
}
|
||||
|
||||
if firewall := b.GetFirewall(); firewall != nil {
|
||||
p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall)))
|
||||
}
|
||||
|
||||
p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions()))
|
||||
|
||||
p.Assembler = output.Assembler(arch.UEFI, size)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (r *RHEL81) Sources(packages []rpmmd.PackageSpec) *osbuild.Sources {
|
||||
return &osbuild.Sources{}
|
||||
}
|
||||
|
||||
func (r *RHEL81) Runner() string {
|
||||
return "org.osbuild.rhel81"
|
||||
}
|
||||
|
||||
func (r *RHEL81) buildPipeline(arch arch, checksums map[string]string) *osbuild.Pipeline {
|
||||
packages, err := r.BuildPackages(arch.Name)
|
||||
if err != nil {
|
||||
panic("impossibly invalid arch")
|
||||
}
|
||||
|
||||
p := &osbuild.Pipeline{}
|
||||
p.AddStage(osbuild.NewDNFStage(r.dnfStageOptions(arch, nil, checksums, packages, nil)))
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *RHEL81) dnfStageOptions(arch arch, additionalRepos []rpmmd.RepoConfig, checksums map[string]string, packages, excludedPackages []string) *osbuild.DNFStageOptions {
|
||||
options := &osbuild.DNFStageOptions{
|
||||
ReleaseVersion: "8",
|
||||
BaseArchitecture: arch.Name,
|
||||
ModulePlatformId: ModulePlatformID,
|
||||
}
|
||||
for _, repo := range append(arch.Repositories, additionalRepos...) {
|
||||
options.AddRepository(&osbuild.DNFRepository{
|
||||
BaseURL: repo.BaseURL,
|
||||
MetaLink: repo.Metalink,
|
||||
MirrorList: repo.MirrorList,
|
||||
Checksum: checksums[repo.Id],
|
||||
})
|
||||
}
|
||||
|
||||
sort.Strings(packages)
|
||||
for _, pkg := range packages {
|
||||
options.AddPackage(pkg)
|
||||
}
|
||||
|
||||
sort.Strings(excludedPackages)
|
||||
for _, pkg := range excludedPackages {
|
||||
options.ExcludePackage(pkg)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (r *RHEL81) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) {
|
||||
options := osbuild.UsersStageOptions{
|
||||
Users: make(map[string]osbuild.UsersStageOptionsUser),
|
||||
}
|
||||
|
||||
for _, c := range users {
|
||||
if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) {
|
||||
cryptedPassword, err := crypt.CryptSHA512(*c.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Password = &cryptedPassword
|
||||
}
|
||||
|
||||
user := osbuild.UsersStageOptionsUser{
|
||||
Groups: c.Groups,
|
||||
Description: c.Description,
|
||||
Home: c.Home,
|
||||
Shell: c.Shell,
|
||||
Password: c.Password,
|
||||
Key: c.Key,
|
||||
}
|
||||
|
||||
if c.UID != nil {
|
||||
uid := strconv.Itoa(*c.UID)
|
||||
user.UID = &uid
|
||||
}
|
||||
|
||||
if c.GID != nil {
|
||||
gid := strconv.Itoa(*c.GID)
|
||||
user.GID = &gid
|
||||
}
|
||||
|
||||
options.Users[c.Name] = user
|
||||
}
|
||||
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
func (r *RHEL81) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions {
|
||||
options := osbuild.GroupsStageOptions{
|
||||
Groups: map[string]osbuild.GroupsStageOptionsGroup{},
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
groupData := osbuild.GroupsStageOptionsGroup{
|
||||
Name: group.Name,
|
||||
}
|
||||
if group.GID != nil {
|
||||
gid := strconv.Itoa(*group.GID)
|
||||
groupData.GID = &gid
|
||||
}
|
||||
|
||||
options.Groups[group.Name] = groupData
|
||||
}
|
||||
|
||||
return &options
|
||||
}
|
||||
|
||||
func (r *RHEL81) 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 (r *RHEL81) 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 (r *RHEL81) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions {
|
||||
options := osbuild.FSTabStageOptions{}
|
||||
options.AddFilesystem("0bd700f8-090f-4556-b797-b340297ea1bd", "xfs", "/", "defaults", 0, 0)
|
||||
if uefi {
|
||||
options.AddFilesystem("46BB-8120", "vfat", "/boot/efi", "umask=0077,shortname=winnt", 0, 2)
|
||||
}
|
||||
return &options
|
||||
}
|
||||
|
||||
func (r *RHEL81) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRUB2StageOptions {
|
||||
id, err := uuid.Parse("0bd700f8-090f-4556-b797-b340297ea1bd")
|
||||
if err != nil {
|
||||
panic("invalid UUID")
|
||||
}
|
||||
|
||||
var uefiOptions *osbuild.GRUB2UEFI
|
||||
if uefi {
|
||||
uefiOptions = &osbuild.GRUB2UEFI{
|
||||
Vendor: "redhat",
|
||||
}
|
||||
}
|
||||
|
||||
return &osbuild.GRUB2StageOptions{
|
||||
RootFilesystemUUID: id,
|
||||
KernelOptions: kernelOptions,
|
||||
Legacy: !uefi,
|
||||
UEFI: uefiOptions,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RHEL81) selinuxStageOptions() *osbuild.SELinuxStageOptions {
|
||||
return &osbuild.SELinuxStageOptions{
|
||||
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RHEL81) qemuAssembler(format string, filename string, uefi bool, size uint64) *osbuild.Assembler {
|
||||
var options osbuild.QEMUAssemblerOptions
|
||||
if uefi {
|
||||
fstype := uuid.MustParse("C12A7328-F81F-11D2-BA4B-00A0C93EC93B")
|
||||
options = osbuild.QEMUAssemblerOptions{
|
||||
Format: format,
|
||||
Filename: filename,
|
||||
Size: size,
|
||||
PTUUID: "8DFDFF87-C96E-EA48-A3A6-9408F1F6B1EF",
|
||||
PTType: "gpt",
|
||||
Partitions: []osbuild.QEMUPartition{
|
||||
{
|
||||
Start: 2048,
|
||||
Size: 972800,
|
||||
Type: &fstype,
|
||||
Filesystem: osbuild.QEMUFilesystem{
|
||||
Type: "vfat",
|
||||
UUID: "46BB-8120",
|
||||
Label: "EFI System Partition",
|
||||
Mountpoint: "/boot/efi",
|
||||
},
|
||||
},
|
||||
{
|
||||
Start: 976896,
|
||||
Filesystem: osbuild.QEMUFilesystem{
|
||||
Type: "xfs",
|
||||
UUID: "0bd700f8-090f-4556-b797-b340297ea1bd",
|
||||
Mountpoint: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
options = osbuild.QEMUAssemblerOptions{
|
||||
Format: format,
|
||||
Filename: filename,
|
||||
Size: size,
|
||||
PTUUID: "0x14fc63d2",
|
||||
PTType: "mbr",
|
||||
Partitions: []osbuild.QEMUPartition{
|
||||
{
|
||||
Start: 2048,
|
||||
Bootable: true,
|
||||
Filesystem: osbuild.QEMUFilesystem{
|
||||
Type: "xfs",
|
||||
UUID: "0bd700f8-090f-4556-b797-b340297ea1bd",
|
||||
Mountpoint: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return osbuild.NewQEMUAssembler(&options)
|
||||
}
|
||||
|
||||
func (r *RHEL81) tarAssembler(filename, compression string) *osbuild.Assembler {
|
||||
return osbuild.NewTarAssembler(
|
||||
&osbuild.TarAssemblerOptions{
|
||||
Filename: filename,
|
||||
Compression: compression,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *RHEL81) rawFSAssembler(filename string, size uint64) *osbuild.Assembler {
|
||||
id, err := uuid.Parse("0bd700f8-090f-4556-b797-b340297ea1bd")
|
||||
if err != nil {
|
||||
panic("invalid UUID")
|
||||
}
|
||||
return osbuild.NewRawFSAssembler(
|
||||
&osbuild.RawFSAssemblerOptions{
|
||||
Filename: filename,
|
||||
RootFilesystemUUDI: id,
|
||||
Size: size,
|
||||
FilesystemType: "xfs",
|
||||
})
|
||||
}
|
||||
113
internal/distro/rhel81/distro_test.go
Normal file
113
internal/distro/rhel81/distro_test.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package rhel81_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
)
|
||||
|
||||
func TestListOutputFormats(t *testing.T) {
|
||||
want := []string{
|
||||
"ami",
|
||||
"ext4-filesystem",
|
||||
"openstack",
|
||||
"partitioned-disk",
|
||||
"qcow2",
|
||||
"tar",
|
||||
"vhd",
|
||||
"vmdk",
|
||||
}
|
||||
|
||||
distros := distro.NewRegistry([]string{"../../../"})
|
||||
rhel81 := distros.GetDistro("rhel-8.2")
|
||||
if got := rhel81.ListOutputFormats(); !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("ListOutputFormats() = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
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.xz",
|
||||
want1: "application/octet-stream",
|
||||
},
|
||||
{
|
||||
name: "ext4",
|
||||
args: args{"ext4-filesystem"},
|
||||
want: "filesystem.img",
|
||||
want1: "application/octet-stream",
|
||||
},
|
||||
{
|
||||
name: "openstack",
|
||||
args: args{"openstack"},
|
||||
want: "disk.qcow2",
|
||||
want1: "application/x-qemu-disk",
|
||||
},
|
||||
{
|
||||
name: "partitioned-disk",
|
||||
args: args{"partitioned-disk"},
|
||||
want: "disk.img",
|
||||
want1: "application/octet-stream",
|
||||
},
|
||||
{
|
||||
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: "invalid-output-type",
|
||||
args: args{"foobar"},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
distros := distro.NewRegistry([]string{"../../../"})
|
||||
rhel81 := distros.GetDistro("rhel-8.2")
|
||||
got, got1, err := rhel81.FilenameFromType(tt.args.outputFormat)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("FilenameFromType() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr {
|
||||
if got != tt.want {
|
||||
t.Errorf("FilenameFromType() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("FilenameFromType() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
26
repositories/rhel-8.1.json
Normal file
26
repositories/rhel-8.1.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"aarch64": [
|
||||
{
|
||||
"id": "baseos",
|
||||
"name": "BaseOS",
|
||||
"BaseURL": "http://download.devel.redhat.com/rhel-8/rel-eng/RHEL-8/RHEL-8.1.0-RC-1.1/compose/BaseOS/aarch64/os"
|
||||
},
|
||||
{
|
||||
"id": "appstream",
|
||||
"name": "AppStream",
|
||||
"BaseURL": "http://download.devel.redhat.com/rhel-8/rel-eng/RHEL-8/RHEL-8.1.0-RC-1.1/compose/AppStream/aarch64/os"
|
||||
}
|
||||
],
|
||||
"x86_64": [
|
||||
{
|
||||
"id": "baseos",
|
||||
"name": "BaseOS",
|
||||
"BaseURL": "http://download.devel.redhat.com/rhel-8/rel-eng/RHEL-8/RHEL-8.1.0-RC-1.1/compose/BaseOS/x86_64/os"
|
||||
},
|
||||
{
|
||||
"id": "appstream",
|
||||
"name": "AppStream",
|
||||
"BaseURL": "http://download.devel.redhat.com/rhel-8/rel-eng/RHEL-8/RHEL-8.1.0-RC-1.1/compose/AppStream/x86_64/os"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue