Skip to content

Commit

Permalink
cmd: implement manifest command
Browse files Browse the repository at this point in the history
This commit implements the `manifest` command for `image-builder`.
It will generate an osbuild manifest based on the given inputs,
e.g.:
```
$ ./image-builder manifest centos-9 qcow2
{"version":"2","pipelines":[{"name":"build","runner":",...
```

Note that there is an integration test but because of the depsolve
it will be slow. It will be skipped when doing `go test -short`.
  • Loading branch information
mvo5 committed Dec 2, 2024
1 parent 094c6fd commit 3dc94a3
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 16 deletions.
12 changes: 9 additions & 3 deletions cmd/image-builder/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"io"
"os"

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

var (
GetOneImage = getOneImage
Run = run
)

func MockOsArgs(new []string) (restore func()) {
Expand Down Expand Up @@ -49,6 +51,10 @@ func MockNewRepoRegistry(f func() (*reporegistry.RepoRegistry, error)) (restore
}
}

var (
Run = run
)
func MockDistrofactoryNew(f func() *distrofactory.Factory) (restore func()) {
saved := distrofactoryNew
distrofactoryNew = f
return func() {
distrofactoryNew = saved
}
}
5 changes: 4 additions & 1 deletion cmd/image-builder/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import (
"github.com/osbuild/images/pkg/imagefilter"
)

var distrofactoryNew = distrofactory.NewDefault

func newImageFilterDefault(dataDir string) (*imagefilter.ImageFilter, error) {
fac := distrofactory.NewDefault()
fac := distrofactoryNew()
repos, err := newRepoRegistry(dataDir)
if err != nil {
return nil, err
}

return imagefilter.New(fac, repos)
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/image-builder/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"github.com/osbuild/images/pkg/imagefilter"
)

func listImages(output string, filterExprs []string, opts *cmdlineOpts) error {
imageFilter, err := newImageFilterDefault(opts.dataDir)
func listImages(dataDir, output string, filterExprs []string) error {
imageFilter, err := newImageFilterDefault(dataDir)
if err != nil {
return err
}
Expand All @@ -19,7 +19,7 @@ func listImages(output string, filterExprs []string, opts *cmdlineOpts) error {
if err != nil {
return err
}
if err := fmter.Output(opts.out, filteredResult); err != nil {
if err := fmter.Output(osStdout, filteredResult); err != nil {
return err
}

Expand Down
64 changes: 55 additions & 9 deletions cmd/image-builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import (

"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint"

"github.com/osbuild/image-builder-cli/internal/manifestgen"
)

var (
osStdout io.Writer = os.Stdout
osStderr io.Writer = os.Stderr
)

type cmdlineOpts struct {
dataDir string
out io.Writer
}

func cmdListImages(cmd *cobra.Command, args []string) error {
filter, err := cmd.Flags().GetStringArray("filter")
if err != nil {
Expand All @@ -33,11 +33,46 @@ func cmdListImages(cmd *cobra.Command, args []string) error {
return err
}

opts := &cmdlineOpts{
out: osStdout,
dataDir: dataDir,
return listImages(dataDir, output, filter)
}

func cmdManifest(cmd *cobra.Command, args []string) error {
dataDir, err := cmd.Flags().GetString("datadir")
if err != nil {
return err
}

distroStr := args[0]
imgTypeStr := args[1]
var archStr string
if len(args) > 2 {
archStr = args[2]
} else {
archStr = arch.Current().String()
}
return listImages(output, filter, opts)
// XXX: this is not symetric, ideally we would only pass
// either a single reporegistry from a datadir everywhere
// or we would pass datadir everywhere but with just
// datadir we cannot create test distros as they cannot be
// defined outside of code so manifestgen needs to take a
// reporegistry instead of just a datadir
res, err := getOneImage(dataDir, distroStr, imgTypeStr, archStr)
if err != nil {
return err
}
repos, err := newRepoRegistry(dataDir)
if err != nil {
return err
}
// XXX: add --rpmmd/cachedir option like bib
mg, err := manifestgen.New(repos, &manifestgen.Options{
Output: osStdout,
})
if err != nil {
return err
}
var bp blueprint.Blueprint
return mg.Generate(&bp, res.Distro, res.ImgType, res.Arch, nil)
}

func run() error {
Expand Down Expand Up @@ -69,6 +104,17 @@ operating sytsems like centos and RHEL with easy customizations support.`,
listImagesCmd.Flags().String("output", "", "Output in a specific format (text, json)")
rootCmd.AddCommand(listImagesCmd)

manifestCmd := &cobra.Command{
Use: "manifest <distro> <image-type> [<arch>]",
Short: "Build manifest for the given distro/image-type, e.g. centos-9 qcow2",
RunE: cmdManifest,
SilenceUsage: true,
Args: cobra.MinimumNArgs(2),
Hidden: true,
}
// XXX: add blueprint switch
rootCmd.AddCommand(manifestCmd)

return rootCmd.Execute()
}

Expand Down
37 changes: 37 additions & 0 deletions cmd/image-builder/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main_test
import (
"bytes"
"encoding/json"
"os"
"testing"

"github.com/sirupsen/logrus"
Expand All @@ -11,6 +12,7 @@ import (
testrepos "github.com/osbuild/images/test/data/repositories"

"github.com/osbuild/image-builder-cli/cmd/image-builder"
"github.com/osbuild/image-builder-cli/internal/manifesttest"
)

func init() {
Expand Down Expand Up @@ -108,3 +110,38 @@ func TestListImagesOverrideDatadir(t *testing.T) {
err := main.Run()
assert.EqualError(t, err, `no repositories found in the given paths: [/this/path/does/not/exist]`)
}

func hasDepsolveDnf() bool {
// XXX: expose images/pkg/depsolve:findDepsolveDnf()
_, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf")
return err == nil
}

// XXX: move to pytest like bib maybe?
func TestManifestIntegrationSmoke(t *testing.T) {
if testing.Short() {
t.Skip("manifest generation takes a while")
}
if !hasDepsolveDnf() {
t.Skip("no osbuild-depsolve-dnf binary found")
}

restore := main.MockNewRepoRegistry(testrepos.New)
defer restore()

restore = main.MockOsArgs([]string{
"manifest", "centos-9", "qcow2"},
)
defer restore()

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

err := main.Run()
assert.NoError(t, err)

pipelineNames, err := manifesttest.PipelineNamesFrom(fakeStdout.Bytes())
assert.NoError(t, err)
assert.Contains(t, pipelineNames, "qcow2")
}

0 comments on commit 3dc94a3

Please sign in to comment.