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".
1125 lines
29 KiB
Go
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
|
|
}
|