mirror of
https://github.com/hauler-dev/hauler.git
synced 2026-08-24 11:47:20 +00:00
Update imagetxt to align with 0.3, add tests; make content image type public
This commit is contained in:
@@ -22,8 +22,8 @@ type ImageTxt struct {
|
||||
IncludeSources map[string]bool
|
||||
ExcludeSources map[string]bool
|
||||
|
||||
getter local.Opener
|
||||
lock *sync.Mutex
|
||||
getter local.Opener
|
||||
computed bool
|
||||
contents map[name.Reference]artifact.OCI
|
||||
}
|
||||
@@ -34,23 +34,6 @@ type Option interface {
|
||||
Apply(*ImageTxt) error
|
||||
}
|
||||
|
||||
type withRef string
|
||||
|
||||
func (o withRef) Apply(it *ImageTxt) error {
|
||||
ref := string(o)
|
||||
|
||||
if strings.HasPrefix(ref, "http") || strings.HasPrefix(ref, "https") {
|
||||
it.getter = local.RemoteOpener(ref)
|
||||
} else {
|
||||
it.getter = local.LocalOpener(ref)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithRef(ref string) Option {
|
||||
return withRef(ref)
|
||||
}
|
||||
|
||||
type withIncludeSources []string
|
||||
|
||||
func (o withIncludeSources) Apply(it *ImageTxt) error {
|
||||
@@ -83,11 +66,19 @@ func WithExcludeSources(exclude ...string) Option {
|
||||
return withExcludeSources(exclude)
|
||||
}
|
||||
|
||||
func New(opts ...Option) (*ImageTxt, error) {
|
||||
func New(ref string, opts ...Option) (*ImageTxt, error) {
|
||||
it := &ImageTxt{
|
||||
Ref: ref,
|
||||
|
||||
lock: &sync.Mutex{},
|
||||
}
|
||||
|
||||
if strings.HasPrefix(ref, "http") || strings.HasPrefix(ref, "https") {
|
||||
it.getter = local.RemoteOpener(ref)
|
||||
} else {
|
||||
it.getter = local.LocalOpener(ref)
|
||||
}
|
||||
|
||||
for i, o := range opts {
|
||||
if err := o.Apply(it); err != nil {
|
||||
return nil, fmt.Errorf("invalid option %d: %v", i, err)
|
||||
@@ -139,7 +130,7 @@ func (it *ImageTxt) compute() error {
|
||||
}
|
||||
|
||||
var pullAll bool
|
||||
var targetSources map[string]bool
|
||||
targetSources := make(map[string]bool)
|
||||
|
||||
if len(foundSources) == 0 || (len(it.IncludeSources) == 0 && len(it.ExcludeSources) == 0) {
|
||||
// pull all found images
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
package imagetxt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
artifacts "github.com/rancherfederal/hauler/pkg/artifact"
|
||||
"github.com/rancherfederal/hauler/pkg/content/image"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidRef = errors.New("invalid reference")
|
||||
ErrRefNotFound = errors.New("ref not found")
|
||||
ErrRefNotImage = errors.New("ref is not image")
|
||||
ErrExtraRefsFound = errors.New("extra refs found in contents")
|
||||
)
|
||||
|
||||
var (
|
||||
testServer *httptest.Server
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
setup()
|
||||
code := m.Run()
|
||||
teardown()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func setup() {
|
||||
dir := http.Dir("./testdata/http/")
|
||||
h := http.FileServer(dir)
|
||||
testServer = httptest.NewServer(h)
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
if testServer != nil {
|
||||
testServer.Close()
|
||||
}
|
||||
}
|
||||
|
||||
type failKind string
|
||||
|
||||
const (
|
||||
failKindNew = failKind("New")
|
||||
failKindContents = failKind("Contents")
|
||||
)
|
||||
|
||||
func checkError(checkedFailKind failKind) func(*testing.T, error, bool, failKind) {
|
||||
return func(cet *testing.T, err error, testShouldFail bool, testFailKind failKind) {
|
||||
if err != nil {
|
||||
// if error should not have happened at all OR error should have happened
|
||||
// at a different point, test failed
|
||||
if !testShouldFail || testFailKind != checkedFailKind {
|
||||
cet.Fatalf("unexpected error at %s: %v", checkedFailKind, err)
|
||||
}
|
||||
// test should fail at this point, test passed
|
||||
return
|
||||
}
|
||||
// if no error occurred but error should have happened at this point, test
|
||||
// failed
|
||||
if testShouldFail && testFailKind == checkedFailKind {
|
||||
cet.Fatalf("unexpected nil error at %s", checkedFailKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageTxtCollection(t *testing.T) {
|
||||
type testEntry struct {
|
||||
Name string
|
||||
Ref string
|
||||
IncludeSources []string
|
||||
ExcludeSources []string
|
||||
ExpectedImages []string
|
||||
ShouldFail bool
|
||||
FailKind failKind
|
||||
}
|
||||
tt := []testEntry{
|
||||
{
|
||||
Name: "http ref basic",
|
||||
Ref: fmt.Sprintf("%s/images-http.txt", testServer.URL),
|
||||
ExpectedImages: []string{
|
||||
"busybox",
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
"quay.io/jetstack/cert-manager-controller:v1.6.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "http ref sources format pull all",
|
||||
Ref: fmt.Sprintf("%s/images-src-http.txt", testServer.URL),
|
||||
ExpectedImages: []string{
|
||||
"busybox",
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
"quay.io/jetstack/cert-manager-controller:v1.6.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "http ref sources format include sources A",
|
||||
Ref: fmt.Sprintf("%s/images-src-http.txt", testServer.URL),
|
||||
IncludeSources: []string{
|
||||
"core", "rke",
|
||||
},
|
||||
ExpectedImages: []string{
|
||||
"busybox",
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "http ref sources format include sources B",
|
||||
Ref: fmt.Sprintf("%s/images-src-http.txt", testServer.URL),
|
||||
IncludeSources: []string{
|
||||
"nginx", "rancher", "cert-manager",
|
||||
},
|
||||
ExpectedImages: []string{
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
"quay.io/jetstack/cert-manager-controller:v1.6.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "http ref sources format exclude sources A",
|
||||
Ref: fmt.Sprintf("%s/images-src-http.txt", testServer.URL),
|
||||
ExcludeSources: []string{
|
||||
"cert-manager",
|
||||
},
|
||||
ExpectedImages: []string{
|
||||
"busybox",
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "http ref sources format exclude sources B",
|
||||
Ref: fmt.Sprintf("%s/images-src-http.txt", testServer.URL),
|
||||
ExcludeSources: []string{
|
||||
"core",
|
||||
},
|
||||
ExpectedImages: []string{
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
"quay.io/jetstack/cert-manager-controller:v1.6.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "local file ref",
|
||||
Ref: "./testdata/images-file.txt",
|
||||
ExpectedImages: []string{
|
||||
"busybox",
|
||||
"nginx:1.19",
|
||||
"rancher/hyperkube:v1.21.7-rancher1",
|
||||
"docker.io/rancher/klipper-lb:v0.3.4",
|
||||
"quay.io/jetstack/cert-manager-controller:v1.6.1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
checkErrorNew := checkError(failKindNew)
|
||||
checkErrorContents := checkError(failKindContents)
|
||||
|
||||
for _, curTest := range tt {
|
||||
t.Run(curTest.Name, func(innerT *testing.T) {
|
||||
curImageTxt, err := New(curTest.Ref,
|
||||
WithIncludeSources(curTest.IncludeSources...),
|
||||
WithExcludeSources(curTest.ExcludeSources...),
|
||||
)
|
||||
checkErrorNew(innerT, err, curTest.ShouldFail, curTest.FailKind)
|
||||
|
||||
ociContents, err := curImageTxt.Contents()
|
||||
checkErrorContents(innerT, err, curTest.ShouldFail, curTest.FailKind)
|
||||
|
||||
if err := checkImages(ociContents, curTest.ExpectedImages); err != nil {
|
||||
innerT.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func checkImages(content map[name.Reference]artifacts.OCI, refs []string) error {
|
||||
contentCopy := make(map[name.Reference]artifacts.OCI, len(content))
|
||||
for k, v := range content {
|
||||
contentCopy[k] = v
|
||||
}
|
||||
for _, ref := range refs {
|
||||
nameRef, err := name.ParseReference(ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ref %s: %w", ref, ErrInvalidRef)
|
||||
}
|
||||
target, ok := content[nameRef]
|
||||
if !ok {
|
||||
return fmt.Errorf("ref %s: %w", ref, ErrRefNotFound)
|
||||
}
|
||||
if _, ok := target.(*image.Image); !ok {
|
||||
return fmt.Errorf("got underlying type %T: %w", target, ErrRefNotImage)
|
||||
}
|
||||
delete(contentCopy, nameRef)
|
||||
}
|
||||
|
||||
if len(contentCopy) != 0 {
|
||||
return ErrExtraRefsFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
busybox
|
||||
nginx:1.19
|
||||
rancher/hyperkube:v1.21.7-rancher1
|
||||
docker.io/rancher/klipper-lb:v0.3.4
|
||||
quay.io/jetstack/cert-manager-controller:v1.6.1
|
||||
@@ -0,0 +1,5 @@
|
||||
busybox core
|
||||
nginx:1.19 core,nginx
|
||||
rancher/hyperkube:v1.21.7-rancher1 rancher,rke
|
||||
docker.io/rancher/klipper-lb:v0.3.4 rancher,k3s
|
||||
quay.io/jetstack/cert-manager-controller:v1.6.1 cert-manager
|
||||
@@ -0,0 +1,5 @@
|
||||
busybox
|
||||
nginx:1.19
|
||||
rancher/hyperkube:v1.21.7-rancher1
|
||||
docker.io/rancher/klipper-lb:v0.3.4
|
||||
quay.io/jetstack/cert-manager-controller:v1.6.1
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/rancherfederal/hauler/pkg/artifact"
|
||||
)
|
||||
|
||||
var _ artifact.OCI = (*image)(nil)
|
||||
var _ artifact.OCI = (*Image)(nil)
|
||||
|
||||
func (i *image) MediaType() string {
|
||||
func (i *Image) MediaType() string {
|
||||
mt, err := i.Image.MediaType()
|
||||
if err != nil {
|
||||
return ""
|
||||
@@ -18,15 +18,15 @@ func (i *image) MediaType() string {
|
||||
return string(mt)
|
||||
}
|
||||
|
||||
func (i *image) RawConfig() ([]byte, error) {
|
||||
func (i *Image) RawConfig() ([]byte, error) {
|
||||
return i.RawConfigFile()
|
||||
}
|
||||
|
||||
type image struct {
|
||||
type Image struct {
|
||||
gv1.Image
|
||||
}
|
||||
|
||||
func NewImage(ref string) (*image, error) {
|
||||
func NewImage(ref string) (*Image, error) {
|
||||
r, err := name.ParseReference(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -37,7 +37,7 @@ func NewImage(ref string) (*image, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &image{
|
||||
return &Image{
|
||||
Image: img,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user