diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7a116d2c2c..5e57690190 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -282,7 +282,18 @@ jobs: - *apt_install_dependencies - - run: sudo apt install -y qemu-user-static + - run: sudo apt install -y qemu-user-static dnf + + - uses: actions/checkout@v5 + with: + path: osbuild + repository: osbuild/osbuild + ref: main + + - name: install osbuild + run: + cd osbuild + sudo python3 -m pip install --break-system-packages -e . - name: Check out code into the Go module directory uses: actions/checkout@v5 diff --git a/cmd/gen-manifests/main.go b/cmd/gen-manifests/main.go index b7f356596a..901696b077 100644 --- a/cmd/gen-manifests/main.go +++ b/cmd/gen-manifests/main.go @@ -30,6 +30,7 @@ import ( "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/manifestgen" "github.com/osbuild/images/pkg/manifestgen/manifestmock" + "github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/ostree" "github.com/osbuild/images/pkg/rhsm/facts" "github.com/osbuild/images/pkg/rpmmd" @@ -260,6 +261,10 @@ func makeManifestJob( }() msgq <- fmt.Sprintf("Starting job %s", filename) + opts := &manifest.SerializeOptions{ + RpmDownloader: osbuild.RpmDownloaderLibrepo, + } + manifest, _, err := imgType.Manifest(&bp, options, repos, &seedArg) if err != nil { err = fmt.Errorf("[%s] failed: %s", filename, err) @@ -303,7 +308,7 @@ func makeManifestJob( commitSpecs = manifestmock.ResolveCommits(manifest.GetOSTreeSourceSpecs()) } - mf, err := manifest.Serialize(depsolvedSets, containerSpecs, commitSpecs, nil) + mf, err := manifest.Serialize(depsolvedSets, containerSpecs, commitSpecs, opts) if err != nil { return fmt.Errorf("[%s] manifest serialization failed: %s", filename, err.Error()) } diff --git a/data/distrodefs/fedora/imagetypes.yaml b/data/distrodefs/fedora/imagetypes.yaml index 7f910c7299..de3a4cc9cc 100644 --- a/data/distrodefs/fedora/imagetypes.yaml +++ b/data/distrodefs/fedora/imagetypes.yaml @@ -1718,7 +1718,7 @@ image_types: - "distro" - "customizations.installer" - "minimal-installer": + "minimal-installer": &minimal_installer name_aliases: ["image-installer", "fedora-image-installer"] filename: "installer.iso" mime_type: "application/x-iso9660-image" @@ -1761,6 +1761,125 @@ image_types: - *anaconda_pkgset supported_blueprint_options: *supported_options_anaconda + "bootc-installer": + <<: *minimal_installer + # unset aliases + name_aliases: + package_sets: + installer: + - include: + # from bootc-image-builder:distrodefs + - aajohan-comfortaa-fonts + - abattis-cantarell-fonts + - alsa-firmware + - alsa-tools-firmware + - anaconda + - anaconda-dracut + - anaconda-install-img-deps + - anaconda-widgets + - atheros-firmware + - audit + - bind-utils + - bitmap-fangsongti-fonts + - brcmfmac-firmware + - bzip2 + - cryptsetup + - curl + - dbus-x11 + - dejavu-sans-fonts + - dejavu-sans-mono-fonts + - device-mapper-persistent-data + - dmidecode + - dnf + - dracut-config-generic + - dracut-network + - efibootmgr + - ethtool + - fcoe-utils + - ftp + - gdb-gdbserver + - gdisk + - glibc-all-langpacks + - gnome-kiosk + - google-noto-sans-cjk-ttc-fonts + - grub2-tools + - grub2-tools-extra + - grub2-tools-minimal + - grubby + - gsettings-desktop-schemas + - hdparm + - hexedit + - hostname + - initscripts + - ipmitool + - iwlwifi-dvm-firmware + - iwlwifi-mvm-firmware + - jomolhari-fonts + - kbd + - kbd-misc + - kdump-anaconda-addon + - kernel + - khmeros-base-fonts + - less + - libblockdev-lvm-dbus + - libibverbs + - libreport-plugin-bugzilla + - libreport-plugin-reportuploader + - librsvg2 + - linux-firmware + - lldpad + - lsof + - madan-fonts + - mt-st + - mtr + - net-tools + - nfs-utils + - nm-connection-editor + - nmap-ncat + - nss-tools + - openssh-clients + - openssh-server + - ostree + - pciutils + - perl-interpreter + - pigz + - plymouth + - prefixdevname + - python3-pyatspi + - rdma-core + - realtek-firmware + - rit-meera-new-fonts + - rng-tools + - rpcbind + - rpm-ostree + - rsync + - rsyslog + - selinux-policy-targeted + - sg3_utils + - sil-abyssinica-fonts + - sil-padauk-fonts + - smartmontools + - spice-vdagent + - strace + - systemd + - tar + - tigervnc-server-minimal + - tigervnc-server-module + - udisks2 + - udisks2-iscsi + - usbutils + - vim-minimal + - volume_key + - wget + - xfsdump + - xfsprogs + - xorg-x11-drivers + - xorg-x11-fonts-misc + - xorg-x11-server-Xorg + - xorg-x11-xauth + - xrdb + - xz + container: &container filename: "container.tar" mime_type: "application/x-tar" diff --git a/data/distrodefs/rhel-10/imagetypes.yaml b/data/distrodefs/rhel-10/imagetypes.yaml index c27fbeed0a..9b92adef67 100644 --- a/data/distrodefs/rhel-10/imagetypes.yaml +++ b/data/distrodefs/rhel-10/imagetypes.yaml @@ -1591,7 +1591,7 @@ image_types: - "centos-release" - "image-installer": + "image-installer": &image_installer filename: "installer.iso" mime_type: "application/x-iso9660-image" bootable: true @@ -1746,6 +1746,104 @@ image_types: include: - "dmidecode" + "bootc-installer": + <<: *image_installer + package_sets: + installer: + - include: + # from bootc-image-builder distrodefs + - "@hardware-support" + - alsa-firmware + - alsa-tools-firmware + - anaconda + - anaconda-dracut + - anaconda-install-img-deps + - anaconda-widgets + - audit + - bind-utils + - bzip2 + - cryptsetup + - curl + - dbus-x11 + - dejavu-sans-fonts + - dejavu-sans-mono-fonts + - device-mapper-persistent-data + - dmidecode + - dnf + - dracut-config-generic + - dracut-network + - efibootmgr + - ethtool + - fcoe-utils + - ftp + - gdb-gdbserver + - glibc-all-langpacks + - gnome-kiosk + - google-noto-sans-cjk-ttc-fonts + - grub2-tools + - grub2-tools-extra + - grub2-tools-minimal + - grubby + - gsettings-desktop-schemas + - hdparm + - hexedit + - hostname + - initscripts + - ipmitool + - jomolhari-fonts + - kbd + - kbd-misc + - kdump-anaconda-addon + - kernel + - less + - libblockdev-lvm-dbus + - libibverbs + - librsvg2 + - linux-firmware + - lldpad + - lsof + - madan-fonts + - mt-st + - mtr + - net-tools + - nfs-utils + - nm-connection-editor + - nmap-ncat + - nss-tools + - openssh-clients + - openssh-server + - ostree + - pciutils + - perl-interpreter + - pigz + - plymouth + - prefixdevname + - python3-pyatspi + - rdma-core + - rng-tools + - rpcbind + - rpm-ostree + - rsync + - rsyslog + - selinux-policy-targeted + - sg3_utils + - sil-padauk-fonts + - smartmontools + - spice-vdagent + - strace + - systemd + - tar + - udisks2 + - udisks2-iscsi + - usbutils + - vim-minimal + - volume_key + - wget + - xfsdump + - xfsprogs + - xrdb + - xz + gce: # this image type is set to `gcp` in image-builder-crc # & `osbuild-composer`, so set the alias here diff --git a/data/distrodefs/rhel-9/imagetypes.yaml b/data/distrodefs/rhel-9/imagetypes.yaml index 45f026c84a..0827d04990 100644 --- a/data/distrodefs/rhel-9/imagetypes.yaml +++ b/data/distrodefs/rhel-9/imagetypes.yaml @@ -2115,8 +2115,7 @@ image_types: - "centos-logos" - "centos-release" - - "image-installer": + "image-installer": &image_installer filename: "installer.iso" mime_type: "application/x-iso9660-image" bootable: true @@ -2179,6 +2178,117 @@ image_types: - *installer_pkgset - *anaconda_pkgset + "bootc-installer": + <<: *image_installer + package_sets: + installer: + - include: + # from bootc-image-builder imagedefs + - aajohan-comfortaa-fonts + - abattis-cantarell-fonts + - alsa-firmware + - alsa-tools-firmware + - anaconda + - anaconda-dracut + - anaconda-install-env-deps + - anaconda-widgets + - audit + - bind-utils + - bitmap-fangsongti-fonts + - bzip2 + - cryptsetup + - curl + - dbus-x11 + - dejavu-sans-fonts + - dejavu-sans-mono-fonts + - device-mapper-persistent-data + - dmidecode + - dnf + - dracut-config-generic + - dracut-network + - efibootmgr + - ethtool + - fcoe-utils + - ftp + - gdb-gdbserver + - gdisk + - glibc-all-langpacks + - gnome-kiosk + - google-noto-sans-cjk-ttc-fonts + - grub2-tools + - grub2-tools-extra + - grub2-tools-minimal + - grubby + - gsettings-desktop-schemas + - hdparm + - hexedit + - hostname + - initscripts + - ipmitool + - jomolhari-fonts + - kbd + - kbd-misc + - kdump-anaconda-addon + - kernel + - khmeros-base-fonts + - less + - libblockdev-lvm-dbus + - libibverbs + - libreport-plugin-bugzilla + - libreport-plugin-reportuploader + - librsvg2 + - linux-firmware + - lldpad + - lsof + - madan-fonts + - mt-st + - mtr + - net-tools + - nfs-utils + - nm-connection-editor + - nmap-ncat + - nss-tools + - openssh-clients + - openssh-server + - ostree + - pciutils + - perl-interpreter + - pigz + - plymouth + - prefixdevname + - python3-pyatspi + - rdma-core + - rng-tools + - rpcbind + - rpm-ostree + - rsync + - rsyslog + - selinux-policy-targeted + - sg3_utils + - sil-abyssinica-fonts + - sil-padauk-fonts + - smartmontools + - spice-vdagent + - strace + - systemd + - tar + - tigervnc-server-minimal + - tigervnc-server-module + - udisks2 + - udisks2-iscsi + - usbutils + - vim-minimal + - volume_key + - wget + - xfsdump + - xfsprogs + - xorg-x11-drivers + - xorg-x11-fonts-misc + - xorg-x11-server-Xorg + - xorg-x11-xauth + - xrdb + - xz + gce: # this image type is set to `gcp` in image-builder-crc # & `osbuild-composer`, so set the alias here diff --git a/pkg/distro/bootc/bootc.go b/pkg/distro/bootc/bootc.go index 8888c10be2..712a3d6806 100644 --- a/pkg/distro/bootc/bootc.go +++ b/pkg/distro/bootc/bootc.go @@ -3,9 +3,13 @@ package bootc import ( "errors" "fmt" + "slices" "sort" + "strconv" "strings" + "github.com/sirupsen/logrus" + "github.com/osbuild/blueprint/pkg/blueprint" "github.com/osbuild/images/internal/common" @@ -13,18 +17,23 @@ import ( bibcontainer "github.com/osbuild/images/pkg/bib/container" "github.com/osbuild/images/pkg/bib/osinfo" "github.com/osbuild/images/pkg/container" + "github.com/osbuild/images/pkg/customizations/anaconda" + "github.com/osbuild/images/pkg/customizations/kickstart" "github.com/osbuild/images/pkg/customizations/users" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/distro" + "github.com/osbuild/images/pkg/distro/defs" + "github.com/osbuild/images/pkg/dnfjson" "github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/manifest" + "github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/platform" "github.com/osbuild/images/pkg/policies" "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/runner" ) -var _ = distro.Distro(&BootcDistro{}) +var _ = distro.CustomDepsolverDistro(&BootcDistro{}) type BootcDistro struct { imgref string @@ -58,6 +67,8 @@ type BootcImageType struct { export string // file extension ext string + // image is an iso + iso bool } func (d *BootcDistro) SetBuildContainer(imgref string) (err error) { @@ -123,6 +134,31 @@ func (d *BootcDistro) OSTreeRef() string { return "" } +func (d *BootcDistro) Depsolver(rpmCacheRoot string, archi arch.Arch) (solver *dnfjson.Solver, cleanup func(), err error) { + cnt, err := bibcontainer.New(d.buildImgref) + if err != nil { + return nil, nil, err + } + defer func() { + if err != nil { + err = errors.Join(err, cnt.Stop()) + } + }() + + cleanup = func() { + cnt.Stop() + } + if err := cnt.InitDNF(); err != nil { + return nil, nil, err + } + solver, err = cnt.NewContainerSolver(rpmCacheRoot, archi, d.buildSourceInfo) + if err != nil { + return nil, nil, err + } + + return solver, cleanup, nil +} + func (d *BootcDistro) ListArches() []string { archs := make([]string, 0, len(d.arches)) for name := range d.arches { @@ -201,6 +237,9 @@ func (t *BootcImageType) Arch() distro.Arch { } func (t *BootcImageType) Filename() string { + if t.iso { + return "install.iso" + } return fmt.Sprintf("disk.%s", t.ext) } @@ -266,7 +305,7 @@ func (t *BootcImageType) RequiredBlueprintOptions() []string { return nil } -func (t *BootcImageType) Manifest(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { +func (t *BootcImageType) manifestForDisk(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { if t.arch.distro.imgref == "" { return nil, nil, fmt.Errorf("internal error: no base image defined") } @@ -366,6 +405,215 @@ func (t *BootcImageType) Manifest(bp *blueprint.Blueprint, options distro.ImageO return &mf, nil, nil } +func needsRHELLoraxTemplates(si osinfo.OSRelease) bool { + return si.ID == "rhel" || slices.Contains(si.IDLike, "rhel") || si.VersionID == "eln" +} +func getDistroAndRunner(osRelease osinfo.OSRelease) (manifest.Distro, runner.Runner, error) { + switch osRelease.ID { + case "fedora": + version, err := strconv.ParseUint(osRelease.VersionID, 10, 64) + if err != nil { + return manifest.DISTRO_NULL, nil, fmt.Errorf("cannot parse Fedora version (%s): %w", osRelease.VersionID, err) + } + + return manifest.DISTRO_FEDORA, &runner.Fedora{ + Version: version, + }, nil + case "centos": + version, err := strconv.ParseUint(osRelease.VersionID, 10, 64) + if err != nil { + return manifest.DISTRO_NULL, nil, fmt.Errorf("cannot parse CentOS version (%s): %w", osRelease.VersionID, err) + } + r := &runner.CentOS{ + Version: version, + } + switch version { + case 9: + return manifest.DISTRO_EL9, r, nil + case 10: + return manifest.DISTRO_EL10, r, nil + default: + logrus.Warnf("Unknown CentOS version %d, using default distro for manifest generation", version) + return manifest.DISTRO_NULL, r, nil + } + + case "rhel": + versionParts := strings.Split(osRelease.VersionID, ".") + if len(versionParts) != 2 { + return manifest.DISTRO_NULL, nil, fmt.Errorf("invalid RHEL version format: %s", osRelease.VersionID) + } + major, err := strconv.ParseUint(versionParts[0], 10, 64) + if err != nil { + return manifest.DISTRO_NULL, nil, fmt.Errorf("cannot parse RHEL major version (%s): %w", versionParts[0], err) + } + minor, err := strconv.ParseUint(versionParts[1], 10, 64) + if err != nil { + return manifest.DISTRO_NULL, nil, fmt.Errorf("cannot parse RHEL minor version (%s): %w", versionParts[1], err) + } + r := &runner.RHEL{ + Major: major, + Minor: minor, + } + switch major { + case 9: + return manifest.DISTRO_EL9, r, nil + case 10: + return manifest.DISTRO_EL10, r, nil + default: + logrus.Warnf("Unknown RHEL version %d, using default distro for manifest generation", major) + return manifest.DISTRO_NULL, r, nil + } + } + + logrus.Warnf("Unknown distro %s, using default runner", osRelease.ID) + return manifest.DISTRO_NULL, &runner.Linux{}, nil +} + +func labelForISO(os *osinfo.OSRelease, arch *arch.Arch) string { + switch os.ID { + case "fedora": + return fmt.Sprintf("Fedora-S-dvd-%s-%s", arch, os.VersionID) + case "centos": + labelTemplate := "CentOS-Stream-%s-BaseOS-%s" + if os.VersionID == "8" { + labelTemplate = "CentOS-Stream-%s-%s-dvd" + } + return fmt.Sprintf(labelTemplate, os.VersionID, arch) + case "rhel": + version := strings.ReplaceAll(os.VersionID, ".", "-") + return fmt.Sprintf("RHEL-%s-BaseOS-%s", version, arch) + default: + return fmt.Sprintf("Container-Installer-%s", arch) + } +} + +func (t *BootcImageType) manifestForISO(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { + if t.arch.distro.imgref == "" { + return nil, nil, fmt.Errorf("pipeline: no base image defined") + } + + containerSource := container.SourceSpec{ + Source: t.arch.distro.imgref, + Name: t.arch.distro.imgref, + Local: true, + } + + // XXX: duplicated + archi := common.Must(arch.FromString(t.arch.Name())) + platform := &platform.Data{ + Arch: archi, + UEFIVendor: t.arch.distro.sourceInfo.UEFIVendor, + QCOW2Compat: "1.1", + } + switch archi { + case arch.ARCH_X86_64: + platform.BIOSPlatform = "i386-pc" + case arch.ARCH_PPC64LE: + platform.BIOSPlatform = "powerpc-ieee1275" + case arch.ARCH_S390X: + platform.ZiplSupport = true + } + + // The ref is not needed and will be removed from the ctor later + // in time + img := image.NewAnacondaContainerInstaller(platform, "install.iso", containerSource, "") + img.ContainerRemoveSignatures = true + img.RootfsCompression = "zstd" + + if archi == arch.ARCH_X86_64 { + img.InstallerCustomizations.ISOBoot = manifest.Grub2ISOBoot + } + + img.InstallerCustomizations.Product = t.arch.distro.sourceInfo.OSRelease.Name + img.InstallerCustomizations.OSVersion = t.arch.distro.sourceInfo.OSRelease.VersionID + + nameVer := fmt.Sprintf("%s-%v", t.arch.distro.sourceInfo.OSRelease.ID, t.arch.distro.sourceInfo.OSRelease.VersionID) + id, err := distro.ParseID(nameVer) + if err != nil { + return nil, nil, err + } + // XXX: we need to fallback to distro-like here + dy, err := defs.NewDistroYAML(nameVer) + if err != nil { + return nil, nil, err + } + di, ok := dy.ImageTypes()["bootc-installer"] + if !ok { + return nil, nil, fmt.Errorf("no image bootc image type for %q", dy.Name) + } + img.ExtraBasePackages = rpmmd.PackageSet{ + Include: di.PackageSets(*id, t.arch.Name())["installer"].Include, + } + // XXX: use dy.getISOLabelFunc() + img.InstallerCustomizations.ISOLabel = labelForISO(&t.arch.distro.sourceInfo.OSRelease, &archi) + + var customizations *blueprint.Customizations + if bp != nil { + customizations = bp.Customizations + } + img.InstallerCustomizations.FIPS = customizations.GetFIPS() + img.Kickstart, err = kickstart.New(customizations) + if err != nil { + return nil, nil, err + } + img.Kickstart.Path = osbuild.KickstartPathOSBuild + if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" { + img.Kickstart.KernelOptionsAppend = append(img.Kickstart.KernelOptionsAppend, kopts.Append) + } + img.Kickstart.NetworkOnBoot = true + + instCust, err := customizations.GetInstaller() + if err != nil { + return nil, nil, err + } + if instCust != nil && instCust.Modules != nil { + img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, instCust.Modules.Enable...) + img.InstallerCustomizations.DisabledAnacondaModules = append(img.InstallerCustomizations.DisabledAnacondaModules, instCust.Modules.Disable...) + } + img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, + // XXX: ??? + "org.fedoraproject.Anaconda.Modules.Network", + "org.fedoraproject.Anaconda.Modules.Payloads", + "org.fedoraproject.Anaconda.Modules.Runtime", + "org.fedoraproject.Anaconda.Modules.Storage", + anaconda.ModuleUsers, + anaconda.ModuleServices, + anaconda.ModuleSecurity, + ) + + img.Kickstart.OSTree = &kickstart.OSTree{ + OSName: "default", + } + img.InstallerCustomizations.UseRHELLoraxTemplates = needsRHELLoraxTemplates(t.arch.distro.sourceInfo.OSRelease) + // see https://github.com/osbuild/bootc-image-builder/issues/733 + img.InstallerCustomizations.ISORootfsType = manifest.SquashfsRootfs + + installRootfsType, err := disk.NewFSType(t.arch.distro.defaultFs) + if err != nil { + return nil, nil, err + } + img.InstallRootfsType = installRootfsType + + mf := manifest.New() + + foundDistro, foundRunner, err := getDistroAndRunner(t.arch.distro.sourceInfo.OSRelease) + if err != nil { + return nil, nil, fmt.Errorf("failed to infer distro and runner: %w", err) + } + mf.Distro = foundDistro + + rng := createRand() + _, err = img.InstantiateManifest(&mf, repos, foundRunner, rng) + return &mf, nil, err +} + +func (t *BootcImageType) Manifest(bp *blueprint.Blueprint, options distro.ImageOptions, repos []rpmmd.RepoConfig, seedp *int64) (*manifest.Manifest, []string, error) { + if t.iso { + return t.manifestForISO(bp, options, repos, seedp) + } + return t.manifestForDisk(bp, options, repos, seedp) +} + // newBootcDistro returns a new instance of BootcDistro // from the given url func NewBootcDistro(imgref string) (bd *BootcDistro, err error) { @@ -448,6 +696,17 @@ func NewBootcDistro(imgref string) (bd *BootcDistro, err error) { export: "gce", ext: "tar.gz", }, + // Image types that build ISOs + BootcImageType{ + name: "anaconda-iso", + export: "bootiso", + iso: true, + }, + BootcImageType{ + name: "iso", + export: "bootiso", + iso: true, + }, ) bd.addArches(ba) } diff --git a/pkg/distro/distro.go b/pkg/distro/distro.go index e6e41049c7..d5fbf55fcd 100644 --- a/pkg/distro/distro.go +++ b/pkg/distro/distro.go @@ -4,9 +4,11 @@ import ( "math/rand" "github.com/osbuild/blueprint/pkg/blueprint" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/customizations/subscription" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk/partition" + "github.com/osbuild/images/pkg/dnfjson" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/ostree" "github.com/osbuild/images/pkg/platform" @@ -56,6 +58,12 @@ type Distro interface { GetArch(arch string) (Arch, error) } +type CustomDepsolverDistro interface { + Distro + + Depsolver(cacheDir string, archi arch.Arch) (solver *dnfjson.Solver, cleanup func(), err error) +} + // An Arch represents a given distribution's support for a given architecture. type Arch interface { // Returns the name of the architecture. diff --git a/pkg/manifestgen/manifestgen.go b/pkg/manifestgen/manifestgen.go index b689abb81f..ac96b0ffbf 100644 --- a/pkg/manifestgen/manifestgen.go +++ b/pkg/manifestgen/manifestgen.go @@ -12,6 +12,8 @@ import ( "strings" "github.com/osbuild/blueprint/pkg/blueprint" + "github.com/osbuild/images/internal/common" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/dnfjson" @@ -152,7 +154,10 @@ func (mg *Generator) Generate(bp *blueprint.Blueprint, dist distro.Distro, imgTy } else { repos, err = mg.reporegistry.ReposByImageTypeName(dist.Name(), a.Name(), imgType.Name()) if err != nil { - return err + // XXX: hack! + if !strings.HasPrefix(dist.Name(), "bootc-") { + return err + } } } // To support "user" a.k.a. "3rd party" repositories, these @@ -171,10 +176,12 @@ func (mg *Generator) Generate(bp *blueprint.Blueprint, dist distro.Distro, imgTy return fmt.Errorf("Warnings during manifest creation:\n%v", warn) } } + depsolved, err := mg.depsolver(mg.cacheDir, mg.depsolveWarningsOutput, preManifest.GetPackageSetChains(), dist, a.Name()) if err != nil { return err } + containerSpecs, err := mg.containerResolver(preManifest.GetContainerSourceSpecs(), a.Name()) if err != nil { return err @@ -245,7 +252,7 @@ func xdgCacheHome() (string, error) { // DefaultDepsolver provides a default implementation for depsolving. // It should rarely be necessary to use it directly and will be used // by default by manifestgen (unless overriden) -func DefaultDepsolver(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]dnfjson.DepsolveResult, error) { +func DefaultDepsolver(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, dist distro.Distro, archi string) (map[string]dnfjson.DepsolveResult, error) { if cacheDir == "" { xdgCacheHomeDir, err := xdgCacheHome() if err != nil { @@ -253,8 +260,17 @@ func DefaultDepsolver(cacheDir string, depsolveWarningsOutput io.Writer, package } cacheDir = filepath.Join(xdgCacheHomeDir, defaultDepsolveCacheDir) } - - solver := dnfjson.NewSolver(d.ModulePlatformID(), d.Releasever(), arch, d.Name(), cacheDir) + var solver *dnfjson.Solver + if dd, ok := dist.(distro.CustomDepsolverDistro); ok { + soli, cleanupFunc, err := dd.Depsolver(cacheDir, common.Must(arch.FromString(archi))) + if err != nil { + return nil, err + } + solver = soli + defer cleanupFunc() + } else { + solver = dnfjson.NewSolver(dist.ModulePlatformID(), dist.Releasever(), archi, dist.Name(), cacheDir) + } if depsolveWarningsOutput != nil { solver.Stderr = depsolveWarningsOutput diff --git a/tools/gen-bootc-diff b/tools/gen-bootc-diff index 986fbd4430..839b883239 100755 --- a/tools/gen-bootc-diff +++ b/tools/gen-bootc-diff @@ -10,10 +10,6 @@ set -o pipefail (cd "$(dirname "$0")"/../cmd/gen-manifests && go build -buildvcs=false) -# we only need to test a single type, all bootc disk manifests -# contain all possible types by default -TYPE=qcow2 - BPDIR=$(mktemp -d) trap 'rm -rf -- "$BPDIR"' EXIT BP_EMPTY="$BPDIR/empty.json" @@ -75,54 +71,76 @@ cat < "$BP_LVM" } EOF - for REF in quay.io/centos-bootc/centos-bootc:stream9 \ quay.io/fedora/fedora-bootc:42; do for ARCH in x86_64 aarch64; do for BP in "$BP_FULL_FS" "$BP_LVM" "$BP_EMPTY"; do - for BUILD_REF in "" "quay.io/fedora/fedora-bootc:41"; do - echo "Testing $REF;$ARCH;$(basename "$BP")" - sudo podman pull -q --arch "$ARCH" "$REF" - if [ -n "$BUILD_REF" ]; then - sudo podman pull -q --arch "$ARCH" "$BUILD_REF" - fi + for BUILD_REF in "quay.io/fedora/fedora-bootc:41" ""; do + for TYPE in anaconda-iso qcow2; do + echo "Testing $REF;$ARCH;$(basename "$BP");$BUILD_REF" + + # XXX: --build-ref for ISO is very problematic + # as the buildcontainer will point to different + # repos. + if [ "$TYPE" = "anaconda-iso" ] && [ -n "$BUILD_REF" ]; then + echo "Skipping ISO with buildref" + continue + fi + + sudo podman pull -q --arch "$ARCH" "$REF" + if [ -n "$BUILD_REF" ]; then + sudo podman pull -q --arch "$ARCH" "$BUILD_REF" + fi + + TMPDIR=$(mktemp -d) + trap 'rm -rf -- "$TMPDIR"' EXIT - TMPDIR=$(mktemp -d) - trap 'rm -rf -- "$TMPDIR"' EXIT + ROOTFS="" + if grep -q fedora <(echo "$REF"); then + ROOTFS="ext4" + fi - ROOTFS="" - if grep -q fedora <(echo "$REF"); then - ROOTFS="ext4" - fi + # we cannot just go run + # github.com/osbuild/bootc-image-builder... here + # because bib uses a "imagedefs" directory that + # is loaded from real files + sudo podman run \ + --quiet \ + --rm -i \ + --privileged \ + --pull=newer \ + --security-opt label=type:unconfined_t \ + -v "$BP":/config.json \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + ghcr.io/osbuild/bootc-image-builder:latest \ + manifest "$REF" \ + --target-arch "$ARCH" \ + --rootfs "$ROOTFS" \ + --build-container "$BUILD_REF" \ + --type "$TYPE" > "$TMPDIR/bib.json" - sudo go run \ - -buildvcs=false \ - github.com/osbuild/bootc-image-builder/bib/cmd/bootc-image-builder@main \ - manifest -v "$REF" \ - --config "$BP" \ - --target-arch "$ARCH" \ - --rootfs "$ROOTFS" \ - --build-container "$BUILD_REF" \ - --type "$TYPE" | jq > "$TMPDIR/bib.json" + # oh well, we need to convert our blueprint into the + # gen-manifests config :/ + echo '{"blueprint":' > "$TMPDIR"/gm-conf.json + cat "$BP" >> "$TMPDIR"/gm-conf.json + echo '}' >> "$TMPDIR"/gm-conf.json + sudo ./cmd/gen-manifests/gen-manifests \ + -types "$TYPE" \ + -arches "$ARCH" \ + -distros ignore \ + -metadata=false \ + -config "$TMPDIR"/gm-conf.json \ + -bootc-refs "$REF#$BUILD_REF" \ + -output "$TMPDIR" - # oh well, we need to convert our blueprint into the - # gen-manifests config :/ - echo '{"blueprint":' > "$TMPDIR"/gm-conf.json - cat "$BP" >> "$TMPDIR"/gm-conf.json - echo '}' >> "$TMPDIR"/gm-conf.json - sudo ./cmd/gen-manifests/gen-manifests \ - -types "$TYPE" \ - -arches "$ARCH" \ - -distros ignore \ - -metadata=false \ - -config "$TMPDIR"/gm-conf.json \ - -bootc-refs "$REF#$BUILD_REF" \ - -output "$TMPDIR" + # ensure manifests are identical (but skip uuid diffs) + echo "Comparing images and bootc-image-builder generated manifests" + diff -u <(jq < "$TMPDIR"/bootc_*.json | grep -E -v '(uuid|volid)' ) <(jq < "$TMPDIR"/bib.json | grep -E -v '(uuid|volid)') - # ensure manifests are identical (but skip uuid diffs) - echo "Comparing images and bootc-image-builder generated manifests" - diff -u <(grep -v uuid "$TMPDIR"/bootc_*.json) <(grep -v uuid "$TMPDIR"/bib.json) + echo "DONE" + echo + done done done done