diff --git a/internal/common/types.go b/internal/common/types.go index 292e9d35a..c3b2af0c2 100644 --- a/internal/common/types.go +++ b/internal/common/types.go @@ -236,6 +236,7 @@ type Distribution int const ( Fedora30 Distribution = iota Fedora31 + Fedora32 RHEL82 ) @@ -245,6 +246,7 @@ func getDistributionMapping() map[string]int { mapping := map[string]int{ "fedora-30": int(Fedora30), "fedora-31": int(Fedora31), + "fedora-32": int(Fedora32), "rhel-8.2": int(RHEL82), } return mapping diff --git a/internal/distro/distro.go b/internal/distro/distro.go index a18d9f7f9..3efacb92d 100644 --- a/internal/distro/distro.go +++ b/internal/distro/distro.go @@ -15,6 +15,7 @@ import ( "github.com/osbuild/osbuild-composer/internal/distro/fedora30" "github.com/osbuild/osbuild-composer/internal/distro/fedora31" + "github.com/osbuild/osbuild-composer/internal/distro/fedora32" "github.com/osbuild/osbuild-composer/internal/distro/rhel82" ) @@ -74,6 +75,7 @@ func NewRegistry(confPaths []string) *Registry { } distros.register(fedora30.New(confPaths)) distros.register(fedora31.New(confPaths)) + distros.register(fedora32.New(confPaths)) distros.register(rhel82.New(confPaths)) return distros } diff --git a/internal/distro/fedora32/distro.go b/internal/distro/fedora32/distro.go new file mode 100644 index 000000000..d2a7b737e --- /dev/null +++ b/internal/distro/fedora32/distro.go @@ -0,0 +1,719 @@ +package fedora32 + +import ( + "errors" + "log" + "sort" + "strconv" + + "github.com/osbuild/osbuild-composer/internal/common" + "github.com/osbuild/osbuild-composer/internal/osbuild" + + "github.com/google/uuid" + + "github.com/osbuild/osbuild-composer/internal/blueprint" + "github.com/osbuild/osbuild-composer/internal/crypt" + "github.com/osbuild/osbuild-composer/internal/rpmmd" +) + +type Fedora32 struct { + arches map[string]arch + outputs map[string]output + buildPackages []string +} + +type arch struct { + Name string + BootloaderPackages []string + BuildPackages []string + UEFI bool + Repositories []rpmmd.RepoConfig +} + +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" + +func New(confPaths []string) *Fedora32 { + const GigaByte = 1024 * 1024 * 1024 + + r := Fedora32{ + arches: map[string]arch{}, + outputs: map[string]output{}, + buildPackages: []string{ + "dnf", + "dosfstools", + "e2fsprogs", + "policycoreutils", + "qemu-img", + "systemd", + "tar", + }, + } + + repoMap, err := rpmmd.LoadRepositories(confPaths, r.Name()) + if err != nil { + log.Printf("Could not load repository data for %s: %s", r.Name(), err.Error()) + return nil + } + + repos, exists := repoMap["x86_64"] + if !exists { + log.Printf("Could not load architecture-specific repository data for x86_64 (%s): %s", r.Name(), err.Error()) + } else { + r.arches["x86_64"] = arch{ + Name: "x86_64", + BootloaderPackages: []string{ + "grub2-pc", + }, + BuildPackages: []string{ + "grub2-pc", + }, + Repositories: repos, + } + } + + repos, exists = repoMap["aarch64"] + if !exists { + log.Printf("Could not load architecture-specific repository data for x86_64 (%s): %s", r.Name(), err.Error()) + } else { + r.arches["aarch64"] = arch{ + Name: "aarch64", + BootloaderPackages: []string{ + "dracut-config-generic", + "efibootmgr", + "grub2-efi-aa64", + "grub2-tools", + "shim-aa64", + }, + UEFI: true, + Repositories: repos, + } + } + + r.outputs["ami"] = output{ + Name: "image.raw.xz", + MimeType: "application/octet-stream", + Packages: []string{ + "@Core", + "chrony", + "kernel", + "selinux-policy-targeted", + "langpacks-en", + "libxcrypt-compat", + "xfsprogs", + "cloud-init", + "checkpolicy", + "net-tools", + }, + ExcludedPackages: []string{ + "dracut-config-rescue", + }, + 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 { + return r.qemuAssembler("raw.xz", "image.raw.xz", uefi, size) + }, + } + + r.outputs["ext4-filesystem"] = output{ + Name: "filesystem.img", + MimeType: "application/octet-stream", + Packages: []string{ + "policycoreutils", + "selinux-policy-targeted", + "kernel", + "firewalld", + "chrony", + "langpacks-en", + }, + 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) }, + } + + r.outputs["partitioned-disk"] = output{ + Name: "disk.img", + MimeType: "application/octet-stream", + Packages: []string{ + "@core", + "chrony", + "firewalld", + "kernel", + "langpacks-en", + "selinux-policy-targeted", + }, + 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 { + return r.qemuAssembler("raw", "disk.img", uefi, size) + }, + } + + r.outputs["qcow2"] = output{ + Name: "disk.qcow2", + MimeType: "application/x-qemu-disk", + Packages: []string{ + "kernel-core", + "@Fedora Cloud Server", + "chrony", + "polkit", + "systemd-udev", + "selinux-policy-targeted", + "langpacks-en", + }, + 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 { + return r.qemuAssembler("qcow2", "disk.qcow2", uefi, size) + }, + } + + r.outputs["openstack"] = output{ + Name: "disk.qcow2", + MimeType: "application/x-qemu-disk", + Packages: []string{ + "@Core", + "chrony", + "kernel", + "selinux-policy-targeted", + "spice-vdagent", + "qemu-guest-agent", + "xen-libs", + "langpacks-en", + "cloud-init", + "libdrm", + }, + ExcludedPackages: []string{ + "dracut-config-rescue", + }, + 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{ + "policycoreutils", + "selinux-policy-targeted", + "kernel", + "firewalld", + "chrony", + "langpacks-en", + }, + 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") }, + } + + r.outputs["vhd"] = output{ + Name: "disk.vhd", + MimeType: "application/x-vhd", + Packages: []string{ + "@Core", + "chrony", + "kernel", + "selinux-policy-targeted", + "langpacks-en", + "net-tools", + "ntfsprogs", + "WALinuxAgent", + "libxcrypt-compat", + "initscripts", + "glibc-all-langpacks", + "dracut-config-generic", + }, + ExcludedPackages: []string{ + "dracut-config-rescue", + }, + EnabledServices: []string{ + "sshd", + "waagent", // needed to run in Azure + }, + DisabledServices: []string{ + "proc-sys-fs-binfmt_misc.mount", + "loadmodules.service", + }, + // These kernel parameters are required by Azure documentation + KernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", + Bootable: true, + DefaultSize: 2 * GigaByte, + Assembler: func(uefi bool, 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{ + "@core", + "chrony", + "firewalld", + "kernel", + "langpacks-en", + "open-vm-tools", + "selinux-policy-targeted", + }, + 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 { + return r.qemuAssembler("vmdk", "disk.vmdk", uefi, size) + }, + } + + return &r +} + +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) Repositories(arch string) []rpmmd.RepoConfig { + return r.arches[arch].Repositories +} + +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 +} + +func (r *Fedora32) FilenameFromType(outputFormat string) (string, string, error) { + if output, exists := r.outputs[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 + } + if size == 0 { + size = r.outputs[outputFormat].DefaultSize + } + 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(b *blueprint.Blueprint, additionalRepos []rpmmd.RepoConfig, packageSpecs, buildPackageSpecs []rpmmd.PackageSpec, checksums map[string]string, 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) + } + + p := &osbuild.Pipeline{} + p.SetBuild(r.buildPipeline(arch, checksums), "org.osbuild.fedora32") + + packages, excludedPackages, err := r.BasePackages(outputFormat, outputArchitecture) + if err != nil { + return nil, err + } + packages = append(packages, b.GetPackages()...) + + p.AddStage(osbuild.NewDNFStage(r.dnfStageOptions(arch, additionalRepos, checksums, packages, excludedPackages))) + p.AddStage(osbuild.NewFixBLSStage()) + + // TODO support setting all languages and install corresponding langpack-* package + language, keyboard := b.GetPrimaryLocale() + + if language != nil { + p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{*language})) + } else { + p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{"en_US"})) + } + + if keyboard != nil { + p.AddStage(osbuild.NewKeymapStage(&osbuild.KeymapStageOptions{*keyboard})) + } + + if hostname := b.GetHostname(); hostname != nil { + p.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{*hostname})) + } + + timezone, ntpServers := b.GetTimezoneSettings() + + // TODO install chrony when this is set? + if timezone != nil { + p.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{*timezone})) + } + + if len(ntpServers) > 0 { + p.AddStage(osbuild.NewChronyStage(&osbuild.ChronyStageOptions{ntpServers})) + } + + if users := b.GetUsers(); len(users) > 0 { + options, err := r.userStageOptions(users) + if err != nil { + return nil, err + } + p.AddStage(osbuild.NewUsersStage(options)) + } + + if groups := b.GetGroups(); len(groups) > 0 { + p.AddStage(osbuild.NewGroupsStage(r.groupStageOptions(groups))) + } + + if output.Bootable { + p.AddStage(osbuild.NewFSTabStage(r.fsTabStageOptions(arch.UEFI))) + } + p.AddStage(osbuild.NewGRUB2Stage(r.grub2StageOptions(output.KernelOptions, b.GetKernel(), arch.UEFI))) + + if services := b.GetServices(); services != nil || output.EnabledServices != nil { + p.AddStage(osbuild.NewSystemdStage(r.systemdStageOptions(output.EnabledServices, output.DisabledServices, services))) + } + + if firewall := b.GetFirewall(); firewall != nil { + p.AddStage(osbuild.NewFirewallStage(r.firewallStageOptions(firewall))) + } + + p.AddStage(osbuild.NewSELinuxStage(r.selinuxStageOptions())) + + p.Assembler = output.Assembler(arch.UEFI, size) + + return p, nil +} + +func (r *Fedora32) Sources(packages []rpmmd.PackageSpec) *osbuild.Sources { + return &osbuild.Sources{} +} + +func (r *Fedora32) Runner() string { + return "org.osbuild.fedora32" +} + +func (r *Fedora32) buildPipeline(arch arch, checksums map[string]string) *osbuild.Pipeline { + packages, err := r.BuildPackages(arch.Name) + if err != nil { + panic("impossibly invalid arch") + } + + p := &osbuild.Pipeline{} + p.AddStage(osbuild.NewDNFStage(r.dnfStageOptions(arch, nil, checksums, packages, nil))) + return p +} + +func (r *Fedora32) dnfStageOptions(arch arch, additionalRepos []rpmmd.RepoConfig, checksums map[string]string, packages, excludedPackages []string) *osbuild.DNFStageOptions { + options := &osbuild.DNFStageOptions{ + ReleaseVersion: "32", + BaseArchitecture: arch.Name, + ModulePlatformId: ModulePlatformID, + } + + for _, repo := range append(arch.Repositories, additionalRepos...) { + options.AddRepository(&osbuild.DNFRepository{ + BaseURL: repo.BaseURL, + MetaLink: repo.Metalink, + MirrorList: repo.MirrorList, + GPGKey: repo.GPGKey, + Checksum: checksums[repo.Id], + }) + } + + sort.Strings(packages) + for _, pkg := range packages { + options.AddPackage(pkg) + } + + sort.Strings(excludedPackages) + for _, pkg := range excludedPackages { + options.ExcludePackage(pkg) + } + + return options +} + +func (r *Fedora32) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { + options := osbuild.UsersStageOptions{ + Users: make(map[string]osbuild.UsersStageOptionsUser), + } + + for _, c := range users { + if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { + cryptedPassword, err := crypt.CryptSHA512(*c.Password) + if err != nil { + return nil, err + } + + c.Password = &cryptedPassword + } + + user := osbuild.UsersStageOptionsUser{ + Groups: c.Groups, + Description: c.Description, + Home: c.Home, + Shell: c.Shell, + Password: c.Password, + Key: c.Key, + } + + if c.UID != nil { + uid := strconv.Itoa(*c.UID) + user.UID = &uid + } + + if c.GID != nil { + gid := strconv.Itoa(*c.GID) + user.GID = &gid + } + + options.Users[c.Name] = user + } + + return &options, nil +} + +func (r *Fedora32) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { + options := osbuild.GroupsStageOptions{ + Groups: map[string]osbuild.GroupsStageOptionsGroup{}, + } + + for _, group := range groups { + groupData := osbuild.GroupsStageOptionsGroup{ + Name: group.Name, + } + if group.GID != nil { + gid := strconv.Itoa(*group.GID) + groupData.GID = &gid + } + + options.Groups[group.Name] = groupData + } + + return &options +} + +func (r *Fedora32) firewallStageOptions(firewall *blueprint.FirewallCustomization) *osbuild.FirewallStageOptions { + options := osbuild.FirewallStageOptions{ + Ports: firewall.Ports, + } + + if firewall.Services != nil { + options.EnabledServices = firewall.Services.Enabled + options.DisabledServices = firewall.Services.Disabled + } + + return &options +} + +func (r *Fedora32) systemdStageOptions(enabledServices, disabledServices []string, s *blueprint.ServicesCustomization) *osbuild.SystemdStageOptions { + if s != nil { + enabledServices = append(enabledServices, s.Enabled...) + disabledServices = append(disabledServices, s.Disabled...) + } + return &osbuild.SystemdStageOptions{ + EnabledServices: enabledServices, + DisabledServices: disabledServices, + } +} + +func (r *Fedora32) fsTabStageOptions(uefi bool) *osbuild.FSTabStageOptions { + options := osbuild.FSTabStageOptions{} + options.AddFilesystem("76a22bf4-f153-4541-b6c7-0332c0dfaeac", "ext4", "/", "defaults", 1, 1) + if uefi { + options.AddFilesystem("46BB-8120", "vfat", "/boot/efi", "umask=0077,shortname=winnt", 0, 2) + } + return &options +} + +func (r *Fedora32) 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") + } + + if kernel != nil { + kernelOptions += " " + kernel.Append + } + + var uefiOptions *osbuild.GRUB2UEFI + if uefi { + uefiOptions = &osbuild.GRUB2UEFI{ + Vendor: "fedora", + } + } + + return &osbuild.GRUB2StageOptions{ + RootFilesystemUUID: id, + KernelOptions: kernelOptions, + Legacy: !uefi, + UEFI: uefiOptions, + } +} + +func (r *Fedora32) selinuxStageOptions() *osbuild.SELinuxStageOptions { + return &osbuild.SELinuxStageOptions{ + FileContexts: "etc/selinux/targeted/contexts/files/file_contexts", + } +} + +func (r *Fedora32) qemuAssembler(format string, filename string, uefi bool, size uint64) *osbuild.Assembler { + var options osbuild.QEMUAssemblerOptions + if uefi { + fstype := uuid.MustParse("C12A7328-F81F-11D2-BA4B-00A0C93EC93B") + options = osbuild.QEMUAssemblerOptions{ + Format: format, + Filename: filename, + Size: size, + PTUUID: "8DFDFF87-C96E-EA48-A3A6-9408F1F6B1EF", + PTType: "gpt", + Partitions: []osbuild.QEMUPartition{ + { + Start: 2048, + Size: 972800, + Type: &fstype, + Filesystem: osbuild.QEMUFilesystem{ + Type: "vfat", + UUID: "46BB-8120", + Label: "EFI System Partition", + Mountpoint: "/boot/efi", + }, + }, + { + Start: 976896, + Filesystem: osbuild.QEMUFilesystem{ + Type: "ext4", + UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac", + Mountpoint: "/", + }, + }, + }, + } + } else { + options = osbuild.QEMUAssemblerOptions{ + Format: format, + Filename: filename, + Size: size, + PTUUID: "0x14fc63d2", + PTType: "mbr", + Partitions: []osbuild.QEMUPartition{ + { + Start: 2048, + Bootable: true, + Filesystem: osbuild.QEMUFilesystem{ + Type: "ext4", + UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac", + Mountpoint: "/", + }, + }, + }, + } + } + return osbuild.NewQEMUAssembler(&options) +} + +func (r *Fedora32) tarAssembler(filename, compression string) *osbuild.Assembler { + return osbuild.NewTarAssembler( + &osbuild.TarAssemblerOptions{ + Filename: filename, + Compression: compression, + }) +} + +func (r *Fedora32) rawFSAssembler(filename string, size uint64) *osbuild.Assembler { + id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac") + if err != nil { + panic("invalid UUID") + } + return osbuild.NewRawFSAssembler( + &osbuild.RawFSAssemblerOptions{ + Filename: filename, + RootFilesystemUUDI: id, + Size: size, + }) +} diff --git a/internal/distro/fedora32/distro_test.go b/internal/distro/fedora32/distro_test.go new file mode 100644 index 000000000..0ceb192ab --- /dev/null +++ b/internal/distro/fedora32/distro_test.go @@ -0,0 +1,113 @@ +package fedora32_test + +import ( + "reflect" + "testing" + + "github.com/osbuild/osbuild-composer/internal/distro" +) + +func TestListOutputFormats(t *testing.T) { + want := []string{ + "ami", + "ext4-filesystem", + "openstack", + "partitioned-disk", + "qcow2", + "tar", + "vhd", + "vmdk", + } + + distros := distro.NewRegistry([]string{"../../../"}) + f32 := distros.GetDistro("fedora-32") + 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 + } + tests := []struct { + name string + args args + want string + want1 string + wantErr bool + }{ + { + name: "ami", + args: args{"ami"}, + want: "image.raw.xz", + want1: "application/octet-stream", + }, + { + name: "ext4", + args: args{"ext4-filesystem"}, + want: "filesystem.img", + want1: "application/octet-stream", + }, + { + name: "openstack", + args: args{"openstack"}, + want: "disk.qcow2", + want1: "application/x-qemu-disk", + }, + { + name: "partitioned-disk", + args: args{"partitioned-disk"}, + want: "disk.img", + want1: "application/octet-stream", + }, + { + name: "qcow2", + args: args{"qcow2"}, + want: "disk.qcow2", + want1: "application/x-qemu-disk", + }, + { + name: "tar", + args: args{"tar"}, + want: "root.tar.xz", + want1: "application/x-tar", + }, + { + name: "vhd", + args: args{"vhd"}, + want: "disk.vhd", + want1: "application/x-vhd", + }, + { + name: "vmdk", + args: args{"vmdk"}, + want: "disk.vmdk", + want1: "application/x-vmdk", + }, + { + name: "invalid-output-type", + args: args{"foobar"}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + distros := distro.NewRegistry([]string{"../../../"}) + f32 := distros.GetDistro("fedora-32") + got, got1, err := f32.FilenameFromType(tt.args.outputFormat) + if (err != nil) != tt.wantErr { + t.Errorf("FilenameFromType() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got != tt.want { + t.Errorf("FilenameFromType() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("FilenameFromType() got1 = %v, want %v", got1, tt.want1) + } + } + }) + } +} diff --git a/repositories/fedora-32.json b/repositories/fedora-32.json new file mode 100644 index 000000000..d930f0d79 --- /dev/null +++ b/repositories/fedora-32.json @@ -0,0 +1,18 @@ +{ + "x86_64": [ + { + "id": "fedora", + "name": "Fedora 32", + "metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-32&arch=x86_64", + "gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF1RVqsBEADWMBqYv/G1r4PwyiPQCfg5fXFGXV1FCZ32qMi9gLUTv1CX7rYy\nH4Inj93oic+lt1kQ0kQCkINOwQczOkm6XDkEekmMrHknJpFLwrTK4AS28bYF2RjL\nM+QJ/dGXDMPYsP0tkLvoxaHr9WTRq89A+AmONcUAQIMJg3JxXAAafBi2UszUUEPI\nU35MyufFt2ePd1k/6hVAO8S2VT72TxXSY7Ha4X2J0pGzbqQ6Dq3AVzogsnoIi09A\n7fYutYZPVVAEGRUqavl0th8LyuZShASZ38CdAHBMvWV4bVZghd/wDV5ev3LXUE0o\nitLAqNSeiDJ3grKWN6v0qdU0l3Ya60sugABd3xaE+ROe8kDCy3WmAaO51Q880ZA2\niXOTJFObqkBTP9j9+ZeQ+KNE8SBoiH1EybKtBU8HmygZvu8ZC1TKUyL5gwGUJt8v\nergy5Bw3Q7av520sNGD3cIWr4fBAVYwdBoZT8RcsnU1PP67NmOGFcwSFJ/LpiOMC\npZ1IBvjOC7KyKEZY2/63kjW73mB7OHOd18BHtGVkA3QAdVlcSule/z68VOAy6bih\nE6mdxP28D4INsts8w6yr4G+3aEIN8u0qRQq66Ri5mOXTyle+ONudtfGg3U9lgicg\nz6oVk17RT0jV9uL6K41sGZ1sH/6yTXQKagdAYr3w1ix2L46JgzC+/+6SSwARAQAB\ntDFGZWRvcmEgKDMyKSA8ZmVkb3JhLTMyLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJdUVarAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRBsEwJtEslE0LdAD/wKdAMtfzr7O2y06/sOPnrb3D39Y2DXbB8y0iEmRdBL29Bq\n5btxwmAka7JZRJVFxPsOVqZ6KARjS0/oCBmJc0jCRANFCtM4UjVHTSsxrJfuPkel\nvrlNE9tcR6OCRpuj/PZgUa39iifF/FTUfDgh4Q91xiQoLqfBxOJzravQHoK9VzrM\nNTOu6J6l4zeGzY/ocj6DpT+5fdUO/3HgGFNiNYPC6GVzeiA3AAVR0sCyGENuqqdg\nwUxV3BIht05M5Wcdvxg1U9x5I3yjkLQw+idvX4pevTiCh9/0u+4g80cT/21Cxsdx\n7+DVHaewXbF87QQIcOAing0S5QE67r2uPVxmWy/56TKUqDoyP8SNsV62lT2jutsj\nLevNxUky011g5w3bc61UeaeKrrurFdRs+RwBVkXmtqm/i6g0ZTWZyWGO6gJd+HWA\nqY1NYiq4+cMvNLatmA2sOoCsRNmE9q6jM/ESVgaH8hSp8GcLuzt9/r4PZZGl5CvU\neldOiD221u8rzuHmLs4dsgwJJ9pgLT0cUAsOpbMPI0JpGIPQ2SG6yK7LmO6HFOxb\nAkz7IGUt0gy1MzPTyBvnB+WgD1I+IQXXsJbhP5+d+d3mOnqsd6oDM/grKBzrhoUe\noNadc9uzjqKlOrmrdIR3Bz38SSiWlde5fu6xPqJdmGZRNjXtcyJlbSPVDIloxw==\n=QWRO\n-----END PGP PUBLIC KEY BLOCK-----\n" + } + ], + "aarch64": [ + { + "id": "fedora", + "name": "Fedora 32", + "metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-32&arch=aarch64", + "gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF1RVqsBEADWMBqYv/G1r4PwyiPQCfg5fXFGXV1FCZ32qMi9gLUTv1CX7rYy\nH4Inj93oic+lt1kQ0kQCkINOwQczOkm6XDkEekmMrHknJpFLwrTK4AS28bYF2RjL\nM+QJ/dGXDMPYsP0tkLvoxaHr9WTRq89A+AmONcUAQIMJg3JxXAAafBi2UszUUEPI\nU35MyufFt2ePd1k/6hVAO8S2VT72TxXSY7Ha4X2J0pGzbqQ6Dq3AVzogsnoIi09A\n7fYutYZPVVAEGRUqavl0th8LyuZShASZ38CdAHBMvWV4bVZghd/wDV5ev3LXUE0o\nitLAqNSeiDJ3grKWN6v0qdU0l3Ya60sugABd3xaE+ROe8kDCy3WmAaO51Q880ZA2\niXOTJFObqkBTP9j9+ZeQ+KNE8SBoiH1EybKtBU8HmygZvu8ZC1TKUyL5gwGUJt8v\nergy5Bw3Q7av520sNGD3cIWr4fBAVYwdBoZT8RcsnU1PP67NmOGFcwSFJ/LpiOMC\npZ1IBvjOC7KyKEZY2/63kjW73mB7OHOd18BHtGVkA3QAdVlcSule/z68VOAy6bih\nE6mdxP28D4INsts8w6yr4G+3aEIN8u0qRQq66Ri5mOXTyle+ONudtfGg3U9lgicg\nz6oVk17RT0jV9uL6K41sGZ1sH/6yTXQKagdAYr3w1ix2L46JgzC+/+6SSwARAQAB\ntDFGZWRvcmEgKDMyKSA8ZmVkb3JhLTMyLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJdUVarAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRBsEwJtEslE0LdAD/wKdAMtfzr7O2y06/sOPnrb3D39Y2DXbB8y0iEmRdBL29Bq\n5btxwmAka7JZRJVFxPsOVqZ6KARjS0/oCBmJc0jCRANFCtM4UjVHTSsxrJfuPkel\nvrlNE9tcR6OCRpuj/PZgUa39iifF/FTUfDgh4Q91xiQoLqfBxOJzravQHoK9VzrM\nNTOu6J6l4zeGzY/ocj6DpT+5fdUO/3HgGFNiNYPC6GVzeiA3AAVR0sCyGENuqqdg\nwUxV3BIht05M5Wcdvxg1U9x5I3yjkLQw+idvX4pevTiCh9/0u+4g80cT/21Cxsdx\n7+DVHaewXbF87QQIcOAing0S5QE67r2uPVxmWy/56TKUqDoyP8SNsV62lT2jutsj\nLevNxUky011g5w3bc61UeaeKrrurFdRs+RwBVkXmtqm/i6g0ZTWZyWGO6gJd+HWA\nqY1NYiq4+cMvNLatmA2sOoCsRNmE9q6jM/ESVgaH8hSp8GcLuzt9/r4PZZGl5CvU\neldOiD221u8rzuHmLs4dsgwJJ9pgLT0cUAsOpbMPI0JpGIPQ2SG6yK7LmO6HFOxb\nAkz7IGUt0gy1MzPTyBvnB+WgD1I+IQXXsJbhP5+d+d3mOnqsd6oDM/grKBzrhoUe\noNadc9uzjqKlOrmrdIR3Bz38SSiWlde5fu6xPqJdmGZRNjXtcyJlbSPVDIloxw==\n=QWRO\n-----END PGP PUBLIC KEY BLOCK-----\n" + } + ] +} \ No newline at end of file