Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 83 additions & 7 deletions cmd/gen-manifests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"

"github.com/gobwas/glob"
"gopkg.in/yaml.v3"

"github.com/osbuild/blueprint/pkg/blueprint"
"github.com/osbuild/images/internal/buildconfig"
"github.com/osbuild/images/internal/cmdutil"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/bib/osinfo"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/depsolvednf"
"github.com/osbuild/images/pkg/distro"
Expand Down Expand Up @@ -141,12 +143,9 @@ func loadConfigMap(configPath string, opts *buildconfig.Options) *BuildConfigs {
panic(fmt.Sprintf("failed to open config map %q: %s", configPath, err.Error()))
}
defer fp.Close()
data, err := io.ReadAll(fp)
if err != nil {
panic(fmt.Sprintf("failed to read config map %q: %s", configPath, err.Error()))
}

var cfgMap configMap
if err := json.Unmarshal(data, &cfgMap); err != nil {
if err := json.NewDecoder(fp).Decode(&cfgMap); err != nil {
panic(fmt.Sprintf("failed to unmarshal config map %q: %s", configPath, err.Error()))
}

Expand Down Expand Up @@ -258,6 +257,11 @@ func makeManifestJob(
}
msgq <- msg
}()
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("[%s] failed with panic: %s", filename, r)
}
}()
msgq <- fmt.Sprintf("Starting job %s", filename)

manifest, _, err := imgType.Manifest(&bp, options, repos, &seedArg)
Expand Down Expand Up @@ -395,10 +399,11 @@ func main() {
flag.BoolVar(&buildconfigAllowUnknown, "buildconfig-allow-unknown", false, "allow unknown keys in buildconfig")

// content args
var packages, containers, commits bool
var packages, containers, commits, fakeBootc bool
flag.BoolVar(&packages, "packages", true, "depsolve package sets")
flag.BoolVar(&containers, "containers", true, "resolve container checksums")
flag.BoolVar(&commits, "commits", false, "resolve ostree commit IDs")
flag.BoolVar(&fakeBootc, "fake-bootc", false, "create fake bootc containers based on test/bootc-fake-containers.yaml")

// manifest selection args
var arches, distros, imgTypes, bootcRefs cmdutil.MultiValue
Expand Down Expand Up @@ -568,6 +573,77 @@ func main() {
}
}
}
if fakeBootc {
p := "test/bootc-fake-containers.yaml"
f, err := os.Open(p)
if err != nil {
panic(fmt.Errorf("cannot find %q", p))
}
defer f.Close()
type fakeBootcContainerYAML struct {
Arch arch.Arch `yaml:"arch"`
Info osinfo.Info `yaml:"info"`
DefaultFs string `yaml:"default_fs"`
ContainerSize uint64 `yaml:"container_size"`
ImageRef string `yaml:"image_ref"`

BuildContainerRef string `yaml:"build_container_ref"`
BuildContainerInfo osinfo.Info `yaml:"build_container_info"`
}
type fakeContainersYAML struct {
Containers []fakeBootcContainerYAML
}
var fakeContainers fakeContainersYAML
dec := yaml.NewDecoder(f)
dec.KnownFields(true)
if err := dec.Decode(&fakeContainers); err != nil {
panic(err)
}
for _, fakeBootcCnt := range fakeContainers.Containers {
distribution, err := bootc.NewBootcDistroForTesting(fakeBootcCnt.Arch.String(), &fakeBootcCnt.Info, fakeBootcCnt.ImageRef, fakeBootcCnt.DefaultFs, fakeBootcCnt.ContainerSize)
if err != nil {
panic(err)
}
if fakeBootcCnt.BuildContainerRef != "" {
if err := distribution.SetBuildContainerForTesting(fakeBootcCnt.BuildContainerRef, &fakeBootcCnt.BuildContainerInfo); err != nil {
panic(err)
}
}

arches, _ := arches.ResolveArgValues(distribution.ListArches())
for _, archName := range arches {
archi, err := distribution.GetArch(archName)
if err != nil {
panic(err)
}
imgTypes, _ := imgTypes.ResolveArgValues(archi.ListImageTypes())
for _, imgTypeName := range imgTypes {
imgType, err := archi.GetImageType(imgTypeName)
if err != nil {
panic(err)
}
// XXX: copied from loop above
imgTypeConfigs := configs.Get(distribution.Name(), archName, imgTypeName)
if len(imgTypeConfigs) == 0 {
if skipNoconfig {
continue
}
panic(fmt.Sprintf("no configs defined for image type %q for %s/%s", imgTypeName, distribution.Name(), archi.Name()))
}
for _, itConfig := range imgTypeConfigs {
if needsSkipping, reason := configs.needsSkipping(distribution.Name(), itConfig); needsSkipping {
fmt.Printf("Skipping %s for %s/%s (reason: %v)\n", itConfig.Name, imgTypeName, distribution.Name(), reason)
continue
}

var repos []rpmmd.RepoConfig
job := makeManifestJob(itConfig, imgType, distribution, repos, archName, cacheRoot, outputDir, contentResolve, metadata, tmpdirRoot)
jobs = append(jobs, job)
}
}
}
}
}

nJobs := len(jobs)
fmt.Printf("Collected %d jobs\n", nJobs)
Expand Down
4 changes: 3 additions & 1 deletion internal/cmdutil/rand.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ func SeedArgFor(bc *buildconfig.BuildConfig, imgTypeName, distributionName, arch
h.Write([]byte(distributionName))
h.Write([]byte(archName))
h.Write([]byte(imgTypeName))
h.Write([]byte(bc.Name))
if bc != nil {
h.Write([]byte(bc.Name))
}

// nolint:gosec
return rngSeed + int64(h.Sum64()), nil
Expand Down
40 changes: 40 additions & 0 deletions pkg/bib/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package container

import (
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
Expand All @@ -16,6 +17,7 @@ import (
type Container struct {
id string
root string
arch string
}

// New creates a new running container from the given image reference.
Expand Down Expand Up @@ -62,6 +64,15 @@ func New(ref string) (*Container, error) {
c = nil
}
}()
// not all containers set {{.Architecture}} so fallback
c.arch, err = findContainerArchInspect(c.id, ref)
if err != nil {
var err2 error
c.arch, err2 = findContainerArchUname(c.id, ref)
if err2 != nil {
return nil, errors.Join(err, err2)
}
}

/* #nosec G204 */
output, err = exec.Command("podman", "mount", c.id).Output()
Expand Down Expand Up @@ -98,6 +109,11 @@ func (c *Container) Root() string {
return c.root
}

// Arch returns the architecture of the container
func (c *Container) Arch() string {
return c.arch
}

// Reads a file from the container
func (c *Container) ReadFile(path string) ([]byte, error) {
/* #nosec G204 */
Expand Down Expand Up @@ -168,3 +184,27 @@ func (c *Container) DefaultRootfsType() (string, error) {

return fsType, nil
}

func findContainerArchInspect(cntId, ref string) (string, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK the associated image always has an arch, I was able to retrieve the arch for ubi9 like this:

obudai@outland ~> podman ps
CONTAINER ID  IMAGE                                   COMMAND     CREATED             STATUS             PORTS       NAMES
2eaa8a5d582c  registry.access.redhat.com/ubi9:latest  /bin/bash   About a minute ago  Up About a minute              charming_dubinsky
obudai@outland ~> podman inspect -f '{{.Image}}' 2eaa8a5d582c
28fbac8f0a2b3ee82129b9feaae59d029a5eba93e5372002d2612d965979101a
obudai@outland ~> podman image inspect -f '{{.Architecture}}' 28fbac8f0a2b3ee82129b9feaae59d029a5eba93e5372002d2612d965979101a
arm64

Could be a tad cleaner than execing? Not sure. Alternatively, we can just always exec so there's just one codepath.

/* #nosec G204 */
output, err := exec.Command("podman", "inspect", "-f", "{{.Architecture}}", cntId).Output()
if err != nil {
if err, ok := err.(*exec.ExitError); ok {
return "", fmt.Errorf("inspecting container %q failed: %w\nstderr:\n%s", ref, err, err.Stderr)
}
return "", fmt.Errorf("inspecting %s container failed with generic error: %w", ref, err)
}
return strings.TrimSpace(string(output)), nil
}

func findContainerArchUname(cntId, ref string) (string, error) {
/* #nosec G204 */
output, err := exec.Command("podman", "exec", cntId, "uname", "-m").Output()
if err != nil {
if err, ok := err.(*exec.ExitError); ok {
return "", fmt.Errorf("running 'uname -m' from container %q failed: %w\nstderr:\n%s", cntId, err, err.Stderr)
}
return "", fmt.Errorf("running 'uname -m' from container %q failed with generic error: %w", cntId, err)
}
return strings.TrimSpace(string(output)), nil
}
6 changes: 3 additions & 3 deletions pkg/bib/osinfo/osinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ type KernelInfo struct {
}

type Info struct {
OSRelease OSRelease
UEFIVendor string
SELinuxPolicy string
OSRelease OSRelease `yaml:"os_release"`
UEFIVendor string `yaml:"uefi_vendor"`
SELinuxPolicy string `yaml:"selinux_policy"`
ImageCustomization *blueprint.Customizations
KernelInfo *KernelInfo

Expand Down
Loading
Loading