main: add new --registrations options
This new flag allows to add a file with registration data. This
is meant to eventually hold all sort of registrations like
ansible or satelite but initially only contains the redhat
subscription. Currently only JSON is supported.
It looks like:
```json:
{
"redhat": {
"subscription": {
"activation_key": "ak_123",
"organization": "org_123",
"server_url": "server_url_123",
"base_url": "base_url_123",
"insights": true,
"rhc": true,
"proxy": "proxy_123"
}
}
}
```
This is not part of the blueprint (today) because its more
ephemeral than the things we usually put into the blueprint.
This allows us to build images that are immediately registered. It
also keeps our options open in the future. If we move to a new
blueprint format where we support multiple blueprints and also
ephemeral data like this the "registrations" flag just becomes an
alias for "--blueprint".
This commit is contained in:
parent
020dbd6f41
commit
aecbe5928a
4 changed files with 140 additions and 3 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/osbuild/images/pkg/cloud"
|
||||
"github.com/osbuild/images/pkg/cloud/awscloud"
|
||||
"github.com/osbuild/images/pkg/manifestgen"
|
||||
"github.com/osbuild/images/pkg/reporegistry"
|
||||
)
|
||||
|
||||
|
|
@ -71,3 +72,11 @@ func MockAwscloudNewUploader(f func(string, string, string, *awscloud.UploaderOp
|
|||
awscloudNewUploader = saved
|
||||
}
|
||||
}
|
||||
|
||||
func MockManifestgenDepsolver(new manifestgen.DepsolveFunc) (restore func()) {
|
||||
saved := manifestgenDepsolver
|
||||
manifestgenDepsolver = new
|
||||
return func() {
|
||||
manifestgenDepsolver = saved
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -17,6 +18,7 @@ import (
|
|||
|
||||
"github.com/osbuild/image-builder-cli/pkg/progress"
|
||||
"github.com/osbuild/images/pkg/arch"
|
||||
"github.com/osbuild/images/pkg/customizations/subscription"
|
||||
"github.com/osbuild/images/pkg/imagefilter"
|
||||
"github.com/osbuild/images/pkg/osbuild"
|
||||
"github.com/osbuild/images/pkg/ostree"
|
||||
|
|
@ -97,6 +99,37 @@ func ostreeImageOptions(cmd *cobra.Command) (*ostree.ImageOptions, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
type registrations struct {
|
||||
Redhat struct {
|
||||
Subscription *subscription.ImageOptions `json:"subscription,omitempty"`
|
||||
} `json:"redhat,omitempty"`
|
||||
}
|
||||
|
||||
func subscriptionImageOptions(cmd *cobra.Command) (*subscription.ImageOptions, error) {
|
||||
regFilePath, err := cmd.Flags().GetString("registrations")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if regFilePath == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
f, err := os.Open(regFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot open registrations file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// XXX: support yaml eventually
|
||||
var regs registrations
|
||||
dec := json.NewDecoder(f)
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(®s); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse registrations file: %w", err)
|
||||
}
|
||||
return regs.Redhat.Subscription, nil
|
||||
}
|
||||
|
||||
type cmdManifestWrapperOptions struct {
|
||||
useBootstrapIfNeeded bool
|
||||
}
|
||||
|
|
@ -160,6 +193,10 @@ func cmdManifestWrapper(pbar progress.ProgressBar, cmd *cobra.Command, args []st
|
|||
}
|
||||
customSeed = &seedFlagVal
|
||||
}
|
||||
subscription, err := subscriptionImageOptions(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// no error check here as this is (deliberately) not defined on
|
||||
// "manifest" (if "images" learn to set the output filename in
|
||||
// manifests we would change this
|
||||
|
|
@ -199,6 +236,7 @@ func cmdManifestWrapper(pbar progress.ProgressBar, cmd *cobra.Command, args []st
|
|||
RpmDownloader: rpmDownloader,
|
||||
WithSBOM: withSBOM,
|
||||
CustomSeed: customSeed,
|
||||
Subscription: subscription,
|
||||
|
||||
ForceRepos: forceRepos,
|
||||
}
|
||||
|
|
@ -407,7 +445,7 @@ operating systems like Fedora, CentOS and RHEL with easy customizations support.
|
|||
RunE: cmdListImages,
|
||||
SilenceUsage: true,
|
||||
Args: cobra.NoArgs,
|
||||
Aliases: []string{"list-images"},
|
||||
Aliases: []string{"list-images"},
|
||||
}
|
||||
listCmd.Flags().StringArray("filter", nil, `Filter distributions by a specific criteria (e.g. "type:iot*")`)
|
||||
listCmd.Flags().String("format", "", "Output in a specific format (text, json)")
|
||||
|
|
@ -430,6 +468,7 @@ operating systems like Fedora, CentOS and RHEL with easy customizations support.
|
|||
manifestCmd.Flags().String("ostree-url", "", `OSTREE url`)
|
||||
manifestCmd.Flags().Bool("use-librepo", true, `use librepo to download packages (disable if you use old versions of osbuild)`)
|
||||
manifestCmd.Flags().Bool("with-sbom", false, `export SPDX SBOM document`)
|
||||
manifestCmd.Flags().String("registrations", "", `filename of a registrations file with e.g. subscription details`)
|
||||
rootCmd.AddCommand(manifestCmd)
|
||||
|
||||
uploadCmd := &cobra.Command{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package main_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -18,6 +19,9 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/osbuild/images/pkg/distro"
|
||||
"github.com/osbuild/images/pkg/dnfjson"
|
||||
"github.com/osbuild/images/pkg/rpmmd"
|
||||
testrepos "github.com/osbuild/images/test/data/repositories"
|
||||
|
||||
main "github.com/osbuild/image-builder-cli/cmd/image-builder"
|
||||
|
|
@ -948,3 +952,81 @@ func TestBasenameFor(t *testing.T) {
|
|||
assert.Equal(t, tc.expected, main.BasenameFor(res, tc.basename))
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: move into as manifestgen.FakeDepsolve
|
||||
func fakeDepsolve(cacheDir string, depsolveWarningsOutput io.Writer, packageSets map[string][]rpmmd.PackageSet, d distro.Distro, arch string) (map[string]dnfjson.DepsolveResult, error) {
|
||||
depsolvedSets := make(map[string]dnfjson.DepsolveResult)
|
||||
|
||||
for name, pkgSetChain := range packageSets {
|
||||
specSet := make([]rpmmd.PackageSpec, 0)
|
||||
for _, pkgSet := range pkgSetChain {
|
||||
include := pkgSet.Include
|
||||
slices.Sort(include)
|
||||
for _, pkgName := range include {
|
||||
checksum := fmt.Sprintf("%x", sha256.Sum256([]byte(pkgName)))
|
||||
spec := rpmmd.PackageSpec{
|
||||
Name: pkgName,
|
||||
Checksum: "sha256:" + checksum,
|
||||
}
|
||||
specSet = append(specSet, spec)
|
||||
}
|
||||
|
||||
depsolvedSets[name] = dnfjson.DepsolveResult{
|
||||
Packages: specSet,
|
||||
Repos: pkgSet.Repositories,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return depsolvedSets, nil
|
||||
}
|
||||
|
||||
func TestManifestIntegrationWithRegistrations(t *testing.T) {
|
||||
restore := main.MockManifestgenDepsolver(fakeDepsolve)
|
||||
defer restore()
|
||||
|
||||
restore = main.MockNewRepoRegistry(testrepos.New)
|
||||
defer restore()
|
||||
|
||||
// XXX: only "proxy_123", "server_url_123" are actually observable
|
||||
// in the manifest(?)
|
||||
fakeRegContent := `{
|
||||
"redhat": {
|
||||
"subscription": {
|
||||
"activation_key": "ak_123",
|
||||
"organization": "org_123",
|
||||
"server_url": "server_url_123",
|
||||
"base_url": "base_url_123",
|
||||
"insights": true,
|
||||
"rhc": true,
|
||||
"proxy": "proxy_123"
|
||||
}
|
||||
}
|
||||
}`
|
||||
fakeRegistrationsPath := filepath.Join(t.TempDir(), "registrations.json")
|
||||
err := os.WriteFile(fakeRegistrationsPath, []byte(fakeRegContent), 0644)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// XXX: fake the depsolving or we will need full support for
|
||||
// subscripbed hosts in the tests
|
||||
restore = main.MockOsArgs([]string{
|
||||
"manifest",
|
||||
"qcow2",
|
||||
"--arch=x86_64",
|
||||
"--distro=rhel-9.6",
|
||||
"--registrations", fakeRegistrationsPath,
|
||||
})
|
||||
defer restore()
|
||||
|
||||
var fakeStdout bytes.Buffer
|
||||
restore = main.MockOsStdout(&fakeStdout)
|
||||
defer restore()
|
||||
|
||||
err = main.Run()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// XXX: manifesttest really needs to grow more helpers
|
||||
assert.Contains(t, fakeStdout.String(), `{"type":"org.osbuild.insights-client.config","options":{"proxy":"proxy_123"}}`)
|
||||
assert.Contains(t, fakeStdout.String(), `"type":"org.osbuild.systemd.unit.create","options":{"filename":"osbuild-subscription-register.service"`)
|
||||
assert.Contains(t, fakeStdout.String(), `server_url_123`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/images/pkg/customizations/subscription"
|
||||
"github.com/osbuild/images/pkg/distro"
|
||||
"github.com/osbuild/images/pkg/imagefilter"
|
||||
"github.com/osbuild/images/pkg/manifestgen"
|
||||
|
|
@ -22,6 +23,7 @@ type manifestOptions struct {
|
|||
OutputFilename string
|
||||
BlueprintPath string
|
||||
Ostree *ostree.ImageOptions
|
||||
Subscription *subscription.ImageOptions
|
||||
RpmDownloader osbuild.RpmDownloader
|
||||
WithSBOM bool
|
||||
CustomSeed *int64
|
||||
|
|
@ -46,6 +48,9 @@ func sbomWriter(outputDir, filename string, content io.Reader) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// used in tests
|
||||
var manifestgenDepsolver manifestgen.DepsolveFunc
|
||||
|
||||
func generateManifest(dataDir string, extraRepos []string, img *imagefilter.Result, output io.Writer, depsolveWarningsOutput io.Writer, opts *manifestOptions) error {
|
||||
repos, err := newRepoRegistry(dataDir, extraRepos)
|
||||
if err != nil {
|
||||
|
|
@ -58,6 +63,7 @@ func generateManifest(dataDir string, extraRepos []string, img *imagefilter.Resu
|
|||
RpmDownloader: opts.RpmDownloader,
|
||||
UseBootstrapContainer: opts.UseBootstrapContainer,
|
||||
CustomSeed: opts.CustomSeed,
|
||||
Depsolver: manifestgenDepsolver,
|
||||
}
|
||||
if opts.WithSBOM {
|
||||
outputDir := basenameFor(img, opts.OutputDir)
|
||||
|
|
@ -84,9 +90,10 @@ func generateManifest(dataDir string, extraRepos []string, img *imagefilter.Resu
|
|||
return err
|
||||
}
|
||||
var imgOpts *distro.ImageOptions
|
||||
if opts.Ostree != nil {
|
||||
if opts.Ostree != nil || opts.Subscription != nil {
|
||||
imgOpts = &distro.ImageOptions{
|
||||
OSTree: opts.Ostree,
|
||||
OSTree: opts.Ostree,
|
||||
Subscription: opts.Subscription,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue