Skip to content

Commit

Permalink
cmd: add new image-builder binary and initial list-images cmd
Browse files Browse the repository at this point in the history
This commit adds a new `image-builder` binary that will (eventually)
be capable to build images standalone (daemonless). There are various
use-cases for this, the most important one is CI/CD pipelines but also
providing a common abstraction over the "images" library (and potentially
later "otk").

This commit implements basic a `list-images` command with filtering
and text and json output, e.g.
```
$ image-builder list-images --filter bootmode:none --filter name:fedora-39 --filter arch:s390x
fedora-39 --arch s390x --type container

$ ./image-builder list-images --filter bootmode:none --filter name:fedora-39 --filter arch:s390x --format=json
{"distro":{"name":"fedora-39"},"arch":{"name":"s390x"},"image_type":{"name":"container"}}
```
  • Loading branch information
mvo5 committed Oct 30, 2024
1 parent 1b53d5e commit a1cc037
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
26 changes: 26 additions & 0 deletions cmd/image-builder/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"io"
"os"
)

func MockOsArgs(new []string) (restore func()) {
saved := os.Args
os.Args = append([]string{"argv0"}, new...)
return func() {
os.Args = saved
}
}

func MockOsStdout(new io.Writer) (restore func()) {
saved := osStdout
osStdout = new
return func() {
osStdout = saved
}
}

var (
Run = run
)
48 changes: 48 additions & 0 deletions cmd/image-builder/list_images.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"io"
"os"
"strings"

"github.com/osbuild/images/pkg/distrofactory"
"github.com/osbuild/images/pkg/reporegistry"
)

// XXX: copied from "composer", should be exported there so
// that we keep this in sync
// XXX2: means we need to depend on osbuild-composer-common or something
var repositoryConfigs = []string{
"/etc/osbuild-composer",
"/usr/share/osbuild-composer",
}

func listImages(out io.Writer, format string, filterExprs []string) error {
// useful for development/debugging, e.g. run:
// go build && IMAGE_BUILDER_EXTRA_REPOS_PATH=../../test/data ./image-builder
if extraReposPath := os.Getenv("IMAGE_BUILDER_EXTRA_REPOS_PATH"); extraReposPath != "" {
repositoryConfigs = append(repositoryConfigs, strings.Split(extraReposPath, ":")...)
}

repos, err := reporegistry.New(repositoryConfigs)
if err != nil {
return err
}
filters, err := NewFilters(filterExprs)
if err != nil {
return err
}
fac := distrofactory.NewDefault()
filteredResult, err := FilterDistros(fac, repos.ListDistros(), filters)
if err != nil {
return err
}

fmter, err := NewFilteredResultFormatter(format)
if err != nil {
return err
}
fmter.Output(out, filteredResult)

Check failure on line 45 in cmd/image-builder/list_images.go

View workflow job for this annotation

GitHub Actions / ⌨ Lint

Error return value of `fmter.Output` is not checked (errcheck)

return nil
}
61 changes: 61 additions & 0 deletions cmd/image-builder/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"io"
"log"
"os"

"github.com/sirupsen/logrus"

"github.com/spf13/cobra"
)

var osStdout io.Writer = os.Stdout

func cmdListImages(cmd *cobra.Command, args []string) error {
filter, err := cmd.Flags().GetStringArray("filter")
if err != nil {
return err
}
format, err := cmd.Flags().GetString("format")
if err != nil {
return err
}

return listImages(osStdout, format, filter)
}

func run() error {
// images logs a bunch of stuff to Debug/Info that we we do not
// want to show
logrus.SetLevel(logrus.WarnLevel)

rootCmd := &cobra.Command{
Use: "image-builder",
Short: "Build operating system images from a given blueprint",
Long: `Build operating system images from a given blueprint
Image-builder builds operating system images for a range of predefined
operating sytsems like centos and RHEL with easy customizations support.`,
}

// XXX: this will list 802 images right now, we need a sensible
// default here, maybe without --filter just list all available
// distro names?
listImagesCmd := &cobra.Command{
Use: "list-images",
RunE: cmdListImages,
SilenceUsage: true,
}
listImagesCmd.Flags().StringArray("filter", nil, "Filter distributions by a specific criteria")
listImagesCmd.Flags().String("format", "", "Output in a specific format (text,json)")
rootCmd.AddCommand(listImagesCmd)

return rootCmd.Execute()
}

func main() {
if err := run(); err != nil {
log.Fatalf("error: %s", err)
}
}
26 changes: 26 additions & 0 deletions cmd/image-builder/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main_test

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"

"github.com/osbuild/images/cmd/image-builder"
)

func TestListImagesSmoke(t *testing.T) {
t.Setenv("IMAGE_BUILDER_EXTRA_REPOS_PATH", "../../test/data")

restore := main.MockOsArgs([]string{"list-images"})
defer restore()

var fakeStdout bytes.Buffer
restore = main.MockOsStdout(&fakeStdout)
defer restore()

err := main.Run()
assert.NoError(t, err)
// output is sorted
assert.Regexp(t, `(?ms)rhel-8.9.*rhel-8.10`, fakeStdout.String())
}

0 comments on commit a1cc037

Please sign in to comment.