debian-forge-composer/internal/distro/rhel8/distro.go
Achilleas Koutsou 541cbab0f6 distro/rhel84: new imageType implementation
imageTypeS2 implements the distro.ImageType interface buts generates a
Manifest matching the new osbuild v2 schema.

Two new image types are added to the rhel84 distro (x84_64 and aarch64)
for generating OCI containers contain an Edge (ostree) commit and, when
run, start a web serer to serve the commit.

The image type uses the new PackageSets map to define packages (and
excludes) for the image.  The old methods (Packages() and
BuildPackages()) are implemented for compatibility with the old
workflow.
The image also defines an extra package set for the container that will
serve the package: "httpd" (and its dependencies).

The distro.ImageType interface has a new method: Exports()
It should return a list of names or IDs of artefacts that should be
exported from osbuild when the job is complete.
For the old image types, this is simply set to "assembler".
2021-03-17 18:12:17 +00:00

1125 lines
29 KiB
Go

package rhel8
import (
"encoding/json"
"errors"
"fmt"
"sort"
"github.com/osbuild/osbuild-composer/internal/distro"
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild1"
"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"
)
const name = "rhel-8"
const modulePlatformID = "platform:el8"
const ostreeRef = "rhel/8/%s/edge"
type distribution struct {
arches map[string]architecture
imageTypes map[string]imageType
buildPackages []string
}
type architecture struct {
distro *distribution
name string
bootloaderPackages []string
buildPackages []string
legacy string
uefi bool
imageTypes map[string]imageType
}
type imageType struct {
arch *architecture
name string
filename string
mimeType string
packages []string
excludedPackages []string
enabledServices []string
disabledServices []string
defaultTarget string
kernelOptions string
bootable bool
rpmOstree bool
defaultSize uint64
assembler func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler
}
func (a *architecture) Distro() distro.Distro {
return a.distro
}
func (t *imageType) Arch() distro.Arch {
return t.arch
}
func (d *distribution) ListArches() []string {
archs := make([]string, 0, len(d.arches))
for name := range d.arches {
archs = append(archs, name)
}
sort.Strings(archs)
return archs
}
func (d *distribution) GetArch(arch string) (distro.Arch, error) {
a, exists := d.arches[arch]
if !exists {
return nil, errors.New("invalid architecture: " + arch)
}
return &a, nil
}
func (d *distribution) setArches(arches ...architecture) {
d.arches = map[string]architecture{}
for _, a := range arches {
d.arches[a.name] = architecture{
distro: d,
name: a.name,
bootloaderPackages: a.bootloaderPackages,
buildPackages: a.buildPackages,
uefi: a.uefi,
imageTypes: a.imageTypes,
}
}
}
func (a *architecture) Name() string {
return a.name
}
func (a *architecture) ListImageTypes() []string {
formats := make([]string, 0, len(a.imageTypes))
for name := range a.imageTypes {
formats = append(formats, name)
}
sort.Strings(formats)
return formats
}
func (a *architecture) GetImageType(imageType string) (distro.ImageType, error) {
t, exists := a.imageTypes[imageType]
if !exists {
return nil, errors.New("invalid image type: " + imageType)
}
return &t, nil
}
func (a *architecture) setImageTypes(imageTypes ...imageType) {
a.imageTypes = map[string]imageType{}
for _, it := range imageTypes {
a.imageTypes[it.name] = imageType{
arch: a,
name: it.name,
filename: it.filename,
mimeType: it.mimeType,
packages: it.packages,
excludedPackages: it.excludedPackages,
enabledServices: it.enabledServices,
disabledServices: it.disabledServices,
defaultTarget: it.defaultTarget,
kernelOptions: it.kernelOptions,
bootable: it.bootable,
rpmOstree: it.rpmOstree,
defaultSize: it.defaultSize,
assembler: it.assembler,
}
}
}
func (t *imageType) Name() string {
return t.name
}
func (t *imageType) Filename() string {
return t.filename
}
func (t *imageType) MIMEType() string {
return t.mimeType
}
func (t *imageType) OSTreeRef() string {
if t.rpmOstree {
return fmt.Sprintf(ostreeRef, t.arch.name)
}
return ""
}
func (t *imageType) 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 *imageType) Packages(bp blueprint.Blueprint) ([]string, []string) {
packages := append(t.packages, bp.GetPackages()...)
timezone, _ := bp.Customizations.GetTimezoneSettings()
if timezone != nil {
packages = append(packages, "chrony")
}
if t.bootable {
packages = append(packages, t.arch.bootloaderPackages...)
}
return packages, t.excludedPackages
}
func (t *imageType) BuildPackages() []string {
packages := append(t.arch.distro.buildPackages, t.arch.buildPackages...)
if t.rpmOstree {
packages = append(packages, "rpm-ostree")
}
return packages
}
func (t *imageType) PackageSets(bp blueprint.Blueprint) map[string]rpmmd.PackageSet {
includePackages, excludePackages := t.Packages(bp)
return map[string]rpmmd.PackageSet{
"packages": {
Include: includePackages,
Exclude: excludePackages,
},
"build-packages": {
Include: t.BuildPackages(),
},
}
}
func (t *imageType) Exports() []string {
return []string{"assembler"}
}
func (t *imageType) Manifest(c *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSpecSets map[string][]rpmmd.PackageSpec,
seed int64) (distro.Manifest, error) {
pipeline, err := t.pipeline(c, options, repos, packageSpecSets["packages"], packageSpecSets["build-packages"])
if err != nil {
return distro.Manifest{}, err
}
return json.Marshal(
osbuild.Manifest{
Sources: *sources(append(packageSpecSets["packages"], packageSpecSets["build-packages"]...)),
Pipeline: *pipeline,
},
)
}
func (d *distribution) Name() string {
return name
}
func (d *distribution) ModulePlatformID() string {
return modulePlatformID
}
func sources(packages []rpmmd.PackageSpec) *osbuild.Sources {
files := &osbuild.FilesSource{
URLs: make(map[string]osbuild.FileSource),
}
for _, pkg := range packages {
fileSource := osbuild.FileSource{
URL: pkg.RemoteLocation,
}
if pkg.Secrets == "org.osbuild.rhsm" {
fileSource.Secrets = &osbuild.Secret{
Name: "org.osbuild.rhsm",
}
}
files.URLs[pkg.Checksum] = fileSource
}
return &osbuild.Sources{
"org.osbuild.files": files,
}
}
func (t *imageType) pipeline(c *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec) (*osbuild.Pipeline, error) {
if kernelOpts := c.GetKernel(); kernelOpts != nil && kernelOpts.Append != "" && t.rpmOstree {
return nil, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
}
p := &osbuild.Pipeline{}
p.SetBuild(t.buildPipeline(repos, *t.arch, buildPackageSpecs), "org.osbuild.rhel82")
if t.arch.Name() == "s390x" {
p.AddStage(osbuild.NewKernelCmdlineStage(&osbuild.KernelCmdlineStageOptions{
RootFsUUID: "0bd700f8-090f-4556-b797-b340297ea1bd",
KernelOpts: "net.ifnames=0 crashkernel=auto",
}))
}
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch, repos, packageSpecs)))
p.AddStage(osbuild.NewFixBLSStage())
if t.bootable {
p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.uefi)))
if t.arch.Name() != "s390x" {
p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(t.kernelOptions, c.GetKernel(), t.arch.uefi)))
}
}
// TODO support setting all languages and install corresponding langpack-* package
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"}))
}
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}))
}
if len(ntpServers) > 0 {
p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{Timeservers: ntpServers}))
}
if groups := c.GetGroups(); len(groups) > 0 {
p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups)))
}
if users := c.GetUsers(); len(users) > 0 {
options, err := t.userStageOptions(users)
if err != nil {
return nil, err
}
p.AddStage(osbuild.NewUsersStage(options))
}
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.arch.Name() == "s390x" {
p.AddStage(osbuild.NewZiplStage(&osbuild.ZiplStageOptions{}))
}
p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions()))
if t.rpmOstree {
p.AddStage(osbuild.NewRPMOSTreeStage(&osbuild.RPMOSTreeStageOptions{
EtcGroupMembers: []string{
// NOTE: We may want to make this configurable.
"wheel", "docker",
},
}))
}
if options.Subscription != nil {
commands := []string{
fmt.Sprintf("/usr/sbin/subscription-manager register --org=%d --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,
},
))
} else {
// RHSM DNF plugins should be by default disabled on RHEL Guest KVM images
if t.Name() == "qcow2" {
p.AddStage(osbuild.NewRHSMStage(&osbuild.RHSMStageOptions{
DnfPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
ProductID: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
SubscriptionManager: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
},
}))
}
}
p.Assembler = t.assembler(t.arch.uefi, options, t.arch)
return p, nil
}
func (t *imageType) buildPipeline(repos []rpmmd.RepoConfig, arch architecture, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline {
p := &osbuild.Pipeline{}
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(arch, repos, buildPackageSpecs)))
p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions()))
return p
}
func (t *imageType) rpmStageOptions(arch architecture, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions {
var gpgKeys []string
for _, repo := range repos {
if repo.GPGKey == "" {
continue
}
gpgKeys = append(gpgKeys, repo.GPGKey)
}
var packages []osbuild.RPMPackage
for _, spec := range specs {
pkg := osbuild.RPMPackage{
Checksum: spec.Checksum,
CheckGPG: spec.CheckGPG,
}
packages = append(packages, pkg)
}
return &osbuild.RPMStageOptions{
GPGKeys: gpgKeys,
Packages: packages,
}
}
func (t *imageType) 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,
}
user.UID = c.UID
user.GID = c.GID
options.Users[c.Name] = user
}
return &options, nil
}
func (t *imageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions {
options := osbuild.GroupsStageOptions{
Groups: map[string]osbuild.GroupsStageOptionsGroup{},
}
for _, group := range groups {
groupData := osbuild.GroupsStageOptionsGroup{
Name: group.Name,
}
groupData.GID = group.GID
options.Groups[group.Name] = groupData
}
return &options
}
func (t *imageType) 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 *imageType) 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 *imageType) 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 (t *imageType) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions {
id := uuid.MustParse("0bd700f8-090f-4556-b797-b340297ea1bd")
if kernel != nil && kernel.Append != "" {
kernelOptions += " " + kernel.Append
}
var uefiOptions *osbuild.GRUB2UEFI
if uefi {
uefiOptions = &osbuild.GRUB2UEFI{
Vendor: "redhat",
}
}
var legacy string
if !uefi {
legacy = t.arch.legacy
}
return &osbuild.GRUB2StageOptions{
RootFilesystemUUID: id,
KernelOptions: kernelOptions,
Legacy: legacy,
UEFI: uefiOptions,
}
}
func (t *imageType) selinuxStageOptions() *osbuild.SELinuxStageOptions {
return &osbuild.SELinuxStageOptions{
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
}
}
func qemuAssembler(format string, filename string, uefi bool, imageOptions distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
var options osbuild.QEMUAssemblerOptions
if uefi {
options = osbuild.QEMUAssemblerOptions{
Format: format,
Filename: filename,
Size: imageOptions.Size,
PTUUID: "8DFDFF87-C96E-EA48-A3A6-9408F1F6B1EF",
PTType: "gpt",
Partitions: []osbuild.QEMUPartition{
{
Start: 2048,
Size: 972800,
Type: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B",
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 {
if arch.Name() == "ppc64le" {
options = osbuild.QEMUAssemblerOptions{
Bootloader: &osbuild.QEMUBootloader{
Type: "grub2",
Platform: "powerpc-ieee1275",
},
Format: format,
Filename: filename,
Size: imageOptions.Size,
PTUUID: "0x14fc63d2",
PTType: "dos",
Partitions: []osbuild.QEMUPartition{
{
Size: 8192,
Type: "41",
Bootable: true,
},
{
Start: 10240,
Filesystem: &osbuild.QEMUFilesystem{
Type: "xfs",
UUID: "0bd700f8-090f-4556-b797-b340297ea1bd",
Mountpoint: "/",
},
},
},
}
} else if arch.Name() == "s390x" {
options = osbuild.QEMUAssemblerOptions{
Bootloader: &osbuild.QEMUBootloader{
Type: "zipl",
},
Format: format,
Filename: filename,
Size: imageOptions.Size,
PTUUID: "0x14fc63d2",
PTType: "dos",
Partitions: []osbuild.QEMUPartition{
{
Start: 2048,
Bootable: true,
Filesystem: &osbuild.QEMUFilesystem{
Type: "xfs",
UUID: "0bd700f8-090f-4556-b797-b340297ea1bd",
Mountpoint: "/",
},
},
},
}
} else {
options = osbuild.QEMUAssemblerOptions{
Format: format,
Filename: filename,
Size: imageOptions.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 tarAssembler(filename, compression string) *osbuild.Assembler {
return osbuild.NewTarAssembler(
&osbuild.TarAssemblerOptions{
Filename: filename,
Compression: compression,
})
}
func ostreeCommitAssembler(options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return osbuild.NewOSTreeCommitAssembler(
&osbuild.OSTreeCommitAssemblerOptions{
Ref: options.OSTree.Ref,
Parent: options.OSTree.Parent,
Tar: osbuild.OSTreeCommitAssemblerTarOptions{
Filename: "commit.tar",
},
},
)
}
// New creates a new distro object, defining the supported architectures and image types
func New() distro.Distro {
const GigaByte = 1024 * 1024 * 1024
edgeImgTypeX86_64 := imageType{
name: "rhel-edge-commit",
filename: "commit.tar",
mimeType: "application/x-tar",
packages: []string{
"redhat-release", // TODO: is this correct for Edge?
"glibc", "glibc-minimal-langpack", "nss-altfiles",
"dracut-config-generic", "dracut-network",
"basesystem", "bash", "platform-python",
"shadow-utils", "chrony", "setup", "shadow-utils",
"sudo", "systemd", "coreutils", "util-linux",
"curl", "vim-minimal",
"rpm", "rpm-ostree", "polkit",
"lvm2", "cryptsetup", "pinentry",
"e2fsprogs", "dosfstools",
"keyutils", "gnupg2",
"attr", "xz", "gzip",
"firewalld", "iptables",
"NetworkManager", "NetworkManager-wifi", "NetworkManager-wwan",
"wpa_supplicant",
"dnsmasq", "traceroute",
"hostname", "iproute", "iputils",
"openssh-clients", "procps-ng", "rootfiles",
"openssh-server", "passwd",
"policycoreutils", "policycoreutils-python-utils",
"selinux-policy-targeted", "setools-console",
"less", "tar", "rsync",
"fwupd", "usbguard",
"bash-completion", "tmux",
"ima-evm-utils",
"audit", "rng-tools",
"podman", "container-selinux", "skopeo", "criu",
"slirp4netns", "fuse-overlayfs",
"clevis", "clevis-dracut", "clevis-luks",
"greenboot", "greenboot-grub2", "greenboot-rpm-ostree-grub2", "greenboot-reboot", "greenboot-status",
// x86 specific
"grub2", "grub2-efi-x64", "efibootmgr", "shim-x64", "microcode_ctl",
"iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", "iwl135-firmware",
"iwl2000-firmware", "iwl2030-firmware", "iwl3160-firmware", "iwl5000-firmware",
"iwl5150-firmware", "iwl6000-firmware", "iwl6050-firmware", "iwl7260-firmware",
},
excludedPackages: []string{
"subscription-manager",
},
enabledServices: []string{
"NetworkManager.service", "firewalld.service", "rngd.service", "sshd.service",
"greenboot-grub2-set-counter", "greenboot-grub2-set-success", "greenboot-healthcheck",
"greenboot-rpm-ostree-grub2-check-fallback", "greenboot-status", "greenboot-task-runner",
"redboot-auto-reboot", "redboot-task-runner",
},
rpmOstree: true,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return ostreeCommitAssembler(options, arch)
},
}
edgeImgTypeAarch64 := imageType{
name: "rhel-edge-commit",
filename: "commit.tar",
mimeType: "application/x-tar",
packages: []string{
"redhat-release", // TODO: is this correct for Edge?
"glibc", "glibc-minimal-langpack", "nss-altfiles",
"dracut-config-generic", "dracut-network",
"basesystem", "bash", "platform-python",
"shadow-utils", "chrony", "setup", "shadow-utils",
"sudo", "systemd", "coreutils", "util-linux",
"curl", "vim-minimal",
"rpm", "rpm-ostree", "polkit",
"lvm2", "cryptsetup", "pinentry",
"e2fsprogs", "dosfstools",
"keyutils", "gnupg2",
"attr", "xz", "gzip",
"firewalld", "iptables",
"NetworkManager", "NetworkManager-wifi", "NetworkManager-wwan",
"wpa_supplicant",
"dnsmasq", "traceroute",
"hostname", "iproute", "iputils",
"openssh-clients", "procps-ng", "rootfiles",
"openssh-server", "passwd",
"policycoreutils", "policycoreutils-python-utils",
"selinux-policy-targeted", "setools-console",
"less", "tar", "rsync",
"fwupd", "usbguard",
"bash-completion", "tmux",
"ima-evm-utils",
"audit", "rng-tools",
"podman", "container-selinux", "skopeo", "criu",
"slirp4netns", "fuse-overlayfs",
"clevis", "clevis-dracut", "clevis-luks",
"greenboot", "greenboot-grub2", "greenboot-rpm-ostree-grub2", "greenboot-reboot", "greenboot-status",
// aarch64 specific
"grub2-efi-aa64", "efibootmgr", "shim-aa64",
"iwl7260-firmware",
},
excludedPackages: []string{
"subscription-manager",
},
enabledServices: []string{
"NetworkManager.service", "firewalld.service", "rngd.service", "sshd.service",
"greenboot-grub2-set-counter", "greenboot-grub2-set-success", "greenboot-healthcheck",
"greenboot-rpm-ostree-grub2-check-fallback", "greenboot-status", "greenboot-task-runner",
"redboot-auto-reboot", "redboot-task-runner",
},
rpmOstree: true,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return ostreeCommitAssembler(options, arch)
},
}
amiImgType := imageType{
name: "ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packages: []string{
"checkpolicy",
"chrony",
"cloud-init",
"cloud-init",
"cloud-utils-growpart",
"@core",
"dhcp-client",
"gdisk",
"insights-client",
"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",
kernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
defaultSize: 6 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("raw", "image.raw", uefi, options, arch)
},
}
qcow2ImageType := imageType{
name: "qcow2",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
packages: []string{
"@core",
"chrony",
"dnf",
"yum",
"nfs-utils",
"dnf-utils",
"cloud-init",
"python3-jsonschema",
"qemu-guest-agent",
"cloud-utils-growpart",
"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",
},
kernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0",
bootable: true,
defaultSize: 4 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("qcow2", "disk.qcow2", uefi, options, arch)
},
}
openstackImgType := imageType{
name: "openstack",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
packages: []string{
// Defaults
"@Core",
"langpacks-en",
// From the lorax kickstart
"selinux-policy-targeted",
"cloud-init",
"qemu-guest-agent",
"spice-vdagent",
},
excludedPackages: []string{
"dracut-config-rescue",
},
kernelOptions: "ro net.ifnames=0",
bootable: true,
defaultSize: 4 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("qcow2", "disk.qcow2", uefi, options, arch)
},
}
tarImgType := imageType{
name: "tar",
filename: "root.tar.xz",
mimeType: "application/x-tar",
packages: []string{
"policycoreutils",
"selinux-policy-targeted",
},
bootable: false,
kernelOptions: "ro net.ifnames=0",
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return tarAssembler("root.tar.xz", "xz")
},
}
vhdImgType := imageType{
name: "vhd",
filename: "disk.vhd",
mimeType: "application/x-vhd",
packages: []string{
// Defaults
"@Core",
"langpacks-en",
// From the lorax kickstart
"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",
kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0",
bootable: true,
defaultSize: 4 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("vpc", "disk.vhd", uefi, options, arch)
},
}
vmdkImgType := imageType{
name: "vmdk",
filename: "disk.vmdk",
mimeType: "application/x-vmdk",
packages: []string{
"@core",
"chrony",
"firewalld",
"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",
},
kernelOptions: "ro net.ifnames=0",
bootable: true,
defaultSize: 4 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("vmdk", "disk.vmdk", uefi, options, arch)
},
}
r := distribution{
imageTypes: map[string]imageType{},
buildPackages: []string{
"dnf",
"dosfstools",
"e2fsprogs",
"glibc",
"policycoreutils",
"python36",
"python3-iniparse", // dependency of org.osbuild.rhsm stage
"qemu-img",
"selinux-policy-targeted",
"systemd",
"tar",
"xfsprogs",
"xz",
},
}
x8664 := architecture{
distro: &r,
name: "x86_64",
bootloaderPackages: []string{
"dracut-config-generic",
"grub2-pc",
},
buildPackages: []string{
"grub2-pc",
},
legacy: "i386-pc",
}
x8664.setImageTypes(
amiImgType,
edgeImgTypeX86_64,
qcow2ImageType,
openstackImgType,
tarImgType,
vhdImgType,
vmdkImgType,
)
aarch64 := architecture{
distro: &r,
name: "aarch64",
bootloaderPackages: []string{
"dracut-config-generic",
"efibootmgr",
"grub2-efi-aa64",
"grub2-tools",
"shim-aa64",
},
uefi: true,
}
aarch64.setImageTypes(
amiImgType,
edgeImgTypeAarch64,
qcow2ImageType,
openstackImgType,
tarImgType,
)
ppc64le := architecture{
distro: &r,
name: "ppc64le",
bootloaderPackages: []string{
"dracut-config-generic",
"powerpc-utils",
"grub2-ppc64le",
"grub2-ppc64le-modules",
},
buildPackages: []string{
"grub2-ppc64le",
"grub2-ppc64le-modules",
},
legacy: "powerpc-ieee1275",
uefi: false,
}
ppc64le.setImageTypes(
qcow2ImageType,
tarImgType,
)
s390x := architecture{
distro: &r,
name: "s390x",
bootloaderPackages: []string{
"dracut-config-generic",
"s390utils-base",
},
uefi: false,
}
s390x.setImageTypes(
tarImgType,
qcow2ImageType,
)
r.setArches(x8664, aarch64, ppc64le, s390x)
return &r
}