mirror of
https://github.com/hauler-dev/hauler.git
synced 2026-08-27 14:07:17 +00:00
add some tests for image discovery, flesh out boot process
This commit is contained in:
+42
-28
@@ -2,8 +2,6 @@ package packager
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
@@ -12,13 +10,20 @@ import (
|
||||
"github.com/rancher/fleet/pkg/helmdeployer"
|
||||
"github.com/rancher/fleet/pkg/manifest"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Imager interface {
|
||||
Images() ([]string, error)
|
||||
}
|
||||
|
||||
type discoveredImages []string
|
||||
func (d discoveredImages) Images() ([]string, error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
//ConcatImages will gather images from various Imager sources and return a single slilce
|
||||
func ConcatImages(imager ...Imager) (map[name.Reference]v1.Image, error) {
|
||||
m := make(map[name.Reference]v1.Image)
|
||||
@@ -43,7 +48,7 @@ func ConcatImages(imager ...Imager) (map[name.Reference]v1.Image, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func IdentifyImages(b *fleetapi.Bundle) (map[name.Reference]v1.Image, error) {
|
||||
func IdentifyImages(b *fleetapi.Bundle) (discoveredImages, error) {
|
||||
opts := fleetapi.BundleDeploymentOptions{
|
||||
DefaultNamespace: "default",
|
||||
}
|
||||
@@ -56,13 +61,17 @@ func IdentifyImages(b *fleetapi.Bundle) (map[name.Reference]v1.Image, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var di discoveredImages
|
||||
|
||||
for _, o := range objs {
|
||||
u := o.(*unstructured.Unstructured)
|
||||
_ = u
|
||||
imageFromRuntimeObject(u)
|
||||
imgs, err := imageFromRuntimeObject(o.(*unstructured.Unstructured))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
di = append(di, imgs...)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return di, err
|
||||
}
|
||||
|
||||
//ResolveRemoteRefs will return a slice of remote images resolved from their fully qualified name
|
||||
@@ -70,6 +79,9 @@ func ResolveRemoteRefs(images ...string) (map[name.Reference]v1.Image, error) {
|
||||
m := make(map[name.Reference]v1.Image)
|
||||
|
||||
for _, i := range images {
|
||||
if i == "" { continue }
|
||||
|
||||
//TODO: This will error out if remote is a v1 image, do better error handling for this
|
||||
ref, err := name.ParseReference(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -87,40 +99,42 @@ func ResolveRemoteRefs(images ...string) (map[name.Reference]v1.Image, error) {
|
||||
}
|
||||
|
||||
var knownImagePaths = []string{
|
||||
"spec.template.spec.containers.#.image",
|
||||
"{.spec.template.spec.containers[*].image}",
|
||||
}
|
||||
|
||||
////imageFromRuntimeObject will return any images found in known obj specs
|
||||
func imageFromRuntimeObject(obj *unstructured.Unstructured) ([]string, error) {
|
||||
data, err := obj.MarshalJSON()
|
||||
if err != nil {
|
||||
func imageFromRuntimeObject(obj *unstructured.Unstructured) (images []string, err error) {
|
||||
objData, _ := obj.MarshalJSON()
|
||||
|
||||
var data interface{}
|
||||
if err := json.Unmarshal(objData, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var images []string
|
||||
|
||||
j := jsonpath.New("imagePath")
|
||||
|
||||
var imageData interface{}
|
||||
|
||||
err = json.Unmarshal(data, &imageData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
j := jsonpath.New("")
|
||||
j.AllowMissingKeys(true)
|
||||
|
||||
for _, path := range knownImagePaths {
|
||||
|
||||
j.Parse(path)
|
||||
buf := new(bytes.Buffer)
|
||||
err = j.Execute(buf, imageData)
|
||||
|
||||
r, err := parseJSONPath(data, j, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
images = append(images, buf.String())
|
||||
images = append(images, r...)
|
||||
}
|
||||
|
||||
return images, nil
|
||||
}
|
||||
|
||||
func parseJSONPath(input interface{}, parser *jsonpath.JSONPath, template string) ([]string, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := parser.Parse(template); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := parser.Execute(buf, input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r:= strings.Split(buf.String(), " ")
|
||||
return r, nil
|
||||
}
|
||||
@@ -1 +1,84 @@
|
||||
package packager
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
jsona = []byte(`{
|
||||
"flatImage": "name/of/image:with-tag",
|
||||
"deeply": {
|
||||
"nested": {
|
||||
"image": "another/image/name:with-a-tag",
|
||||
"set": [
|
||||
{ "image": "first/in/list:123" },
|
||||
{ "image": "second/in:456" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}`)
|
||||
)
|
||||
|
||||
func Test_parseJSONPath(t *testing.T) {
|
||||
var data interface{}
|
||||
if err := json.Unmarshal(jsona, &data); err != nil {
|
||||
t.Errorf("failed to unmarshal test article, %v", err)
|
||||
}
|
||||
|
||||
j := jsonpath.New("")
|
||||
|
||||
type args struct {
|
||||
input interface{}
|
||||
name string
|
||||
template string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "should find flat path with string result",
|
||||
args: args{
|
||||
input: data,
|
||||
name: "wut",
|
||||
template: "{.flatImage}",
|
||||
},
|
||||
want: []string{"name/of/image:with-tag"},
|
||||
},
|
||||
{
|
||||
name: "should find nested path with string result",
|
||||
args: args{
|
||||
input: data,
|
||||
name: "wut",
|
||||
template: "{.deeply.nested.image}",
|
||||
},
|
||||
want: []string{"another/image/name:with-a-tag"},
|
||||
},
|
||||
{
|
||||
name: "should find nested path with slice result",
|
||||
args: args{
|
||||
input: data,
|
||||
name: "wut",
|
||||
template: "{.deeply.nested.set[*].image}",
|
||||
},
|
||||
want: []string{"first/in/list:123", "second/in:456"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseJSONPath(tt.args.input, j, tt.args.template)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseJSONPath() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseJSONPath() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ func Create(ctx context.Context, p v1alpha1.Package, fsys fs.PkgFs, a archiver.A
|
||||
Compress: true,
|
||||
}
|
||||
|
||||
var di discoveredImages
|
||||
|
||||
//Get and write bundles to disk
|
||||
for _, path := range p.Spec.Paths {
|
||||
bundleName := filepath.Base(path)
|
||||
@@ -39,11 +41,13 @@ func Create(ctx context.Context, p v1alpha1.Package, fsys fs.PkgFs, a archiver.A
|
||||
//TODO: Figure out why bundle.Open doesn't return with GVK
|
||||
bn := fleetapi.NewBundle("fleet-local", bundleName, *fb.Definition)
|
||||
|
||||
_, err = IdentifyImages(bn)
|
||||
imgs, err := IdentifyImages(bn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
di = append(di, imgs...)
|
||||
|
||||
if err := fsys.AddBundle(bn); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -68,7 +72,7 @@ func Create(ctx context.Context, p v1alpha1.Package, fsys fs.PkgFs, a archiver.A
|
||||
return err
|
||||
}
|
||||
|
||||
imgMap, err := ConcatImages(d, p.Spec.Fleet)
|
||||
imgMap, err := ConcatImages(d, p.Spec.Fleet, di)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user