From 931f43f8d736a5508a9047e74b28af967c7cd9ba Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Mon, 3 Dec 2018 13:24:20 -0800 Subject: [PATCH] resolve namereference in an array --- .../config/defaultconfig/namereference.go | 4 + pkg/transformers/namereference.go | 69 ++++++++--- pkg/transformers/namereference_test.go | 112 +++++++++++++++++- 3 files changed, 168 insertions(+), 17 deletions(-) diff --git a/pkg/transformers/config/defaultconfig/namereference.go b/pkg/transformers/config/defaultconfig/namereference.go index a0d81db5b..2f31a36b4 100644 --- a/pkg/transformers/config/defaultconfig/namereference.go +++ b/pkg/transformers/config/defaultconfig/namereference.go @@ -226,6 +226,10 @@ nameReference: kind: StorageClass - path: parameters/secretRef kind: StorageClass + - path: rules/resourceNames + kind: Role + - path: rules/resourceNames + kind: ClusterRole - kind: Service version: v1 diff --git a/pkg/transformers/namereference.go b/pkg/transformers/namereference.go index 134bac716..2f65f6848 100644 --- a/pkg/transformers/namereference.go +++ b/pkg/transformers/namereference.go @@ -71,24 +71,61 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error { func (o *nameReferenceTransformer) updateNameReference( backRef gvk.Gvk, m resmap.ResMap) func(in interface{}) (interface{}, error) { return func(in interface{}) (interface{}, error) { - s, ok := in.(string) - if !ok { - return nil, fmt.Errorf("%#v is expected to be %T", in, s) - } - for id, res := range m { - if id.Gvk().IsSelected(&backRef) && id.Name() == s { - matchedIds := m.FindByGVKN(id) - // If there's more than one match, there's no way - // to know which one to pick, so emit error. - if len(matchedIds) > 1 { - return nil, fmt.Errorf( - "Multiple matches for name %s:\n %v", id, matchedIds) + switch in.(type) { + case string: + s, _ := in.(string) + for id, res := range m { + if id.Gvk().IsSelected(&backRef) && id.Name() == s { + matchedIds := m.FindByGVKN(id) + // If there's more than one match, there's no way + // to know which one to pick, so emit error. + if len(matchedIds) > 1 { + return nil, fmt.Errorf( + "Multiple matches for name %s:\n %v", id, matchedIds) + } + // Return transformed name of the object, + // complete with prefixes, hashes, etc. + return res.GetName(), nil } - // Return transformed name of the object, - // complete with prefixes, hashes, etc. - return res.GetName(), nil } + return in, nil + case []interface{}: + l, _ := in.([]interface{}) + var names []string + for _, item := range l { + name, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%#v is expected to be %T", item, name) + } + names = append(names, name) + } + for id, res := range m { + indexes := indexOf(id.Name(), names) + if id.Gvk().IsSelected(&backRef) && len(indexes) > 0 { + matchedIds := m.FindByGVKN(id) + if len(matchedIds) > 1 { + return nil, fmt.Errorf( + "Multiple matches for name %s:\n %v", id, matchedIds) + } + for _, index := range indexes { + l[index] = res.GetName() + } + return l, nil + } + } + return in, nil + default: + return nil, fmt.Errorf("%#v is expected to be either a string or a []interface{}", in) } - return in, nil } } + +func indexOf(s string, slice []string) []int { + var index []int + for i, item := range slice { + if item == s { + index = append(index, i) + } + } + return index +} diff --git a/pkg/transformers/namereference_test.go b/pkg/transformers/namereference_test.go index a98c8cf97..b01bde234 100644 --- a/pkg/transformers/namereference_test.go +++ b/pkg/transformers/namereference_test.go @@ -18,6 +18,7 @@ package transformers import ( "reflect" + "strings" "testing" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" @@ -26,7 +27,7 @@ import ( "sigs.k8s.io/kustomize/pkg/resource" ) -func TestNameReferenceRun(t *testing.T) { +func TestNameReferenceHappyRun(t *testing.T) { rf := resource.NewFactory( kunstruct.NewKunstructuredFactoryImpl()) m := resmap.ResMap{ @@ -214,6 +215,26 @@ func TestNameReferenceRun(t *testing.T) { }, }, }), + resid.NewResId(cr, "cr"): rf.FromMap( + map[string]interface{}{ + "apiVersion": "rbac.authorization.k8s.io/v1", + "kind": "ClusterRole", + "metadata": map[string]interface{}{ + "name": "cr", + }, + "rules": []interface{}{ + map[string]interface{}{ + "resources": []interface{}{ + "secrets", + }, + "resourceNames": []interface{}{ + "secret1", + "secret1", + "secret2", + }, + }, + }, + }), } expected := resmap.ResMap{} @@ -364,6 +385,26 @@ func TestNameReferenceRun(t *testing.T) { }, }, }) + expected[resid.NewResId(cr, "cr")] = rf.FromMap( + map[string]interface{}{ + "apiVersion": "rbac.authorization.k8s.io/v1", + "kind": "ClusterRole", + "metadata": map[string]interface{}{ + "name": "cr", + }, + "rules": []interface{}{ + map[string]interface{}{ + "resources": []interface{}{ + "secrets", + }, + "resourceNames": []interface{}{ + "someprefix-secret1-somehash", + "someprefix-secret1-somehash", + "secret2", + }, + }, + }, + }) nrt, err := NewNameReferenceTransformer(defaultTransformerConfig.NameReference) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -377,3 +418,72 @@ func TestNameReferenceRun(t *testing.T) { t.Fatalf("actual doesn't match expected: %v", err) } } + +func TestNameReferenceUnhappyRun(t *testing.T) { + rf := resource.NewFactory( + kunstruct.NewKunstructuredFactoryImpl()) + tests := []struct { + resMap resmap.ResMap + expectedErr string + }{ + { + resMap: resmap.ResMap{ + resid.NewResId(cr, "cr"): rf.FromMap( + map[string]interface{}{ + "apiVersion": "rbac.authorization.k8s.io/v1", + "kind": "ClusterRole", + "metadata": map[string]interface{}{ + "name": "cr", + }, + "rules": []interface{}{ + map[string]interface{}{ + "resources": []interface{}{ + "secrets", + }, + "resourceNames": []interface{}{ + []interface{}{}, + }, + }, + }, + }), + }, + expectedErr: "is expected to be string"}, + {resMap: resmap.ResMap{ + resid.NewResId(cr, "cr"): rf.FromMap( + map[string]interface{}{ + "apiVersion": "rbac.authorization.k8s.io/v1", + "kind": "ClusterRole", + "metadata": map[string]interface{}{ + "name": "cr", + }, + "rules": []interface{}{ + map[string]interface{}{ + "resources": []interface{}{ + "secrets", + }, + "resourceNames": map[string]interface{}{ + "foo": "bar", + }, + }, + }, + }), + }, + expectedErr: "is expected to be either a string or a []interface{}"}, + } + + nrt, err := NewNameReferenceTransformer(defaultTransformerConfig.NameReference) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + for _, test := range tests { + err = nrt.Transform(test.resMap) + if err == nil { + t.Fatalf("expected error to happen") + } + + if !strings.Contains(err.Error(), test.expectedErr) { + t.Fatalf("Incorrect error.\nExpected: %s, but got %v", test.expectedErr, err) + } + } +}