distro: add fedora 33 support
Fedora 33 images can now be built and test cases are added for the new images. The fedora 33 qcow2 and vmdk images are based off of the official images and their kickstarters found here: https://pagure.io/fedora-kickstarts. The fedora 33 iot image is based off of the the config found here: https://pagure.io/fedora-iot/ostree. The openstack, azure, and amazon image types have changes made to them based off of the changes made to the qcow2. The changes between fedora 32 and fedora 33 are as follows: Grub now loads its kernel command line options from etc/kernel/cmdline, /usr/lib/kernel/cmdline, and /proc/cmdline instead of from grub env. This is addressed by adding kernelCmdlineStageOptions to use osbuild's kernel-cmdline stage to set these options. Alongside `ro biosdevname=0 net.ifnames=0`, we also set `no_timer_check console=tty1 console=ttyS0,115200n8` per what is set in the official qcow2. For azure and amazon, the kernelOptions are still set as they were in fedora 32. The timezone is now set to UTC if a user does not set a timezone in the blueprint customizations. Also, the hostname is set to localhost.localdomain if the hostname isn't set in the blueprint. Finally, the following packages have been removed: polkit geolite2-city geolite2-country zram-generator-defaults
This commit is contained in:
parent
2adf8e660f
commit
678de9d1ef
14 changed files with 60306 additions and 5 deletions
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/osbuild/osbuild-composer/internal/distro/distro_test_common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora31"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora32"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora33"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/rhel8"
|
||||
)
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ func TestDistro_Manifest(t *testing.T) {
|
|||
t,
|
||||
"../../test/cases/",
|
||||
"*",
|
||||
fedora31.New(), fedora32.New(), rhel8.New(),
|
||||
fedora31.New(), fedora32.New(), fedora33.New(), rhel8.New(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -26,10 +27,11 @@ func TestDistro_RegistryList(t *testing.T) {
|
|||
expected := []string{
|
||||
"fedora-31",
|
||||
"fedora-32",
|
||||
"fedora-33",
|
||||
"rhel-8",
|
||||
}
|
||||
|
||||
distros, err := distro.NewRegistry(fedora31.New(), fedora32.New(), rhel8.New())
|
||||
distros, err := distro.NewRegistry(fedora31.New(), fedora32.New(), fedora33.New(), rhel8.New())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equalf(t, expected, distros.List(), "unexpected list of distros")
|
||||
|
|
|
|||
838
internal/distro/fedora33/distro.go
Normal file
838
internal/distro/fedora33/distro.go
Normal file
|
|
@ -0,0 +1,838 @@
|
|||
package fedora33
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
"github.com/osbuild/osbuild-composer/internal/osbuild"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/crypt"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
)
|
||||
|
||||
const name = "fedora-33"
|
||||
const modulePlatformID = "platform:f33"
|
||||
|
||||
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
|
||||
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,
|
||||
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) 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) Manifest(c *blueprint.Customizations,
|
||||
options distro.ImageOptions,
|
||||
repos []rpmmd.RepoConfig,
|
||||
packageSpecs,
|
||||
buildPackageSpecs []rpmmd.PackageSpec) (distro.Manifest, error) {
|
||||
pipeline, err := t.pipeline(c, options, repos, packageSpecs, buildPackageSpecs)
|
||||
if err != nil {
|
||||
return distro.Manifest{}, err
|
||||
}
|
||||
|
||||
return json.Marshal(
|
||||
osbuild.Manifest{
|
||||
Sources: *sources(append(packageSpecs, buildPackageSpecs...)),
|
||||
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,
|
||||
}
|
||||
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) {
|
||||
p := &osbuild.Pipeline{}
|
||||
p.SetBuild(t.buildPipeline(repos, *t.arch, buildPackageSpecs), "org.osbuild.fedora33")
|
||||
|
||||
p.AddStage(osbuild.NewKernelCmdlineStage(t.kernelCmdlineStageOptions()))
|
||||
p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch, repos, packageSpecs)))
|
||||
|
||||
// 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}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: "localhost.localdomain"}))
|
||||
}
|
||||
|
||||
timezone, ntpServers := c.GetTimezoneSettings()
|
||||
|
||||
if timezone != nil {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: *timezone}))
|
||||
} else {
|
||||
p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: "UTC"}))
|
||||
}
|
||||
|
||||
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 t.bootable {
|
||||
p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.uefi)))
|
||||
p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(t.kernelOptions, c.GetKernel(), t.arch.uefi)))
|
||||
}
|
||||
p.AddStage(osbuild.NewFixBLSStage())
|
||||
|
||||
if services := c.GetServices(); services != nil || t.enabledServices != nil {
|
||||
p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.enabledServices, t.disabledServices, services)))
|
||||
}
|
||||
|
||||
if firewall := c.GetFirewall(); firewall != nil {
|
||||
p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall)))
|
||||
}
|
||||
|
||||
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",
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
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)))
|
||||
|
||||
selinuxOptions := osbuild.SELinuxStageOptions{
|
||||
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
|
||||
Labels: map[string]string{
|
||||
"/usr/bin/cp": "system_u:object_r:install_exec_t:s0",
|
||||
},
|
||||
}
|
||||
|
||||
p.AddStage(osbuild.NewSELinuxStage(&selinuxOptions))
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *imageType) kernelCmdlineStageOptions() *osbuild.KernelCmdlineStageOptions {
|
||||
return &osbuild.KernelCmdlineStageOptions{
|
||||
RootFsUUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
KernelOpts: "ro no_timer_check net.ifnames=0 console=tty1 console=ttyS0,115200n8",
|
||||
}
|
||||
}
|
||||
|
||||
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) *osbuild.SystemdStageOptions {
|
||||
if s != nil {
|
||||
enabledServices = append(enabledServices, s.Enabled...)
|
||||
disabledServices = append(disabledServices, s.Disabled...)
|
||||
}
|
||||
return &osbuild.SystemdStageOptions{
|
||||
EnabledServices: enabledServices,
|
||||
DisabledServices: disabledServices,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *imageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions {
|
||||
options := osbuild.FSTabStageOptions{}
|
||||
options.AddFilesystem("76a22bf4-f153-4541-b6c7-0332c0dfaeac", "ext4", "/", "defaults", 1, 1)
|
||||
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("76a22bf4-f153-4541-b6c7-0332c0dfaeac")
|
||||
|
||||
if kernel != nil {
|
||||
kernelOptions += " " + kernel.Append
|
||||
}
|
||||
|
||||
var uefiOptions *osbuild.GRUB2UEFI
|
||||
if uefi {
|
||||
uefiOptions = &osbuild.GRUB2UEFI{
|
||||
Vendor: "fedora",
|
||||
}
|
||||
}
|
||||
|
||||
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) *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",
|
||||
UUID: "02C1E068-1D2F-4DA3-91FD-8DD76A955C9D",
|
||||
Filesystem: &osbuild.QEMUFilesystem{
|
||||
Type: "vfat",
|
||||
UUID: "46BB-8120",
|
||||
Label: "EFI System Partition",
|
||||
Mountpoint: "/boot/efi",
|
||||
},
|
||||
},
|
||||
{
|
||||
Start: 976896,
|
||||
UUID: "8D760010-FAAE-46D1-9E5B-4A2EAC5030CD",
|
||||
Filesystem: &osbuild.QEMUFilesystem{
|
||||
Type: "ext4",
|
||||
UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
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: "ext4",
|
||||
UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
Mountpoint: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return osbuild.NewQEMUAssembler(&options)
|
||||
}
|
||||
|
||||
func ostreeCommitAssembler(options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
ref := options.OSTree.Ref
|
||||
if ref == "" {
|
||||
ref = fmt.Sprintf("fedora/33/%s/iot", arch.Name())
|
||||
}
|
||||
return osbuild.NewOSTreeCommitAssembler(
|
||||
&osbuild.OSTreeCommitAssemblerOptions{
|
||||
Ref: 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
|
||||
|
||||
iotImgType := imageType{
|
||||
name: "fedora-iot-commit",
|
||||
filename: "commit.tar",
|
||||
mimeType: "application/x-tar",
|
||||
packages: []string{
|
||||
"fedora-release-iot",
|
||||
"glibc", "glibc-minimal-langpack", "nss-altfiles",
|
||||
"sssd-client", "libsss_sudo", "shadow-utils",
|
||||
"kernel",
|
||||
"dracut-config-generic", "dracut-network",
|
||||
"rpm-ostree", "polkit", "lvm2",
|
||||
"cryptsetup", "pinentry",
|
||||
"keyutils", "cracklib-dicts",
|
||||
"e2fsprogs", "xfsprogs", "dosfstools",
|
||||
"gnupg2",
|
||||
"basesystem", "python3", "bash",
|
||||
"xz", "gzip",
|
||||
"coreutils", "which", "curl",
|
||||
"firewalld", "iptables",
|
||||
"NetworkManager", "NetworkManager-wifi", "NetworkManager-wwan",
|
||||
"wpa_supplicant", "iwd", "tpm2-pkcs11",
|
||||
"dnsmasq", "traceroute",
|
||||
"hostname", "iproute", "iputils",
|
||||
"openssh-clients", "openssh-server", "passwd",
|
||||
"policycoreutils", "procps-ng", "rootfiles", "rpm",
|
||||
"selinux-policy-targeted", "setup", "shadow-utils",
|
||||
"sudo", "systemd", "util-linux", "vim-minimal",
|
||||
"less", "tar",
|
||||
"fwupd", "usbguard",
|
||||
"greenboot", "greenboot-grub2", "greenboot-rpm-ostree-grub2", "greenboot-reboot", "greenboot-status",
|
||||
"ignition", "zezere-ignition",
|
||||
"rsync", "attr",
|
||||
"ima-evm-utils",
|
||||
"bash-completion",
|
||||
"tmux", "screen",
|
||||
"policycoreutils-python-utils",
|
||||
"setools-console",
|
||||
"audit", "rng-tools", "chrony",
|
||||
"bluez", "bluez-libs", "bluez-mesh",
|
||||
"kernel-tools", "libgpiod-utils",
|
||||
"podman", "container-selinux", "skopeo", "criu",
|
||||
"slirp4netns", "fuse-overlayfs",
|
||||
"clevis", "clevis-dracut", "clevis-luks", "clevis-pin-tpm2",
|
||||
"parsec", "dbus-parsec",
|
||||
// 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",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"NetworkManager.service", "firewalld.service", "rngd.service", "sshd.service",
|
||||
"zezere_ignition.timer", "zezere_ignition_banner.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",
|
||||
"parsec", "dbus-parsec",
|
||||
},
|
||||
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{
|
||||
"@Core",
|
||||
"chrony",
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"langpacks-en",
|
||||
"libxcrypt-compat",
|
||||
"xfsprogs",
|
||||
"cloud-init",
|
||||
"checkpolicy",
|
||||
"net-tools",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"cloud-init.service",
|
||||
},
|
||||
kernelOptions: "ro no_timer_check console=ttyS0,115200n8 console=tty1 biosdevname=0 net.ifnames=0 console=ttyS0,115200",
|
||||
bootable: true,
|
||||
defaultSize: 6 * GigaByte,
|
||||
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
return qemuAssembler("raw", "image.raw", uefi, options)
|
||||
},
|
||||
}
|
||||
|
||||
qcow2ImageType := imageType{
|
||||
name: "qcow2",
|
||||
filename: "disk.qcow2",
|
||||
mimeType: "application/x-qemu-disk",
|
||||
packages: []string{
|
||||
"kernel-core",
|
||||
"@Fedora Cloud Server",
|
||||
"chrony",
|
||||
"systemd-udev",
|
||||
"selinux-policy-targeted",
|
||||
"langpacks-en",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"etables",
|
||||
"firewalld",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"gobject-introspection",
|
||||
"plymouth",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"cloud-init.service",
|
||||
"cloud-config.service",
|
||||
"cloud-final.service",
|
||||
"cloud-init-local.service",
|
||||
},
|
||||
bootable: true,
|
||||
defaultSize: 2 * GigaByte,
|
||||
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
return qemuAssembler("qcow2", "disk.qcow2", uefi, options)
|
||||
},
|
||||
}
|
||||
|
||||
openstackImgType := imageType{
|
||||
name: "openstack",
|
||||
filename: "disk.qcow2",
|
||||
mimeType: "application/x-qemu-disk",
|
||||
packages: []string{
|
||||
"@Core",
|
||||
"chrony",
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"spice-vdagent",
|
||||
"qemu-guest-agent",
|
||||
"xen-libs",
|
||||
"langpacks-en",
|
||||
"cloud-init",
|
||||
"libdrm",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"cloud-init.service",
|
||||
"cloud-config.service",
|
||||
"cloud-final.service",
|
||||
"cloud-init-local.service",
|
||||
},
|
||||
bootable: true,
|
||||
defaultSize: 2 * GigaByte,
|
||||
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
return qemuAssembler("qcow2", "disk.qcow2", uefi, options)
|
||||
},
|
||||
}
|
||||
|
||||
vhdImgType := imageType{
|
||||
name: "vhd",
|
||||
filename: "disk.vhd",
|
||||
mimeType: "application/x-vhd",
|
||||
packages: []string{
|
||||
"@Core",
|
||||
"chrony",
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"langpacks-en",
|
||||
"net-tools",
|
||||
"ntfsprogs",
|
||||
"WALinuxAgent",
|
||||
"libxcrypt-compat",
|
||||
"initscripts",
|
||||
"glibc-all-langpacks",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"sshd",
|
||||
"waagent", // needed to run in Azure
|
||||
},
|
||||
disabledServices: []string{
|
||||
"proc-sys-fs-binfmt_misc.mount",
|
||||
"loadmodules.service",
|
||||
},
|
||||
// These kernel parameters are required by Azure documentation
|
||||
kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0",
|
||||
bootable: true,
|
||||
defaultSize: 2 * GigaByte,
|
||||
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
return qemuAssembler("vpc", "disk.vhd", uefi, options)
|
||||
},
|
||||
}
|
||||
|
||||
vmdkImgType := imageType{
|
||||
name: "vmdk",
|
||||
filename: "disk.vmdk",
|
||||
mimeType: "application/x-vmdk",
|
||||
packages: []string{
|
||||
"kernel-core",
|
||||
"@Fedora Cloud Server",
|
||||
"chrony",
|
||||
"systemd-udev",
|
||||
"selinux-policy-targeted",
|
||||
"langpacks-en",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"etables",
|
||||
"firewalld",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"gobject-introspection",
|
||||
"plymouth",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
enabledServices: []string{
|
||||
"cloud-init.service",
|
||||
"cloud-config.service",
|
||||
"cloud-final.service",
|
||||
"cloud-init-local.service",
|
||||
},
|
||||
bootable: true,
|
||||
defaultSize: 2 * GigaByte,
|
||||
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
|
||||
return qemuAssembler("vmdk", "disk.vmdk", uefi, options)
|
||||
},
|
||||
}
|
||||
|
||||
r := distribution{
|
||||
imageTypes: map[string]imageType{},
|
||||
buildPackages: []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"e2fsprogs",
|
||||
"policycoreutils",
|
||||
"qemu-img",
|
||||
"selinux-policy-targeted",
|
||||
"systemd",
|
||||
"tar",
|
||||
"xz",
|
||||
},
|
||||
}
|
||||
x8664 := architecture{
|
||||
distro: &r,
|
||||
name: "x86_64",
|
||||
bootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"grub2-pc",
|
||||
},
|
||||
buildPackages: []string{
|
||||
"grub2-pc",
|
||||
},
|
||||
legacy: "i386-pc",
|
||||
}
|
||||
x8664.setImageTypes(
|
||||
iotImgType,
|
||||
amiImgType,
|
||||
qcow2ImageType,
|
||||
openstackImgType,
|
||||
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,
|
||||
qcow2ImageType,
|
||||
openstackImgType,
|
||||
)
|
||||
|
||||
r.setArches(x8664, aarch64)
|
||||
|
||||
return &r
|
||||
}
|
||||
344
internal/distro/fedora33/distro_test.go
Normal file
344
internal/distro/fedora33/distro_test.go
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
package fedora33_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/distro_test_common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora33"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFilenameFromType(t *testing.T) {
|
||||
type args struct {
|
||||
outputFormat string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
want1 string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
args: args{"ami"},
|
||||
want: "image.raw",
|
||||
want1: "application/octet-stream",
|
||||
},
|
||||
{
|
||||
name: "openstack",
|
||||
args: args{"openstack"},
|
||||
want: "disk.qcow2",
|
||||
want1: "application/x-qemu-disk",
|
||||
},
|
||||
{
|
||||
name: "qcow2",
|
||||
args: args{"qcow2"},
|
||||
want: "disk.qcow2",
|
||||
want1: "application/x-qemu-disk",
|
||||
},
|
||||
{
|
||||
name: "vhd",
|
||||
args: args{"vhd"},
|
||||
want: "disk.vhd",
|
||||
want1: "application/x-vhd",
|
||||
},
|
||||
{
|
||||
name: "vmdk",
|
||||
args: args{"vmdk"},
|
||||
want: "disk.vmdk",
|
||||
want1: "application/x-vmdk",
|
||||
},
|
||||
{
|
||||
name: "invalid-output-type",
|
||||
args: args{"foobar"},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
dist := fedora33.New()
|
||||
arch, _ := dist.GetArch("x86_64")
|
||||
imgType, err := arch.GetImageType(tt.args.outputFormat)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Arch.GetImageType() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr {
|
||||
got := imgType.Filename()
|
||||
got1 := imgType.MIMEType()
|
||||
if got != tt.want {
|
||||
t.Errorf("ImageType.Filename() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("ImageType.MIMEType() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_BuildPackages(t *testing.T) {
|
||||
x8664BuildPackages := []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"e2fsprogs",
|
||||
"grub2-pc",
|
||||
"policycoreutils",
|
||||
"qemu-img",
|
||||
"selinux-policy-targeted",
|
||||
"systemd",
|
||||
"tar",
|
||||
"xz",
|
||||
}
|
||||
aarch64BuildPackages := []string{
|
||||
"dnf",
|
||||
"dosfstools",
|
||||
"e2fsprogs",
|
||||
"policycoreutils",
|
||||
"qemu-img",
|
||||
"selinux-policy-targeted",
|
||||
"systemd",
|
||||
"tar",
|
||||
"xz",
|
||||
}
|
||||
buildPackages := map[string][]string{
|
||||
"x86_64": x8664BuildPackages,
|
||||
"aarch64": aarch64BuildPackages,
|
||||
}
|
||||
d := fedora33.New()
|
||||
for _, archLabel := range d.ListArches() {
|
||||
archStruct, err := d.GetArch(archLabel)
|
||||
if err != nil {
|
||||
t.Errorf("d.GetArch(%v) returned err = %v; expected nil", archLabel, err)
|
||||
continue
|
||||
}
|
||||
for _, itLabel := range archStruct.ListImageTypes() {
|
||||
itStruct, err := archStruct.GetImageType(itLabel)
|
||||
if err != nil {
|
||||
t.Errorf("d.GetArch(%v) returned err = %v; expected nil", archLabel, err)
|
||||
continue
|
||||
}
|
||||
if itLabel == "fedora-iot-commit" {
|
||||
// For now we only include rpm-ostree when building fedora-iot-commit image types, this we may want
|
||||
// to reconsider. The only reason to specia-case it is that it might pull in a lot of dependencies
|
||||
// for a niche usecase.
|
||||
assert.ElementsMatch(t, append(buildPackages[archLabel], "rpm-ostree"), itStruct.BuildPackages())
|
||||
} else {
|
||||
assert.ElementsMatch(t, buildPackages[archLabel], itStruct.BuildPackages())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_Name(t *testing.T) {
|
||||
distro := fedora33.New()
|
||||
imgMap := []struct {
|
||||
arch string
|
||||
imgNames []string
|
||||
}{
|
||||
{
|
||||
arch: "x86_64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
"vhd",
|
||||
"vmdk",
|
||||
},
|
||||
},
|
||||
{
|
||||
arch: "aarch64",
|
||||
imgNames: []string{
|
||||
"ami",
|
||||
"qcow2",
|
||||
"openstack",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, mapping := range imgMap {
|
||||
arch, err := 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_Size(t *testing.T) {
|
||||
const gigaByte = 1024 * 1024 * 1024
|
||||
sizeMap := []struct {
|
||||
name string
|
||||
inputSize uint64
|
||||
outputSize uint64
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
inputSize: 6*gigaByte + 1,
|
||||
outputSize: 6*gigaByte + 1,
|
||||
},
|
||||
{
|
||||
name: "ami",
|
||||
inputSize: 0,
|
||||
outputSize: 6 * gigaByte,
|
||||
},
|
||||
{
|
||||
name: "vhd",
|
||||
inputSize: 10 * gigaByte,
|
||||
outputSize: 10 * gigaByte,
|
||||
},
|
||||
{
|
||||
name: "vhd",
|
||||
inputSize: 10*gigaByte - 1,
|
||||
outputSize: 10 * gigaByte,
|
||||
},
|
||||
}
|
||||
|
||||
distro := fedora33.New()
|
||||
arch, err := distro.GetArch("x86_64")
|
||||
if assert.NoError(t, err) {
|
||||
for _, mapping := range sizeMap {
|
||||
imgType, err := arch.GetImageType(mapping.name)
|
||||
if assert.NoError(t, err) {
|
||||
size := imgType.Size(mapping.inputSize)
|
||||
assert.Equalf(t, mapping.outputSize, size, "Image type: %s, input size: %d, expected: %d, got: %d",
|
||||
mapping.name, mapping.inputSize, mapping.outputSize, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageType_BasePackages(t *testing.T) {
|
||||
pkgMaps := []struct {
|
||||
name string
|
||||
basePackages []string
|
||||
bootloaderPackages []string
|
||||
excludedPackages []string
|
||||
bootable bool
|
||||
}{
|
||||
{
|
||||
name: "ami",
|
||||
basePackages: []string{
|
||||
"@Core",
|
||||
"chrony",
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"langpacks-en",
|
||||
"libxcrypt-compat",
|
||||
"xfsprogs",
|
||||
"cloud-init",
|
||||
"checkpolicy",
|
||||
"net-tools",
|
||||
},
|
||||
bootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"grub2-pc",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
bootable: true,
|
||||
},
|
||||
{
|
||||
name: "openstack",
|
||||
basePackages: []string{
|
||||
"@Core",
|
||||
"chrony",
|
||||
"kernel",
|
||||
"selinux-policy-targeted",
|
||||
"spice-vdagent",
|
||||
"qemu-guest-agent",
|
||||
"xen-libs",
|
||||
"langpacks-en",
|
||||
"cloud-init",
|
||||
"libdrm",
|
||||
},
|
||||
bootloaderPackages: []string{
|
||||
"dracut-config-generic",
|
||||
"grub2-pc",
|
||||
},
|
||||
excludedPackages: []string{
|
||||
"dracut-config-rescue",
|
||||
"geolite2-city",
|
||||
"geolite2-country",
|
||||
"zram-generator-defaults",
|
||||
},
|
||||
bootable: true,
|
||||
},
|
||||
}
|
||||
distro := fedora33.New()
|
||||
arch, err := distro.GetArch("x86_64")
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, pkgMap := range pkgMaps {
|
||||
imgType, err := arch.GetImageType(pkgMap.name)
|
||||
assert.NoError(t, err)
|
||||
basePackages, excludedPackages := imgType.Packages(blueprint.Blueprint{})
|
||||
assert.Equalf(
|
||||
t,
|
||||
append(pkgMap.basePackages, pkgMap.bootloaderPackages...),
|
||||
basePackages,
|
||||
"image type: %s",
|
||||
pkgMap.name,
|
||||
)
|
||||
assert.Equalf(t, pkgMap.excludedPackages, excludedPackages, "image type: %s", pkgMap.name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDistro_Manifest(t *testing.T) {
|
||||
distro_test_common.TestDistro_Manifest(t, "../../../test/cases/", "fedora_33*", fedora33.New())
|
||||
}
|
||||
|
||||
func TestFedora33_ListArches(t *testing.T) {
|
||||
distro := fedora33.New()
|
||||
arches := distro.ListArches()
|
||||
assert.Equal(t, []string{"aarch64", "x86_64"}, arches)
|
||||
}
|
||||
|
||||
func TestFedora33_GetArch(t *testing.T) {
|
||||
distro := fedora33.New()
|
||||
arches := []struct {
|
||||
name string
|
||||
errorExpected bool
|
||||
}{
|
||||
{
|
||||
name: "x86_64",
|
||||
},
|
||||
{
|
||||
name: "aarch64",
|
||||
},
|
||||
{
|
||||
name: "foo-arch",
|
||||
errorExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, a := range arches {
|
||||
actualArch, err := distro.GetArch(a.name)
|
||||
if !a.errorExpected {
|
||||
assert.Equal(t, a.name, actualArch.Name())
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Nil(t, actualArch)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFedora33_Name(t *testing.T) {
|
||||
distro := fedora33.New()
|
||||
assert.Equal(t, "fedora-33", distro.Name())
|
||||
}
|
||||
|
||||
func TestFedora33_ModulePlatformID(t *testing.T) {
|
||||
distro := fedora33.New()
|
||||
assert.Equal(t, "platform:f33", distro.ModulePlatformID())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue