diff --git a/internal/common/types.go b/internal/common/types.go index 095520462..27edc90b1 100644 --- a/internal/common/types.go +++ b/internal/common/types.go @@ -80,12 +80,6 @@ func toStringHelper(mapping map[string]int, tag int) (string, bool) { return "", false } -// See unmarshalHelper for introduction. Converts between string and TypeAlias(int) -func fromStringHelper(mapping map[string]int, stringInput string) (int, bool) { - value, exists := mapping[stringInput] - return value, exists -} - // Architecture represents one of the supported CPU architectures available for images // produced by osbuild-composer. It is represented as an integer because if it // was a string it would unmarshal from JSON just fine even in case that the architecture @@ -237,70 +231,6 @@ func (imgType ImageType) ToString() (string, bool) { return toStringHelper(getImageTypeMapping(), int(imgType)) } -type Distribution int - -// NOTE: If you want to add more constants here, don't forget to add a mapping below -const ( - Fedora30 Distribution = iota - Fedora31 - Fedora32 - RHEL81 - RHEL82 -) - -// getArchMapping is a helper function that defines the conversion from JSON string value -// to Distribution. -func getDistributionMapping() map[string]int { - // Don't forget to add module-platform-id mapping below - mapping := map[string]int{ - "fedora-30": int(Fedora30), - "fedora-31": int(Fedora31), - "fedora-32": int(Fedora32), - "rhel-8.1": int(RHEL81), - "rhel-8.2": int(RHEL82), - } - return mapping -} - -func (dist *Distribution) ModulePlatformID() (string, error) { - mapping := map[Distribution]string{ - // TODO: this could be refactored so we don't have these strings hard coded in two places - Fedora30: "platform:f30", - Fedora31: "platform:f31", - Fedora32: "platform:f32", - RHEL81: "platform:el8", - RHEL82: "platform:el8", - } - id, exists := mapping[*dist] - if !exists { - return "", &CustomTypeError{reason: "Distribution does not have a module platform ID assigned"} - } else { - return id, nil - } -} - -func (distro *Distribution) UnmarshalJSON(data []byte) error { - value, err := unmarshalHelper(data, " is not a valid JSON value", " is not a valid distribution", getDistributionMapping()) - if err != nil { - return err - } - *distro = Distribution(value) - return nil -} - -func (distro Distribution) MarshalJSON() ([]byte, error) { - return marshalHelper(int(distro), getDistributionMapping(), "is not a valid distribution tag") -} - -func (distro Distribution) ToString() (string, bool) { - return toStringHelper(getDistributionMapping(), int(distro)) -} - -func DistributionFromString(distro string) (Distribution, bool) { - tag, exists := fromStringHelper(getDistributionMapping(), distro) - return Distribution(tag), exists -} - type UploadTarget int // NOTE: If you want to add more constants here, don't forget to add a mapping below diff --git a/internal/distro/fedora30/distro.go b/internal/distro/fedora30/distro.go index 94b16e283..c011638cc 100644 --- a/internal/distro/fedora30/distro.go +++ b/internal/distro/fedora30/distro.go @@ -5,7 +5,6 @@ import ( "sort" "strconv" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" @@ -16,45 +15,45 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -type arch struct { - Name string - BootloaderPackages []string - BuildPackages []string - UEFI bool -} - -type output struct { - Name string - MimeType string - Packages []string - ExcludedPackages []string - EnabledServices []string - DisabledServices []string - KernelOptions string - Bootable bool - DefaultSize uint64 - Assembler func(uefi bool, size uint64) *osbuild.Assembler -} - -const Distro = common.Fedora30 -const ModulePlatformID = "platform:f30" +const name = "fedora-30" +const modulePlatformID = "platform:f30" type Fedora30 struct { arches map[string]arch - outputs map[string]output + imageTypes map[string]imageType buildPackages []string } -type Fedora30Arch struct { +type arch struct { + name string + bootloaderPackages []string + buildPackages []string + uefi bool +} + +type imageType struct { + name string + mimeType string + packages []string + excludedPackages []string + enabledServices []string + disabledServices []string + kernelOptions string + bootable bool + defaultSize uint64 + assembler func(uefi bool, size uint64) *osbuild.Assembler +} + +type fedora30Arch struct { name string distro *Fedora30 arch *arch } -type Fedora30ImageType struct { - name string - arch *Fedora30Arch - output *output +type fedora30ImageType struct { + name string + arch *fedora30Arch + imageType *imageType } func (d *Fedora30) GetArch(arch string) (distro.Arch, error) { @@ -63,75 +62,88 @@ func (d *Fedora30) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &Fedora30Arch{ + return &fedora30Arch{ name: arch, distro: d, arch: &a, }, nil } -func (a *Fedora30Arch) Name() string { +func (a *fedora30Arch) Name() string { return a.name } -func (a *Fedora30Arch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *fedora30Arch) ListImageTypes() []string { + formats := make([]string, 0, len(a.distro.imageTypes)) + for name := range a.distro.imageTypes { + formats = append(formats, name) + } + sort.Strings(formats) + return formats } -func (a *Fedora30Arch) GetImageType(imageType string) (distro.ImageType, error) { - t, exists := a.distro.outputs[imageType] +func (a *fedora30Arch) GetImageType(imageType string) (distro.ImageType, error) { + t, exists := a.distro.imageTypes[imageType] if !exists { return nil, errors.New("invalid image type: " + imageType) } - return &Fedora30ImageType{ - name: imageType, - arch: a, - output: &t, + return &fedora30ImageType{ + name: imageType, + arch: a, + imageType: &t, }, nil } -func (t *Fedora30ImageType) Name() string { +func (t *fedora30ImageType) Name() string { return t.name } -func (t *Fedora30ImageType) Filename() string { - return t.output.Name +func (t *fedora30ImageType) Filename() string { + return t.imageType.name } -func (t *Fedora30ImageType) MIMEType() string { - return t.output.MimeType +func (t *fedora30ImageType) MIMEType() string { + return t.imageType.mimeType } -func (t *Fedora30ImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *fedora30ImageType) 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.imageType.defaultSize + } + return size } -func (t *Fedora30ImageType) BasePackages() ([]string, []string) { - packages := t.output.Packages - if t.output.Bootable { - packages = append(packages, t.arch.arch.BootloaderPackages...) +func (t *fedora30ImageType) BasePackages() ([]string, []string) { + packages := t.imageType.packages + if t.imageType.bootable { + packages = append(packages, t.arch.arch.bootloaderPackages...) } - return packages, t.output.ExcludedPackages + return packages, t.imageType.excludedPackages } -func (t *Fedora30ImageType) BuildPackages() []string { - return append(t.arch.distro.buildPackages, t.arch.arch.BuildPackages...) +func (t *fedora30ImageType) BuildPackages() []string { + return append(t.arch.distro.buildPackages, t.arch.arch.buildPackages...) } -func (t *Fedora30ImageType) Manifest(c *blueprint.Customizations, +func (t *fedora30ImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - pipeline, err := t.arch.distro.pipeline(c, repos, packageSpecs, buildPackageSpecs, t.arch.name, t.name, size) + pipeline, err := t.pipeline(c, repos, packageSpecs, buildPackageSpecs, size) if err != nil { return nil, err } return &osbuild.Manifest{ - Sources: *t.arch.distro.sources(append(packageSpecs, buildPackageSpecs...)), + Sources: *sources(append(packageSpecs, buildPackageSpecs...)), Pipeline: *pipeline, }, nil } @@ -140,7 +152,7 @@ func New() *Fedora30 { const GigaByte = 1024 * 1024 * 1024 r := Fedora30{ - outputs: map[string]output{}, + imageTypes: map[string]imageType{}, buildPackages: []string{ "dnf", "dosfstools", @@ -152,32 +164,32 @@ func New() *Fedora30 { }, arches: map[string]arch{ "x86_64": arch{ - Name: "x86_64", - BootloaderPackages: []string{ + name: "x86_64", + bootloaderPackages: []string{ "grub2-pc", }, - BuildPackages: []string{ + buildPackages: []string{ "grub2-pc", }, }, "aarch64": arch{ - Name: "aarch64", - BootloaderPackages: []string{ + name: "aarch64", + bootloaderPackages: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", "grub2-tools", "shim-aa64", }, - UEFI: true, + uefi: true, }, }, } - r.outputs["ami"] = output{ - Name: "image.raw.xz", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ami"] = imageType{ + name: "image.raw.xz", + mimeType: "application/octet-stream", + packages: []string{ "@Core", "chrony", "kernel", @@ -189,24 +201,24 @@ func New() *Fedora30 { "checkpolicy", "net-tools", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + 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, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) }, } - r.outputs["ext4-filesystem"] = output{ - Name: "filesystem.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ext4-filesystem"] = imageType{ + name: "filesystem.img", + mimeType: "application/octet-stream", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -214,19 +226,19 @@ func New() *Fedora30 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, } - r.outputs["partitioned-disk"] = output{ - Name: "disk.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["partitioned-disk"] = imageType{ + name: "disk.img", + mimeType: "application/octet-stream", + packages: []string{ "@core", "chrony", "firewalld", @@ -234,21 +246,21 @@ func New() *Fedora30 { "langpacks-en", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw", "disk.img", uefi, size) }, } - r.outputs["qcow2"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["qcow2"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "kernel-core", "@Fedora Cloud Server", "chrony", @@ -257,25 +269,25 @@ func New() *Fedora30 { "selinux-policy-targeted", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", "etables", "firewalld", "gobject-introspection", "plymouth", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["openstack"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["openstack"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "@Core", "chrony", "kernel", @@ -287,21 +299,21 @@ func New() *Fedora30 { "cloud-init", "libdrm", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["tar"] = output{ - Name: "root.tar.xz", - MimeType: "application/x-tar", - Packages: []string{ + r.imageTypes["tar"] = imageType{ + name: "root.tar.xz", + mimeType: "application/x-tar", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -309,19 +321,19 @@ func New() *Fedora30 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, } - r.outputs["vhd"] = output{ - Name: "disk.vhd", - MimeType: "application/x-vhd", - Packages: []string{ + r.imageTypes["vhd"] = imageType{ + name: "disk.vhd", + mimeType: "application/x-vhd", + packages: []string{ "@Core", "chrony", "kernel", @@ -335,30 +347,30 @@ func New() *Fedora30 { "glibc-all-langpacks", "dracut-config-generic", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + enabledServices: []string{ "sshd", "waagent", // needed to run in Azure }, - DisabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vpc", "disk.vhd", uefi, size) }, } - r.outputs["vmdk"] = output{ - Name: "disk.vmdk", - MimeType: "application/x-vmdk", - Packages: []string{ + r.imageTypes["vmdk"] = imageType{ + name: "disk.vmdk", + mimeType: "application/x-vmdk", + packages: []string{ "@core", "chrony", "firewalld", @@ -367,13 +379,13 @@ func New() *Fedora30 { "open-vm-tools", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) }, } @@ -382,92 +394,37 @@ func New() *Fedora30 { } func (r *Fedora30) Name() string { - name, exists := Distro.ToString() - if !exists { - panic("Fatal error, hardcoded distro value in fedora30 package is not valid!") - } return name } -func (r *Fedora30) Distribution() common.Distribution { - return Distro -} - func (r *Fedora30) ModulePlatformID() string { - return ModulePlatformID -} - -func (r *Fedora30) ListOutputFormats() []string { - formats := make([]string, 0, len(r.outputs)) - for name := range r.outputs { - formats = append(formats, name) - } - sort.Strings(formats) - return formats + return modulePlatformID } func (r *Fedora30) FilenameFromType(outputFormat string) (string, string, error) { - if output, exists := r.outputs[outputFormat]; exists { - return output.Name, output.MimeType, nil + if output, exists := r.imageTypes[outputFormat]; exists { + return output.name, output.mimeType, nil } return "", "", errors.New("invalid output format: " + outputFormat) } -func (r *Fedora30) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - const MegaByte = 1024 * 1024 - // Microsoft Azure requires vhd images to be rounded up to the nearest MB - if outputFormat == "vhd" && size%MegaByte != 0 { - size = (size/MegaByte + 1) * MegaByte +func sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + files := &osbuild.FilesSource{ + URLs: make(map[string]string), } - if size == 0 { - size = r.outputs[outputFormat].DefaultSize + for _, pkg := range packages { + files.URLs[pkg.Checksum] = pkg.RemoteLocation + } + return &osbuild.Sources{ + "org.osbuild.files": files, } - return size } -func (r *Fedora30) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, nil, errors.New("invalid output format: " + outputFormat) - } - - packages := output.Packages - if output.Bootable { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, nil, errors.New("invalid architecture: " + outputArchitecture) - } - - packages = append(packages, arch.BootloaderPackages...) - } - - return packages, output.ExcludedPackages, nil -} - -func (r *Fedora30) BuildPackages(outputArchitecture string) ([]string, error) { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - - return append(r.buildPackages, arch.BuildPackages...), nil -} - -func (r *Fedora30) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, errors.New("invalid output format: " + outputFormat) - } - - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - +func (t *fedora30ImageType) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Pipeline, error) { p := &osbuild.Pipeline{} - p.SetBuild(r.buildPipeline(repos, arch, buildPackageSpecs), "org.osbuild.fedora30") + p.SetBuild(t.buildPipeline(repos, *t.arch.arch, buildPackageSpecs), "org.osbuild.fedora30") - p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) + p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch.arch, repos, packageSpecs))) p.AddStage(osbuild.NewFixBLSStage()) // TODO support setting all languages and install corresponding langpack-* package @@ -499,7 +456,7 @@ func (r *Fedora30) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if users := c.GetUsers(); len(users) > 0 { - options, err := r.userStageOptions(users) + options, err := t.userStageOptions(users) if err != nil { return nil, err } @@ -507,64 +464,36 @@ func (r *Fedora30) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if groups := c.GetGroups(); len(groups) > 0 { - p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if output.Bootable { - p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + if t.imageType.bootable { + p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.arch.uefi))) } - p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(output.KernelOptions, c.GetKernel(), arch.UEFI))) + p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(t.imageType.kernelOptions, c.GetKernel(), t.arch.arch.uefi))) - if services := c.GetServices(); services != nil || output.EnabledServices != nil { - p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services))) + if services := c.GetServices(); services != nil || t.imageType.enabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.imageType.enabledServices, t.imageType.disabledServices, services))) } if firewall := c.GetFirewall(); firewall != nil { - p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall))) } - p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions())) - p.Assembler = output.Assembler(arch.UEFI, size) + p.Assembler = t.imageType.assembler(t.arch.arch.uefi, size) return p, nil } -func (r *Fedora30) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - files := &osbuild.FilesSource{ - URLs: make(map[string]string), - } - for _, pkg := range packages { - files.URLs[pkg.Checksum] = pkg.RemoteLocation - } - return &osbuild.Sources{ - "org.osbuild.files": files, - } -} - -func (r *Fedora30) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (r *Fedora30) Runner() string { - return "org.osbuild.fedora30" -} - -func (r *Fedora30) buildPipeline(repos []rpmmd.RepoConfig, arch arch, packageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func (r *fedora30ImageType) buildPipeline(repos []rpmmd.RepoConfig, arch arch, packageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { p := &osbuild.Pipeline{} p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) return p } -func (r *Fedora30) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { +func (r *fedora30ImageType) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { var gpgKeys []string for _, repo := range repos { if repo.GPGKey == "" { @@ -584,7 +513,7 @@ func (r *Fedora30) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs [] } } -func (r *Fedora30) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { +func (r *fedora30ImageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { options := osbuild.UsersStageOptions{ Users: make(map[string]osbuild.UsersStageOptionsUser), } @@ -624,7 +553,7 @@ func (r *Fedora30) userStageOptions(users []blueprint.UserCustomization) (*osbui return &options, nil } -func (r *Fedora30) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { +func (r *fedora30ImageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, } @@ -644,7 +573,7 @@ func (r *Fedora30) groupStageOptions(groups []blueprint.GroupCustomization) *osb return &options } -func (r *Fedora30) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { +func (r *fedora30ImageType) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { options := osbuild.FirewallStageOptions{ Ports: firewall.Ports, } @@ -657,7 +586,7 @@ func (r *Fedora30) firewallStageOptions(firewall *blueprint.FirewallCustomizatio return &options } -func (r *Fedora30) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { +func (r *fedora30ImageType) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { if s != nil { enabledServices = append(enabledServices, s.Enabled...) disabledServices = append(disabledServices, s.Disabled...) @@ -668,7 +597,7 @@ func (r *Fedora30) systemdStageOptions(enabledServices, disabledServices []strin } } -func (r *Fedora30) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { +func (r *fedora30ImageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { options := osbuild.FSTabStageOptions{} options.AddFilesystem("76a22bf4-f153-4541-b6c7-0332c0dfaeac", "ext4", "/", "defaults", 1, 1) if uefi { @@ -677,7 +606,7 @@ func (r *Fedora30) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { return &options } -func (r *Fedora30) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { +func (r *fedora30ImageType) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac") if err != nil { panic("invalid UUID") @@ -702,7 +631,7 @@ func (r *Fedora30) grub2StageOptions(kernelOptions string, kernel *blueprint.Ker } } -func (r *Fedora30) selinuxStageOptions() *osbuild.SELinuxStageOptions { +func (r *fedora30ImageType) selinuxStageOptions() *osbuild.SELinuxStageOptions { return &osbuild.SELinuxStageOptions{ FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", } diff --git a/internal/distro/fedora30/distro_test.go b/internal/distro/fedora30/distro_test.go index ac8e89144..3c72a0e94 100644 --- a/internal/distro/fedora30/distro_test.go +++ b/internal/distro/fedora30/distro_test.go @@ -1,31 +1,11 @@ package fedora30_test import ( - "reflect" "testing" "github.com/osbuild/osbuild-composer/internal/distro/fedora30" ) -func TestListOutputFormats(t *testing.T) { - want := []string{ - "ami", - "ext4-filesystem", - "openstack", - "partitioned-disk", - "qcow2", - "tar", - "vhd", - "vmdk", - } - - f30 := fedora30.New() - - if got := f30.ListOutputFormats(); !reflect.DeepEqual(got, want) { - t.Errorf("ListOutputFormats() = %v, want %v", got, want) - } -} - func TestFilenameFromType(t *testing.T) { type args struct { outputFormat string diff --git a/internal/distro/fedora31/distro.go b/internal/distro/fedora31/distro.go index 1df1d92cf..7a65459a1 100644 --- a/internal/distro/fedora31/distro.go +++ b/internal/distro/fedora31/distro.go @@ -5,7 +5,6 @@ import ( "sort" "strconv" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" @@ -16,45 +15,45 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -type arch struct { - Name string - BootloaderPackages []string - BuildPackages []string - UEFI bool -} - -type output struct { - Name string - MimeType string - Packages []string - ExcludedPackages []string - EnabledServices []string - DisabledServices []string - KernelOptions string - Bootable bool - DefaultSize uint64 - Assembler func(uefi bool, size uint64) *osbuild.Assembler -} - -const Distro = common.Fedora31 -const ModulePlatformID = "platform:f31" +const name = "fedora-31" +const modulePlatformID = "platform:f31" type Fedora31 struct { arches map[string]arch - outputs map[string]output + imageTypes map[string]imageType buildPackages []string } -type Fedora31Arch struct { +type arch struct { + name string + bootloaderPackages []string + buildPackages []string + uefi bool +} + +type imageType struct { + name string + mimeType string + packages []string + excludedPackages []string + enabledServices []string + disabledServices []string + kernelOptions string + bootable bool + defaultSize uint64 + assembler func(uefi bool, size uint64) *osbuild.Assembler +} + +type fedora31Arch struct { name string distro *Fedora31 arch *arch } -type Fedora31ImageType struct { - name string - arch *Fedora31Arch - output *output +type fedora31ImageType struct { + name string + arch *fedora31Arch + imageType *imageType } func (d *Fedora31) GetArch(arch string) (distro.Arch, error) { @@ -63,75 +62,88 @@ func (d *Fedora31) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &Fedora31Arch{ + return &fedora31Arch{ name: arch, distro: d, arch: &a, }, nil } -func (a *Fedora31Arch) Name() string { +func (a *fedora31Arch) Name() string { return a.name } -func (a *Fedora31Arch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *fedora31Arch) ListImageTypes() []string { + formats := make([]string, 0, len(a.distro.imageTypes)) + for name := range a.distro.imageTypes { + formats = append(formats, name) + } + sort.Strings(formats) + return formats } -func (a *Fedora31Arch) GetImageType(imageType string) (distro.ImageType, error) { - t, exists := a.distro.outputs[imageType] +func (a *fedora31Arch) GetImageType(imageType string) (distro.ImageType, error) { + t, exists := a.distro.imageTypes[imageType] if !exists { return nil, errors.New("invalid image type: " + imageType) } - return &Fedora31ImageType{ - name: imageType, - arch: a, - output: &t, + return &fedora31ImageType{ + name: imageType, + arch: a, + imageType: &t, }, nil } -func (t *Fedora31ImageType) Name() string { +func (t *fedora31ImageType) Name() string { return t.name } -func (t *Fedora31ImageType) Filename() string { - return t.output.Name +func (t *fedora31ImageType) Filename() string { + return t.imageType.name } -func (t *Fedora31ImageType) MIMEType() string { - return t.output.MimeType +func (t *fedora31ImageType) MIMEType() string { + return t.imageType.mimeType } -func (t *Fedora31ImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *fedora31ImageType) 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.imageType.defaultSize + } + return size } -func (t *Fedora31ImageType) BasePackages() ([]string, []string) { - packages := t.output.Packages - if t.output.Bootable { - packages = append(packages, t.arch.arch.BootloaderPackages...) +func (t *fedora31ImageType) BasePackages() ([]string, []string) { + packages := t.imageType.packages + if t.imageType.bootable { + packages = append(packages, t.arch.arch.bootloaderPackages...) } - return packages, t.output.ExcludedPackages + return packages, t.imageType.excludedPackages } -func (t *Fedora31ImageType) BuildPackages() []string { - return append(t.arch.distro.buildPackages, t.arch.arch.BuildPackages...) +func (t *fedora31ImageType) BuildPackages() []string { + return append(t.arch.distro.buildPackages, t.arch.arch.buildPackages...) } -func (t *Fedora31ImageType) Manifest(c *blueprint.Customizations, +func (t *fedora31ImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - pipeline, err := t.arch.distro.pipeline(c, repos, packageSpecs, buildPackageSpecs, t.arch.name, t.name, size) + pipeline, err := t.pipeline(c, repos, packageSpecs, buildPackageSpecs, size) if err != nil { return nil, err } return &osbuild.Manifest{ - Sources: *t.arch.distro.sources(append(packageSpecs, buildPackageSpecs...)), + Sources: *sources(append(packageSpecs, buildPackageSpecs...)), Pipeline: *pipeline, }, nil } @@ -140,7 +152,7 @@ func New() *Fedora31 { const GigaByte = 1024 * 1024 * 1024 r := Fedora31{ - outputs: map[string]output{}, + imageTypes: map[string]imageType{}, buildPackages: []string{ "dnf", "dosfstools", @@ -152,32 +164,32 @@ func New() *Fedora31 { }, arches: map[string]arch{ "x86_64": arch{ - Name: "x86_64", - BootloaderPackages: []string{ + name: "x86_64", + bootloaderPackages: []string{ "grub2-pc", }, - BuildPackages: []string{ + buildPackages: []string{ "grub2-pc", }, }, "aarch64": arch{ - Name: "aarch64", - BootloaderPackages: []string{ + name: "aarch64", + bootloaderPackages: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", "grub2-tools", "shim-aa64", }, - UEFI: true, + uefi: true, }, }, } - r.outputs["ami"] = output{ - Name: "image.raw.xz", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ami"] = imageType{ + name: "image.raw.xz", + mimeType: "application/octet-stream", + packages: []string{ "@Core", "chrony", "kernel", @@ -189,24 +201,24 @@ func New() *Fedora31 { "checkpolicy", "net-tools", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + 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, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) }, } - r.outputs["ext4-filesystem"] = output{ - Name: "filesystem.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ext4-filesystem"] = imageType{ + name: "filesystem.img", + mimeType: "application/octet-stream", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -214,19 +226,19 @@ func New() *Fedora31 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, } - r.outputs["partitioned-disk"] = output{ - Name: "disk.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["partitioned-disk"] = imageType{ + name: "disk.img", + mimeType: "application/octet-stream", + packages: []string{ "@core", "chrony", "firewalld", @@ -234,21 +246,21 @@ func New() *Fedora31 { "langpacks-en", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw", "disk.img", uefi, size) }, } - r.outputs["qcow2"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["qcow2"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "kernel-core", "@Fedora Cloud Server", "chrony", @@ -257,25 +269,25 @@ func New() *Fedora31 { "selinux-policy-targeted", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", "etables", "firewalld", "gobject-introspection", "plymouth", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["openstack"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["openstack"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "@Core", "chrony", "kernel", @@ -287,21 +299,21 @@ func New() *Fedora31 { "cloud-init", "libdrm", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["tar"] = output{ - Name: "root.tar.xz", - MimeType: "application/x-tar", - Packages: []string{ + r.imageTypes["tar"] = imageType{ + name: "root.tar.xz", + mimeType: "application/x-tar", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -309,19 +321,19 @@ func New() *Fedora31 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, } - r.outputs["vhd"] = output{ - Name: "disk.vhd", - MimeType: "application/x-vhd", - Packages: []string{ + r.imageTypes["vhd"] = imageType{ + name: "disk.vhd", + mimeType: "application/x-vhd", + packages: []string{ "@Core", "chrony", "kernel", @@ -335,30 +347,30 @@ func New() *Fedora31 { "glibc-all-langpacks", "dracut-config-generic", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + enabledServices: []string{ "sshd", "waagent", // needed to run in Azure }, - DisabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vpc", "disk.vhd", uefi, size) }, } - r.outputs["vmdk"] = output{ - Name: "disk.vmdk", - MimeType: "application/x-vmdk", - Packages: []string{ + r.imageTypes["vmdk"] = imageType{ + name: "disk.vmdk", + mimeType: "application/x-vmdk", + packages: []string{ "@core", "chrony", "firewalld", @@ -367,13 +379,13 @@ func New() *Fedora31 { "open-vm-tools", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) }, } @@ -382,92 +394,37 @@ func New() *Fedora31 { } func (r *Fedora31) Name() string { - name, exists := Distro.ToString() - if !exists { - panic("Fatal error, hardcoded distro value in fedora31 package is not valid!") - } return name } -func (r *Fedora31) Distribution() common.Distribution { - return Distro -} - func (r *Fedora31) ModulePlatformID() string { - return ModulePlatformID -} - -func (r *Fedora31) ListOutputFormats() []string { - formats := make([]string, 0, len(r.outputs)) - for name := range r.outputs { - formats = append(formats, name) - } - sort.Strings(formats) - return formats + return modulePlatformID } func (r *Fedora31) FilenameFromType(outputFormat string) (string, string, error) { - if output, exists := r.outputs[outputFormat]; exists { - return output.Name, output.MimeType, nil + if output, exists := r.imageTypes[outputFormat]; exists { + return output.name, output.mimeType, nil } return "", "", errors.New("invalid output format: " + outputFormat) } -func (r *Fedora31) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - const MegaByte = 1024 * 1024 - // Microsoft Azure requires vhd images to be rounded up to the nearest MB - if outputFormat == "vhd" && size%MegaByte != 0 { - size = (size/MegaByte + 1) * MegaByte +func sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + files := &osbuild.FilesSource{ + URLs: make(map[string]string), } - if size == 0 { - size = r.outputs[outputFormat].DefaultSize + for _, pkg := range packages { + files.URLs[pkg.Checksum] = pkg.RemoteLocation + } + return &osbuild.Sources{ + "org.osbuild.files": files, } - return size } -func (r *Fedora31) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, nil, errors.New("invalid output format: " + outputFormat) - } - - packages := output.Packages - if output.Bootable { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, nil, errors.New("invalid architecture: " + outputArchitecture) - } - - packages = append(packages, arch.BootloaderPackages...) - } - - return packages, output.ExcludedPackages, nil -} - -func (r *Fedora31) BuildPackages(outputArchitecture string) ([]string, error) { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - - return append(r.buildPackages, arch.BuildPackages...), nil -} - -func (r *Fedora31) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, errors.New("invalid output format: " + outputFormat) - } - - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - +func (t *fedora31ImageType) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Pipeline, error) { p := &osbuild.Pipeline{} - p.SetBuild(r.buildPipeline(repos, arch, buildPackageSpecs), "org.osbuild.fedora31") + p.SetBuild(t.buildPipeline(repos, *t.arch.arch, buildPackageSpecs), "org.osbuild.fedora31") - p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) + p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch.arch, repos, packageSpecs))) p.AddStage(osbuild.NewFixBLSStage()) // TODO support setting all languages and install corresponding langpack-* package @@ -499,7 +456,7 @@ func (r *Fedora31) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if users := c.GetUsers(); len(users) > 0 { - options, err := r.userStageOptions(users) + options, err := t.userStageOptions(users) if err != nil { return nil, err } @@ -507,64 +464,36 @@ func (r *Fedora31) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if groups := c.GetGroups(); len(groups) > 0 { - p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if output.Bootable { - p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + if t.imageType.bootable { + p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.arch.uefi))) } - p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(output.KernelOptions, c.GetKernel(), arch.UEFI))) + p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(t.imageType.kernelOptions, c.GetKernel(), t.arch.arch.uefi))) - if services := c.GetServices(); services != nil || output.EnabledServices != nil { - p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services))) + if services := c.GetServices(); services != nil || t.imageType.enabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.imageType.enabledServices, t.imageType.disabledServices, services))) } if firewall := c.GetFirewall(); firewall != nil { - p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall))) } - p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions())) - p.Assembler = output.Assembler(arch.UEFI, size) + p.Assembler = t.imageType.assembler(t.arch.arch.uefi, size) return p, nil } -func (r *Fedora31) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - files := &osbuild.FilesSource{ - URLs: make(map[string]string), - } - for _, pkg := range packages { - files.URLs[pkg.Checksum] = pkg.RemoteLocation - } - return &osbuild.Sources{ - "org.osbuild.files": files, - } -} - -func (r *Fedora31) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (r *Fedora31) Runner() string { - return "org.osbuild.fedora31" -} - -func (r *Fedora31) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func (r *fedora31ImageType) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { p := &osbuild.Pipeline{} p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, buildPackageSpecs))) return p } -func (r *Fedora31) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { +func (r *fedora31ImageType) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { var gpgKeys []string for _, repo := range repos { if repo.GPGKey == "" { @@ -584,7 +513,7 @@ func (r *Fedora31) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs [] } } -func (r *Fedora31) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { +func (r *fedora31ImageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { options := osbuild.UsersStageOptions{ Users: make(map[string]osbuild.UsersStageOptionsUser), } @@ -624,7 +553,7 @@ func (r *Fedora31) userStageOptions(users []blueprint.UserCustomization) (*osbui return &options, nil } -func (r *Fedora31) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { +func (r *fedora31ImageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, } @@ -644,7 +573,7 @@ func (r *Fedora31) groupStageOptions(groups []blueprint.GroupCustomization) *osb return &options } -func (r *Fedora31) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { +func (r *fedora31ImageType) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { options := osbuild.FirewallStageOptions{ Ports: firewall.Ports, } @@ -657,7 +586,7 @@ func (r *Fedora31) firewallStageOptions(firewall *blueprint.FirewallCustomizatio return &options } -func (r *Fedora31) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { +func (r *fedora31ImageType) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { if s != nil { enabledServices = append(enabledServices, s.Enabled...) disabledServices = append(disabledServices, s.Disabled...) @@ -668,7 +597,7 @@ func (r *Fedora31) systemdStageOptions(enabledServices, disabledServices []strin } } -func (r *Fedora31) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { +func (r *fedora31ImageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { options := osbuild.FSTabStageOptions{} options.AddFilesystem("76a22bf4-f153-4541-b6c7-0332c0dfaeac", "ext4", "/", "defaults", 1, 1) if uefi { @@ -677,7 +606,7 @@ func (r *Fedora31) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { return &options } -func (r *Fedora31) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { +func (r *fedora31ImageType) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac") if err != nil { panic("invalid UUID") @@ -702,7 +631,7 @@ func (r *Fedora31) grub2StageOptions(kernelOptions string, kernel *blueprint.Ker } } -func (r *Fedora31) selinuxStageOptions() *osbuild.SELinuxStageOptions { +func (r *fedora31ImageType) selinuxStageOptions() *osbuild.SELinuxStageOptions { return &osbuild.SELinuxStageOptions{ FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", } diff --git a/internal/distro/fedora31/distro_test.go b/internal/distro/fedora31/distro_test.go index 0bddb1020..7332a10f4 100644 --- a/internal/distro/fedora31/distro_test.go +++ b/internal/distro/fedora31/distro_test.go @@ -1,31 +1,11 @@ package fedora31_test import ( - "reflect" "testing" "github.com/osbuild/osbuild-composer/internal/distro/fedora31" ) -func TestListOutputFormats(t *testing.T) { - want := []string{ - "ami", - "ext4-filesystem", - "openstack", - "partitioned-disk", - "qcow2", - "tar", - "vhd", - "vmdk", - } - - f31 := fedora31.New() - - if got := f31.ListOutputFormats(); !reflect.DeepEqual(got, want) { - t.Errorf("ListOutputFormats() = %v, want %v", got, want) - } -} - func TestFilenameFromType(t *testing.T) { type args struct { outputFormat string diff --git a/internal/distro/fedora32/distro.go b/internal/distro/fedora32/distro.go index 74afb9610..6de8d3f7f 100644 --- a/internal/distro/fedora32/distro.go +++ b/internal/distro/fedora32/distro.go @@ -5,7 +5,6 @@ import ( "sort" "strconv" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" @@ -16,45 +15,45 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -type arch struct { - Name string - BootloaderPackages []string - BuildPackages []string - UEFI bool -} - -type output struct { - Name string - MimeType string - Packages []string - ExcludedPackages []string - EnabledServices []string - DisabledServices []string - KernelOptions string - Bootable bool - DefaultSize uint64 - Assembler func(uefi bool, size uint64) *osbuild.Assembler -} - -const Distro = common.Fedora32 -const ModulePlatformID = "platform:f32" +const name = "fedora-32" +const modulePlatformID = "platform:f32" type Fedora32 struct { arches map[string]arch - outputs map[string]output + imageTypes map[string]imageType buildPackages []string } -type Fedora32Arch struct { +type arch struct { + name string + bootloaderPackages []string + buildPackages []string + uefi bool +} + +type imageType struct { + name string + mimeType string + packages []string + excludedPackages []string + enabledServices []string + disabledServices []string + kernelOptions string + bootable bool + defaultSize uint64 + assembler func(uefi bool, size uint64) *osbuild.Assembler +} + +type fedora32Arch struct { name string distro *Fedora32 arch *arch } -type Fedora32ImageType struct { - name string - arch *Fedora32Arch - output *output +type fedora32ImageType struct { + name string + arch *fedora32Arch + imageType *imageType } func (d *Fedora32) GetArch(arch string) (distro.Arch, error) { @@ -63,75 +62,88 @@ func (d *Fedora32) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &Fedora32Arch{ + return &fedora32Arch{ name: arch, distro: d, arch: &a, }, nil } -func (a *Fedora32Arch) Name() string { +func (a *fedora32Arch) Name() string { return a.name } -func (a *Fedora32Arch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *fedora32Arch) ListImageTypes() []string { + formats := make([]string, 0, len(a.distro.imageTypes)) + for name := range a.distro.imageTypes { + formats = append(formats, name) + } + sort.Strings(formats) + return formats } -func (a *Fedora32Arch) GetImageType(imageType string) (distro.ImageType, error) { - t, exists := a.distro.outputs[imageType] +func (a *fedora32Arch) GetImageType(imageType string) (distro.ImageType, error) { + t, exists := a.distro.imageTypes[imageType] if !exists { return nil, errors.New("invalid image type: " + imageType) } - return &Fedora32ImageType{ - name: imageType, - arch: a, - output: &t, + return &fedora32ImageType{ + name: imageType, + arch: a, + imageType: &t, }, nil } -func (t *Fedora32ImageType) Name() string { +func (t *fedora32ImageType) Name() string { return t.name } -func (t *Fedora32ImageType) Filename() string { - return t.output.Name +func (t *fedora32ImageType) Filename() string { + return t.imageType.name } -func (t *Fedora32ImageType) MIMEType() string { - return t.output.MimeType +func (t *fedora32ImageType) MIMEType() string { + return t.imageType.mimeType } -func (t *Fedora32ImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *fedora32ImageType) 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.imageType.defaultSize + } + return size } -func (t *Fedora32ImageType) BasePackages() ([]string, []string) { - packages := t.output.Packages - if t.output.Bootable { - packages = append(packages, t.arch.arch.BootloaderPackages...) +func (t *fedora32ImageType) BasePackages() ([]string, []string) { + packages := t.imageType.packages + if t.imageType.bootable { + packages = append(packages, t.arch.arch.bootloaderPackages...) } - return packages, t.output.ExcludedPackages + return packages, t.imageType.excludedPackages } -func (t *Fedora32ImageType) BuildPackages() []string { - return append(t.arch.distro.buildPackages, t.arch.arch.BuildPackages...) +func (t *fedora32ImageType) BuildPackages() []string { + return append(t.arch.distro.buildPackages, t.arch.arch.buildPackages...) } -func (t *Fedora32ImageType) Manifest(c *blueprint.Customizations, +func (t *fedora32ImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - pipeline, err := t.arch.distro.pipeline(c, repos, packageSpecs, buildPackageSpecs, t.arch.name, t.name, size) + pipeline, err := t.pipeline(c, repos, packageSpecs, buildPackageSpecs, size) if err != nil { return nil, err } return &osbuild.Manifest{ - Sources: *t.arch.distro.sources(append(packageSpecs, buildPackageSpecs...)), + Sources: *sources(append(packageSpecs, buildPackageSpecs...)), Pipeline: *pipeline, }, nil } @@ -140,7 +152,7 @@ func New() *Fedora32 { const GigaByte = 1024 * 1024 * 1024 r := Fedora32{ - outputs: map[string]output{}, + imageTypes: map[string]imageType{}, buildPackages: []string{ "dnf", "dosfstools", @@ -152,32 +164,32 @@ func New() *Fedora32 { }, arches: map[string]arch{ "x86_64": arch{ - Name: "x86_64", - BootloaderPackages: []string{ + name: "x86_64", + bootloaderPackages: []string{ "grub2-pc", }, - BuildPackages: []string{ + buildPackages: []string{ "grub2-pc", }, }, "aarch64": arch{ - Name: "aarch64", - BootloaderPackages: []string{ + name: "aarch64", + bootloaderPackages: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", "grub2-tools", "shim-aa64", }, - UEFI: true, + uefi: true, }, }, } - r.outputs["ami"] = output{ - Name: "image.raw.xz", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ami"] = imageType{ + name: "image.raw.xz", + mimeType: "application/octet-stream", + packages: []string{ "@Core", "chrony", "kernel", @@ -189,24 +201,24 @@ func New() *Fedora32 { "checkpolicy", "net-tools", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + 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, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) }, } - r.outputs["ext4-filesystem"] = output{ - Name: "filesystem.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ext4-filesystem"] = imageType{ + name: "filesystem.img", + mimeType: "application/octet-stream", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -214,19 +226,19 @@ func New() *Fedora32 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, } - r.outputs["partitioned-disk"] = output{ - Name: "disk.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["partitioned-disk"] = imageType{ + name: "disk.img", + mimeType: "application/octet-stream", + packages: []string{ "@core", "chrony", "firewalld", @@ -234,21 +246,21 @@ func New() *Fedora32 { "langpacks-en", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw", "disk.img", uefi, size) }, } - r.outputs["qcow2"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["qcow2"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "kernel-core", "@Fedora Cloud Server", "chrony", @@ -257,25 +269,25 @@ func New() *Fedora32 { "selinux-policy-targeted", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", "etables", "firewalld", "gobject-introspection", "plymouth", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["openstack"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["openstack"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "@Core", "chrony", "kernel", @@ -287,21 +299,21 @@ func New() *Fedora32 { "cloud-init", "libdrm", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["tar"] = output{ - Name: "root.tar.xz", - MimeType: "application/x-tar", - Packages: []string{ + r.imageTypes["tar"] = imageType{ + name: "root.tar.xz", + mimeType: "application/x-tar", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -309,19 +321,19 @@ func New() *Fedora32 { "chrony", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: false, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: false, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, } - r.outputs["vhd"] = output{ - Name: "disk.vhd", - MimeType: "application/x-vhd", - Packages: []string{ + r.imageTypes["vhd"] = imageType{ + name: "disk.vhd", + mimeType: "application/x-vhd", + packages: []string{ "@Core", "chrony", "kernel", @@ -335,30 +347,30 @@ func New() *Fedora32 { "glibc-all-langpacks", "dracut-config-generic", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - EnabledServices: []string{ + enabledServices: []string{ "sshd", "waagent", // needed to run in Azure }, - DisabledServices: []string{ + 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, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vpc", "disk.vhd", uefi, size) }, } - r.outputs["vmdk"] = output{ - Name: "disk.vmdk", - MimeType: "application/x-vmdk", - Packages: []string{ + r.imageTypes["vmdk"] = imageType{ + name: "disk.vmdk", + mimeType: "application/x-vmdk", + packages: []string{ "@core", "chrony", "firewalld", @@ -367,13 +379,13 @@ func New() *Fedora32 { "open-vm-tools", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - KernelOptions: "ro biosdevname=0 net.ifnames=0", - Bootable: true, - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + kernelOptions: "ro biosdevname=0 net.ifnames=0", + bootable: true, + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) }, } @@ -382,92 +394,37 @@ func New() *Fedora32 { } func (r *Fedora32) Name() string { - name, exists := Distro.ToString() - if !exists { - panic("Fatal error, hardcoded distro value in fedora32 package is not valid!") - } return name } -func (r *Fedora32) Distribution() common.Distribution { - return Distro -} - func (r *Fedora32) ModulePlatformID() string { - return ModulePlatformID -} - -func (r *Fedora32) ListOutputFormats() []string { - formats := make([]string, 0, len(r.outputs)) - for name := range r.outputs { - formats = append(formats, name) - } - sort.Strings(formats) - return formats + return modulePlatformID } func (r *Fedora32) FilenameFromType(outputFormat string) (string, string, error) { - if output, exists := r.outputs[outputFormat]; exists { - return output.Name, output.MimeType, nil + if output, exists := r.imageTypes[outputFormat]; exists { + return output.name, output.mimeType, nil } return "", "", errors.New("invalid output format: " + outputFormat) } -func (r *Fedora32) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - const MegaByte = 1024 * 1024 - // Microsoft Azure requires vhd images to be rounded up to the nearest MB - if outputFormat == "vhd" && size%MegaByte != 0 { - size = (size/MegaByte + 1) * MegaByte +func sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + files := &osbuild.FilesSource{ + URLs: make(map[string]string), } - if size == 0 { - size = r.outputs[outputFormat].DefaultSize + for _, pkg := range packages { + files.URLs[pkg.Checksum] = pkg.RemoteLocation + } + return &osbuild.Sources{ + "org.osbuild.files": files, } - return size } -func (r *Fedora32) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, nil, errors.New("invalid output format: " + outputFormat) - } - - packages := output.Packages - if output.Bootable { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, nil, errors.New("invalid architecture: " + outputArchitecture) - } - - packages = append(packages, arch.BootloaderPackages...) - } - - return packages, output.ExcludedPackages, nil -} - -func (r *Fedora32) BuildPackages(outputArchitecture string) ([]string, error) { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - - return append(r.buildPackages, arch.BuildPackages...), nil -} - -func (r *Fedora32) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, errors.New("invalid output format: " + outputFormat) - } - - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - +func (t *fedora32ImageType) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Pipeline, error) { p := &osbuild.Pipeline{} - p.SetBuild(r.buildPipeline(repos, arch, buildPackageSpecs), "org.osbuild.fedora32") + p.SetBuild(t.buildPipeline(repos, *t.arch.arch, buildPackageSpecs), "org.osbuild.fedora32") - p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) + p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch.arch, repos, packageSpecs))) p.AddStage(osbuild.NewFixBLSStage()) // TODO support setting all languages and install corresponding langpack-* package @@ -499,7 +456,7 @@ func (r *Fedora32) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if users := c.GetUsers(); len(users) > 0 { - options, err := r.userStageOptions(users) + options, err := t.userStageOptions(users) if err != nil { return nil, err } @@ -507,64 +464,36 @@ func (r *Fedora32) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfi } if groups := c.GetGroups(); len(groups) > 0 { - p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if output.Bootable { - p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + if t.imageType.bootable { + p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.arch.uefi))) } - p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(output.KernelOptions, c.GetKernel(), arch.UEFI))) + p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(t.imageType.kernelOptions, c.GetKernel(), t.arch.arch.uefi))) - if services := c.GetServices(); services != nil || output.EnabledServices != nil { - p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services))) + if services := c.GetServices(); services != nil || t.imageType.enabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.imageType.enabledServices, t.imageType.disabledServices, services))) } if firewall := c.GetFirewall(); firewall != nil { - p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall))) } - p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions())) - p.Assembler = output.Assembler(arch.UEFI, size) + p.Assembler = t.imageType.assembler(t.arch.arch.uefi, size) return p, nil } -func (r *Fedora32) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - files := &osbuild.FilesSource{ - URLs: make(map[string]string), - } - for _, pkg := range packages { - files.URLs[pkg.Checksum] = pkg.RemoteLocation - } - return &osbuild.Sources{ - "org.osbuild.files": files, - } -} - -func (r *Fedora32) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (r *Fedora32) Runner() string { - return "org.osbuild.fedora32" -} - -func (r *Fedora32) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func (r *fedora32ImageType) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { p := &osbuild.Pipeline{} p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, buildPackageSpecs))) return p } -func (r *Fedora32) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { +func (r *fedora32ImageType) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { var gpgKeys []string for _, repo := range repos { if repo.GPGKey == "" { @@ -584,7 +513,7 @@ func (r *Fedora32) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs [] } } -func (r *Fedora32) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { +func (r *fedora32ImageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { options := osbuild.UsersStageOptions{ Users: make(map[string]osbuild.UsersStageOptionsUser), } @@ -624,7 +553,7 @@ func (r *Fedora32) userStageOptions(users []blueprint.UserCustomization) (*osbui return &options, nil } -func (r *Fedora32) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { +func (r *fedora32ImageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, } @@ -644,7 +573,7 @@ func (r *Fedora32) groupStageOptions(groups []blueprint.GroupCustomization) *osb return &options } -func (r *Fedora32) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { +func (r *fedora32ImageType) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { options := osbuild.FirewallStageOptions{ Ports: firewall.Ports, } @@ -657,7 +586,7 @@ func (r *Fedora32) firewallStageOptions(firewall *blueprint.FirewallCustomizatio return &options } -func (r *Fedora32) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { +func (r *fedora32ImageType) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { if s != nil { enabledServices = append(enabledServices, s.Enabled...) disabledServices = append(disabledServices, s.Disabled...) @@ -668,7 +597,7 @@ func (r *Fedora32) systemdStageOptions(enabledServices, disabledServices []strin } } -func (r *Fedora32) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { +func (r *fedora32ImageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { options := osbuild.FSTabStageOptions{} options.AddFilesystem("76a22bf4-f153-4541-b6c7-0332c0dfaeac", "ext4", "/", "defaults", 1, 1) if uefi { @@ -677,7 +606,7 @@ func (r *Fedora32) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { return &options } -func (r *Fedora32) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { +func (r *fedora32ImageType) grub2StageOptions(kernelOptions string, kernel *blueprint.KernelCustomization, uefi bool) *osbuild.GRUB2StageOptions { id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac") if err != nil { panic("invalid UUID") @@ -702,7 +631,7 @@ func (r *Fedora32) grub2StageOptions(kernelOptions string, kernel *blueprint.Ker } } -func (r *Fedora32) selinuxStageOptions() *osbuild.SELinuxStageOptions { +func (r *fedora32ImageType) selinuxStageOptions() *osbuild.SELinuxStageOptions { return &osbuild.SELinuxStageOptions{ FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", } diff --git a/internal/distro/fedora32/distro_test.go b/internal/distro/fedora32/distro_test.go index e01b049db..4c2f2bd8f 100644 --- a/internal/distro/fedora32/distro_test.go +++ b/internal/distro/fedora32/distro_test.go @@ -1,31 +1,11 @@ package fedora32_test import ( - "reflect" "testing" "github.com/osbuild/osbuild-composer/internal/distro/fedora32" ) -func TestListOutputFormats(t *testing.T) { - want := []string{ - "ami", - "ext4-filesystem", - "openstack", - "partitioned-disk", - "qcow2", - "tar", - "vhd", - "vmdk", - } - - f32 := fedora32.New() - - if got := f32.ListOutputFormats(); !reflect.DeepEqual(got, want) { - t.Errorf("ListOutputFormats() = %v, want %v", got, want) - } -} - func TestFilenameFromType(t *testing.T) { type args struct { outputFormat string diff --git a/internal/distro/fedoratest/distro.go b/internal/distro/fedoratest/distro.go index 158c33ae4..ac983add0 100644 --- a/internal/distro/fedoratest/distro.go +++ b/internal/distro/fedoratest/distro.go @@ -4,24 +4,24 @@ import ( "errors" "github.com/osbuild/osbuild-composer/internal/blueprint" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -const ModulePlatformID = "platform:f30" +const name = "fedora-30" +const modulePlatformID = "platform:f30" type FedoraTestDistro struct{} -type FedoraTestDistroArch struct { +type fedoraTestDistroArch struct { name string distro *FedoraTestDistro } -type FedoraTestDistroImageType struct { +type fedoraTestDistroImageType struct { name string - arch *FedoraTestDistroArch + arch *fedoraTestDistroArch } func (d *FedoraTestDistro) GetArch(arch string) (distro.Arch, error) { @@ -29,56 +29,56 @@ func (d *FedoraTestDistro) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &FedoraTestDistroArch{ + return &fedoraTestDistroArch{ name: arch, distro: d, }, nil } -func (a *FedoraTestDistroArch) Name() string { +func (a *fedoraTestDistroArch) Name() string { return a.name } -func (a *FedoraTestDistroArch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *fedoraTestDistroArch) ListImageTypes() []string { + return []string{"qcow2"} } -func (a *FedoraTestDistroArch) GetImageType(imageType string) (distro.ImageType, error) { +func (a *fedoraTestDistroArch) GetImageType(imageType string) (distro.ImageType, error) { if imageType != "qcow2" { return nil, errors.New("invalid image type: " + imageType) } - return &FedoraTestDistroImageType{ + return &fedoraTestDistroImageType{ name: imageType, arch: a, }, nil } -func (t *FedoraTestDistroImageType) Name() string { +func (t *fedoraTestDistroImageType) Name() string { return t.name } -func (t *FedoraTestDistroImageType) Filename() string { +func (t *fedoraTestDistroImageType) Filename() string { return "test.img" } -func (t *FedoraTestDistroImageType) MIMEType() string { +func (t *fedoraTestDistroImageType) MIMEType() string { return "application/x-test" } -func (t *FedoraTestDistroImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *fedoraTestDistroImageType) Size(size uint64) uint64 { + return size } -func (t *FedoraTestDistroImageType) BasePackages() ([]string, []string) { +func (t *fedoraTestDistroImageType) BasePackages() ([]string, []string) { return nil, nil } -func (t *FedoraTestDistroImageType) BuildPackages() []string { +func (t *fedoraTestDistroImageType) BuildPackages() []string { return nil } -func (t *FedoraTestDistroImageType) Manifest(c *blueprint.Customizations, +func (t *fedoraTestDistroImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, @@ -94,19 +94,11 @@ func New() *FedoraTestDistro { } func (d *FedoraTestDistro) Name() string { - return "fedora-30" -} - -func (d *FedoraTestDistro) Distribution() common.Distribution { - return common.Fedora30 + return name } func (d *FedoraTestDistro) ModulePlatformID() string { - return ModulePlatformID -} - -func (d *FedoraTestDistro) ListOutputFormats() []string { - return []string{"qcow2"} + return modulePlatformID } func (d *FedoraTestDistro) FilenameFromType(outputFormat string) (string, string, error) { @@ -116,43 +108,3 @@ func (d *FedoraTestDistro) FilenameFromType(outputFormat string) (string, string return "", "", errors.New("invalid output format: " + outputFormat) } } - -func (r *FedoraTestDistro) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - return 0 -} - -func (d *FedoraTestDistro) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - return nil, nil, nil -} - -func (d *FedoraTestDistro) BuildPackages(outputArchitecture string) ([]string, error) { - return nil, nil -} - -func (d *FedoraTestDistro) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, buildPackages, basePackages []rpmmd.PackageSpec, outputArch, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - if outputFormat == "qcow2" && outputArch == "x86_64" { - return &osbuild.Pipeline{}, nil - } else { - return nil, errors.New("invalid output format or arch: " + outputFormat + " @ " + outputArch) - } -} - -func (r *FedoraTestDistro) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - return &osbuild.Sources{} -} - -func (r *FedoraTestDistro) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (d *FedoraTestDistro) Runner() string { - return "org.osbuild.test" -} diff --git a/internal/distro/rhel81/distro.go b/internal/distro/rhel81/distro.go index 34585d6ab..0a9d88380 100644 --- a/internal/distro/rhel81/distro.go +++ b/internal/distro/rhel81/distro.go @@ -5,7 +5,6 @@ import ( "sort" "strconv" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" @@ -16,46 +15,46 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -type arch struct { - Name string - BootloaderPackages []string - BuildPackages []string - UEFI bool -} - -type output struct { - Name string - MimeType string - Packages []string - ExcludedPackages []string - EnabledServices []string - DisabledServices []string - Bootable bool - DefaultTarget string - KernelOptions string - DefaultSize uint64 - Assembler func(uefi bool, size uint64) *osbuild.Assembler -} - -const Distro = common.RHEL81 -const ModulePlatformID = "platform:el8" +const name = "rhel-8.1" +const modulePlatformID = "platform:el8" type RHEL81 struct { arches map[string]arch - outputs map[string]output + imageTypes map[string]imageType buildPackages []string } -type RHEL81Arch struct { +type arch struct { + name string + bootloaderPackages []string + buildPackages []string + uefi bool +} + +type imageType struct { + name string + mimeType string + packages []string + excludedPackages []string + enabledServices []string + disabledServices []string + bootable bool + defaultTarget string + kernelOptions string + defaultSize uint64 + assembler func(uefi bool, size uint64) *osbuild.Assembler +} + +type rhel81Arch struct { name string distro *RHEL81 arch *arch } -type RHEL81ImageType struct { - name string - arch *RHEL81Arch - output *output +type rhel81ImageType struct { + name string + arch *rhel81Arch + imageType *imageType } func (d *RHEL81) GetArch(arch string) (distro.Arch, error) { @@ -64,75 +63,88 @@ func (d *RHEL81) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &RHEL81Arch{ + return &rhel81Arch{ name: arch, distro: d, arch: &a, }, nil } -func (a *RHEL81Arch) Name() string { +func (a *rhel81Arch) Name() string { return a.name } -func (a *RHEL81Arch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *rhel81Arch) ListImageTypes() []string { + formats := make([]string, 0, len(a.distro.imageTypes)) + for name := range a.distro.imageTypes { + formats = append(formats, name) + } + sort.Strings(formats) + return formats } -func (a *RHEL81Arch) GetImageType(imageType string) (distro.ImageType, error) { - t, exists := a.distro.outputs[imageType] +func (a *rhel81Arch) GetImageType(imageType string) (distro.ImageType, error) { + t, exists := a.distro.imageTypes[imageType] if !exists { return nil, errors.New("invalid image type: " + imageType) } - return &RHEL81ImageType{ - name: imageType, - arch: a, - output: &t, + return &rhel81ImageType{ + name: imageType, + arch: a, + imageType: &t, }, nil } -func (t *RHEL81ImageType) Name() string { +func (t *rhel81ImageType) Name() string { return t.name } -func (t *RHEL81ImageType) Filename() string { - return t.output.Name +func (t *rhel81ImageType) Filename() string { + return t.imageType.name } -func (t *RHEL81ImageType) MIMEType() string { - return t.output.MimeType +func (t *rhel81ImageType) MIMEType() string { + return t.imageType.mimeType } -func (t *RHEL81ImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *rhel81ImageType) 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.imageType.defaultSize + } + return size } -func (t *RHEL81ImageType) BasePackages() ([]string, []string) { - packages := t.output.Packages - if t.output.Bootable { - packages = append(packages, t.arch.arch.BootloaderPackages...) +func (t *rhel81ImageType) BasePackages() ([]string, []string) { + packages := t.imageType.packages + if t.imageType.bootable { + packages = append(packages, t.arch.arch.bootloaderPackages...) } - return packages, t.output.ExcludedPackages + return packages, t.imageType.excludedPackages } -func (t *RHEL81ImageType) BuildPackages() []string { - return append(t.arch.distro.buildPackages, t.arch.arch.BuildPackages...) +func (t *rhel81ImageType) BuildPackages() []string { + return append(t.arch.distro.buildPackages, t.arch.arch.buildPackages...) } -func (t *RHEL81ImageType) Manifest(c *blueprint.Customizations, +func (t *rhel81ImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - pipeline, err := t.arch.distro.pipeline(c, repos, packageSpecs, buildPackageSpecs, t.arch.name, t.name, size) + pipeline, err := t.pipeline(c, repos, packageSpecs, buildPackageSpecs, size) if err != nil { return nil, err } return &osbuild.Manifest{ - Sources: *t.arch.distro.sources(append(packageSpecs, buildPackageSpecs...)), + Sources: *sources(append(packageSpecs, buildPackageSpecs...)), Pipeline: *pipeline, }, nil } @@ -141,7 +153,7 @@ func New() *RHEL81 { const GigaByte = 1024 * 1024 * 1024 r := RHEL81{ - outputs: map[string]output{}, + imageTypes: map[string]imageType{}, buildPackages: []string{ "dnf", "dosfstools", @@ -157,32 +169,32 @@ func New() *RHEL81 { }, arches: map[string]arch{ "x86_64": arch{ - Name: "x86_64", - BootloaderPackages: []string{ + name: "x86_64", + bootloaderPackages: []string{ "grub2-pc", }, - BuildPackages: []string{ + buildPackages: []string{ "grub2-pc", }, }, "aarch64": arch{ - Name: "aarch64", - BootloaderPackages: []string{ + name: "aarch64", + bootloaderPackages: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", "grub2-tools", "shim-aa64", }, - UEFI: true, + uefi: true, }, }, } - r.outputs["ami"] = output{ - Name: "image.raw.xz", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ami"] = imageType{ + name: "image.raw.xz", + mimeType: "application/octet-stream", + packages: []string{ "checkpolicy", "chrony", "cloud-init", @@ -208,7 +220,7 @@ func New() *RHEL81 { // TODO this doesn't exist in BaseOS or AppStream // "rh-amazon-rhui-client", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "aic94xx-firmware", "alsa-firmware", "alsa-lib", @@ -247,19 +259,19 @@ func New() *RHEL81 { // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - DefaultTarget: "multi-user.target", - Bootable: true, - KernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", - DefaultSize: 6 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + defaultTarget: "multi-user.target", + bootable: true, + kernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", + defaultSize: 6 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) }, } - r.outputs["ext4-filesystem"] = output{ - Name: "filesystem.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ext4-filesystem"] = imageType{ + name: "filesystem.img", + mimeType: "application/octet-stream", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -268,23 +280,23 @@ func New() *RHEL81 { "dracut-config-generic", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: false, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, + bootable: false, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, } - r.outputs["partitioned-disk"] = output{ - Name: "disk.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["partitioned-disk"] = imageType{ + name: "disk.img", + mimeType: "application/octet-stream", + packages: []string{ "@core", "chrony", "dracut-config-generic", @@ -293,25 +305,25 @@ func New() *RHEL81 { "langpacks-en", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw", "disk.img", uefi, size) }, } - r.outputs["qcow2"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["qcow2"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "@core", "chrony", "dnf", @@ -344,7 +356,7 @@ func New() *RHEL81 { "insights-client", // TODO: rh-amazon-rhui-client }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", "aic94xx-firmware", "alsa-firmware", @@ -384,18 +396,18 @@ func New() *RHEL81 { // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["openstack"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["openstack"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ // Defaults "@Core", "langpacks-en", @@ -411,21 +423,21 @@ func New() *RHEL81 { "qemu-guest-agent", "spice-vdagent", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["tar"] = output{ - Name: "root.tar.xz", - MimeType: "application/x-tar", - Packages: []string{ + r.imageTypes["tar"] = imageType{ + name: "root.tar.xz", + mimeType: "application/x-tar", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -434,22 +446,22 @@ func New() *RHEL81 { "dracut-config-generic", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: false, - KernelOptions: "ro net.ifnames=0", - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, + bootable: false, + kernelOptions: "ro net.ifnames=0", + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, } - r.outputs["vhd"] = output{ - Name: "disk.vhd", - MimeType: "application/x-vhd", - Packages: []string{ + r.imageTypes["vhd"] = imageType{ + name: "disk.vhd", + mimeType: "application/x-vhd", + packages: []string{ // Defaults "@Core", "langpacks-en", @@ -469,30 +481,30 @@ func New() *RHEL81 { "cloud-utils-growpart", "gdisk", }, - ExcludedPackages: []string{ + 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{ + enabledServices: []string{ "sshd", "waagent", }, - DefaultTarget: "multi-user.target", - Bootable: true, - KernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + defaultTarget: "multi-user.target", + bootable: true, + kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vpc", "disk.vhd", uefi, size) }, } - r.outputs["vmdk"] = output{ - Name: "disk.vmdk", - MimeType: "application/x-vmdk", - Packages: []string{ + r.imageTypes["vmdk"] = imageType{ + name: "disk.vmdk", + mimeType: "application/x-vmdk", + packages: []string{ "@core", "chrony", "dracut-config-generic", @@ -502,17 +514,17 @@ func New() *RHEL81 { "open-vm-tools", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) }, } @@ -521,103 +533,48 @@ func New() *RHEL81 { } func (r *RHEL81) Name() string { - name, exists := Distro.ToString() - if !exists { - panic("Fatal error, hardcoded distro value in rhel81 package is not valid!") - } return name } -func (r *RHEL81) Distribution() common.Distribution { - return Distro -} - func (r *RHEL81) ModulePlatformID() string { - return ModulePlatformID -} - -func (r *RHEL81) ListOutputFormats() []string { - formats := make([]string, 0, len(r.outputs)) - for name := range r.outputs { - formats = append(formats, name) - } - sort.Strings(formats) - return formats + return modulePlatformID } func (r *RHEL81) FilenameFromType(outputFormat string) (string, string, error) { - if output, exists := r.outputs[outputFormat]; exists { - return output.Name, output.MimeType, nil + if output, exists := r.imageTypes[outputFormat]; exists { + return output.name, output.mimeType, nil } return "", "", errors.New("invalid output format: " + outputFormat) } -func (r *RHEL81) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - const MegaByte = 1024 * 1024 - // Microsoft Azure requires vhd images to be rounded up to the nearest MB - if outputFormat == "vhd" && size%MegaByte != 0 { - size = (size/MegaByte + 1) * MegaByte +func sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + files := &osbuild.FilesSource{ + URLs: make(map[string]string), } - if size == 0 { - size = r.outputs[outputFormat].DefaultSize + for _, pkg := range packages { + files.URLs[pkg.Checksum] = pkg.RemoteLocation + } + return &osbuild.Sources{ + "org.osbuild.files": files, } - return size } -func (r *RHEL81) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, nil, errors.New("invalid output format: " + outputFormat) - } - - packages := output.Packages - if output.Bootable { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, nil, errors.New("invalid architecture: " + outputArchitecture) - } - - packages = append(packages, arch.BootloaderPackages...) - } - - return packages, output.ExcludedPackages, nil -} - -func (r *RHEL81) BuildPackages(outputArchitecture string) ([]string, error) { - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - - return append(r.buildPackages, arch.BuildPackages...), nil -} - -func (r *RHEL81) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, errors.New("invalid output format: " + outputFormat) - } - - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) - } - +func (t *rhel81ImageType) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Pipeline, error) { p := &osbuild.Pipeline{} - p.SetBuild(r.buildPipeline(repos, arch, buildPackageSpecs), "org.osbuild.rhel81") + p.SetBuild(t.buildPipeline(repos, *t.arch.arch, buildPackageSpecs), "org.osbuild.rhel81") - p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) + p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch.arch, repos, packageSpecs))) p.AddStage(osbuild.NewFixBLSStage()) - if output.Bootable { - p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + if t.imageType.bootable { + p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.arch.uefi))) } - kernelOptions := output.KernelOptions + kernelOptions := t.imageType.kernelOptions if kernel := c.GetKernel(); kernel != nil { kernelOptions += " " + kernel.Append } - p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(kernelOptions, arch.UEFI))) + p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(kernelOptions, t.arch.arch.uefi))) // TODO support setting all languages and install corresponding langpack-* package language, keyboard := c.GetPrimaryLocale() @@ -648,7 +605,7 @@ func (r *RHEL81) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, } if users := c.GetUsers(); len(users) > 0 { - options, err := r.userStageOptions(users) + options, err := t.userStageOptions(users) if err != nil { return nil, err } @@ -656,59 +613,31 @@ func (r *RHEL81) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, } if groups := c.GetGroups(); len(groups) > 0 { - p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if services := c.GetServices(); services != nil || output.EnabledServices != nil { - p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services, output.DefaultTarget))) + if services := c.GetServices(); services != nil || t.imageType.enabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.imageType.enabledServices, t.imageType.disabledServices, services, t.imageType.defaultTarget))) } if firewall := c.GetFirewall(); firewall != nil { - p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall))) } - p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions())) - p.Assembler = output.Assembler(arch.UEFI, size) + p.Assembler = t.imageType.assembler(t.arch.arch.uefi, size) return p, nil } -func (r *RHEL81) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - files := &osbuild.FilesSource{ - URLs: make(map[string]string), - } - for _, pkg := range packages { - files.URLs[pkg.Checksum] = pkg.RemoteLocation - } - return &osbuild.Sources{ - "org.osbuild.files": files, - } -} - -func (r *RHEL81) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (r *RHEL81) Runner() string { - return "org.osbuild.rhel81" -} - -func (r *RHEL81) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func (r *rhel81ImageType) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { p := &osbuild.Pipeline{} p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, buildPackageSpecs))) return p } -func (r *RHEL81) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { +func (r *rhel81ImageType) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { var gpgKeys []string for _, repo := range repos { if repo.GPGKey == "" { @@ -728,7 +657,7 @@ func (r *RHEL81) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rp } } -func (r *RHEL81) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { +func (r *rhel81ImageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { options := osbuild.UsersStageOptions{ Users: make(map[string]osbuild.UsersStageOptionsUser), } @@ -768,7 +697,7 @@ func (r *RHEL81) userStageOptions(users []blueprint.UserCustomization) (*osbuild return &options, nil } -func (r *RHEL81) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { +func (r *rhel81ImageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, } @@ -788,7 +717,7 @@ func (r *RHEL81) groupStageOptions(groups []blueprint.GroupCustomization) *osbui return &options } -func (r *RHEL81) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { +func (r *rhel81ImageType) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { options := osbuild.FirewallStageOptions{ Ports: firewall.Ports, } @@ -801,7 +730,7 @@ func (r *RHEL81) firewallStageOptions(firewall *blueprint.FirewallCustomization) return &options } -func (r *RHEL81) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization, target string) *osbuild.SystemdStageOptions { +func (r *rhel81ImageType) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization, target string) *osbuild.SystemdStageOptions { if s != nil { enabledServices = append(enabledServices, s.Enabled...) disabledServices = append(disabledServices, s.Disabled...) @@ -813,7 +742,7 @@ func (r *RHEL81) systemdStageOptions(enabledServices, disabledServices []string, } } -func (r *RHEL81) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { +func (r *rhel81ImageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { options := osbuild.FSTabStageOptions{} options.AddFilesystem("0bd700f8-090f-4556-b797-b340297ea1bd", "xfs", "/", "defaults", 0, 0) if uefi { @@ -822,7 +751,7 @@ func (r *RHEL81) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { return &options } -func (r *RHEL81) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRUB2StageOptions { +func (r *rhel81ImageType) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRUB2StageOptions { id, err := uuid.Parse("0bd700f8-090f-4556-b797-b340297ea1bd") if err != nil { panic("invalid UUID") @@ -843,7 +772,7 @@ func (r *RHEL81) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRU } } -func (r *RHEL81) selinuxStageOptions() *osbuild.SELinuxStageOptions { +func (r *rhel81ImageType) selinuxStageOptions() *osbuild.SELinuxStageOptions { return &osbuild.SELinuxStageOptions{ FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", } diff --git a/internal/distro/rhel81/distro_test.go b/internal/distro/rhel81/distro_test.go index 2cecf93f9..6f10917b2 100644 --- a/internal/distro/rhel81/distro_test.go +++ b/internal/distro/rhel81/distro_test.go @@ -1,31 +1,11 @@ package rhel81_test import ( - "reflect" "testing" "github.com/osbuild/osbuild-composer/internal/distro/rhel81" ) -func TestListOutputFormats(t *testing.T) { - want := []string{ - "ami", - "ext4-filesystem", - "openstack", - "partitioned-disk", - "qcow2", - "tar", - "vhd", - "vmdk", - } - - el81 := rhel81.New() - - if got := el81.ListOutputFormats(); !reflect.DeepEqual(got, want) { - t.Errorf("ListOutputFormats() = %v, want %v", got, want) - } -} - func TestFilenameFromType(t *testing.T) { type args struct { outputFormat string diff --git a/internal/distro/rhel82/distro.go b/internal/distro/rhel82/distro.go index eba8738c2..a6bd66846 100644 --- a/internal/distro/rhel82/distro.go +++ b/internal/distro/rhel82/distro.go @@ -5,7 +5,6 @@ import ( "sort" "strconv" - "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/osbuild" @@ -16,46 +15,46 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -type arch struct { - Name string - BootloaderPackages []string - BuildPackages []string - UEFI bool -} - -type output struct { - Name string - MimeType string - Packages []string - ExcludedPackages []string - EnabledServices []string - DisabledServices []string - Bootable bool - DefaultTarget string - KernelOptions string - DefaultSize uint64 - Assembler func(uefi bool, size uint64) *osbuild.Assembler -} - -const Distro = common.RHEL82 -const ModulePlatformID = "platform:el8" +const name = "rhel-8.2" +const modulePlatformID = "platform:el8" type RHEL82 struct { arches map[string]arch - outputs map[string]output + imageTypes map[string]imageType buildPackages []string } -type RHEL82Arch struct { +type arch struct { + name string + bootloaderPackages []string + buildPackages []string + uefi bool +} + +type imageType struct { + name string + mimeType string + packages []string + excludedPackages []string + enabledServices []string + disabledServices []string + bootable bool + defaultTarget string + kernelOptions string + defaultSize uint64 + assembler func(uefi bool, size uint64) *osbuild.Assembler +} + +type rhel82Arch struct { name string distro *RHEL82 arch *arch } -type RHEL82ImageType struct { - name string - arch *RHEL82Arch - output *output +type rhel82ImageType struct { + name string + arch *rhel82Arch + imageType *imageType } func (d *RHEL82) GetArch(arch string) (distro.Arch, error) { @@ -64,75 +63,88 @@ func (d *RHEL82) GetArch(arch string) (distro.Arch, error) { return nil, errors.New("invalid architecture: " + arch) } - return &RHEL82Arch{ + return &rhel82Arch{ name: arch, distro: d, arch: &a, }, nil } -func (a *RHEL82Arch) Name() string { +func (a *rhel82Arch) Name() string { return a.name } -func (a *RHEL82Arch) ListImageTypes() []string { - return a.distro.ListOutputFormats() +func (a *rhel82Arch) ListImageTypes() []string { + formats := make([]string, 0, len(a.distro.imageTypes)) + for name := range a.distro.imageTypes { + formats = append(formats, name) + } + sort.Strings(formats) + return formats } -func (a *RHEL82Arch) GetImageType(imageType string) (distro.ImageType, error) { - t, exists := a.distro.outputs[imageType] +func (a *rhel82Arch) GetImageType(imageType string) (distro.ImageType, error) { + t, exists := a.distro.imageTypes[imageType] if !exists { return nil, errors.New("invalid image type: " + imageType) } - return &RHEL82ImageType{ - name: imageType, - arch: a, - output: &t, + return &rhel82ImageType{ + name: imageType, + arch: a, + imageType: &t, }, nil } -func (t *RHEL82ImageType) Name() string { +func (t *rhel82ImageType) Name() string { return t.name } -func (t *RHEL82ImageType) Filename() string { - return t.output.Name +func (t *rhel82ImageType) Filename() string { + return t.imageType.name } -func (t *RHEL82ImageType) MIMEType() string { - return t.output.MimeType +func (t *rhel82ImageType) MIMEType() string { + return t.imageType.mimeType } -func (t *RHEL82ImageType) Size(size uint64) uint64 { - return t.arch.distro.GetSizeForOutputType(t.name, size) +func (t *rhel82ImageType) 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.imageType.defaultSize + } + return size } -func (t *RHEL82ImageType) BasePackages() ([]string, []string) { - packages := t.output.Packages - if t.output.Bootable { - packages = append(packages, t.arch.arch.BootloaderPackages...) +func (t *rhel82ImageType) BasePackages() ([]string, []string) { + packages := t.imageType.packages + if t.imageType.bootable { + packages = append(packages, t.arch.arch.bootloaderPackages...) } - return packages, t.output.ExcludedPackages + return packages, t.imageType.excludedPackages } -func (t *RHEL82ImageType) BuildPackages() []string { - return append(t.arch.distro.buildPackages, t.arch.arch.BuildPackages...) +func (t *rhel82ImageType) BuildPackages() []string { + return append(t.arch.distro.buildPackages, t.arch.arch.buildPackages...) } -func (t *RHEL82ImageType) Manifest(c *blueprint.Customizations, +func (t *rhel82ImageType) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - pipeline, err := t.arch.distro.pipeline(c, repos, packageSpecs, buildPackageSpecs, t.arch.name, t.name, size) + pipeline, err := t.pipeline(c, repos, packageSpecs, buildPackageSpecs, size) if err != nil { return nil, err } return &osbuild.Manifest{ - Sources: *t.arch.distro.sources(append(packageSpecs, buildPackageSpecs...)), + Sources: *sources(append(packageSpecs, buildPackageSpecs...)), Pipeline: *pipeline, }, nil } @@ -141,7 +153,7 @@ func New() *RHEL82 { const GigaByte = 1024 * 1024 * 1024 r := RHEL82{ - outputs: map[string]output{}, + imageTypes: map[string]imageType{}, buildPackages: []string{ "dnf", "dosfstools", @@ -157,32 +169,32 @@ func New() *RHEL82 { }, arches: map[string]arch{ "x86_64": arch{ - Name: "x86_64", - BootloaderPackages: []string{ + name: "x86_64", + bootloaderPackages: []string{ "grub2-pc", }, - BuildPackages: []string{ + buildPackages: []string{ "grub2-pc", }, }, "aarch64": arch{ - Name: "aarch64", - BootloaderPackages: []string{ + name: "aarch64", + bootloaderPackages: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", "grub2-tools", "shim-aa64", }, - UEFI: true, + uefi: true, }, }, } - r.outputs["ami"] = output{ - Name: "image.raw.xz", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ami"] = imageType{ + name: "image.raw.xz", + mimeType: "application/octet-stream", + packages: []string{ "checkpolicy", "chrony", "cloud-init", @@ -208,7 +220,7 @@ func New() *RHEL82 { // TODO this doesn't exist in BaseOS or AppStream // "rh-amazon-rhui-client", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "aic94xx-firmware", "alsa-firmware", "alsa-lib", @@ -247,19 +259,19 @@ func New() *RHEL82 { // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - DefaultTarget: "multi-user.target", - Bootable: true, - KernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", - DefaultSize: 6 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + defaultTarget: "multi-user.target", + bootable: true, + kernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", + defaultSize: 6 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) }, } - r.outputs["ext4-filesystem"] = output{ - Name: "filesystem.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["ext4-filesystem"] = imageType{ + name: "filesystem.img", + mimeType: "application/octet-stream", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -268,23 +280,23 @@ func New() *RHEL82 { "dracut-config-generic", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: false, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, + bootable: false, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.rawFSAssembler("filesystem.img", size) }, } - r.outputs["partitioned-disk"] = output{ - Name: "disk.img", - MimeType: "application/octet-stream", - Packages: []string{ + r.imageTypes["partitioned-disk"] = imageType{ + name: "disk.img", + mimeType: "application/octet-stream", + packages: []string{ "@core", "chrony", "dracut-config-generic", @@ -293,25 +305,25 @@ func New() *RHEL82 { "langpacks-en", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("raw", "disk.img", uefi, size) }, } - r.outputs["qcow2"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["qcow2"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ "@core", "chrony", "dnf", @@ -344,7 +356,7 @@ func New() *RHEL82 { "insights-client", // TODO: rh-amazon-rhui-client }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", "aic94xx-firmware", "alsa-firmware", @@ -384,18 +396,18 @@ func New() *RHEL82 { // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "console=ttyS0 console=ttyS0,115200n8 no_timer_check crashkernel=auto net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["openstack"] = output{ - Name: "disk.qcow2", - MimeType: "application/x-qemu-disk", - Packages: []string{ + r.imageTypes["openstack"] = imageType{ + name: "disk.qcow2", + mimeType: "application/x-qemu-disk", + packages: []string{ // Defaults "@Core", "langpacks-en", @@ -411,21 +423,21 @@ func New() *RHEL82 { "qemu-guest-agent", "spice-vdagent", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) }, } - r.outputs["tar"] = output{ - Name: "root.tar.xz", - MimeType: "application/x-tar", - Packages: []string{ + r.imageTypes["tar"] = imageType{ + name: "root.tar.xz", + mimeType: "application/x-tar", + packages: []string{ "policycoreutils", "selinux-policy-targeted", "kernel", @@ -434,22 +446,22 @@ func New() *RHEL82 { "dracut-config-generic", "langpacks-en", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: false, - KernelOptions: "ro net.ifnames=0", - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, + bootable: false, + kernelOptions: "ro net.ifnames=0", + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.tarAssembler("root.tar.xz", "xz") }, } - r.outputs["vhd"] = output{ - Name: "disk.vhd", - MimeType: "application/x-vhd", - Packages: []string{ + r.imageTypes["vhd"] = imageType{ + name: "disk.vhd", + mimeType: "application/x-vhd", + packages: []string{ // Defaults "@Core", "langpacks-en", @@ -469,30 +481,30 @@ func New() *RHEL82 { "cloud-utils-growpart", "gdisk", }, - ExcludedPackages: []string{ + 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{ + enabledServices: []string{ "sshd", "waagent", }, - DefaultTarget: "multi-user.target", - Bootable: true, - KernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + defaultTarget: "multi-user.target", + bootable: true, + kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vpc", "disk.vhd", uefi, size) }, } - r.outputs["vmdk"] = output{ - Name: "disk.vmdk", - MimeType: "application/x-vmdk", - Packages: []string{ + r.imageTypes["vmdk"] = imageType{ + name: "disk.vmdk", + mimeType: "application/x-vmdk", + packages: []string{ "@core", "chrony", "dracut-config-generic", @@ -502,17 +514,17 @@ func New() *RHEL82 { "open-vm-tools", "selinux-policy-targeted", }, - ExcludedPackages: []string{ + excludedPackages: []string{ "dracut-config-rescue", // TODO setfiles failes because of usr/sbin/timedatex. Exlude until // https://errata.devel.redhat.com/advisory/47339 lands "timedatex", }, - Bootable: true, - KernelOptions: "ro net.ifnames=0", - DefaultSize: 2 * GigaByte, - Assembler: func(uefi bool, size uint64) *osbuild.Assembler { + bootable: true, + kernelOptions: "ro net.ifnames=0", + defaultSize: 2 * GigaByte, + assembler: func(uefi bool, size uint64) *osbuild.Assembler { return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) }, } @@ -521,66 +533,37 @@ func New() *RHEL82 { } func (r *RHEL82) Name() string { - name, exists := Distro.ToString() - if !exists { - panic("Fatal error, hardcoded distro value in rhel82 package is not valid!") - } return name } -func (r *RHEL82) Distribution() common.Distribution { - return Distro -} - func (r *RHEL82) ModulePlatformID() string { - return ModulePlatformID -} - -func (r *RHEL82) ListOutputFormats() []string { - formats := make([]string, 0, len(r.outputs)) - for name := range r.outputs { - formats = append(formats, name) - } - sort.Strings(formats) - return formats + return modulePlatformID } func (r *RHEL82) FilenameFromType(outputFormat string) (string, string, error) { - if output, exists := r.outputs[outputFormat]; exists { - return output.Name, output.MimeType, nil + if output, exists := r.imageTypes[outputFormat]; exists { + return output.name, output.mimeType, nil } return "", "", errors.New("invalid output format: " + outputFormat) } -func (r *RHEL82) GetSizeForOutputType(outputFormat string, size uint64) uint64 { - const MegaByte = 1024 * 1024 - // Microsoft Azure requires vhd images to be rounded up to the nearest MB - if outputFormat == "vhd" && size%MegaByte != 0 { - size = (size/MegaByte + 1) * MegaByte - } - if size == 0 { - size = r.outputs[outputFormat].DefaultSize - } - return size -} - func (r *RHEL82) BasePackages(outputFormat string, outputArchitecture string) ([]string, []string, error) { - output, exists := r.outputs[outputFormat] + output, exists := r.imageTypes[outputFormat] if !exists { return nil, nil, errors.New("invalid output format: " + outputFormat) } - packages := output.Packages - if output.Bootable { + packages := output.packages + if output.bootable { arch, exists := r.arches[outputArchitecture] if !exists { return nil, nil, errors.New("invalid architecture: " + outputArchitecture) } - packages = append(packages, arch.BootloaderPackages...) + packages = append(packages, arch.bootloaderPackages...) } - return packages, output.ExcludedPackages, nil + return packages, output.excludedPackages, nil } func (r *RHEL82) BuildPackages(outputArchitecture string) ([]string, error) { @@ -589,35 +572,37 @@ func (r *RHEL82) BuildPackages(outputArchitecture string) ([]string, error) { return nil, errors.New("invalid architecture: " + outputArchitecture) } - return append(r.buildPackages, arch.BuildPackages...), nil + return append(r.buildPackages, arch.buildPackages...), nil } -func (r *RHEL82) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - output, exists := r.outputs[outputFormat] - if !exists { - return nil, errors.New("invalid output format: " + outputFormat) +func sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + files := &osbuild.FilesSource{ + URLs: make(map[string]string), } - - arch, exists := r.arches[outputArchitecture] - if !exists { - return nil, errors.New("invalid architecture: " + outputArchitecture) + for _, pkg := range packages { + files.URLs[pkg.Checksum] = pkg.RemoteLocation } + return &osbuild.Sources{ + "org.osbuild.files": files, + } +} +func (t *rhel82ImageType) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Pipeline, error) { p := &osbuild.Pipeline{} - p.SetBuild(r.buildPipeline(repos, arch, buildPackageSpecs), "org.osbuild.rhel82") + p.SetBuild(t.buildPipeline(repos, *t.arch.arch, buildPackageSpecs), "org.osbuild.rhel82") - p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, packageSpecs))) + p.AddStage(osbuild.NewRPMStage(t.rpmStageOptions(*t.arch.arch, repos, packageSpecs))) p.AddStage(osbuild.NewFixBLSStage()) - if output.Bootable { - p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + if t.imageType.bootable { + p.AddStage(osbuild.NewFSTabStage(t.fsTabStageOptions(t.arch.arch.uefi))) } - kernelOptions := output.KernelOptions + kernelOptions := t.imageType.kernelOptions if kernel := c.GetKernel(); kernel != nil { kernelOptions += " " + kernel.Append } - p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(kernelOptions, arch.UEFI))) + p.AddStage(osbuild.NewGRUB2Stage(t.grub2StageOptions(kernelOptions, t.arch.arch.uefi))) // TODO support setting all languages and install corresponding langpack-* package language, keyboard := c.GetPrimaryLocale() @@ -648,7 +633,7 @@ func (r *RHEL82) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, } if users := c.GetUsers(); len(users) > 0 { - options, err := r.userStageOptions(users) + options, err := t.userStageOptions(users) if err != nil { return nil, err } @@ -656,59 +641,31 @@ func (r *RHEL82) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, } if groups := c.GetGroups(); len(groups) > 0 { - p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if services := c.GetServices(); services != nil || output.EnabledServices != nil { - p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services, output.DefaultTarget))) + if services := c.GetServices(); services != nil || t.imageType.enabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(t.systemdStageOptions(t.imageType.enabledServices, t.imageType.disabledServices, services, t.imageType.defaultTarget))) } if firewall := c.GetFirewall(); firewall != nil { - p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + p.AddStage(osbuild.NewFirewallStage(t.firewallStageOptions(firewall))) } - p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + p.AddStage(osbuild.NewSELinuxStage(t.selinuxStageOptions())) - p.Assembler = output.Assembler(arch.UEFI, size) + p.Assembler = t.imageType.assembler(t.arch.arch.uefi, size) return p, nil } -func (r *RHEL82) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - files := &osbuild.FilesSource{ - URLs: make(map[string]string), - } - for _, pkg := range packages { - files.URLs[pkg.Checksum] = pkg.RemoteLocation - } - return &osbuild.Sources{ - "org.osbuild.files": files, - } -} - -func (r *RHEL82) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (r *RHEL82) Runner() string { - return "org.osbuild.rhel82" -} - -func (r *RHEL82) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func (r *rhel82ImageType) buildPipeline(repos []rpmmd.RepoConfig, arch arch, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { p := &osbuild.Pipeline{} p.AddStage(osbuild.NewRPMStage(r.rpmStageOptions(arch, repos, buildPackageSpecs))) return p } -func (r *RHEL82) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { +func (r *rhel82ImageType) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rpmmd.PackageSpec) *osbuild.RPMStageOptions { var gpgKeys []string for _, repo := range repos { if repo.GPGKey == "" { @@ -727,7 +684,7 @@ func (r *RHEL82) rpmStageOptions(arch arch, repos []rpmmd.RepoConfig, specs []rp Packages: packages, } } -func (r *RHEL82) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { +func (r *rhel82ImageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { options := osbuild.UsersStageOptions{ Users: make(map[string]osbuild.UsersStageOptionsUser), } @@ -767,7 +724,7 @@ func (r *RHEL82) userStageOptions(users []blueprint.UserCustomization) (*osbuild return &options, nil } -func (r *RHEL82) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { +func (r *rhel82ImageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, } @@ -787,7 +744,7 @@ func (r *RHEL82) groupStageOptions(groups []blueprint.GroupCustomization) *osbui return &options } -func (r *RHEL82) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { +func (r *rhel82ImageType) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { options := osbuild.FirewallStageOptions{ Ports: firewall.Ports, } @@ -800,7 +757,7 @@ func (r *RHEL82) firewallStageOptions(firewall *blueprint.FirewallCustomization) return &options } -func (r *RHEL82) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization, target string) *osbuild.SystemdStageOptions { +func (r *rhel82ImageType) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization, target string) *osbuild.SystemdStageOptions { if s != nil { enabledServices = append(enabledServices, s.Enabled...) disabledServices = append(disabledServices, s.Disabled...) @@ -812,7 +769,7 @@ func (r *RHEL82) systemdStageOptions(enabledServices, disabledServices []string, } } -func (r *RHEL82) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { +func (r *rhel82ImageType) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { options := osbuild.FSTabStageOptions{} options.AddFilesystem("0bd700f8-090f-4556-b797-b340297ea1bd", "xfs", "/", "defaults", 0, 0) if uefi { @@ -821,7 +778,7 @@ func (r *RHEL82) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { return &options } -func (r *RHEL82) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRUB2StageOptions { +func (r *rhel82ImageType) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRUB2StageOptions { id, err := uuid.Parse("0bd700f8-090f-4556-b797-b340297ea1bd") if err != nil { panic("invalid UUID") @@ -842,7 +799,7 @@ func (r *RHEL82) grub2StageOptions(kernelOptions string, uefi bool) *osbuild.GRU } } -func (r *RHEL82) selinuxStageOptions() *osbuild.SELinuxStageOptions { +func (r *rhel82ImageType) selinuxStageOptions() *osbuild.SELinuxStageOptions { return &osbuild.SELinuxStageOptions{ FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", } diff --git a/internal/distro/rhel82/distro_test.go b/internal/distro/rhel82/distro_test.go index 6066eeac4..4874b40ac 100644 --- a/internal/distro/rhel82/distro_test.go +++ b/internal/distro/rhel82/distro_test.go @@ -1,31 +1,11 @@ package rhel82_test import ( - "reflect" "testing" "github.com/osbuild/osbuild-composer/internal/distro/rhel82" ) -func TestListOutputFormats(t *testing.T) { - want := []string{ - "ami", - "ext4-filesystem", - "openstack", - "partitioned-disk", - "qcow2", - "tar", - "vhd", - "vmdk", - } - - el82 := rhel82.New() - - if got := el82.ListOutputFormats(); !reflect.DeepEqual(got, want) { - t.Errorf("ListOutputFormats() = %v, want %v", got, want) - } -} - func TestFilenameFromType(t *testing.T) { type args struct { outputFormat string diff --git a/internal/distro/test/distro.go b/internal/distro/test/distro.go index 6cf56a3a2..8cfc1eb7e 100644 --- a/internal/distro/test/distro.go +++ b/internal/distro/test/distro.go @@ -10,60 +10,63 @@ import ( ) type TestDistro struct{} -type TestArch struct{} -type TestImageType struct{} +type testArch struct{} +type testImageType struct{} -const Name = "test-distro" -const ModulePlatformID = "platform:test" +const name = "test-distro" +const modulePlatformID = "platform:test" func (d *TestDistro) GetArch(arch string) (distro.Arch, error) { if arch != "test_arch" { return nil, errors.New("invalid arch: " + arch) } - return &TestArch{}, nil + return &testArch{}, nil } -func (a *TestArch) Name() string { - return Name +func (a *testArch) Name() string { + return "test_format" } -func (a *TestArch) ListImageTypes() []string { +func (a *testArch) ListImageTypes() []string { return []string{"test-format"} } -func (a *TestArch) GetImageType(imageType string) (distro.ImageType, error) { +func (a *testArch) GetImageType(imageType string) (distro.ImageType, error) { if imageType != "test_output" { return nil, errors.New("invalid image type: " + imageType) } - return &TestImageType{}, nil + return &testImageType{}, nil } -func (t *TestImageType) Name() string { +func (t *testImageType) Name() string { return "test-format" } -func (t *TestImageType) Filename() string { +func (t *testImageType) Filename() string { return "test.img" } -func (t *TestImageType) MIMEType() string { +func (t *testImageType) MIMEType() string { return "application/x-test" } -func (t *TestImageType) Size(size uint64) uint64 { +func (t *testImageType) Size(size uint64) uint64 { return 0 } -func (t *TestImageType) BasePackages() ([]string, []string) { +func (t *testImageType) BasePackages() ([]string, []string) { return nil, nil } -func (t *TestImageType) BuildPackages() []string { +func (t *testImageType) BuildPackages() []string { return nil } -func (t *TestImageType) Manifest(b *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { - return &osbuild.Manifest{}, nil +func (t *testImageType) Manifest(b *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, size uint64) (*osbuild.Manifest, error) { + return &osbuild.Manifest{ + Sources: osbuild.Sources{}, + Pipeline: osbuild.Pipeline{}, + }, nil } func New() *TestDistro { @@ -71,15 +74,11 @@ func New() *TestDistro { } func (d *TestDistro) Name() string { - return Name + return name } func (d *TestDistro) ModulePlatformID() string { - return ModulePlatformID -} - -func (d *TestDistro) ListOutputFormats() []string { - return []string{"test_format"} + return modulePlatformID } func (d *TestDistro) FilenameFromType(outputFormat string) (string, string, error) { @@ -89,39 +88,3 @@ func (d *TestDistro) FilenameFromType(outputFormat string) (string, string, erro return "", "", errors.New("invalid output format: " + outputFormat) } - -func (d *TestDistro) BasePackages(outputFormat, outputArchitecture string) ([]string, []string, error) { - return nil, nil, nil -} - -func (d *TestDistro) BuildPackages(outputArchitecture string) ([]string, error) { - return nil, nil -} - -func (d *TestDistro) pipeline(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArch, outputFormat string, size uint64) (*osbuild.Pipeline, error) { - if outputFormat == "test_output" && outputArch == "test_arch" { - return &osbuild.Pipeline{}, nil - } - - return nil, errors.New("invalid output format or arch: " + outputFormat + " @ " + outputArch) -} - -func (d *TestDistro) sources(packages []rpmmd.PackageSpec) *osbuild.Sources { - return &osbuild.Sources{} -} - -func (r *TestDistro) Manifest(c *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, outputArchitecture, outputFormat string, size uint64) (*osbuild.Manifest, error) { - pipeline, err := r.pipeline(c, repos, packageSpecs, buildPackageSpecs, outputArchitecture, outputFormat, size) - if err != nil { - return nil, err - } - - return &osbuild.Manifest{ - Sources: *r.sources(append(packageSpecs, buildPackageSpecs...)), - Pipeline: *pipeline, - }, nil -} - -func (d *TestDistro) Runner() string { - return "org.osbuild.test" -}