mirror of
https://github.com/hauler-dev/hauler.git
synced 2026-08-19 04:16:27 +00:00
allow reference string to be passed to AddArtifact instead of name.ParseReference for ease of use, move reference validation within AddArtifact
This commit is contained in:
+12
-23
@@ -2,8 +2,10 @@ package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
|
||||
@@ -94,17 +96,13 @@ func storeFile(ctx context.Context, s *store.Store, fi v1alpha1.File) error {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
f := file.NewFile(fi.Ref)
|
||||
ref, err := name.ParseReference(f.Name(fi.Ref), name.WithDefaultRegistry(""))
|
||||
|
||||
desc, err := s.AddArtifact(ctx, f, f.Name(fi.Ref))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
desc, err := s.AddArtifact(ctx, f, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", ref.Name())
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", desc.Annotations[ocispec.AnnotationRefName])
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -133,17 +131,12 @@ func storeImage(ctx context.Context, s *store.Store, i v1alpha1.Image) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(i.Ref)
|
||||
desc, err := s.AddArtifact(ctx, oci, i.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
desc, err := s.AddArtifact(ctx, oci, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", ref.Name())
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", i.Ref)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -171,29 +164,25 @@ func AddChartCmd(ctx context.Context, o *AddChartOpts, s *store.Store, chartName
|
||||
return storeChart(ctx, s, cfg)
|
||||
}
|
||||
|
||||
func storeChart(ctx context.Context, s *store.Store, ch v1alpha1.Chart) error {
|
||||
func storeChart(ctx context.Context, s *store.Store, cfg v1alpha1.Chart) error {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
oci, err := chart.NewChart(ch.Name, ch.RepoURL, ch.Version)
|
||||
oci, err := chart.NewChart(cfg.Name, cfg.RepoURL, cfg.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tag := ch.Version
|
||||
tag := cfg.Version
|
||||
if tag == "" {
|
||||
tag = name.DefaultTag
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(ch.Name, name.WithDefaultRegistry(""), name.WithDefaultTag(tag))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ref := fmt.Sprintf("%s:%s", cfg.Name, tag)
|
||||
desc, err := s.AddArtifact(ctx, oci, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", ref.Name())
|
||||
l.With(log.Fields{"type": s.Identify(ctx, desc)}).Infof("added [%s] to store", ref)
|
||||
return nil
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
@@ -20,5 +19,5 @@ type OCI interface {
|
||||
|
||||
type Collection interface {
|
||||
// Contents returns the list of contents in the collection
|
||||
Contents() (map[name.Reference]OCI, error)
|
||||
Contents() (map[string]OCI, error)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ type tchart struct {
|
||||
config v1alpha1.ThickChart
|
||||
|
||||
computed bool
|
||||
contents map[gname.Reference]artifact.OCI
|
||||
contents map[string]artifact.OCI
|
||||
}
|
||||
|
||||
func NewChart(cfg v1alpha1.ThickChart) (artifact.Collection, error) {
|
||||
@@ -29,11 +29,11 @@ func NewChart(cfg v1alpha1.ThickChart) (artifact.Collection, error) {
|
||||
return &tchart{
|
||||
chart: o,
|
||||
config: cfg,
|
||||
contents: make(map[gname.Reference]artifact.OCI),
|
||||
contents: make(map[string]artifact.OCI),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *tchart) Contents() (map[gname.Reference]artifact.OCI, error) {
|
||||
func (c *tchart) Contents() (map[string]artifact.OCI, error) {
|
||||
if err := c.compute(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,12 +70,7 @@ func (c *tchart) chartContents() error {
|
||||
tag = gname.DefaultTag
|
||||
}
|
||||
|
||||
ref, err := gname.ParseReference(c.config.Name, gname.WithDefaultRegistry(""), gname.WithDefaultTag(tag))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.contents[ref] = oci
|
||||
c.contents[c.config.Name] = oci
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -91,32 +86,22 @@ func (c *tchart) dependentImages() error {
|
||||
}
|
||||
|
||||
for _, img := range imgs.Spec.Images {
|
||||
ref, err := gname.ParseReference(img.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i, err := image.NewImage(img.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.contents[ref] = i
|
||||
c.contents[img.Ref] = i
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *tchart) extraImages() error {
|
||||
for _, img := range c.config.ExtraImages {
|
||||
ref, err := gname.ParseReference(img.Reference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i, err := image.NewImage(img.Reference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.contents[ref] = i
|
||||
c.contents[img.Reference] = i
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
"github.com/rancherfederal/hauler/internal/getter"
|
||||
"github.com/rancherfederal/hauler/pkg/artifact"
|
||||
"github.com/rancherfederal/hauler/pkg/content/file"
|
||||
@@ -38,7 +36,7 @@ type k3s struct {
|
||||
arch string
|
||||
|
||||
computed bool
|
||||
contents map[name.Reference]artifact.OCI
|
||||
contents map[string]artifact.OCI
|
||||
channels map[string]string
|
||||
client *getter.Client
|
||||
}
|
||||
@@ -46,11 +44,11 @@ type k3s struct {
|
||||
func NewK3s(version string) (artifact.Collection, error) {
|
||||
return &k3s{
|
||||
version: version,
|
||||
contents: make(map[name.Reference]artifact.OCI),
|
||||
contents: make(map[string]artifact.OCI),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k *k3s) Contents() (map[name.Reference]artifact.OCI, error) {
|
||||
func (k *k3s) Contents() (map[string]artifact.OCI, error) {
|
||||
if err := k.compute(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,11 +96,7 @@ func (k *k3s) executable() error {
|
||||
|
||||
f := file.NewFile(fref)
|
||||
|
||||
ref, err := name.ParseReference("k3s", name.WithDefaultTag(k.dnsCompliantVersion()), name.WithDefaultRegistry(""))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ref := fmt.Sprintf("k3s:%s", k.dnsCompliantVersion())
|
||||
k.contents[ref] = f
|
||||
return nil
|
||||
}
|
||||
@@ -110,13 +104,7 @@ func (k *k3s) executable() error {
|
||||
func (k *k3s) bootstrap() error {
|
||||
namedBootstrapUrl := fmt.Sprintf("%s?filename=%s", bootstrapUrl, "k3s-init.sh")
|
||||
f := file.NewFile(namedBootstrapUrl)
|
||||
|
||||
ref, err := name.ParseReference("k3s-init.sh", name.WithDefaultRegistry(""), name.WithDefaultTag("latest"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.contents[ref] = f
|
||||
k.contents["k3s-init.sh"] = f
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -132,16 +120,12 @@ func (k *k3s) images() error {
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for scanner.Scan() {
|
||||
reference := scanner.Text()
|
||||
ref, err := name.ParseReference(reference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o, err := image.NewImage(reference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.contents[ref] = o
|
||||
k.contents[reference] = o
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,73 +1 @@
|
||||
package chart_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
|
||||
"github.com/rancherfederal/hauler/pkg/content/chart"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
func TestChart_Copy(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
l := log.NewLogger(os.Stdout)
|
||||
ctx = l.WithContext(ctx)
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "hauler")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer os.Remove(tmpdir)
|
||||
|
||||
s, err := store.NewStore(tmpdir)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
registry string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg v1alpha1.Chart
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: This test isn't self-contained
|
||||
{
|
||||
name: "should work with unversioned chart",
|
||||
cfg: v1alpha1.Chart{
|
||||
Name: "loki",
|
||||
RepoURL: "https://grafana.github.io/helm-charts",
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
registry: "",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c, err := chart.NewChart(tt.cfg.Name, tt.cfg.RepoURL, tt.cfg.Version)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ref, err := name.ParseReference(path.Join("hauler", tt.cfg.Name))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := s.AddArtifact(ctx, c, ref); (err != nil) != tt.wantErr {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,100 +1 @@
|
||||
package image_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
|
||||
"github.com/rancherfederal/hauler/pkg/content/image"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
func TestImage_Copy(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
l := log.NewLogger(os.Stdout)
|
||||
ctx = l.WithContext(ctx)
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "hauler")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer os.Remove(tmpdir)
|
||||
|
||||
s, err := store.NewStore(tmpdir)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
registry string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg v1alpha1.Image
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: These mostly test functionality we're not responsible for (go-containerregistry), refactor these to only stuff we care about
|
||||
{
|
||||
name: "should work with tagged image",
|
||||
cfg: v1alpha1.Image{
|
||||
Ref: "busybox:1.34.1",
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
// registry: s.Registry(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "should work with digest image",
|
||||
cfg: v1alpha1.Image{
|
||||
Ref: "busybox@sha256:6066ca124f8c2686b7ae71aa1d6583b28c6dc3df3bdc386f2c89b92162c597d9",
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
// registry: s.Registry(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "should work with tagged image",
|
||||
cfg: v1alpha1.Image{
|
||||
Ref: "registry:2",
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
// registry: s.Registry(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i, err := image.NewImage(tt.cfg.Ref)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(path.Join("hauler", filepath.Base(tt.cfg.Ref)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := s.AddArtifact(ctx, i, ref); (err != nil) != tt.wantErr {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// if err := s.Add(tt.args.ctx, i, ref); (err != nil) != tt.wantErr {
|
||||
// t.Errorf("Copy() error = %v, wantErr %v", err, tt.wantErr)
|
||||
// }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"oras.land/oras-go/pkg/content"
|
||||
"oras.land/oras-go/pkg/oras"
|
||||
"oras.land/oras-go/pkg/target"
|
||||
@@ -24,6 +25,10 @@ type Store struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidReference = errors.New("invalid reference")
|
||||
)
|
||||
|
||||
func NewStore(rootdir string, opts ...Options) (*Store, error) {
|
||||
ociStore, err := content.NewOCI(rootdir)
|
||||
if err != nil {
|
||||
@@ -46,7 +51,7 @@ func NewStore(rootdir string, opts ...Options) (*Store, error) {
|
||||
// saved, the entirety of the layout is copied to the store (which is just a registry). This allows us to not only use
|
||||
// strict types to define generic content, but provides a processing pipeline suitable for extensibility. In the
|
||||
// future we'll allow users to define their own content that must adhere either by artifact.OCI or simply an OCI layout.
|
||||
func (s *Store) AddArtifact(ctx context.Context, oci artifact.OCI, reference name.Reference) (ocispec.Descriptor, error) {
|
||||
func (s *Store) AddArtifact(ctx context.Context, oci artifact.OCI, reference string) (ocispec.Descriptor, error) {
|
||||
stage, err := newLayout()
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
@@ -57,7 +62,13 @@ func (s *Store) AddArtifact(ctx context.Context, oci artifact.OCI, reference nam
|
||||
oci = cached
|
||||
}
|
||||
|
||||
if err := stage.add(ctx, oci, reference); err != nil {
|
||||
// Ensure that index.docker.io isn't prepended
|
||||
ref, err := name.ParseReference(reference, name.WithDefaultRegistry(""), name.WithDefaultTag("latest"))
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
|
||||
if err := stage.add(ctx, oci, ref); err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
return stage.commit(ctx, s)
|
||||
|
||||
+11
-9
@@ -8,7 +8,6 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
gv1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/partial"
|
||||
"github.com/google/go-containerregistry/pkg/v1/random"
|
||||
@@ -41,24 +40,27 @@ func TestStore_AddArtifact(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "should add artifact with a valid reference",
|
||||
name: "should add artifact with a valid tagged reference",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
reference: "random:v1",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "should fail with ErrInvalidReference when an invalid reference is provided",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
reference: "n0tV@l!d:v1",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ref, err := name.ParseReference(tt.args.reference)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oci, want := genArtifact(t, tt.args.reference)
|
||||
|
||||
oci, want := genArtifact(t, ref.Name())
|
||||
|
||||
got, err := s.AddArtifact(tt.args.ctx, oci, ref)
|
||||
got, err := s.AddArtifact(tt.args.ctx, oci, tt.args.reference)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("AddArtifact() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user