From ef71cb478f2ccaf210961ccd4c71cb838944ff79 Mon Sep 17 00:00:00 2001 From: jregan Date: Thu, 31 May 2018 23:22:46 -0700 Subject: [PATCH] Introduce ResId and ResMap. --- pkg/app/application.go | 35 +- pkg/app/application_test.go | 79 +-- pkg/configmapandsecret/configmap_secret.go | 46 -- pkg/diff/rundiff.go | 13 +- .../{fake_loader.go => fakeloader.go} | 0 pkg/{resource => resmap}/configmap.go | 19 +- pkg/{resource => resmap}/configmap_test.go | 44 +- pkg/{types/gvkn_sort.go => resmap/idslice.go} | 22 +- pkg/{resource => resmap}/kv.go | 2 +- pkg/{resource => resmap}/kv_test.go | 2 +- pkg/resmap/resmap.go | 247 ++++++++++ pkg/resmap/resmap_test.go | 222 +++++++++ pkg/{resource => resmap}/secret.go | 17 +- pkg/{resource => resmap}/secret_test.go | 18 +- pkg/resource/appresource.go | 57 --- pkg/resource/appresource_test.go | 110 ----- pkg/{types/types.go => resource/resid.go} | 31 +- pkg/resource/resource.go | 123 +++-- pkg/resource/resource_test.go | 75 --- pkg/resource/util.go | 174 ------- pkg/resource/util_test.go | 151 ------ pkg/transformers/labelsandannotations.go | 10 +- pkg/transformers/labelsandannotations_test.go | 140 ++---- pkg/transformers/multitransformer.go | 4 +- pkg/transformers/namehash.go | 14 +- pkg/transformers/namehash_test.go | 88 ++-- pkg/transformers/namereference.go | 36 +- pkg/transformers/namereference_test.go | 68 +-- pkg/transformers/nooptransformer.go | 4 +- pkg/transformers/overlay.go | 51 +- pkg/transformers/overlay_test.go | 460 ++++++++---------- pkg/transformers/pathconfig.go | 12 +- pkg/transformers/prefixname.go | 10 +- pkg/transformers/prefixname_test.go | 48 +- pkg/transformers/transformer.go | 4 +- pkg/transformers/util_test.go | 49 -- pkg/types/kustomization.go | 4 +- pkg/types/{util.go => selectbygvk.go} | 17 +- .../{util_test.go => selectbygvk_test.go} | 4 +- 39 files changed, 1063 insertions(+), 1447 deletions(-) rename pkg/loader/loadertest/{fake_loader.go => fakeloader.go} (100%) rename pkg/{resource => resmap}/configmap.go (84%) rename pkg/{resource => resmap}/configmap_test.go (81%) rename pkg/{types/gvkn_sort.go => resmap/idslice.go} (56%) rename pkg/{resource => resmap}/kv.go (99%) rename pkg/{resource => resmap}/kv_test.go (98%) create mode 100644 pkg/resmap/resmap.go create mode 100644 pkg/resmap/resmap_test.go rename pkg/{resource => resmap}/secret.go (76%) rename pkg/{resource => resmap}/secret_test.go (84%) delete mode 100644 pkg/resource/appresource.go delete mode 100644 pkg/resource/appresource_test.go rename pkg/{types/types.go => resource/resid.go} (52%) delete mode 100644 pkg/resource/resource_test.go delete mode 100644 pkg/resource/util.go delete mode 100644 pkg/resource/util_test.go delete mode 100644 pkg/transformers/util_test.go rename pkg/types/{util.go => selectbygvk.go} (68%) rename pkg/types/{util_test.go => selectbygvk_test.go} (97%) diff --git a/pkg/app/application.go b/pkg/app/application.go index 161b12ca3..13e0cb2ef 100644 --- a/pkg/app/application.go +++ b/pkg/app/application.go @@ -25,6 +25,7 @@ import ( "github.com/kubernetes-sigs/kustomize/pkg/constants" interror "github.com/kubernetes-sigs/kustomize/pkg/internal/error" "github.com/kubernetes-sigs/kustomize/pkg/loader" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/transformers" "github.com/kubernetes-sigs/kustomize/pkg/types" @@ -32,14 +33,14 @@ import ( type Application interface { // Resources computes and returns the resources for the app. - Resources() (resource.ResourceCollection, error) + Resources() (resmap.ResMap, error) // SemiResources computes and returns the resources without name hash and name reference for the app - SemiResources() (resource.ResourceCollection, error) + SemiResources() (resmap.ResMap, error) // RawResources computes and returns the raw resources from the kustomization file. // It contains resources from // 1) untransformed resources from current kustomization file // 2) transformed resources from sub packages - RawResources() (resource.ResourceCollection, error) + RawResources() (resmap.ResMap, error) } var _ Application = &applicationImpl{} @@ -68,7 +69,7 @@ func New(loader loader.Loader) (Application, error) { // Resources computes and returns the resources from the kustomization file. // The namehashing for configmap/secrets and resolving name reference is only done // in the most top overlay once at the end of getting resources. -func (a *applicationImpl) Resources() (resource.ResourceCollection, error) { +func (a *applicationImpl) Resources() (resmap.ResMap, error) { res, err := a.SemiResources() if err != nil { return nil, err @@ -85,32 +86,32 @@ func (a *applicationImpl) Resources() (resource.ResourceCollection, error) { } // SemiResources computes and returns the resources without name hash and name reference for the app -func (a *applicationImpl) SemiResources() (resource.ResourceCollection, error) { +func (a *applicationImpl) SemiResources() (resmap.ResMap, error) { errs := &interror.KustomizationErrors{} raw, err := a.rawResources() if err != nil { errs.Append(err) } - cms, err := resource.NewFromConfigMaps(a.loader, a.kustomization.ConfigMapGenerator) + cms, err := resmap.NewResMapFromConfigMapArgs(a.loader, a.kustomization.ConfigMapGenerator) if err != nil { errs.Append(err) } - secrets, err := resource.NewFromSecretGenerators(a.loader.Root(), a.kustomization.SecretGenerator) + secrets, err := resmap.NewResMapFromSecretArgs(a.loader.Root(), a.kustomization.SecretGenerator) if err != nil { errs.Append(err) } - res, err := resource.Merge(cms, secrets) + res, err := resmap.Merge(cms, secrets) if err != nil { return nil, err } - allRes, err := resource.MergeWithOverride(raw, res) + allRes, err := resmap.MergeWithOverride(raw, res) if err != nil { return nil, err } - patches, err := resource.NewFromPatches(a.loader, a.kustomization.Patches) + patches, err := resmap.NewResourceSliceFromPatches(a.loader, a.kustomization.Patches) if err != nil { errs.Append(err) } @@ -134,7 +135,7 @@ func (a *applicationImpl) SemiResources() (resource.ResourceCollection, error) { // RawResources computes and returns the raw resources from the kustomization file. // The namehashing for configmap/secrets and resolving name reference is only done // in the most top overlay once at the end of getting resources. -func (a *applicationImpl) RawResources() (resource.ResourceCollection, error) { +func (a *applicationImpl) RawResources() (resmap.ResMap, error) { res, err := a.rawResources() if err != nil { return nil, err @@ -150,9 +151,9 @@ func (a *applicationImpl) RawResources() (resource.ResourceCollection, error) { return res, nil } -func (a *applicationImpl) rawResources() (resource.ResourceCollection, error) { +func (a *applicationImpl) rawResources() (resmap.ResMap, error) { subAppResources, errs := a.subAppResources() - resources, err := resource.NewFromResources(a.loader, a.kustomization.Resources) + resources, err := resmap.NewResMapFromFiles(a.loader, a.kustomization.Resources) if err != nil { errs.Append(err) } @@ -161,11 +162,11 @@ func (a *applicationImpl) rawResources() (resource.ResourceCollection, error) { return nil, errs } - return resource.Merge(resources, subAppResources) + return resmap.Merge(resources, subAppResources) } -func (a *applicationImpl) subAppResources() (resource.ResourceCollection, *interror.KustomizationErrors) { - sliceOfSubAppResources := []resource.ResourceCollection{} +func (a *applicationImpl) subAppResources() (resmap.ResMap, *interror.KustomizationErrors) { + sliceOfSubAppResources := []resmap.ResMap{} errs := &interror.KustomizationErrors{} for _, pkgPath := range a.kustomization.Bases { subloader, err := a.loader.New(pkgPath) @@ -186,7 +187,7 @@ func (a *applicationImpl) subAppResources() (resource.ResourceCollection, *inter } sliceOfSubAppResources = append(sliceOfSubAppResources, subAppResources) } - allResources, err := resource.Merge(sliceOfSubAppResources...) + allResources, err := resmap.Merge(sliceOfSubAppResources...) if err != nil { errs.Append(err) } diff --git a/pkg/app/application_test.go b/pkg/app/application_test.go index 3a0e0dd0a..f123e439d 100644 --- a/pkg/app/application_test.go +++ b/pkg/app/application_test.go @@ -18,15 +18,14 @@ package app import ( "encoding/base64" - "fmt" "reflect" "testing" "github.com/kubernetes-sigs/kustomize/pkg/constants" "github.com/kubernetes-sigs/kustomize/pkg/loader" "github.com/kubernetes-sigs/kustomize/pkg/loader/loadertest" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" - "github.com/kubernetes-sigs/kustomize/pkg/types" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -71,13 +70,14 @@ metadata: return loader } +var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} +var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"} +var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"} + func TestResources(t *testing.T) { - expected := resource.ResourceCollection{ - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "dply1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(deploy, "dply1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -108,13 +108,9 @@ func TestResources(t *testing.T) { }, }, }, - }, - }, - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "literalConfigMap", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(cmap, "literalConfigMap"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -133,13 +129,9 @@ func TestResources(t *testing.T) { "DB_PASSWORD": "somepw", }, }, - }, - }, - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(secret, "secret"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -159,8 +151,7 @@ func TestResources(t *testing.T) { "DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")), }, }, - }, - }, + }), } l := setupTest(t) app, err := New(l) @@ -173,18 +164,15 @@ func TestResources(t *testing.T) { } if !reflect.DeepEqual(actual, expected) { - err = compareMap(actual, expected) + err = expected.ErrorIfNotEqual(actual) t.Fatalf("unexpected error: %v", err) } } func TestRawResources(t *testing.T) { - expected := resource.ResourceCollection{ - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "dply1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(deploy, "dply1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -192,8 +180,7 @@ func TestRawResources(t *testing.T) { "name": "dply1", }, }, - }, - }, + }), } l := setupTest(t) app, err := New(l) @@ -205,31 +192,7 @@ func TestRawResources(t *testing.T) { t.Fatalf("Unexpected error %v", err) } - if err := compareMap(actual, expected); err != nil { + if err := expected.ErrorIfNotEqual(actual); err != nil { t.Fatalf("unexpected error: %v", err) } } - -func compareMap(m1, m2 resource.ResourceCollection) error { - if len(m1) != len(m2) { - keySet1 := []types.GroupVersionKindName{} - keySet2 := []types.GroupVersionKindName{} - for GVKn := range m1 { - keySet1 = append(keySet1, GVKn) - } - for GVKn := range m1 { - keySet2 = append(keySet2, GVKn) - } - return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2) - } - for GVKn, obj1 := range m1 { - obj2, found := m2[GVKn] - if !found { - return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2) - } - if !reflect.DeepEqual(obj1, obj2) { - return fmt.Errorf("%#v doesn't match %#v", obj1, obj2) - } - } - return nil -} diff --git a/pkg/configmapandsecret/configmap_secret.go b/pkg/configmapandsecret/configmap_secret.go index 7240ceb35..aa0fa5e61 100644 --- a/pkg/configmapandsecret/configmap_secret.go +++ b/pkg/configmapandsecret/configmap_secret.go @@ -27,7 +27,6 @@ import ( cutil "github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret/util" "github.com/kubernetes-sigs/kustomize/pkg/hash" - "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/types" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -122,51 +121,6 @@ func makeSecret(secret types.SecretArgs, path string) (*corev1.Secret, error) { return corev1secret, nil } -func populateMap(m resource.ResourceCollection, obj *unstructured.Unstructured, newName string) error { - oldName := obj.GetName() - gvk := obj.GroupVersionKind() - gvkn := types.GroupVersionKindName{GVK: gvk, Name: oldName} - - if _, found := m[gvkn]; found { - return fmt.Errorf("The already exists in the map", oldName, gvk) - } - obj.SetName(newName) - m[gvkn] = &resource.Resource{Data: obj} - return nil -} - -// MakeConfigMapsResourceCollection returns a map of -> unstructured object. -func MakeConfigMapsResourceCollection(maps []types.ConfigMapArgs) (resource.ResourceCollection, error) { - m := resource.ResourceCollection{} - for _, cm := range maps { - unstructuredConfigMap, nameWithHash, err := MakeConfigmapAndGenerateName(cm) - if err != nil { - return nil, err - } - err = populateMap(m, unstructuredConfigMap, nameWithHash) - if err != nil { - return nil, err - } - } - return m, nil -} - -// MakeSecretsResourceCollection returns a map of -> unstructured object. -func MakeSecretsResourceCollection(secrets []types.SecretArgs, path string) (resource.ResourceCollection, error) { - m := resource.ResourceCollection{} - for _, secret := range secrets { - unstructuredSecret, nameWithHash, err := MakeSecretAndGenerateName(secret, path) - if err != nil { - return nil, err - } - err = populateMap(m, unstructuredSecret, nameWithHash) - if err != nil { - return nil, err - } - } - return m, nil -} - func createSecretKey(wd string, command string) ([]byte, error) { fi, err := os.Stat(wd) if err != nil || !fi.IsDir() { diff --git a/pkg/diff/rundiff.go b/pkg/diff/rundiff.go index 785f6bdb8..4d36312a6 100644 --- a/pkg/diff/rundiff.go +++ b/pkg/diff/rundiff.go @@ -5,12 +5,11 @@ import ( "io" - "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" ) -// RunDiff runs system diff program to compare two ResourceCollections. -func RunDiff(raw, transformed resource.ResourceCollection, - out, errOut io.Writer) error { +// RunDiff runs system diff program to compare two Maps. +func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) error { transformedDir, err := writeYamlToNewDir(transformed, "transformed") if err != nil { return err @@ -26,10 +25,10 @@ func RunDiff(raw, transformed resource.ResourceCollection, return newProgram(out, errOut).run(noopDir.name(), transformedDir.name()) } -// writeYamlToNewDir writes each obj in ResourceCollection to a file in a new directory. +// writeYamlToNewDir writes each obj in ResMap to a file in a new directory. // The directory's name will begin with the given prefix. // Each file is named with GroupVersionKindName. -func writeYamlToNewDir(in resource.ResourceCollection, prefix string) (*directory, error) { +func writeYamlToNewDir(in resmap.ResMap, prefix string) (*directory, error) { dir, err := newDirectory(prefix) if err != nil { return nil, err @@ -40,7 +39,7 @@ func writeYamlToNewDir(in resource.ResourceCollection, prefix string) (*director if err != nil { return nil, err } - err = print(obj.Data, f) + err = print(obj.Unstruct(), f) f.Close() if err != nil { return nil, err diff --git a/pkg/loader/loadertest/fake_loader.go b/pkg/loader/loadertest/fakeloader.go similarity index 100% rename from pkg/loader/loadertest/fake_loader.go rename to pkg/loader/loadertest/fakeloader.go diff --git a/pkg/resource/configmap.go b/pkg/resmap/configmap.go similarity index 84% rename from pkg/resource/configmap.go rename to pkg/resmap/configmap.go index fc5751928..6c24a9745 100644 --- a/pkg/resource/configmap.go +++ b/pkg/resmap/configmap.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resource +package resmap import ( "fmt" @@ -22,22 +22,23 @@ import ( cutil "github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret/util" "github.com/kubernetes-sigs/kustomize/pkg/loader" + "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/types" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation" ) -func newFromConfigMap(l loader.Loader, cm types.ConfigMapArgs) (*Resource, error) { +func newResourceFromConfigMap(l loader.Loader, cm types.ConfigMapArgs) (*resource.Resource, error) { corev1CM, err := makeConfigMap(l, cm) if err != nil { return nil, err } - data, err := objectToUnstructured(corev1CM) + data, err := newUnstructuredFromObject(corev1CM) if err != nil { return nil, err } - return &Resource{Data: data, Behavior: cm.Behavior}, nil + return resource.NewResource(data, cm.Behavior), nil } func makeConfigMap(l loader.Loader, cm types.ConfigMapArgs) (*corev1.ConfigMap, error) { @@ -130,15 +131,15 @@ func addKV(m map[string]string, kv kvPair) error { return nil } -// NewFromConfigMaps returns a Resource slice given a configmap metadata slice from kustomization file. -func NewFromConfigMaps(loader loader.Loader, cmList []types.ConfigMapArgs) (ResourceCollection, error) { - allResources := []*Resource{} +// NewResMapFromConfigMapArgs returns a Resource slice given a configmap metadata slice from kustomization file. +func NewResMapFromConfigMapArgs(loader loader.Loader, cmList []types.ConfigMapArgs) (ResMap, error) { + allResources := []*resource.Resource{} for _, cm := range cmList { - res, err := newFromConfigMap(loader, cm) + res, err := newResourceFromConfigMap(loader, cm) if err != nil { return nil, err } allResources = append(allResources, res) } - return resourceCollectionFromResources(allResources) + return newResMapFromResourceSlice(allResources) } diff --git a/pkg/resource/configmap_test.go b/pkg/resmap/configmap_test.go similarity index 81% rename from pkg/resource/configmap_test.go rename to pkg/resmap/configmap_test.go index 75a9f1512..ea10010d8 100644 --- a/pkg/resource/configmap_test.go +++ b/pkg/resmap/configmap_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resource_test +package resmap import ( "reflect" @@ -27,13 +27,15 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) +var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"} + func TestNewFromConfigMaps(t *testing.T) { type testCase struct { description string input []types.ConfigMapArgs filepath string content string - expected resource.ResourceCollection + expected ResMap } l := loadertest.NewFakeLoader("/home/seans/project/") @@ -50,12 +52,9 @@ func TestNewFromConfigMaps(t *testing.T) { }, filepath: "/home/seans/project/app.env", content: "DB_USERNAME=admin\nDB_PASSWORD=somepw", - expected: resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "envConfigMap", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected: ResMap{ + resource.NewResId(cmap, "envConfigMap"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -68,8 +67,7 @@ func TestNewFromConfigMaps(t *testing.T) { "DB_PASSWORD": "somepw", }, }, - }, - }, + }), }, }, { @@ -83,12 +81,9 @@ func TestNewFromConfigMaps(t *testing.T) { }, filepath: "/home/seans/project/app-init.ini", content: "FOO=bar\nBAR=baz\n", - expected: resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "fileConfigMap", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected: ResMap{ + resource.NewResId(cmap, "fileConfigMap"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -102,8 +97,7 @@ BAR=baz `, }, }, - }, - }, + }), }, }, { @@ -116,12 +110,9 @@ BAR=baz }, }, }, - expected: resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "literalConfigMap", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected: ResMap{ + resource.NewResId(cmap, "literalConfigMap"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -134,8 +125,7 @@ BAR=baz "b": "y", }, }, - }, - }, + }), }, }, // TODO: add testcase for data coming from multiple sources like @@ -147,7 +137,7 @@ BAR=baz if ferr := l.AddFile(tc.filepath, []byte(tc.content)); ferr != nil { t.Fatalf("Error adding fake file: %v\n", ferr) } - r, err := resource.NewFromConfigMaps(l, tc.input) + r, err := NewResMapFromConfigMapArgs(l, tc.input) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/pkg/types/gvkn_sort.go b/pkg/resmap/idslice.go similarity index 56% rename from pkg/types/gvkn_sort.go rename to pkg/resmap/idslice.go index df3baf1ab..7eebfd9a1 100644 --- a/pkg/types/gvkn_sort.go +++ b/pkg/resmap/idslice.go @@ -14,22 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -package types +package resmap import ( "sort" + + "github.com/kubernetes-sigs/kustomize/pkg/resource" ) -// ByGVKN implements the sort interface. -type ByGVKN []GroupVersionKindName +// IdSlice implements the sort interface. +type IdSlice []resource.ResId -var _ sort.Interface = ByGVKN{} +var _ sort.Interface = IdSlice{} -func (a ByGVKN) Len() int { return len(a) } -func (a ByGVKN) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a ByGVKN) Less(i, j int) bool { - if a[i].GVK.String() != a[j].GVK.String() { - return a[i].GVK.String() < a[j].GVK.String() +func (a IdSlice) Len() int { return len(a) } +func (a IdSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a IdSlice) Less(i, j int) bool { + if a[i].Gvk().String() != a[j].Gvk().String() { + return a[i].Gvk().String() < a[j].Gvk().String() } - return a[i].Name < a[j].Name + return a[i].Name() < a[j].Name() } diff --git a/pkg/resource/kv.go b/pkg/resmap/kv.go similarity index 99% rename from pkg/resource/kv.go rename to pkg/resmap/kv.go index 25c546816..9663fa5e1 100644 --- a/pkg/resource/kv.go +++ b/pkg/resmap/kv.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resource +package resmap import ( "bufio" diff --git a/pkg/resource/kv_test.go b/pkg/resmap/kv_test.go similarity index 98% rename from pkg/resource/kv_test.go rename to pkg/resmap/kv_test.go index dd423b0e6..fefa03240 100644 --- a/pkg/resource/kv_test.go +++ b/pkg/resmap/kv_test.go @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package resource +package resmap import ( "reflect" diff --git a/pkg/resmap/resmap.go b/pkg/resmap/resmap.go new file mode 100644 index 000000000..6d47f5ce1 --- /dev/null +++ b/pkg/resmap/resmap.go @@ -0,0 +1,247 @@ +package resmap + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "reflect" + "sort" + + "github.com/ghodss/yaml" + "github.com/golang/glog" + "github.com/kubernetes-sigs/kustomize/pkg/loader" + "github.com/kubernetes-sigs/kustomize/pkg/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + k8syaml "k8s.io/apimachinery/pkg/util/yaml" +) + +// ResMap is a map from ResId to Resource +type ResMap map[resource.ResId]*resource.Resource + +// EncodeAsYaml encodes a ResMap to YAML; encoded objects separated by `---`. +func (m ResMap) EncodeAsYaml() ([]byte, error) { + ids := []resource.ResId{} + for gvkn := range m { + ids = append(ids, gvkn) + } + sort.Sort(IdSlice(ids)) + + firstObj := true + var b []byte + buf := bytes.NewBuffer(b) + for _, id := range ids { + obj := m[id].Unstruct() + out, err := yaml.Marshal(obj) + if err != nil { + return nil, err + } + if firstObj { + firstObj = false + } else { + _, err = buf.WriteString("---\n") + if err != nil { + return nil, err + } + } + _, err = buf.Write(out) + if err != nil { + return nil, err + } + } + return buf.Bytes(), nil +} + +func (m1 ResMap) ErrorIfNotEqual(m2 ResMap) error { + if len(m1) != len(m2) { + keySet1 := []resource.ResId{} + keySet2 := []resource.ResId{} + for id := range m1 { + keySet1 = append(keySet1, id) + } + for id := range m2 { + keySet2 = append(keySet2, id) + } + return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2) + } + for id, obj1 := range m1 { + obj2, found := m2[id] + if !found { + return fmt.Errorf("%#v doesn't exist in %#v", id, m2) + } + if !reflect.DeepEqual(obj1.Unstruct(), obj2.Unstruct()) { + return fmt.Errorf("%#v doesn't match %#v", obj1.Unstruct(), obj2.Unstruct()) + } + } + return nil +} + +func (m ResMap) insert(newName string, obj *unstructured.Unstructured) error { + oldName := obj.GetName() + gvk := obj.GroupVersionKind() + id := resource.NewResId(gvk, oldName) + + if _, found := m[id]; found { + return fmt.Errorf("The already exists in the map", oldName, gvk) + } + obj.SetName(newName) + m[id] = resource.NewBehaviorlessResource(obj) + return nil +} + +// NewResourceSliceFromPatches returns a slice of Resources given a patch path slice from kustomization file. +func NewResourceSliceFromPatches( + loader loader.Loader, paths []string) ([]*resource.Resource, error) { + result := []*resource.Resource{} + for _, path := range paths { + content, err := loader.Load(path) + if err != nil { + return nil, err + } + + res, err := newResourceSliceFromBytes(content) + if err != nil { + return nil, err + } + result = append(result, res...) + } + return result, nil +} + +// NewResMapFromFiles returns a ResMap given a resource path slice. +func NewResMapFromFiles(loader loader.Loader, paths []string) (ResMap, error) { + result := []ResMap{} + for _, path := range paths { + content, err := loader.Load(path) + if err != nil { + return nil, err + } + + res, err := newResMapFromBytes(content) + if err != nil { + return nil, err + } + result = append(result, res) + } + return Merge(result...) +} + +// newResMapFromBytes decodes a list of objects in byte array format. +func newResMapFromBytes(b []byte) (ResMap, error) { + resources, err := newResourceSliceFromBytes(b) + if err != nil { + return nil, err + } + + result := ResMap{} + for _, res := range resources { + gvkn := res.Id() + if _, found := result[gvkn]; found { + return result, fmt.Errorf("GroupVersionKindName: %#v already exists b the map", gvkn) + } + result[gvkn] = res + } + return result, nil +} + +func newResMapFromResourceSlice(resources []*resource.Resource) (ResMap, error) { + result := ResMap{} + for _, res := range resources { + gvkn := res.Id() + if _, found := result[gvkn]; found { + return nil, fmt.Errorf("duplicated %#v is not allowed", gvkn) + } + result[gvkn] = res + } + return result, nil +} + +func newResourceSliceFromBytes(in []byte) ([]*resource.Resource, error) { + decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024) + result := []*resource.Resource{} + + var err error + for { + var out unstructured.Unstructured + err = decoder.Decode(&out) + if err != nil { + break + } + result = append(result, resource.NewBehaviorlessResource(&out)) + } + if err != io.EOF { + return nil, err + } + return result, nil +} + +// Merge combines many maps to one. +func Merge(maps ...ResMap) (ResMap, error) { + result := ResMap{} + for _, m := range maps { + for gvkn, obj := range m { + if _, found := result[gvkn]; found { + return nil, fmt.Errorf("there is already an entry: %q", gvkn) + } + result[gvkn] = obj + } + } + + return result, nil +} + +const behaviorCreate = "create" +const behaviorReplace = "replace" +const behaviorMerge = "merge" + +// MergeWithOverride merges the entries in the ResMap slice with Override. +// If there is already an entry with the same Id , different actions are performed +// according to value of behavior field: +// 'create': create a new one; +// 'replace': replace the data only; keep the labels and annotations +// 'merge': merge the data; keep the labels and annotations +func MergeWithOverride(maps ...ResMap) (ResMap, error) { + result := ResMap{} + for _, m := range maps { + for gvkn, resource := range m { + if _, found := result[gvkn]; found { + switch resource.Behavior() { + case "", behaviorCreate: + return nil, fmt.Errorf("Create an existing gvkn %#v is not allowed", gvkn) + case behaviorReplace: + glog.V(4).Infof("Replace object %v by %v", result[gvkn].Unstruct().Object, resource.Unstruct().Object) + resource.Replace(result[gvkn]) + result[gvkn] = resource + case behaviorMerge: + glog.V(4).Infof("Merge object %v with %v", result[gvkn].Unstruct().Object, resource.Unstruct().Object) + resource.Merge(result[gvkn]) + result[gvkn] = resource + glog.V(4).Infof("The merged object is %v", result[gvkn].Unstruct().Object) + default: + return nil, fmt.Errorf("The behavior of %#v must be one of merge and replace since it already exists in the base", gvkn) + } + } else { + switch resource.Behavior() { + case "", behaviorCreate: + result[gvkn] = resource + case behaviorMerge, behaviorReplace: + return nil, fmt.Errorf("No merge or replace is allowed for non existing gvkn %#v", gvkn) + default: + return nil, fmt.Errorf("The behavior of %#v must be create since it doesn't exist", gvkn) + } + } + } + } + return result, nil +} + +func newUnstructuredFromObject(in runtime.Object) (*unstructured.Unstructured, error) { + marshaled, err := json.Marshal(in) + if err != nil { + return nil, err + } + var out unstructured.Unstructured + err = out.UnmarshalJSON(marshaled) + return &out, err +} diff --git a/pkg/resmap/resmap_test.go b/pkg/resmap/resmap_test.go new file mode 100644 index 000000000..b76f0e89d --- /dev/null +++ b/pkg/resmap/resmap_test.go @@ -0,0 +1,222 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resmap + +import ( + "fmt" + "reflect" + "testing" + + "github.com/kubernetes-sigs/kustomize/pkg/loader/loadertest" + "github.com/kubernetes-sigs/kustomize/pkg/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} +var statefulset = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"} + +func TestEncodeAsYaml(t *testing.T) { + encoded := []byte(`apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 +`) + input := ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "cm1", + }, + }, + }), + resource.NewResId(cmap, "cm2"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "cm2", + }, + }, + }), + } + out, err := input.EncodeAsYaml() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(out, encoded) { + t.Fatalf("%s doesn't match expected %s", out, encoded) + } +} + +func TestNewMapFromFiles(t *testing.T) { + + resourceStr := `apiVersion: apps/v1 +kind: Deployment +metadata: + name: dply1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dply2 +` + + l := loadertest.NewFakeLoader("/home/seans/project") + if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil { + t.Fatalf("Error adding fake file: %v\n", ferr) + } + expected := ResMap{resource.NewResId(deploy, "dply1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "dply1", + }, + }, + }), + resource.NewResId(deploy, "dply2"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "dply2", + }, + }, + }), + } + + m, _ := NewResMapFromFiles(l, []string{"/home/seans/project/deployment.yaml"}) + if len(m) != 2 { + t.Fatalf("%#v should contain 2 appResource, but got %d", m, len(m)) + } + + if err := expected.ErrorIfNotEqual(m); err != nil { + t.Fatalf("actual doesn't match expected: %v", err) + } +} + +func TestNewMapFromBytes(t *testing.T) { + encoded := []byte(`apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 +`) + expected := ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "cm1", + }, + }, + }), + resource.NewResId(cmap, "cm2"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "cm2", + }, + }, + }), + } + m, err := newResMapFromBytes(encoded) + fmt.Printf("%v\n", m) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(m, expected) { + t.Fatalf("%#v doesn't match expected %#v", m, expected) + } +} + +func TestMerge(t *testing.T) { + input1 := ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "foo-deploy1", + }, + }, + }), + } + input2 := ResMap{ + resource.NewResId(statefulset, "stateful1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "StatefulSet", + "metadata": map[string]interface{}{ + "name": "bar-stateful", + }, + }, + }), + } + input := []ResMap{input1, input2} + expected := ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "foo-deploy1", + }, + }, + }), + resource.NewResId(statefulset, "stateful1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "StatefulSet", + "metadata": map[string]interface{}{ + "name": "bar-stateful", + }, + }, + }), + } + merged, err := Merge(input...) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(merged, expected) { + t.Fatalf("%#v doesn't equal expected %#v", merged, expected) + } +} diff --git a/pkg/resource/secret.go b/pkg/resmap/secret.go similarity index 76% rename from pkg/resource/secret.go rename to pkg/resmap/secret.go index 69839ad5f..810c2cd5d 100644 --- a/pkg/resource/secret.go +++ b/pkg/resmap/secret.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resource +package resmap import ( "context" @@ -23,11 +23,12 @@ import ( "path/filepath" "time" + "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/types" corev1 "k8s.io/api/core/v1" ) -func newFromSecretGenerator(p string, s types.SecretArgs) (*Resource, error) { +func newFromSecretGenerator(p string, s types.SecretArgs) (*resource.Resource, error) { corev1secret := &corev1.Secret{} corev1secret.APIVersion = "v1" corev1secret.Kind = "Secret" @@ -46,13 +47,13 @@ func newFromSecretGenerator(p string, s types.SecretArgs) (*Resource, error) { corev1secret.Data[k] = out } - obj, err := objectToUnstructured(corev1secret) + obj, err := newUnstructuredFromObject(corev1secret) if err != nil { return nil, err } - return &Resource{Data: obj, Behavior: s.Behavior}, nil + return resource.NewResource(obj, s.Behavior), nil } func createSecretKey(wd string, command string) ([]byte, error) { @@ -68,10 +69,10 @@ func createSecretKey(wd string, command string) ([]byte, error) { return cmd.Output() } -// NewFromSecretGenerators takes a SecretGenerator slice and executes its command in directory p +// NewResMapFromSecretArgs takes a SecretArgs slice and executes its command in directory p // then writes the output to a Resource slice and return it. -func NewFromSecretGenerators(p string, secretList []types.SecretArgs) (ResourceCollection, error) { - allResources := []*Resource{} +func NewResMapFromSecretArgs(p string, secretList []types.SecretArgs) (ResMap, error) { + allResources := []*resource.Resource{} for _, secret := range secretList { res, err := newFromSecretGenerator(p, secret) if err != nil { @@ -79,5 +80,5 @@ func NewFromSecretGenerators(p string, secretList []types.SecretArgs) (ResourceC } allResources = append(allResources, res) } - return resourceCollectionFromResources(allResources) + return newResMapFromResourceSlice(allResources) } diff --git a/pkg/resource/secret_test.go b/pkg/resmap/secret_test.go similarity index 84% rename from pkg/resource/secret_test.go rename to pkg/resmap/secret_test.go index c97fb6211..b2b495143 100644 --- a/pkg/resource/secret_test.go +++ b/pkg/resmap/secret_test.go @@ -14,19 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resource +package resmap import ( "encoding/base64" "reflect" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/types" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" ) +var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"} + func TestNewFromSecretGenerators(t *testing.T) { secrets := []types.SecretArgs{ { @@ -38,17 +41,14 @@ func TestNewFromSecretGenerators(t *testing.T) { Type: "Opaque", }, } - re, err := NewFromSecretGenerators(".", secrets) + re, err := NewResMapFromSecretArgs(".", secrets) if err != nil { t.Fatalf("unexpected error: %v", err) } - expected := ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret", - }: &Resource{ - Data: &unstructured.Unstructured{ + expected := ResMap{ + resource.NewResId(secret, "secret"): resource.NewResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -63,7 +63,7 @@ func TestNewFromSecretGenerators(t *testing.T) { }, }, }, - }, + ""), } if !reflect.DeepEqual(re, expected) { diff --git a/pkg/resource/appresource.go b/pkg/resource/appresource.go deleted file mode 100644 index fd61ab867..000000000 --- a/pkg/resource/appresource.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resource - -import ( - "github.com/kubernetes-sigs/kustomize/pkg/loader" -) - -// NewFromResources returns a ResourceCollection given a resource path slice from kustomization file. -func NewFromResources(loader loader.Loader, paths []string) (ResourceCollection, error) { - allResources := []ResourceCollection{} - for _, path := range paths { - content, err := loader.Load(path) - if err != nil { - return nil, err - } - - res, err := decodeToResourceCollection(content) - if err != nil { - return nil, err - } - allResources = append(allResources, res) - } - return Merge(allResources...) -} - -// NewFromPatches returns a slice of Resources given a patch path slice from kustomization file. -func NewFromPatches(loader loader.Loader, paths []string) ([]*Resource, error) { - allResources := []*Resource{} - for _, path := range paths { - content, err := loader.Load(path) - if err != nil { - return nil, err - } - - res, err := decode(content) - if err != nil { - return nil, err - } - allResources = append(allResources, res...) - } - return allResources, nil -} diff --git a/pkg/resource/appresource_test.go b/pkg/resource/appresource_test.go deleted file mode 100644 index 20e665565..000000000 --- a/pkg/resource/appresource_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resource - -import ( - "fmt" - "reflect" - "testing" - - "github.com/kubernetes-sigs/kustomize/pkg/loader/loadertest" - "github.com/kubernetes-sigs/kustomize/pkg/types" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -func TestNewFromPaths(t *testing.T) { - - resourceStr := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: dply1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dply2 -` - - l := loadertest.NewFakeLoader("/home/seans/project") - if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil { - t.Fatalf("Error adding fake file: %v\n", ferr) - } - expected := ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "dply1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "dply1", - }, - }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "dply2", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "dply2", - }, - }, - }, - }, - } - - resources, _ := NewFromResources(l, []string{"/home/seans/project/deployment.yaml"}) - if len(resources) != 2 { - t.Fatalf("%#v should contain 2 appResource, but got %d", resources, len(resources)) - } - - if err := compareMap(resources, expected); err != nil { - t.Fatalf("actual doesn't match expected: %v", err) - } -} - -func compareMap(m1, m2 ResourceCollection) error { - if len(m1) != len(m2) { - keySet1 := []types.GroupVersionKindName{} - keySet2 := []types.GroupVersionKindName{} - for GVKn := range m1 { - keySet1 = append(keySet1, GVKn) - } - for GVKn := range m1 { - keySet2 = append(keySet2, GVKn) - } - return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2) - } - for GVKn, obj1 := range m1 { - obj2, found := m2[GVKn] - if !found { - return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2) - } - if !reflect.DeepEqual(obj1.Data, obj2.Data) { - return fmt.Errorf("%#v doesn't match %#v", obj1.Data, obj2.Data) - } - } - return nil -} diff --git a/pkg/types/types.go b/pkg/resource/resid.go similarity index 52% rename from pkg/types/types.go rename to pkg/resource/resid.go index 230a22969..f7935e278 100644 --- a/pkg/types/types.go +++ b/pkg/resource/resid.go @@ -14,16 +14,37 @@ See the License for the specific language governing permissions and limitations under the License. */ -package types +package resource import ( + "strings" + "k8s.io/apimachinery/pkg/runtime/schema" ) -// GroupVersionKindName contains GroupVersionKind and original name of the resource. -type GroupVersionKindName struct { +// ResId conflates GroupVersionKind with a textual name to uniquely identify a kubernetes resource (object). +type ResId struct { // GroupVersionKind of the resource. - GVK schema.GroupVersionKind + gvk schema.GroupVersionKind // original name of the resource before transformation. - Name string + name string +} + +func NewResId(g schema.GroupVersionKind, n string) ResId { + return ResId{gvk: g, name: n} +} + +func (n ResId) String() string { + if n.gvk.Group == "" { + return strings.Join([]string{n.gvk.Version, n.gvk.Kind, n.name}, "_") + ".yaml" + } + return strings.Join([]string{n.gvk.Group, n.gvk.Version, n.gvk.Kind, n.name}, "_") + ".yaml" +} + +func (n ResId) Gvk() schema.GroupVersionKind { + return n.gvk +} + +func (n ResId) Name() string { + return n.name } diff --git a/pkg/resource/resource.go b/pkg/resource/resource.go index f33037db3..f129f711b 100644 --- a/pkg/resource/resource.go +++ b/pkg/resource/resource.go @@ -17,35 +17,89 @@ limitations under the License. package resource import ( - "bytes" "encoding/json" - "sort" - "github.com/ghodss/yaml" - - "github.com/kubernetes-sigs/kustomize/pkg/types" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" ) -// Resource represents a Kubernetes Resource Object for ex. Deployment, Server -// ConfigMap etc. +// Resource is a Kubernetes Resource Object paired with a behavior. type Resource struct { - Data *unstructured.Unstructured - Behavior string + unstruct *unstructured.Unstructured + behavior string } -// GVKN returns Group/Version/Kind/Name for the resource. -func (r *Resource) GVKN() types.GroupVersionKindName { - var emptyZVKN types.GroupVersionKindName - if r.Data == nil { - return emptyZVKN +// NewResource returns a new instance of Resource. +func NewResource(u *unstructured.Unstructured, b string) *Resource { + return &Resource{unstruct: u, behavior: b} +} + +// NewBehaviorlessResource returns a new instance of Resource. +func NewBehaviorlessResource(u *unstructured.Unstructured) *Resource { + return &Resource{unstruct: u} +} + +// Behavior returns the behavior for the resource. +func (r *Resource) Behavior() string { + return r.behavior +} + +// Unstruct returns the unstructured object holding the resource. +func (r *Resource) Unstruct() *unstructured.Unstructured { + return r.unstruct +} + +// SetUnstruct sets a new member. +func (r *Resource) SetUnstruct(u *unstructured.Unstructured) { + r.unstruct = u +} + +// Id returns the ResId for the resource. +func (r *Resource) Id() ResId { + var empty ResId + if r.unstruct == nil { + return empty } - gvk := r.Data.GroupVersionKind() - return types.GroupVersionKindName{GVK: gvk, Name: r.Data.GetName()} + gvk := r.unstruct.GroupVersionKind() + return NewResId(gvk, r.unstruct.GetName()) } -func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) { +func (r *Resource) Merge(other *Resource) { + r.Replace(other) + mergeConfigmap(r.unstruct.Object, other.unstruct.Object, r.unstruct.Object) +} + +func (r *Resource) Replace(other *Resource) { + r.unstruct.SetLabels(mergeStringMaps(other.unstruct.GetLabels(), r.unstruct.GetLabels())) + r.unstruct.SetAnnotations(mergeStringMaps(other.unstruct.GetAnnotations(), r.unstruct.GetAnnotations())) + r.unstruct.SetName(other.unstruct.GetName()) +} + +// TODO: Add BinaryData once we sync to new k8s.io/api +func mergeConfigmap(mergedTo map[string]interface{}, maps ...map[string]interface{}) { + mergedMap := map[string]interface{}{} + for _, m := range maps { + datamap, ok := m["data"].(map[string]interface{}) + if ok { + for key, value := range datamap { + mergedMap[key] = value + } + } + } + mergedTo["data"] = mergedMap +} + +func mergeStringMaps(maps ...map[string]string) map[string]string { + result := map[string]string{} + for _, m := range maps { + for key, value := range m { + result[key] = value + } + } + return result +} + +func newUnstructuredFromObject(in runtime.Object) (*unstructured.Unstructured, error) { marshaled, err := json.Marshal(in) if err != nil { return nil, err @@ -54,38 +108,3 @@ func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) err = out.UnmarshalJSON(marshaled) return &out, err } - -// ResourceCollection is a map from GroupVersionKindName to Resource -type ResourceCollection map[types.GroupVersionKindName]*Resource - -// EncodeAsYaml encodes the map `in` and output the encoded objects separated by `---`. -func (in ResourceCollection) EncodeAsYaml() ([]byte, error) { - gvknList := []types.GroupVersionKindName{} - for gvkn := range in { - gvknList = append(gvknList, gvkn) - } - sort.Sort(types.ByGVKN(gvknList)) - - firstObj := true - var b []byte - buf := bytes.NewBuffer(b) - for _, gvkn := range gvknList { - obj := in[gvkn].Data - out, err := yaml.Marshal(obj) - if err != nil { - return nil, err - } - if !firstObj { - _, err = buf.WriteString("---\n") - if err != nil { - return nil, err - } - } - _, err = buf.Write(out) - if err != nil { - return nil, err - } - firstObj = false - } - return buf.Bytes(), nil -} diff --git a/pkg/resource/resource_test.go b/pkg/resource/resource_test.go deleted file mode 100644 index 9d986fe15..000000000 --- a/pkg/resource/resource_test.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resource - -import ( - "reflect" - "testing" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -func TestEncode(t *testing.T) { - encoded := []byte(`apiVersion: v1 -kind: ConfigMap -metadata: - name: cm1 ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cm2 -`) - input := ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "ConfigMap", - "metadata": map[string]interface{}{ - "name": "cm1", - }, - }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm2", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "ConfigMap", - "metadata": map[string]interface{}{ - "name": "cm2", - }, - }, - }, - }, - } - out, err := input.EncodeAsYaml() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !reflect.DeepEqual(out, encoded) { - t.Fatalf("%s doesn't match expected %s", out, encoded) - } -} diff --git a/pkg/resource/util.go b/pkg/resource/util.go deleted file mode 100644 index c6dbf4ebd..000000000 --- a/pkg/resource/util.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resource - -import ( - "bytes" - "fmt" - "io" - - "github.com/golang/glog" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - k8syaml "k8s.io/apimachinery/pkg/util/yaml" -) - -// decode decodes a list of objects in byte array format -func decode(in []byte) ([]*Resource, error) { - decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024) - resources := []*Resource{} - - var err error - for { - var out unstructured.Unstructured - err = decoder.Decode(&out) - if err != nil { - break - } - resources = append(resources, &Resource{Data: &out}) - } - if err != io.EOF { - return nil, err - } - return resources, nil -} - -// decodeToResourceCollection decodes a list of objects in byte array format. -// it will return a ResourceCollection. -func decodeToResourceCollection(in []byte) (ResourceCollection, error) { - resources, err := decode(in) - if err != nil { - return nil, err - } - - into := ResourceCollection{} - for _, res := range resources { - gvkn := res.GVKN() - if _, found := into[gvkn]; found { - return into, fmt.Errorf("GroupVersionKindName: %#v already exists in the map", gvkn) - } - into[gvkn] = res - } - return into, nil -} - -func resourceCollectionFromResources(resources []*Resource) (ResourceCollection, error) { - out := ResourceCollection{} - for _, res := range resources { - gvkn := res.GVKN() - if _, found := out[gvkn]; found { - return nil, fmt.Errorf("duplicated %#v is not allowed", gvkn) - } - out[gvkn] = res - } - return out, nil -} - -// Merge will merge all of the entries in the slice of ResourceCollection. -func Merge(rcs ...ResourceCollection) (ResourceCollection, error) { - all := ResourceCollection{} - for _, rc := range rcs { - for gvkn, obj := range rc { - if _, found := all[gvkn]; found { - return nil, fmt.Errorf("there is already an entry: %q", gvkn) - } - all[gvkn] = obj - } - } - - return all, nil -} - -const behaviorCreate = "create" -const behaviorReplace = "replace" -const behaviorMerge = "merge" - -// MergeWithOverride merges the entries in the ResourceCollection slice with Override. -// If there is already an entry with the same GVKN , different actions are performed -// according to value of Behavior field: -// 'create': create a new one; -// 'replace': replace the data only; keep the labels and annotations -// 'merge': merge the data; keep the labels and annotations -func MergeWithOverride(rcs ...ResourceCollection) (ResourceCollection, error) { - all := ResourceCollection{} - - for _, rc := range rcs { - for gvkn, obj := range rc { - if _, found := all[gvkn]; found { - switch obj.Behavior { - case "", behaviorCreate: - return nil, fmt.Errorf("Create an existing gvkn %#v is not allowed", gvkn) - case behaviorReplace: - glog.V(4).Infof("Replace object %v by %v", all[gvkn].Data.Object, obj.Data.Object) - obj.replace(all[gvkn]) - all[gvkn] = obj - case behaviorMerge: - glog.V(4).Infof("Merge object %v with %v", all[gvkn].Data.Object, obj.Data.Object) - obj.merge(all[gvkn]) - all[gvkn] = obj - glog.V(4).Infof("The merged object is %v", all[gvkn].Data.Object) - default: - return nil, fmt.Errorf("The behavior of %#v must be one of merge and replace since it already exists in the base", gvkn) - } - } else { - switch obj.Behavior { - case "", behaviorCreate: - all[gvkn] = obj - case behaviorMerge, behaviorReplace: - return nil, fmt.Errorf("No merge or replace is allowed for non existing gvkn %#v", gvkn) - default: - return nil, fmt.Errorf("The behavior of %#v must be create since it doesn't exist", gvkn) - } - } - } - } - return all, nil -} -func (r *Resource) replace(other *Resource) { - r.Data.SetLabels(mergeMap(other.Data.GetLabels(), r.Data.GetLabels())) - r.Data.SetAnnotations(mergeMap(other.Data.GetAnnotations(), r.Data.GetAnnotations())) - r.Data.SetName(other.Data.GetName()) -} - -func (r *Resource) merge(other *Resource) { - r.replace(other) - mergeConfigmap(r.Data.Object, other.Data.Object, r.Data.Object) -} - -func mergeMap(maps ...map[string]string) map[string]string { - mergedMap := map[string]string{} - for _, m := range maps { - for key, value := range m { - mergedMap[key] = value - } - } - return mergedMap -} - -// TODO: Add BinaryData once we sync to new k8s.io/api -func mergeConfigmap(mergedTo map[string]interface{}, maps ...map[string]interface{}) { - mergedMap := map[string]interface{}{} - for _, m := range maps { - datamap, ok := m["data"].(map[string]interface{}) - if ok { - for key, value := range datamap { - mergedMap[key] = value - } - } - } - mergedTo["data"] = mergedMap -} diff --git a/pkg/resource/util_test.go b/pkg/resource/util_test.go deleted file mode 100644 index 77aced49d..000000000 --- a/pkg/resource/util_test.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resource - -import ( - "fmt" - "reflect" - "testing" - - "github.com/kubernetes-sigs/kustomize/pkg/types" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -func TestDecodeToResourceCollection(t *testing.T) { - encoded := []byte(`apiVersion: v1 -kind: ConfigMap -metadata: - name: cm1 ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cm2 -`) - expected := ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "ConfigMap", - "metadata": map[string]interface{}{ - "name": "cm1", - }, - }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm2", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "ConfigMap", - "metadata": map[string]interface{}{ - "name": "cm2", - }, - }, - }, - }, - } - m, err := decodeToResourceCollection(encoded) - fmt.Printf("%v\n", m) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !reflect.DeepEqual(m, expected) { - t.Fatalf("%#v doesn't match expected %#v", m, expected) - } -} - -func TestMerge(t *testing.T) { - input1 := ResourceCollection{ - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "foo-deploy1", - }, - }, - }, - }, - } - input2 := ResourceCollection{ - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}, - Name: "stateful1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "StatefulSet", - "metadata": map[string]interface{}{ - "name": "bar-stateful", - }, - }, - }, - }, - } - input := []ResourceCollection{input1, input2} - expected := ResourceCollection{ - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "foo-deploy1", - }, - }, - }, - }, - types.GroupVersionKindName{ - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}, - Name: "stateful1", - }: &Resource{ - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "StatefulSet", - "metadata": map[string]interface{}{ - "name": "bar-stateful", - }, - }, - }, - }, - } - merged, err := Merge(input...) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !reflect.DeepEqual(merged, expected) { - t.Fatalf("%#v doesn't equal expected %#v", merged, expected) - } -} diff --git a/pkg/transformers/labelsandannotations.go b/pkg/transformers/labelsandannotations.go index a8ca3e132..763380302 100644 --- a/pkg/transformers/labelsandannotations.go +++ b/pkg/transformers/labelsandannotations.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" - "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/types" ) @@ -56,12 +56,12 @@ func NewMapTransformer(pc []PathConfig, m map[string]string) (Transformer, error // Transform apply each pair in the mapTransformer to the // fields specified in mapTransformer. -func (o *mapTransformer) Transform(m resource.ResourceCollection) error { - for gvkn := range m { - obj := m[gvkn].Data +func (o *mapTransformer) Transform(m resmap.ResMap) error { + for id := range m { + obj := m[id].Unstruct() objMap := obj.UnstructuredContent() for _, path := range o.pathConfigs { - if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) { + if !types.SelectByGVK(id.Gvk(), path.GroupVersionKind) { continue } err := mutateField(objMap, path.Path, path.CreateIfNotPresent, o.addMap) diff --git a/pkg/transformers/labelsandannotations_test.go b/pkg/transformers/labelsandannotations_test.go index b3e4748ea..43b676d97 100644 --- a/pkg/transformers/labelsandannotations_test.go +++ b/pkg/transformers/labelsandannotations_test.go @@ -20,18 +20,23 @@ import ( "reflect" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" ) +var service = schema.GroupVersionKind{Version: "v1", Kind: "Service"} +var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"} +var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"} +var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} +var statefulset = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"} +var foo = schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"} + func TestLabelsRun(t *testing.T) { - m := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + m := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -39,13 +44,9 @@ func TestLabelsRun(t *testing.T) { "name": "cm1", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -71,13 +72,9 @@ func TestLabelsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -93,15 +90,11 @@ func TestLabelsRun(t *testing.T) { }, }, }, - }, - }, + }), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -113,13 +106,9 @@ func TestLabelsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -157,13 +146,9 @@ func TestLabelsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -187,8 +172,7 @@ func TestLabelsRun(t *testing.T) { }, }, }, - }, - }, + }), } lt, err := NewDefaultingLabelsMapTransformer(map[string]string{"label-key1": "label-value1", "label-key2": "label-value2"}) @@ -200,7 +184,7 @@ func TestLabelsRun(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(m, expected) { - err = compareMap(m, expected) + err = expected.ErrorIfNotEqual(m) t.Fatalf("actual doesn't match expected: %v", err) } } @@ -284,12 +268,9 @@ func makeAnnotatededService() *unstructured.Unstructured { } func TestAnnotationsRun(t *testing.T) { - m := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + m := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -297,13 +278,9 @@ func TestAnnotationsRun(t *testing.T) { "name": "cm1", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -329,13 +306,9 @@ func TestAnnotationsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -351,15 +324,11 @@ func TestAnnotationsRun(t *testing.T) { }, }, }, - }, - }, + }), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -371,13 +340,9 @@ func TestAnnotationsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -411,13 +376,9 @@ func TestAnnotationsRun(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -437,8 +398,7 @@ func TestAnnotationsRun(t *testing.T) { }, }, }, - }, - }, + }), } at, err := NewDefaultingAnnotationsMapTransformer(map[string]string{"anno-key1": "anno-value1", "anno-key2": "anno-value2"}) if err != nil { @@ -449,7 +409,7 @@ func TestAnnotationsRun(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(m, expected) { - err = compareMap(m, expected) + err = expected.ErrorIfNotEqual(m) t.Fatalf("actual doesn't match expected: %v", err) } } diff --git a/pkg/transformers/multitransformer.go b/pkg/transformers/multitransformer.go index 5be43d6d8..cc36a099d 100644 --- a/pkg/transformers/multitransformer.go +++ b/pkg/transformers/multitransformer.go @@ -16,7 +16,7 @@ limitations under the License. package transformers -import "github.com/kubernetes-sigs/kustomize/pkg/resource" +import "github.com/kubernetes-sigs/kustomize/pkg/resmap" // multiTransformer contains a list of transformers. type multiTransformer struct { @@ -34,7 +34,7 @@ func NewMultiTransformer(t []Transformer) Transformer { } // Transform prepends the name prefix. -func (o *multiTransformer) Transform(m resource.ResourceCollection) error { +func (o *multiTransformer) Transform(m resmap.ResMap) error { for _, t := range o.transformers { err := t.Transform(m) if err != nil { diff --git a/pkg/transformers/namehash.go b/pkg/transformers/namehash.go index ad2387eb1..a82ba6ee6 100644 --- a/pkg/transformers/namehash.go +++ b/pkg/transformers/namehash.go @@ -21,7 +21,7 @@ import ( "fmt" "github.com/kubernetes-sigs/kustomize/pkg/hash" - "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/types" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -40,14 +40,14 @@ func NewNameHashTransformer() Transformer { } // Transform appends hash to configmaps and secrets. -func (o *nameHashTransformer) Transform(m resource.ResourceCollection) error { - for gvkn, obj := range m { +func (o *nameHashTransformer) Transform(m resmap.ResMap) error { + for id, obj := range m { switch { - case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}): - appendHashForConfigMap(obj.Data) + case types.SelectByGVK(id.Gvk(), &schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}): + appendHashForConfigMap(obj.Unstruct()) - case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "Secret"}): - appendHashForSecret(obj.Data) + case types.SelectByGVK(id.Gvk(), &schema.GroupVersionKind{Version: "v1", Kind: "Secret"}): + appendHashForSecret(obj.Unstruct()) } } return nil diff --git a/pkg/transformers/namehash_test.go b/pkg/transformers/namehash_test.go index caad96d86..c9112d367 100644 --- a/pkg/transformers/namehash_test.go +++ b/pkg/transformers/namehash_test.go @@ -20,18 +20,15 @@ import ( "reflect" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" ) func TestNameHashTransformer(t *testing.T) { - objs := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + objs := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -39,13 +36,9 @@ func TestNameHashTransformer(t *testing.T) { "name": "cm1", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -71,13 +64,9 @@ func TestNameHashTransformer(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -93,13 +82,9 @@ func TestNameHashTransformer(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(secret, "secret1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -107,16 +92,12 @@ func TestNameHashTransformer(t *testing.T) { "name": "secret1", }, }, - }, - }, + }), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -124,13 +105,9 @@ func TestNameHashTransformer(t *testing.T) { "name": "cm1-m462kdfb68", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -156,13 +133,9 @@ func TestNameHashTransformer(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"}, - Name: "svc1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(service, "svc1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Service", @@ -178,13 +151,9 @@ func TestNameHashTransformer(t *testing.T) { }, }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(secret, "secret1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -192,15 +161,14 @@ func TestNameHashTransformer(t *testing.T) { "name": "secret1-7kc45hd5f7", }, }, - }, - }, + }), } tran := NewNameHashTransformer() tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { - err := compareMap(objs, expected) + err := expected.ErrorIfNotEqual(objs) t.Fatalf("actual doesn't match expected: %v", err) } } diff --git a/pkg/transformers/namereference.go b/pkg/transformers/namereference.go index f2cffd92a..a2516ef66 100644 --- a/pkg/transformers/namereference.go +++ b/pkg/transformers/namereference.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" - "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/types" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -51,13 +51,13 @@ func NewNameReferenceTransformer(pc []referencePathConfig) (Transformer, error) // associated with the key. e.g. if is one of the key-value pair in the map, // then the old name is k.Name and the new name is v.GetName() func (o *nameReferenceTransformer) Transform( - m resource.ResourceCollection) error { - for GVKn := range m { - obj := m[GVKn].Data + m resmap.ResMap) error { + for id := range m { + obj := m[id].Unstruct() objMap := obj.UnstructuredContent() for _, referencePathConfig := range o.pathConfigs { for _, path := range referencePathConfig.pathConfigs { - if !types.SelectByGVK(GVKn.GVK, path.GroupVersionKind) { + if !types.SelectByGVK(id.Gvk(), path.GroupVersionKind) { continue } err := mutateField(objMap, path.Path, path.CreateIfNotPresent, @@ -71,25 +71,9 @@ func (o *nameReferenceTransformer) Transform( return nil } -// noMatchingGVKNError indicates failing to find a gvkn.GroupVersionKindName. -type noMatchingGVKNError struct { - message string -} - -// newNoMatchingGVKNError constructs an instance of noMatchingGVKNError with -// a given error message. -func newNoMatchingGVKNError(errMsg string) noMatchingGVKNError { - return noMatchingGVKNError{errMsg} -} - -// Error returns the error in string format. -func (err noMatchingGVKNError) Error() string { - return err.message -} - func (o *nameReferenceTransformer) updateNameReference( GVK schema.GroupVersionKind, - m resource.ResourceCollection, + m resmap.ResMap, ) func(in interface{}) (interface{}, error) { return func(in interface{}) (interface{}, error) { s, ok := in.(string) @@ -97,12 +81,12 @@ func (o *nameReferenceTransformer) updateNameReference( return nil, fmt.Errorf("%#v is expectd to be %T", in, s) } - for GVKn, obj := range m { - if !types.SelectByGVK(GVKn.GVK, &GVK) { + for id, obj := range m { + if !types.SelectByGVK(id.Gvk(), &GVK) { continue } - if GVKn.Name == s { - return obj.Data.GetName(), nil + if id.Name() == s { + return obj.Unstruct().GetName(), nil } } return in, nil diff --git a/pkg/transformers/namereference_test.go b/pkg/transformers/namereference_test.go index 90ea29849..41a181f7e 100644 --- a/pkg/transformers/namereference_test.go +++ b/pkg/transformers/namereference_test.go @@ -20,18 +20,15 @@ import ( "reflect" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" ) func TestNameReferenceRun(t *testing.T) { - m := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + m := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -39,13 +36,9 @@ func TestNameReferenceRun(t *testing.T) { "name": "someprefix-cm1-somehash", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(secret, "secret1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -53,13 +46,9 @@ func TestNameReferenceRun(t *testing.T) { "name": "someprefix-secret1-somehash", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -122,16 +111,12 @@ func TestNameReferenceRun(t *testing.T) { }, }, }, - }, - }, + }), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -139,13 +124,9 @@ func TestNameReferenceRun(t *testing.T) { "name": "someprefix-cm1-somehash", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"}, - Name: "secret1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(secret, "secret1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Secret", @@ -153,13 +134,9 @@ func TestNameReferenceRun(t *testing.T) { "name": "someprefix-secret1-somehash", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "group": "apps", "apiVersion": "v1", @@ -222,8 +199,7 @@ func TestNameReferenceRun(t *testing.T) { }, }, }, - }, - }, + }), } nrt, err := NewDefaultingNameReferenceTransformer() @@ -232,7 +208,7 @@ func TestNameReferenceRun(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(m, expected) { - err = compareMap(m, expected) + err = expected.ErrorIfNotEqual(m) t.Fatalf("actual doesn't match expected: %v", err) } } diff --git a/pkg/transformers/nooptransformer.go b/pkg/transformers/nooptransformer.go index d34dd1cfa..58171b13a 100644 --- a/pkg/transformers/nooptransformer.go +++ b/pkg/transformers/nooptransformer.go @@ -16,7 +16,7 @@ limitations under the License. package transformers -import "github.com/kubernetes-sigs/kustomize/pkg/resource" +import "github.com/kubernetes-sigs/kustomize/pkg/resmap" // noOpTransformer contains a no-op transformer. type noOpTransformer struct{} @@ -29,6 +29,6 @@ func NewNoOpTransformer() Transformer { } // Transform does nothing. -func (o *noOpTransformer) Transform(_ resource.ResourceCollection) error { +func (o *noOpTransformer) Transform(_ resmap.ResMap) error { return nil } diff --git a/pkg/transformers/overlay.go b/pkg/transformers/overlay.go index 569f08f7c..23ca61486 100644 --- a/pkg/transformers/overlay.go +++ b/pkg/transformers/overlay.go @@ -22,6 +22,7 @@ import ( jsonpatch "github.com/evanphx/json-patch" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -45,8 +46,8 @@ func NewOverlayTransformer(overlay []*resource.Resource) (Transformer, error) { } // Transform apply the overlay on top of the base resources. -func (o *overlayTransformer) Transform(baseResourceMap resource.ResourceCollection) error { - // Merge and then index the patches by GVKN. +func (o *overlayTransformer) Transform(baseResourceMap resmap.ResMap) error { + // Merge and then index the patches by Id. overlays, err := o.mergePatches() if err != nil { return err @@ -55,22 +56,22 @@ func (o *overlayTransformer) Transform(baseResourceMap resource.ResourceCollecti // Strategic merge the resources exist in both base and overlay. for _, overlay := range overlays { // Merge overlay with base resource. - gvkn := overlay.GVKN() - base, found := baseResourceMap[gvkn] + id := overlay.Id() + base, found := baseResourceMap[id] if !found { - return fmt.Errorf("failed to find an object with %#v to apply the patch", gvkn.GVK) + return fmt.Errorf("failed to find an object with %#v to apply the patch", id.Gvk()) } merged := map[string]interface{}{} - versionedObj, err := scheme.Scheme.New(gvkn.GVK) - baseName := base.Data.GetName() + versionedObj, err := scheme.Scheme.New(id.Gvk()) + baseName := base.Unstruct().GetName() switch { case runtime.IsNotRegisteredError(err): // Use JSON merge patch to handle types w/o schema - baseBytes, err := json.Marshal(base.Data) + baseBytes, err := json.Marshal(base.Unstruct()) if err != nil { return err } - patchBytes, err := json.Marshal(overlay.Data) + patchBytes, err := json.Marshal(overlay.Unstruct()) if err != nil { return err } @@ -94,33 +95,33 @@ func (o *overlayTransformer) Transform(baseResourceMap resource.ResourceCollecti return err } merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta( - base.Data.Object, - overlay.Data.Object, + base.Unstruct().Object, + overlay.Unstruct().Object, lookupPatchMeta) if err != nil { return err } } - base.Data.SetName(baseName) - baseResourceMap[gvkn].Data.Object = merged + base.Unstruct().SetName(baseName) + baseResourceMap[id].Unstruct().Object = merged } return nil } -// mergePatches merge and index patches by GVKN. +// mergePatches merge and index patches by Id. // It errors out if there is conflict between patches. -func (o *overlayTransformer) mergePatches() (resource.ResourceCollection, error) { - rc := resource.ResourceCollection{} +func (o *overlayTransformer) mergePatches() (resmap.ResMap, error) { + rc := resmap.ResMap{} patches := resourcesToObjects(o.overlay) for ix, patch := range o.overlay { - gvkn := patch.GVKN() - existing, found := rc[gvkn] + id := patch.Id() + existing, found := rc[id] if !found { - rc[gvkn] = patch + rc[id] = patch continue } - versionedObj, err := scheme.Scheme.New(gvkn.GVK) + versionedObj, err := scheme.Scheme.New(id.Gvk()) if err != nil && !runtime.IsNotRegisteredError(err) { return nil, err } @@ -134,7 +135,7 @@ func (o *overlayTransformer) mergePatches() (resource.ResourceCollection, error) } } - conflict, err := cd.hasConflict(existing.Data, patch.Data) + conflict, err := cd.hasConflict(existing.Unstruct(), patch.Unstruct()) if err != nil { return nil, err } @@ -143,13 +144,13 @@ func (o *overlayTransformer) mergePatches() (resource.ResourceCollection, error) if err != nil { return nil, err } - return nil, fmt.Errorf("there is conflict between %#v and %#v", conflictingPatch.Object, patch.Data.Object) + return nil, fmt.Errorf("there is conflict between %#v and %#v", conflictingPatch.Object, patch.Unstruct().Object) } else { - merged, err := cd.mergePatches(existing.Data, patch.Data) + merged, err := cd.mergePatches(existing.Unstruct(), patch.Unstruct()) if err != nil { return nil, err } - existing.Data = merged + existing.SetUnstruct(merged) } } return rc, nil @@ -158,7 +159,7 @@ func (o *overlayTransformer) mergePatches() (resource.ResourceCollection, error) func resourcesToObjects(rs []*resource.Resource) []*unstructured.Unstructured { objectList := make([]*unstructured.Unstructured, len(rs)) for i := range rs { - objectList[i] = rs[i].Data + objectList[i] = rs[i].Unstruct() } return objectList } diff --git a/pkg/transformers/overlay_test.go b/pkg/transformers/overlay_test.go index 522de67cc..13bd16d2d 100644 --- a/pkg/transformers/overlay_test.go +++ b/pkg/transformers/overlay_test.go @@ -21,18 +21,15 @@ import ( "strings" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" ) func TestOverlayRun(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -57,35 +54,32 @@ func TestOverlayRun(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "another-label": "foo", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deploy1", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "another-label": "foo", }, - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:latest", - "env": []interface{}{ - map[string]interface{}{ - "name": "SOMEENV", - "value": "BAR", - }, + }, + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "image": "nginx:latest", + "env": []interface{}{ + map[string]interface{}{ + "name": "SOMEENV", + "value": "BAR", }, }, }, @@ -95,13 +89,11 @@ func TestOverlayRun(t *testing.T) { }, }, }, + ), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -133,8 +125,7 @@ func TestOverlayRun(t *testing.T) { }, }, }, - }, - }, + }), } lt, err := NewOverlayTransformer(overlay) if err != nil { @@ -145,18 +136,15 @@ func TestOverlayRun(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(base, expected) { - err = compareMap(base, expected) + err = expected.ErrorIfNotEqual(base) t.Fatalf("actual doesn't match expected: %v", err) } } func TestMultiplePatches(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -176,30 +164,27 @@ func TestMultiplePatches(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:latest", - "env": []interface{}{ - map[string]interface{}{ - "name": "SOMEENV", - "value": "BAR", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deploy1", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "image": "nginx:latest", + "env": []interface{}{ + map[string]interface{}{ + "name": "SOMEENV", + "value": "BAR", }, }, }, @@ -209,31 +194,30 @@ func TestMultiplePatches(t *testing.T) { }, }, }, - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "env": []interface{}{ - map[string]interface{}{ - "name": "ANOTHERENV", - "value": "HELLO", - }, + ), + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deploy1", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "env": []interface{}{ + map[string]interface{}{ + "name": "ANOTHERENV", + "value": "HELLO", }, }, - map[string]interface{}{ - "name": "busybox", - "image": "busybox", - }, + }, + map[string]interface{}{ + "name": "busybox", + "image": "busybox", }, }, }, @@ -241,13 +225,11 @@ func TestMultiplePatches(t *testing.T) { }, }, }, + ), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -281,8 +263,7 @@ func TestMultiplePatches(t *testing.T) { }, }, }, - }, - }, + }), } lt, err := NewOverlayTransformer(overlay) if err != nil { @@ -293,18 +274,15 @@ func TestMultiplePatches(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(base, expected) { - err = compareMap(base, expected) + err = expected.ErrorIfNotEqual(base) t.Fatalf("actual doesn't match expected: %v", err) } } func TestMultiplePatchesWithConflict(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - Name: "deploy1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(deploy, "deploy1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -324,30 +302,27 @@ func TestMultiplePatchesWithConflict(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:latest", - "env": []interface{}{ - map[string]interface{}{ - "name": "SOMEENV", - "value": "BAR", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deploy1", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "image": "nginx:latest", + "env": []interface{}{ + map[string]interface{}{ + "name": "SOMEENV", + "value": "BAR", }, }, }, @@ -357,22 +332,21 @@ func TestMultiplePatchesWithConflict(t *testing.T) { }, }, }, - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:1.7.9", - }, + ), + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "name": "deploy1", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "image": "nginx:1.7.9", }, }, }, @@ -380,6 +354,7 @@ func TestMultiplePatchesWithConflict(t *testing.T) { }, }, }, + ), } lt, err := NewOverlayTransformer(overlay) @@ -396,12 +371,9 @@ func TestMultiplePatchesWithConflict(t *testing.T) { } func TestNoSchemaOverlayRun(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}, - Name: "my-foo", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(foo, "my-foo"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "example.com/v1", "kind": "Foo", @@ -415,34 +387,29 @@ func TestNoSchemaOverlayRun(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "example.com/v1", - "kind": "Foo", - "metadata": map[string]interface{}{ - "name": "my-foo", - }, - "spec": map[string]interface{}{ - "bar": map[string]interface{}{ - "B": nil, - "C": "Z", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.com/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "my-foo", + }, + "spec": map[string]interface{}{ + "bar": map[string]interface{}{ + "B": nil, + "C": "Z", }, }, }, }, + ), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}, - Name: "my-foo", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(foo, "my-foo"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "example.com/v1", "kind": "Foo", @@ -456,8 +423,7 @@ func TestNoSchemaOverlayRun(t *testing.T) { }, }, }, - }, - }, + }), } lt, err := NewOverlayTransformer(overlay) @@ -468,18 +434,15 @@ func TestNoSchemaOverlayRun(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if err = compareMap(base, expected); err != nil { + if err = expected.ErrorIfNotEqual(base); err != nil { t.Fatalf("actual doesn't match expected: %v", err) } } func TestNoSchemaMultiplePatches(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}, - Name: "my-foo", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(foo, "my-foo"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "example.com/v1", "kind": "Foo", @@ -493,54 +456,48 @@ func TestNoSchemaMultiplePatches(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "example.com/v1", - "kind": "Foo", - "metadata": map[string]interface{}{ - "name": "my-foo", - }, - "spec": map[string]interface{}{ - "bar": map[string]interface{}{ - "B": nil, - "C": "Z", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.com/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "my-foo", + }, + "spec": map[string]interface{}{ + "bar": map[string]interface{}{ + "B": nil, + "C": "Z", }, }, }, }, - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "example.com/v1", - "kind": "Foo", - "metadata": map[string]interface{}{ - "name": "my-foo", + ), + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.com/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "my-foo", + }, + "spec": map[string]interface{}{ + "bar": map[string]interface{}{ + "C": "Z", + "D": "W", }, - "spec": map[string]interface{}{ - "bar": map[string]interface{}{ - "C": "Z", - "D": "W", - }, - "baz": map[string]interface{}{ - "hello": "world", - }, + "baz": map[string]interface{}{ + "hello": "world", }, }, }, }, + ), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}, - Name: "my-foo", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(foo, "my-foo"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "example.com/v1", "kind": "Foo", @@ -558,8 +515,7 @@ func TestNoSchemaMultiplePatches(t *testing.T) { }, }, }, - }, - }, + }), } lt, err := NewOverlayTransformer(overlay) @@ -570,18 +526,15 @@ func TestNoSchemaMultiplePatches(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if err = compareMap(base, expected); err != nil { + if err = expected.ErrorIfNotEqual(base); err != nil { t.Fatalf("actual doesn't match expected: %v", err) } } func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) { - base := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"}, - Name: "my-foo", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + base := resmap.ResMap{ + resource.NewResId(foo, "my-foo"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "example.com/v1", "kind": "Foo", @@ -595,43 +548,38 @@ func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) { }, }, }, - }, - }, + }), } overlay := []*resource.Resource{ - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "example.com/v1", - "kind": "Foo", - "metadata": map[string]interface{}{ - "name": "my-foo", - }, - "spec": map[string]interface{}{ - "bar": map[string]interface{}{ - "B": nil, - "C": "Z", - }, + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.com/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "my-foo", + }, + "spec": map[string]interface{}{ + "bar": map[string]interface{}{ + "B": nil, + "C": "Z", }, }, }, - }, - { - Data: &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "example.com/v1", - "kind": "Foo", - "metadata": map[string]interface{}{ - "name": "my-foo", - }, - "spec": map[string]interface{}{ - "bar": map[string]interface{}{ - "C": "NOT_Z", - }, + }), + resource.NewBehaviorlessResource(&unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.com/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "my-foo", + }, + "spec": map[string]interface{}{ + "bar": map[string]interface{}{ + "C": "NOT_Z", }, }, }, - }, + }), } lt, err := NewOverlayTransformer(overlay) diff --git a/pkg/transformers/pathconfig.go b/pkg/transformers/pathconfig.go index aad2569d5..67a1f6e20 100644 --- a/pkg/transformers/pathconfig.go +++ b/pkg/transformers/pathconfig.go @@ -20,14 +20,14 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -// PathConfig contains the configuration of a field, including the GVK it ties to, +// PathConfig contains the configuration of a field, including the gvk it ties to, // path to the field, etc. type PathConfig struct { // If true, it will create the path if it is not found. CreateIfNotPresent bool - // The GVK that this path tied to. - // If unset, it applied to any GVK - // If some fields are set, it applies to all matching GVK. + // The gvk that this path tied to. + // If unset, it applied to any gvk + // If some fields are set, it applies to all matching gvk. GroupVersionKind *schema.GroupVersionKind // Path to the field that will be munged. Path []string @@ -48,8 +48,8 @@ type PathConfig struct { // } type referencePathConfig struct { // referencedGVK is the GroupVersionKind that is referenced by - // the PathConfig's GVK in the path of PathConfig.Path. + // the PathConfig's gvk in the path of PathConfig.Path. referencedGVK schema.GroupVersionKind - // PathConfig is the GVK that is referencing the referencedGVK object's name. + // PathConfig is the gvk that is referencing the referencedGVK object's name. pathConfigs []PathConfig } diff --git a/pkg/transformers/prefixname.go b/pkg/transformers/prefixname.go index d2115e7af..4634158e8 100644 --- a/pkg/transformers/prefixname.go +++ b/pkg/transformers/prefixname.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" - "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/types" ) @@ -57,12 +57,12 @@ func NewNamePrefixTransformer(pc []PathConfig, np string) (Transformer, error) { } // Transform prepends the name prefix. -func (o *namePrefixTransformer) Transform(m resource.ResourceCollection) error { - for gvkn := range m { - obj := m[gvkn].Data +func (o *namePrefixTransformer) Transform(m resmap.ResMap) error { + for id := range m { + obj := m[id].Unstruct() objMap := obj.UnstructuredContent() for _, path := range o.pathConfigs { - if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) { + if !types.SelectByGVK(id.Gvk(), path.GroupVersionKind) { continue } err := mutateField(objMap, path.Path, path.CreateIfNotPresent, o.addPrefix) diff --git a/pkg/transformers/prefixname_test.go b/pkg/transformers/prefixname_test.go index 4d8c43a49..09eaffa23 100644 --- a/pkg/transformers/prefixname_test.go +++ b/pkg/transformers/prefixname_test.go @@ -20,18 +20,15 @@ import ( "reflect" "testing" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" ) func TestPrefixNameRun(t *testing.T) { - m := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + m := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -39,13 +36,9 @@ func TestPrefixNameRun(t *testing.T) { "name": "cm1", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm2", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(cmap, "cm2"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -53,15 +46,11 @@ func TestPrefixNameRun(t *testing.T) { "name": "cm2", }, }, - }, - }, + }), } - expected := resource.ResourceCollection{ - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm1", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + expected := resmap.ResMap{ + resource.NewResId(cmap, "cm1"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -69,13 +58,9 @@ func TestPrefixNameRun(t *testing.T) { "name": "someprefix-cm1", }, }, - }, - }, - { - GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, - Name: "cm2", - }: &resource.Resource{ - Data: &unstructured.Unstructured{ + }), + resource.NewResId(cmap, "cm2"): resource.NewBehaviorlessResource( + &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", @@ -83,8 +68,7 @@ func TestPrefixNameRun(t *testing.T) { "name": "someprefix-cm2", }, }, - }, - }, + }), } npt, err := NewDefaultingNamePrefixTransformer("someprefix-") @@ -96,7 +80,7 @@ func TestPrefixNameRun(t *testing.T) { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(m, expected) { - err = compareMap(m, expected) + err = expected.ErrorIfNotEqual(m) t.Fatalf("actual doesn't match expected: %v", err) } } diff --git a/pkg/transformers/transformer.go b/pkg/transformers/transformer.go index e749e9055..6dbfe406b 100644 --- a/pkg/transformers/transformer.go +++ b/pkg/transformers/transformer.go @@ -16,10 +16,10 @@ limitations under the License. package transformers -import "github.com/kubernetes-sigs/kustomize/pkg/resource" +import "github.com/kubernetes-sigs/kustomize/pkg/resmap" // Transformer can transform objects. type Transformer interface { // Transform modifies objects in a map, e.g. add prefixes or additional labels. - Transform(m resource.ResourceCollection) error + Transform(m resmap.ResMap) error } diff --git a/pkg/transformers/util_test.go b/pkg/transformers/util_test.go deleted file mode 100644 index 790544c38..000000000 --- a/pkg/transformers/util_test.go +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package transformers - -import ( - "fmt" - "reflect" - - "github.com/kubernetes-sigs/kustomize/pkg/resource" - "github.com/kubernetes-sigs/kustomize/pkg/types" -) - -func compareMap(m1, m2 resource.ResourceCollection) error { - if len(m1) != len(m2) { - keySet1 := []types.GroupVersionKindName{} - keySet2 := []types.GroupVersionKindName{} - for GVKn := range m1 { - keySet1 = append(keySet1, GVKn) - } - for GVKn := range m1 { - keySet2 = append(keySet2, GVKn) - } - return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2) - } - for GVKn, obj1 := range m1 { - obj2, found := m2[GVKn] - if !found { - return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2) - } - if !reflect.DeepEqual(obj1.Data, obj2.Data) { - return fmt.Errorf("%#v doesn't match %#v", obj1.Data, obj2.Data) - } - } - return nil -} diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index c3354baea..6cc23e6de 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -67,7 +67,7 @@ type ConfigMapArgs struct { // hash(content of configmap). Name string `json:"name,omitempty" yaml:"name,omitempty"` - // Behavior of configmap, must be one of create, merge and replace + // behavior of configmap, must be one of create, merge and replace // 'create': create a new one; // 'replace': replace the existing one; // 'merge': merge the existing one. @@ -84,7 +84,7 @@ type SecretArgs struct { // hash(content of secret). Name string `json:"name,omitempty" yaml:"name,omitempty"` - // Behavior of secretGenerator, must be one of create, merge and replace + // behavior of secretGenerator, must be one of create, merge and replace // 'create': create a new one; // 'replace': replace the existing one; // 'merge': merge the existing one. diff --git a/pkg/types/util.go b/pkg/types/selectbygvk.go similarity index 68% rename from pkg/types/util.go rename to pkg/types/selectbygvk.go index 6a156aadb..4ff1b7afb 100644 --- a/pkg/types/util.go +++ b/pkg/types/selectbygvk.go @@ -17,25 +17,16 @@ limitations under the License. package types import ( - "strings" - "k8s.io/apimachinery/pkg/runtime/schema" ) -func (gvkn GroupVersionKindName) String() string { - if gvkn.GVK.Group == "" { - return strings.Join([]string{gvkn.GVK.Version, gvkn.GVK.Kind, gvkn.Name}, "_") + ".yaml" - } - return strings.Join([]string{gvkn.GVK.Group, gvkn.GVK.Version, gvkn.GVK.Kind, gvkn.Name}, "_") + ".yaml" -} - // SelectByGVK returns true if `selector` selects `in`; otherwise, false. // If `selector` and `in` are the same, return true. // If `selector` is nil, it is considered as a wildcard and always return true. -// e.g. selector CAN select -// . -// selector CANNOT select -// . +// e.g. selector CAN select +// . +// selector CANNOT select +// . func SelectByGVK(in schema.GroupVersionKind, selector *schema.GroupVersionKind) bool { if selector == nil { return true diff --git a/pkg/types/util_test.go b/pkg/types/selectbygvk_test.go similarity index 97% rename from pkg/types/util_test.go rename to pkg/types/selectbygvk_test.go index 1bc2606d7..0c7571983 100644 --- a/pkg/types/util_test.go +++ b/pkg/types/selectbygvk_test.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -func TestFilterByGVK(t *testing.T) { +func TestSelectByGVK(t *testing.T) { type testCase struct { description string in schema.GroupVersionKind @@ -37,7 +37,7 @@ func TestFilterByGVK(t *testing.T) { expected: true, }, { - description: "GVK matches", + description: "gvk matches", in: schema.GroupVersionKind{ Group: "group1", Version: "version1",