Merge pull request #592 from Liujingfang1/namereference

resolve namereference in an array
This commit is contained in:
Jeff Regan
2018-12-04 15:51:00 -08:00
committed by GitHub
3 changed files with 168 additions and 17 deletions

View File

@@ -226,6 +226,10 @@ nameReference:
kind: StorageClass kind: StorageClass
- path: parameters/secretRef - path: parameters/secretRef
kind: StorageClass kind: StorageClass
- path: rules/resourceNames
kind: Role
- path: rules/resourceNames
kind: ClusterRole
- kind: Service - kind: Service
version: v1 version: v1

View File

@@ -71,24 +71,61 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
func (o *nameReferenceTransformer) updateNameReference( func (o *nameReferenceTransformer) updateNameReference(
backRef gvk.Gvk, m resmap.ResMap) func(in interface{}) (interface{}, error) { backRef gvk.Gvk, m resmap.ResMap) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) { return func(in interface{}) (interface{}, error) {
s, ok := in.(string) switch in.(type) {
if !ok { case string:
return nil, fmt.Errorf("%#v is expected to be %T", in, s) s, _ := in.(string)
} for id, res := range m {
for id, res := range m { if id.Gvk().IsSelected(&backRef) && id.Name() == s {
if id.Gvk().IsSelected(&backRef) && id.Name() == s { matchedIds := m.FindByGVKN(id)
matchedIds := m.FindByGVKN(id) // If there's more than one match, there's no way
// If there's more than one match, there's no way // to know which one to pick, so emit error.
// to know which one to pick, so emit error. if len(matchedIds) > 1 {
if len(matchedIds) > 1 { return nil, fmt.Errorf(
return nil, fmt.Errorf( "Multiple matches for name %s:\n %v", id, matchedIds)
"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
}

View File

@@ -18,6 +18,7 @@ package transformers
import ( import (
"reflect" "reflect"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
@@ -26,7 +27,7 @@ import (
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
) )
func TestNameReferenceRun(t *testing.T) { func TestNameReferenceHappyRun(t *testing.T) {
rf := resource.NewFactory( rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()) kunstruct.NewKunstructuredFactoryImpl())
m := resmap.ResMap{ 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{} 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) nrt, err := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
@@ -377,3 +418,72 @@ func TestNameReferenceRun(t *testing.T) {
t.Fatalf("actual doesn't match expected: %v", err) 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)
}
}
}