distro: add support for building a rhel 7 (qcow2)

Based on the RHEL 8.6 pipelines, needs a special buildroot with two
extra packages: python3-iniparse and python3-PyYAML.
Only x86_64 support for now.
This commit is contained in:
Christian Kellner 2022-05-30 20:45:30 +02:00
parent 13ce6140b9
commit 06e05df620
11 changed files with 21479 additions and 0 deletions

View file

@ -0,0 +1,503 @@
package rhel7
import (
"encoding/json"
"errors"
"fmt"
"math/rand"
"path"
"sort"
"strings"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
const (
// package set names
// build package set name
buildPkgsKey = "build"
// main/common os image package set name
osPkgsKey = "packages"
// blueprint package set name
blueprintPkgsKey = "blueprint"
)
var mountpointAllowList = []string{
"/", "/var", "/opt", "/srv", "/usr", "/app", "/data", "/home", "/tmp",
}
// RHEL-based OS image configuration defaults
var defaultDistroImageConfig = &distro.ImageConfig{
Timezone: "America/New_York",
Locale: "en_US.UTF-8",
GPGKeyFiles: []string{
"/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
},
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
}
// distribution objects without the arches > image types
var distroMap = map[string]distribution{
"rhel-7": {
name: "rhel-7",
product: "Red Hat Enterprise Linux",
osVersion: "7.9",
nick: "Maipo",
releaseVersion: "7",
modulePlatformID: "platform:el7",
vendor: "redhat",
runner: "org.osbuild.rhel7",
defaultImageConfig: defaultDistroImageConfig,
},
}
// --- Distribution ---
type distribution struct {
name string
product string
nick string
osVersion string
releaseVersion string
modulePlatformID string
vendor string
runner string
arches map[string]distro.Arch
defaultImageConfig *distro.ImageConfig
}
func (d *distribution) Name() string {
return d.name
}
func (d *distribution) Releasever() string {
return d.releaseVersion
}
func (d *distribution) ModulePlatformID() string {
return d.modulePlatformID
}
func (d *distribution) OSTreeRef() string {
return "" // not supported
}
func (d *distribution) ListArches() []string {
archNames := make([]string, 0, len(d.arches))
for name := range d.arches {
archNames = append(archNames, name)
}
sort.Strings(archNames)
return archNames
}
func (d *distribution) GetArch(name string) (distro.Arch, error) {
arch, exists := d.arches[name]
if !exists {
return nil, errors.New("invalid architecture: " + name)
}
return arch, nil
}
func (d *distribution) addArches(arches ...architecture) {
if d.arches == nil {
d.arches = map[string]distro.Arch{}
}
// Do not make copies of architectures, as opposed to image types,
// because architecture definitions are not used by more than a single
// distro definition.
for idx := range arches {
d.arches[arches[idx].name] = &arches[idx]
}
}
func (d *distribution) isRHEL() bool {
return strings.HasPrefix(d.name, "rhel")
}
func (d *distribution) getDefaultImageConfig() *distro.ImageConfig {
return d.defaultImageConfig
}
// --- Architecture ---
type architecture struct {
distro *distribution
name string
imageTypes map[string]distro.ImageType
imageTypeAliases map[string]string
legacy string
bootType distro.BootType
}
func (a *architecture) Name() string {
return a.name
}
func (a *architecture) ListImageTypes() []string {
itNames := make([]string, 0, len(a.imageTypes))
for name := range a.imageTypes {
itNames = append(itNames, name)
}
sort.Strings(itNames)
return itNames
}
func (a *architecture) GetImageType(name string) (distro.ImageType, error) {
t, exists := a.imageTypes[name]
if !exists {
aliasForName, exists := a.imageTypeAliases[name]
if !exists {
return nil, errors.New("invalid image type: " + name)
}
t, exists = a.imageTypes[aliasForName]
if !exists {
panic(fmt.Sprintf("image type '%s' is an alias to a non-existing image type '%s'", name, aliasForName))
}
}
return t, nil
}
func (a *architecture) addImageTypes(imageTypes ...imageType) {
if a.imageTypes == nil {
a.imageTypes = map[string]distro.ImageType{}
}
for idx := range imageTypes {
it := imageTypes[idx]
it.arch = a
a.imageTypes[it.name] = &it
for _, alias := range it.nameAliases {
if a.imageTypeAliases == nil {
a.imageTypeAliases = map[string]string{}
}
if existingAliasFor, exists := a.imageTypeAliases[alias]; exists {
panic(fmt.Sprintf("image type alias '%s' for '%s' is already defined for another image type '%s'", alias, it.name, existingAliasFor))
}
a.imageTypeAliases[alias] = it.name
}
}
}
func (a *architecture) Distro() distro.Distro {
return a.distro
}
// --- Image Type ---
type pipelinesFunc func(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error)
type packageSetFunc func(t *imageType) rpmmd.PackageSet
type imageType struct {
arch *architecture
name string
nameAliases []string
filename string
mimeType string
packageSets map[string]packageSetFunc
packageSetChains map[string][]string
defaultImageConfig *distro.ImageConfig
kernelOptions string
defaultSize uint64
buildPipelines []string
payloadPipelines []string
exports []string
pipelines pipelinesFunc
// bootable image
bootable bool
// If set to a value, it is preferred over the architecture value
bootType distro.BootType
// List of valid arches for the image type
basePartitionTables distro.BasePartitionTableMap
}
func (t *imageType) Name() string {
return t.name
}
func (t *imageType) Arch() distro.Arch {
return t.arch
}
func (t *imageType) Filename() string {
return t.filename
}
func (t *imageType) MIMEType() string {
return t.mimeType
}
func (t *imageType) OSTreeRef() string {
// Not supported
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) getPackages(name string) rpmmd.PackageSet {
getter := t.packageSets[name]
if getter == nil {
return rpmmd.PackageSet{}
}
return getter(t)
}
func (t *imageType) PackageSets(bp blueprint.Blueprint, repos []rpmmd.RepoConfig) map[string][]rpmmd.PackageSet {
// merge package sets that appear in the image type with the package sets
// of the same name from the distro and arch
mergedSets := make(map[string]rpmmd.PackageSet)
imageSets := t.packageSets
for name := range imageSets {
mergedSets[name] = t.getPackages(name)
}
if _, hasPackages := imageSets[osPkgsKey]; !hasPackages {
// should this be possible??
mergedSets[osPkgsKey] = rpmmd.PackageSet{}
}
// every image type must define a 'build' package set
if _, hasBuild := imageSets[buildPkgsKey]; !hasBuild {
panic(fmt.Sprintf("'%s' image type has no '%s' package set defined", t.name, buildPkgsKey))
}
// blueprint packages
bpPackages := bp.GetPackages()
timezone, _ := bp.Customizations.GetTimezoneSettings()
if timezone != nil {
bpPackages = append(bpPackages, "chrony")
}
// if we have file system customization that will need to a new mount point
// the layout is converted to LVM so we need to corresponding packages
archName := t.arch.Name()
pt := t.basePartitionTables[archName]
haveNewMountpoint := false
if fs := bp.Customizations.GetFilesystems(); fs != nil {
for i := 0; !haveNewMountpoint && i < len(fs); i++ {
haveNewMountpoint = !pt.ContainsMountpoint(fs[i].Mountpoint)
}
}
if haveNewMountpoint {
bpPackages = append(bpPackages, "lvm2")
}
// depsolve bp packages separately
// bp packages aren't restricted by exclude lists
mergedSets[blueprintPkgsKey] = rpmmd.PackageSet{Include: bpPackages}
kernel := bp.Customizations.GetKernel().Name
// add bp kernel to main OS package set to avoid duplicate kernels
mergedSets[osPkgsKey] = mergedSets[osPkgsKey].Append(rpmmd.PackageSet{Include: []string{kernel}})
return distro.MakePackageSetChains(t, mergedSets, repos)
}
func (t *imageType) BuildPipelines() []string {
return t.buildPipelines
}
func (t *imageType) PayloadPipelines() []string {
return t.payloadPipelines
}
func (t *imageType) PayloadPackageSets() []string {
return []string{blueprintPkgsKey}
}
func (t *imageType) PackageSetsChains() map[string][]string {
return t.packageSetChains
}
func (t *imageType) Exports() []string {
if len(t.exports) == 0 {
panic(fmt.Sprintf("programming error: no exports for '%s'", t.name))
}
return t.exports
}
// getBootType returns the BootType which should be used for this particular
// combination of architecture and image type.
func (t *imageType) getBootType() distro.BootType {
bootType := t.arch.bootType
if t.bootType != distro.UnsetBootType {
bootType = t.bootType
}
return bootType
}
func (t *imageType) getPartitionTable(
mountpoints []blueprint.FilesystemCustomization,
options distro.ImageOptions,
rng *rand.Rand,
) (*disk.PartitionTable, error) {
archName := t.arch.Name()
basePartitionTable, exists := t.basePartitionTables[archName]
if !exists {
return nil, fmt.Errorf("unknown arch: " + archName)
}
imageSize := t.Size(options.Size)
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, true, rng)
}
func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
// ensure that image always returns non-nil default config
imageConfig := t.defaultImageConfig
if imageConfig == nil {
imageConfig = &distro.ImageConfig{}
}
return imageConfig.InheritFrom(t.arch.distro.getDefaultImageConfig())
}
func (t *imageType) PartitionType() string {
archName := t.arch.Name()
basePartitionTable, exists := t.basePartitionTables[archName]
if !exists {
return ""
}
return basePartitionTable.Type
}
func (t *imageType) Manifest(customizations *blueprint.Customizations,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
packageSpecSets map[string][]rpmmd.PackageSpec,
seed int64) (distro.Manifest, error) {
if err := t.checkOptions(customizations, options); err != nil {
return distro.Manifest{}, err
}
source := rand.NewSource(seed)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(source)
pipelines, err := t.pipelines(t, customizations, options, repos, packageSpecSets, rng)
if err != nil {
return distro.Manifest{}, err
}
// flatten spec sets for sources
allPackageSpecs := make([]rpmmd.PackageSpec, 0)
for _, specs := range packageSpecSets {
allPackageSpecs = append(allPackageSpecs, specs...)
}
return json.Marshal(
osbuild.Manifest{
Version: "2",
Pipelines: pipelines,
Sources: osbuild.GenSources(allPackageSpecs, nil, nil),
},
)
}
func isMountpointAllowed(mountpoint string) bool {
for _, allowed := range mountpointAllowList {
match, _ := path.Match(allowed, mountpoint)
if match {
return true
}
// ensure that only clean mountpoints
// are valid
if strings.Contains(mountpoint, "//") {
return false
}
match = strings.HasPrefix(mountpoint, allowed+"/")
if allowed != "/" && match {
return true
}
}
return false
}
// checkOptions checks the validity and compatibility of options and customizations for the image type.
func (t *imageType) checkOptions(customizations *blueprint.Customizations, options distro.ImageOptions) error {
mountpoints := customizations.GetFilesystems()
invalidMountpoints := []string{}
for _, m := range mountpoints {
if !isMountpointAllowed(m.Mountpoint) {
invalidMountpoints = append(invalidMountpoints, m.Mountpoint)
}
}
if len(invalidMountpoints) > 0 {
return fmt.Errorf("The following custom mountpoints are not supported %+q", invalidMountpoints)
}
return nil
}
// New creates a new distro object, defining the supported architectures and image types
func New() distro.Distro {
return newDistro("rhel-7")
}
func NewHostDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
return newDistro("rhel-7")
}
func newDistro(distroName string) distro.Distro {
rd := distroMap[distroName]
// Architecture definitions
x86_64 := architecture{
name: distro.X86_64ArchName,
distro: &rd,
legacy: "i386-pc",
bootType: distro.HybridBootType,
}
x86_64.addImageTypes(
qcow2ImgType,
)
rd.addArches(
x86_64,
)
return &rd
}

View file

@ -0,0 +1,445 @@
package rhel7_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/distro/distro_test_common"
"github.com/osbuild/osbuild-composer/internal/distro/rhel7"
)
type rhelFamilyDistro struct {
name string
distro distro.Distro
}
var rhelFamilyDistros = []rhelFamilyDistro{
{
name: "rhel",
distro: rhel7.New(),
},
}
func TestFilenameFromType(t *testing.T) {
type args struct {
outputFormat string
}
type wantResult struct {
filename string
mimeType string
wantErr bool
}
tests := []struct {
name string
args args
want wantResult
}{
{
name: "qcow2",
args: args{"qcow2"},
want: wantResult{
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
},
},
{
name: "invalid-output-type",
args: args{"foobar"},
want: wantResult{wantErr: true},
},
}
for _, dist := range rhelFamilyDistros {
t.Run(dist.name, func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dist := dist.distro
arch, _ := dist.GetArch("x86_64")
imgType, err := arch.GetImageType(tt.args.outputFormat)
if (err != nil) != tt.want.wantErr {
t.Errorf("Arch.GetImageType() error = %v, wantErr %v", err, tt.want.wantErr)
return
}
if !tt.want.wantErr {
gotFilename := imgType.Filename()
gotMIMEType := imgType.MIMEType()
if gotFilename != tt.want.filename {
t.Errorf("ImageType.Filename() got = %v, want %v", gotFilename, tt.want.filename)
}
if gotMIMEType != tt.want.mimeType {
t.Errorf("ImageType.MIMEType() got1 = %v, want %v", gotMIMEType, tt.want.mimeType)
}
}
})
}
})
}
}
func TestImageType_BuildPackages(t *testing.T) {
x8664BuildPackages := []string{
"dnf",
"dosfstools",
"e2fsprogs",
"grub2-efi-x64",
"grub2-pc",
"policycoreutils",
"shim-x64",
"systemd",
"tar",
"qemu-img",
"xz",
}
buildPackages := map[string][]string{
"x86_64": x8664BuildPackages,
}
for _, dist := range rhelFamilyDistros {
t.Run(dist.name, func(t *testing.T) {
d := dist.distro
for _, archLabel := range d.ListArches() {
archStruct, err := d.GetArch(archLabel)
if assert.NoErrorf(t, err, "d.GetArch(%v) returned err = %v; expected nil", archLabel, err) {
continue
}
for _, itLabel := range archStruct.ListImageTypes() {
itStruct, err := archStruct.GetImageType(itLabel)
if assert.NoErrorf(t, err, "d.GetArch(%v) returned err = %v; expected nil", archLabel, err) {
continue
}
buildPkgs := itStruct.PackageSets(blueprint.Blueprint{}, nil)["build"]
assert.NotNil(t, buildPkgs)
assert.Len(t, buildPkgs, 1)
assert.ElementsMatch(t, buildPackages[archLabel], buildPkgs[0].Include)
}
}
})
}
}
func TestImageType_Name(t *testing.T) {
imgMap := []struct {
arch string
imgNames []string
}{
{
arch: "x86_64",
imgNames: []string{
"qcow2",
},
},
}
for _, dist := range rhelFamilyDistros {
t.Run(dist.name, func(t *testing.T) {
for _, mapping := range imgMap {
arch, err := dist.distro.GetArch(mapping.arch)
if assert.NoError(t, err) {
for _, imgName := range mapping.imgNames {
imgType, err := arch.GetImageType(imgName)
if assert.NoError(t, err) {
assert.Equalf(t, imgName, imgType.Name(), "arch: %s", mapping.arch)
}
}
}
}
})
}
}
// Check that Manifest() function returns an error for unsupported
// configurations.
func TestDistro_ManifestError(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Kernel: &blueprint.KernelCustomization{
Append: "debug",
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
imgOpts := distro.ImageOptions{
Size: imgType.Size(0),
}
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, imgOpts, nil, testPackageSpecSets, 0)
assert.NoError(t, err)
}
}
}
func TestArchitecture_ListImageTypes(t *testing.T) {
imgMap := []struct {
arch string
imgNames []string
rhelAdditionalImageTypes []string
}{
{
arch: "x86_64",
imgNames: []string{
"qcow2",
},
},
}
for _, dist := range rhelFamilyDistros {
t.Run(dist.name, func(t *testing.T) {
for _, mapping := range imgMap {
arch, err := dist.distro.GetArch(mapping.arch)
require.NoError(t, err)
imageTypes := arch.ListImageTypes()
var expectedImageTypes []string
expectedImageTypes = append(expectedImageTypes, mapping.imgNames...)
if dist.name == "rhel" {
expectedImageTypes = append(expectedImageTypes, mapping.rhelAdditionalImageTypes...)
}
require.ElementsMatch(t, expectedImageTypes, imageTypes)
}
})
}
}
func TestRhel7_ListArches(t *testing.T) {
arches := rhel7.New().ListArches()
assert.Equal(t, []string{"x86_64"}, arches)
}
func TestRhel7_GetArch(t *testing.T) {
arches := []struct {
name string
errorExpected bool
errorExpectedInCentos bool
}{
{
name: "x86_64",
},
{
name: "foo-arch",
errorExpected: true,
},
}
for _, dist := range rhelFamilyDistros {
t.Run(dist.name, func(t *testing.T) {
for _, a := range arches {
actualArch, err := dist.distro.GetArch(a.name)
if a.errorExpected || (a.errorExpectedInCentos && dist.name == "centos") {
assert.Nil(t, actualArch)
assert.Error(t, err)
} else {
assert.Equal(t, a.name, actualArch.Name())
assert.NoError(t, err)
}
}
})
}
}
func TestRhel7_Name(t *testing.T) {
distro := rhel7.New()
assert.Equal(t, "rhel-7", distro.Name())
}
func TestRhel7_ModulePlatformID(t *testing.T) {
distro := rhel7.New()
assert.Equal(t, "platform:el7", distro.ModulePlatformID())
}
func TestRhel7_KernelOption(t *testing.T) {
distro_test_common.TestDistro_KernelOption(t, rhel7.New())
}
func TestDistro_CustomFileSystemManifestError(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/boot",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0)
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/boot\"]")
}
}
}
func TestDistro_TestRootMountPoint(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, 0)
assert.NoError(t, err)
}
}
}
func TestDistro_CustomFileSystemSubDirectories(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/var/log",
},
{
MinSize: 1024,
Mountpoint: "/var/log/audit",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, 0)
assert.NoError(t, err)
}
}
}
func TestDistro_MountpointsWithArbitraryDepthAllowed(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/var/a",
},
{
MinSize: 1024,
Mountpoint: "/var/a/b",
},
{
MinSize: 1024,
Mountpoint: "/var/a/b/c",
},
{
MinSize: 1024,
Mountpoint: "/var/a/b/c/d",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, 0)
assert.NoError(t, err)
}
}
}
func TestDistro_DirtyMountpointsNotAllowed(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "//",
},
{
MinSize: 1024,
Mountpoint: "/var//",
},
{
MinSize: 1024,
Mountpoint: "/var//log/audit/",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0)
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"//\" \"/var//\" \"/var//log/audit/\"]")
}
}
}
func TestDistro_CustomFileSystemPatternMatching(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/variable",
},
{
MinSize: 1024,
Mountpoint: "/variable/log/audit",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0)
assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/variable\" \"/variable/log/audit\"]")
}
}
}
func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
r7distro := rhel7.New()
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/usr",
},
},
},
}
for _, archName := range r7distro.ListArches() {
arch, _ := r7distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
testPackageSpecSets := distro_test_common.GetTestingImagePackageSpecSets("kernel", imgType)
_, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, testPackageSpecSets, 0)
assert.NoError(t, err)
}
}
}

View file

@ -0,0 +1,124 @@
package rhel7
import (
"fmt"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
// BUILD PACKAGE SETS
// distro-wide build package set
func distroBuildPackageSet(t *imageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"dosfstools",
"e2fsprogs",
"gdisk",
"lvm2",
"parted",
"policycoreutils",
"python3",
"python3-iniparse",
"python3-PyYAML",
"qemu-img",
"rpm",
"selinux-policy-targeted",
"systemd",
"tar",
"util-linux",
"xfsprogs",
"xz",
},
}
switch t.arch.Name() {
case distro.X86_64ArchName:
ps = ps.Append(x8664BuildPackageSet(t))
}
return ps
}
// x86_64 build package set
func x8664BuildPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-pc",
},
}
}
// BOOT PACKAGE SETS
func bootPackageSet(t *imageType) rpmmd.PackageSet {
if !t.bootable {
return rpmmd.PackageSet{}
}
var addLegacyBootPkg bool
var addUEFIBootPkg bool
switch bt := t.getBootType(); bt {
case distro.LegacyBootType:
addLegacyBootPkg = true
case distro.UEFIBootType:
addUEFIBootPkg = true
case distro.HybridBootType:
addLegacyBootPkg = true
addUEFIBootPkg = true
default:
panic(fmt.Sprintf("unsupported boot type: %q", bt))
}
ps := rpmmd.PackageSet{}
switch t.arch.Name() {
case distro.X86_64ArchName:
if addLegacyBootPkg {
ps = ps.Append(x8664LegacyBootPackageSet(t))
}
if addUEFIBootPkg {
ps = ps.Append(x8664UEFIBootPackageSet(t))
}
default:
panic(fmt.Sprintf("unsupported boot arch: %s", t.arch.Name()))
}
return ps
}
// x86_64 Legacy arch-specific boot package set
func x8664LegacyBootPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"dracut-config-generic",
"grub2-pc",
},
}
}
// x86_64 UEFI arch-specific boot package set
func x8664UEFIBootPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"dracut-config-generic",
"efibootmgr",
"grub2-efi-x64",
"shim-x64",
},
}
}
// packages that are only in some (sub)-distributions
func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet {
if t.arch.distro.isRHEL() {
return rpmmd.PackageSet{
Include: []string{"insights-client"},
}
}
return rpmmd.PackageSet{}
}

View file

@ -0,0 +1,66 @@
package rhel7
import (
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
)
// shared constants
const GigaByte = 1024 * 1024 * 1024
// ////////// Partition table //////////
var defaultBasePartitionTables = distro.BasePartitionTableMap{
distro.X86_64ArchName: disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1048576, // 1MB
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 209715200, // 200 MB
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 524288000, // 500 MB
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2147483648, // 2GiB
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
}

View file

@ -0,0 +1,340 @@
package rhel7
import (
"fmt"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
func buildPipeline(repos []rpmmd.RepoConfig, buildPackageSpecs []rpmmd.PackageSpec, runner string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "build"
p.Runner = runner
p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(buildPackageSpecs)))
p.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(true)))
return p
}
func prependKernelCmdlineStage(pipeline *osbuild.Pipeline, t *imageType, pt *disk.PartitionTable) *osbuild.Pipeline {
if t.arch.name == distro.S390xArchName {
rootFs := pt.FindMountable("/")
if rootFs == nil {
panic("s390x image must have a root filesystem, this is a programming error")
}
kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootFs.GetFSSpec().UUID, t.kernelOptions))
pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...)
}
return pipeline
}
func osPipeline(t *imageType,
repos []rpmmd.RepoConfig,
packages []rpmmd.PackageSpec,
c *blueprint.Customizations,
options distro.ImageOptions,
pt *disk.PartitionTable) (*osbuild.Pipeline, error) {
imageConfig := t.getDefaultImageConfig()
p := new(osbuild.Pipeline)
p.Name = "os"
p.Build = "name:build"
rpmOptions := osbuild.NewRPMStageOptions(repos)
rpmOptions.GPGKeysFromTree = imageConfig.GPGKeyFiles
p.AddStage(osbuild.NewRPMStage(rpmOptions, osbuild.NewRpmStageSourceFilesInputs(packages)))
// Difference to RHEL8, 9 pipelines: no BLS stage
language, keyboard := c.GetPrimaryLocale()
if language != nil {
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: *language}))
} else {
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: imageConfig.Locale}))
}
if keyboard != nil {
p.AddStage(osbuild.NewKeymapStage(&osbuild.KeymapStageOptions{Keymap: *keyboard}))
} else if imageConfig.Keyboard != nil {
p.AddStage(osbuild.NewKeymapStage(imageConfig.Keyboard))
}
if hostname := c.GetHostname(); hostname != nil {
p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: *hostname}))
}
timezone, ntpServers := c.GetTimezoneSettings()
if timezone != nil {
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: *timezone}))
} else {
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: imageConfig.Timezone}))
}
if len(ntpServers) > 0 {
p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{Timeservers: ntpServers}))
} else if imageConfig.TimeSynchronization != nil {
p.AddStage(osbuild.NewChronyStage(imageConfig.TimeSynchronization))
}
if groups := c.GetGroups(); len(groups) > 0 {
p.AddStage(osbuild.NewGroupsStage(osbuild.NewGroupsStageOptions(groups)))
}
if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil {
return nil, err
} else if userOptions != nil {
p.AddStage(osbuild.NewUsersStage(userOptions))
}
if services := c.GetServices(); services != nil || imageConfig.EnabledServices != nil ||
imageConfig.DisabledServices != nil || imageConfig.DefaultTarget != "" {
p.AddStage(osbuild.NewSystemdStage(systemdStageOptions(
imageConfig.EnabledServices,
imageConfig.DisabledServices,
services,
imageConfig.DefaultTarget,
)))
}
var fwStageOptions *osbuild.FirewallStageOptions
if firewallCustomization := c.GetFirewall(); firewallCustomization != nil {
fwStageOptions = firewallStageOptions(firewallCustomization)
}
if firewallConfig := imageConfig.Firewall; firewallConfig != nil {
// merge the user-provided firewall config with the default one
if fwStageOptions != nil {
fwStageOptions = &osbuild.FirewallStageOptions{
// Prefer the firewall ports and services settings provided
// via BP customization.
Ports: fwStageOptions.Ports,
EnabledServices: fwStageOptions.EnabledServices,
DisabledServices: fwStageOptions.DisabledServices,
// Default zone can not be set using BP customizations, therefore
// default to the one provided in the default image configuration.
DefaultZone: firewallConfig.DefaultZone,
}
} else {
fwStageOptions = firewallConfig
}
}
if fwStageOptions != nil {
p.AddStage(osbuild.NewFirewallStage(fwStageOptions))
}
for _, sysconfigConfig := range imageConfig.Sysconfig {
p.AddStage(osbuild.NewSysconfigStage(sysconfigConfig))
}
if t.arch.distro.isRHEL() {
if options.Subscription != nil {
commands := []string{
fmt.Sprintf("/usr/sbin/subscription-manager register --org=%s --activationkey=%s --serverurl %s --baseurl %s", options.Subscription.Organization, options.Subscription.ActivationKey, options.Subscription.ServerUrl, options.Subscription.BaseUrl),
}
if options.Subscription.Insights {
commands = append(commands, "/usr/bin/insights-client --register")
}
p.AddStage(osbuild.NewFirstBootStage(&osbuild.FirstBootStageOptions{
Commands: commands,
WaitForNetwork: true,
}))
if rhsmConfig, exists := imageConfig.RHSMConfig[distro.RHSMConfigWithSubscription]; exists {
p.AddStage(osbuild.NewRHSMStage(rhsmConfig))
}
} else {
if rhsmConfig, exists := imageConfig.RHSMConfig[distro.RHSMConfigNoSubscription]; exists {
p.AddStage(osbuild.NewRHSMStage(rhsmConfig))
}
}
}
for _, systemdLogindConfig := range imageConfig.SystemdLogind {
p.AddStage(osbuild.NewSystemdLogindStage(systemdLogindConfig))
}
for _, cloudInitConfig := range imageConfig.CloudInit {
p.AddStage(osbuild.NewCloudInitStage(cloudInitConfig))
}
for _, modprobeConfig := range imageConfig.Modprobe {
p.AddStage(osbuild.NewModprobeStage(modprobeConfig))
}
for _, dracutConfConfig := range imageConfig.DracutConf {
p.AddStage(osbuild.NewDracutConfStage(dracutConfConfig))
}
for _, systemdUnitConfig := range imageConfig.SystemdUnit {
p.AddStage(osbuild.NewSystemdUnitStage(systemdUnitConfig))
}
if authselectConfig := imageConfig.Authselect; authselectConfig != nil {
p.AddStage(osbuild.NewAuthselectStage(authselectConfig))
}
if seLinuxConfig := imageConfig.SELinuxConfig; seLinuxConfig != nil {
p.AddStage(osbuild.NewSELinuxConfigStage(seLinuxConfig))
}
if tunedConfig := imageConfig.Tuned; tunedConfig != nil {
p.AddStage(osbuild.NewTunedStage(tunedConfig))
}
for _, tmpfilesdConfig := range imageConfig.Tmpfilesd {
p.AddStage(osbuild.NewTmpfilesdStage(tmpfilesdConfig))
}
for _, pamLimitsConfConfig := range imageConfig.PamLimitsConf {
p.AddStage(osbuild.NewPamLimitsConfStage(pamLimitsConfConfig))
}
for _, sysctldConfig := range imageConfig.Sysctld {
p.AddStage(osbuild.NewSysctldStage(sysctldConfig))
}
for _, dnfConfig := range imageConfig.DNFConfig {
p.AddStage(osbuild.NewDNFConfigStage(dnfConfig))
}
if sshdConfig := imageConfig.SshdConfig; sshdConfig != nil {
p.AddStage((osbuild.NewSshdConfigStage(sshdConfig)))
}
if authConfig := imageConfig.Authconfig; authConfig != nil {
p.AddStage(osbuild.NewAuthconfigStage(authConfig))
}
if pwQuality := imageConfig.PwQuality; pwQuality != nil {
p.AddStage(osbuild.NewPwqualityConfStage(pwQuality))
}
if waConfig := imageConfig.WAAgentConfig; waConfig != nil {
p.AddStage(osbuild.NewWAAgentConfStage(waConfig))
}
if yumConfig := imageConfig.YumConfig; yumConfig != nil {
p.AddStage(osbuild.NewYumConfigStage(yumConfig))
}
for _, yumRepo := range imageConfig.YUMRepos {
p.AddStage(osbuild.NewYumReposStage(yumRepo))
}
if udevRules := imageConfig.UdevRules; udevRules != nil {
p.AddStage(osbuild.NewUdevRulesStage(udevRules))
}
if pt != nil {
kernelOptions := osbuild.GenImageKernelOptions(pt)
if t.kernelOptions != "" {
kernelOptions = append(kernelOptions, t.kernelOptions)
}
if bpKernel := c.GetKernel(); bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append)
}
p.AddStage(osbuild.NewFSTabStage(osbuild.NewFSTabStageOptions(pt)))
kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packages, c.GetKernel().Name)
var bootloader *osbuild.Stage
if t.arch.name == distro.S390xArchName {
p = prependKernelCmdlineStage(p, t, pt)
bootloader = osbuild.NewZiplStage(new(osbuild.ZiplStageOptions))
} else {
product := osbuild.GRUB2Product{
Name: t.arch.distro.product,
Version: t.arch.distro.osVersion,
Nick: t.arch.distro.nick,
}
ver, _ := rpmmd.GetVerStrFromPackageSpecList(packages, "dracut-config-rescue")
haveRescue := ver != ""
id := "76a22bf4-f153-4541-b6c7-0332c0dfaeac"
entries := osbuild.MakeGrub2MenuEntries(id, kernelVer, product, haveRescue)
var vendor string // whether to boot via uefi, and if so the vendor
var legacy string // whether to boot via legacy, and if so the platform
bt := t.getBootType()
if bt == distro.HybridBootType || bt == distro.LegacyBootType {
legacy = t.arch.legacy
}
if bt == distro.HybridBootType || bt == distro.UEFIBootType {
vendor = t.arch.distro.vendor
}
// we rely on stage option validation to detect invalid boot configurations
options := osbuild.NewGrub2LegacyStageOptions(
imageConfig.Grub2Config,
pt,
kernelOptions,
legacy,
vendor,
entries,
)
bootloader = osbuild.NewGrub2LegacyStage(options)
}
p.AddStage(bootloader)
}
p.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false)))
return p, nil
}
func liveImagePipeline(inputPipelineName string, outputFilename string, pt *disk.PartitionTable, arch *architecture, kernelVer string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "image"
p.Build = "name:build"
for _, stage := range osbuild.GenImagePrepareStages(pt, outputFilename, osbuild.PTSgdisk) {
p.AddStage(stage)
}
inputName := "root-tree"
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, inputPipelineName, outputFilename, pt)
copyInputs := osbuild.NewCopyStagePipelineTreeInputs(inputName, inputPipelineName)
p.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
for _, stage := range osbuild.GenImageFinishStages(pt, outputFilename) {
p.AddStage(stage)
}
loopback := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: outputFilename})
p.AddStage(bootloaderInstStage(outputFilename, pt, arch, kernelVer, copyDevices, copyMounts, loopback))
return p
}
func qemuPipeline(inputPipelineName, inputFilename, outputFilename string, format osbuild.QEMUFormat, formatOptions osbuild.QEMUFormatOptions) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = string(format)
p.Build = "name:build"
qemuStage := osbuild.NewQEMUStage(
osbuild.NewQEMUStageOptions(outputFilename, format, formatOptions),
osbuild.NewQemuStagePipelineFilesInputs(inputPipelineName, inputFilename),
)
p.AddStage(qemuStage)
return p
}
func xzArchivePipeline(inputPipelineName, inputFilename, outputFilename string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "archive"
p.Build = "name:build"
p.AddStage(osbuild.NewXzStage(
osbuild.NewXzStageOptions(outputFilename),
osbuild.NewFilesInputs(osbuild.NewFilesInputReferencesPipeline(inputPipelineName, inputFilename)),
))
return p
}

View file

@ -0,0 +1,152 @@
package rhel7
import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/distro"
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"kernel",
"nfs-utils",
"yum-utils",
"cloud-init",
//"ovirt-guest-agent-common",
"rhn-setup",
"yum-rhn-plugin",
"cloud-utils-growpart",
"dracut-config-generic",
"tar",
"tcpdump",
"rsync",
},
Exclude: []string{
"biosdevname",
"dracut-config-rescue",
"iprutils",
"NetworkManager-team",
"NetworkManager-tui",
"NetworkManager",
"plymouth",
"aic94xx-firmware",
"alsa-firmware",
"alsa-lib",
"alsa-tools-firmware",
"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",
},
}.Append(bootPackageSet(t)).Append(distroSpecificPackageSet(t))
return ps
}
func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
pipelines := make([]osbuild.Pipeline, 0)
pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner))
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil {
return nil, err
}
pipelines = append(pipelines, *treePipeline)
diskfile := "disk.img"
kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packageSetSpecs[osPkgsKey], customizations.GetKernel().Name)
imagePipeline := liveImagePipeline(treePipeline.Name, diskfile, partitionTable, t.arch, kernelVer)
pipelines = append(pipelines, *imagePipeline)
qemuPipeline := qemuPipeline(imagePipeline.Name, diskfile, t.filename, osbuild.QEMUFormatQCOW2, osbuild.QCOW2Options{Compat: "0.10"})
pipelines = append(pipelines, *qemuPipeline)
return pipelines, nil
}
var qcow2ImgType = imageType{
name: "qcow2",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto",
packageSets: map[string]packageSetFunc{
buildPkgsKey: distroBuildPackageSet,
osPkgsKey: qcow2CommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
DefaultTarget: "multi-user.target",
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
NetworkScripts: &osbuild.NetworkScriptsOptions{
IfcfgFiles: map[string]osbuild.IfcfgFile{
"eth0": {
Device: "eth0",
Bootproto: osbuild.IfcfgBootprotoDHCP,
OnBoot: common.BoolToPtr(true),
Type: osbuild.IfcfgTypeEthernet,
UserCtl: common.BoolToPtr(true),
PeerDNS: common.BoolToPtr(true),
IPv6Init: common.BoolToPtr(false),
},
},
},
},
},
RHSMConfig: map[distro.RHSMSubscriptionStatus]*osbuild.RHSMStageOptions{
distro.RHSMConfigNoSubscription: {
YumPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
ProductID: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
SubscriptionManager: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
},
},
},
},
bootable: true,
defaultSize: 10 * GigaByte,
pipelines: qcow2Pipelines,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}

View file

@ -0,0 +1,80 @@
package rhel7
import (
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
func bootloaderInstStage(filename string, pt *disk.PartitionTable, arch *architecture, kernelVer string, devices *osbuild.Devices, mounts *osbuild.Mounts, disk *osbuild.Device) *osbuild.Stage {
platform := arch.legacy
if platform != "" {
return osbuild.NewGrub2InstStage(osbuild.NewGrub2InstStageOption(filename, pt, platform))
}
if arch.name == distro.S390xArchName {
return osbuild.NewZiplInstStage(osbuild.NewZiplInstStageOptions(kernelVer, pt), disk, devices, mounts)
}
return nil
}
func rpmStageOptions(repos []rpmmd.RepoConfig) *osbuild.RPMStageOptions {
var gpgKeys []string
for _, repo := range repos {
if repo.GPGKey == "" {
continue
}
gpgKeys = append(gpgKeys, repo.GPGKey)
}
return &osbuild.RPMStageOptions{
GPGKeys: gpgKeys,
}
}
// selinuxStageOptions returns the options for the org.osbuild.selinux stage.
// Setting the argument to 'true' relabels the '/usr/bin/cp' and '/usr/bin/tar'
// binaries with 'install_exec_t'. This should be set in the build root.
func selinuxStageOptions(labelcp bool) *osbuild.SELinuxStageOptions {
options := &osbuild.SELinuxStageOptions{
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
}
if labelcp {
options.Labels = map[string]string{
"/usr/bin/cp": "system_u:object_r:install_exec_t:s0",
"/usr/bin/tar": "system_u:object_r:install_exec_t:s0",
}
} else {
options.ForceAutorelabel = common.BoolToPtr(true)
}
return options
}
func firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions {
options := osbuild.FirewallStageOptions{
Ports: firewall.Ports,
}
if firewall.Services != nil {
options.EnabledServices = firewall.Services.Enabled
options.DisabledServices = firewall.Services.Disabled
}
return &options
}
func 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,
}
}

View file

@ -8,6 +8,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/distro/fedora"
"github.com/osbuild/osbuild-composer/internal/distro/rhel7"
"github.com/osbuild/osbuild-composer/internal/distro/rhel8"
"github.com/osbuild/osbuild-composer/internal/distro/rhel84"
"github.com/osbuild/osbuild-composer/internal/distro/rhel85"
@ -22,6 +23,7 @@ var supportedDistros = []supportedDistro{
{fedora.NewF34, fedora.NewHostDistro},
{fedora.NewF35, fedora.NewHostDistro},
{fedora.NewF36, fedora.NewHostDistro},
{rhel7.New, rhel7.NewHostDistro},
{rhel8.New, rhel8.NewHostDistro},
{rhel84.New, rhel84.NewHostDistro},
{rhel85.New, rhel85.NewHostDistro},

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -145,6 +145,37 @@
}
]
},
"rhel-7": {
"x86_64": [
{
"name": "server",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-server-r7.9-20220530"
},
{
"name": "server-extras",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-server-extras-r7.9-20220530"
},
{
"name": "server-optional",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-server-optional-r7.9-20220530"
},
{
"name": "server-dotnet",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-server-dotnet-r1.1-20220530"
},
{
"name": "rhel-eng",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-eng-rel-20220530",
"package-sets": [
"build"
]
},
{
"name": "azure-rhui-7",
"baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el7/el7-x86_64-rhui-azure-20220530"
}
]
},
"rhel-8": {
"aarch64": [
{