From af057a95c5ced1d39899295d680b6c4a4b0da4a6 Mon Sep 17 00:00:00 2001 From: Donny Xia Date: Wed, 22 Jul 2020 14:46:14 -0700 Subject: [PATCH] Refactor refvartransformer with kyaml --- api/filters/refvar/doc.go | 3 + api/filters/refvar/refvar.go | 104 +++++++ api/filters/refvar/refvar_test.go | 286 ++++++++++++++++++ api/go.sum | 5 + api/internal/accumulator/refvartransformer.go | 70 +---- .../accumulator/refvartransformer_test.go | 35 ++- api/testutils/filtertest/runfilter.go | 22 +- kustomize/go.mod | 5 +- 8 files changed, 457 insertions(+), 73 deletions(-) create mode 100644 api/filters/refvar/doc.go create mode 100644 api/filters/refvar/refvar.go create mode 100644 api/filters/refvar/refvar_test.go diff --git a/api/filters/refvar/doc.go b/api/filters/refvar/doc.go new file mode 100644 index 000000000..b4330f3e9 --- /dev/null +++ b/api/filters/refvar/doc.go @@ -0,0 +1,3 @@ +// Package refvar contains a kio.Filter implementation of the kustomize +// refvar transformer. +package refvar diff --git a/api/filters/refvar/refvar.go b/api/filters/refvar/refvar.go new file mode 100644 index 000000000..560fe77e0 --- /dev/null +++ b/api/filters/refvar/refvar.go @@ -0,0 +1,104 @@ +package refvar + +import ( + "fmt" + "strconv" + + "sigs.k8s.io/kustomize/api/filters/fieldspec" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" + + expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion" +) + +// Filter updates $(VAR) style variables with values. +// The fieldSpecs are the places to look for occurrences of $(VAR). +type Filter struct { + MappingFunc func(string) interface{} `json:"mappingFunc,omitempty" yaml:"mappingFunc,omitempty"` + FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"` +} + +func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes) +} + +func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) { + err := node.PipeE(fieldspec.Filter{ + FieldSpec: f.FieldSpec, + SetValue: f.set, + }) + return node, err +} + +func (f Filter) set(node *yaml.RNode) error { + if yaml.IsMissingOrNull(node) { + return nil + } + switch node.YNode().Kind { + case yaml.ScalarNode: + return f.setScalar(node) + case yaml.MappingNode: + return f.setMap(node) + case yaml.SequenceNode: + return f.setSeq(node) + default: + return fmt.Errorf("invalid type encountered %v", node.YNode().Kind) + } +} + +func updateNodeValue(node *yaml.Node, newValue interface{}) { + switch newValue := newValue.(type) { + case int64: + node.Value = strconv.FormatInt(newValue, 10) + node.Tag = yaml.NodeTagInt + case bool: + node.SetString(strconv.FormatBool(newValue)) + node.Tag = yaml.NodeTagBool + case float64: + node.SetString(strconv.FormatFloat(newValue, 'f', -1, 64)) + node.Tag = yaml.NodeTagFloat + default: + node.SetString(newValue.(string)) + node.Tag = yaml.NodeTagString + } + node.Style = 0 +} + +func (f Filter) setScalar(node *yaml.RNode) error { + if node.YNode().Kind != yaml.ScalarNode || node.YNode().Tag != yaml.StringTag { + // Only process string values + return nil + } + v := expansion2.Expand(node.YNode().Value, f.MappingFunc) + updateNodeValue(node.YNode(), v) + return nil +} + +func (f Filter) setMap(node *yaml.RNode) error { + contents := node.YNode().Content + for i := 0; i < len(contents); i += 2 { + if contents[i].Kind != yaml.ScalarNode || contents[i].Tag != yaml.StringTag { + return fmt.Errorf("invalid map key: %s, type: %s", contents[i].Value, contents[i].Tag) + } + if contents[i+1].Kind != yaml.ScalarNode || contents[i+1].Tag != yaml.StringTag { + // value is not a string + continue + } + newValue := expansion2.Expand(contents[i+1].Value, f.MappingFunc) + updateNodeValue(contents[i+1], newValue) + } + return nil +} + +func (f Filter) setSeq(node *yaml.RNode) error { + for _, item := range node.YNode().Content { + if item.Kind != yaml.ScalarNode || item.Tag != yaml.StringTag { + // value is not a string + return fmt.Errorf("invalid value type expect a string") + } + newValue := expansion2.Expand(item.Value, f.MappingFunc) + updateNodeValue(item, newValue) + } + return nil +} diff --git a/api/filters/refvar/refvar_test.go b/api/filters/refvar/refvar_test.go new file mode 100644 index 000000000..10fedff0e --- /dev/null +++ b/api/filters/refvar/refvar_test.go @@ -0,0 +1,286 @@ +package refvar + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion" + filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" + "sigs.k8s.io/kustomize/api/types" +) + +func TestFilter(t *testing.T) { + replacementCounts := make(map[string]int) + + testCases := map[string]struct { + input string + expected string + filter Filter + }{ + "simple scalar": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: $(VAR)`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: 5`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "VAR": int64(5), + }), + FieldSpec: types.FieldSpec{Path: "spec/replicas"}, + }, + }, + "non-string scalar": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: 1`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: 1`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "VAR": int64(5), + }), + FieldSpec: types.FieldSpec{Path: "spec/replicas"}, + }, + }, + "wrong path": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: 1`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +spec: + replicas: 1`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "VAR": int64(5), + }), + FieldSpec: types.FieldSpec{Path: "a/b/c"}, + }, + }, + "sequence": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: +- $(FOO) +- $(BAR) +- $(BAZ) +- $(FOO)+$(BAR) +- $(BOOL) +- $(FLOAT)`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: +- foo +- bar +- $(BAZ) +- foo+bar +- false +- 1.23`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "FOO": "foo", + "BAR": "bar", + "BOOL": false, + "FLOAT": 1.23, + }), + FieldSpec: types.FieldSpec{Path: "data"}, + }, + }, + "maps": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + FOO: $(FOO) + BAR: $(BAR) + BAZ: $(BAZ) + PLUS: $(FOO)+$(BAR)`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + FOO: foo + BAR: bar + BAZ: $(BAZ) + PLUS: foo+bar`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "FOO": "foo", + "BAR": "bar", + }), + FieldSpec: types.FieldSpec{Path: "data"}, + }, + }, + "complicated case": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + slice1: + - $(FOO) + slice2: + FOO: $(FOO) + BAR: $(BAR) + BOOL: false + INT: 0 + SLICE: + - $(FOO)`, + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + slice1: + - $(FOO) + slice2: + FOO: foo + BAR: bar + BOOL: false + INT: 0 + SLICE: + - $(FOO)`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "FOO": "foo", + "BAR": "bar", + }), + FieldSpec: types.FieldSpec{Path: "data/slice2"}, + }, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + if !assert.Equal(t, + strings.TrimSpace(tc.expected), + strings.TrimSpace( + filtertest_test.RunFilter(t, tc.input, tc.filter))) { + t.FailNow() + } + }) + } +} + +func TestFilterUnhappy(t *testing.T) { + replacementCounts := make(map[string]int) + + testCases := map[string]struct { + input string + expectedError string + filter Filter + }{ + "non-string in sequence": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + slice: + - false`, + expectedError: `obj 'apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep + annotations: + config.kubernetes.io/index: '0' +data: + slice: + - false +' at path 'data/slice': invalid value type expect a string`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "VAR": int64(5), + }), + FieldSpec: types.FieldSpec{Path: "data/slice"}, + }, + }, + "invalid key in map": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + 1: str`, + expectedError: `obj 'apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep + annotations: + config.kubernetes.io/index: '0' +data: + 1: str +' at path 'data': invalid map key: 1, type: !!int`, + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{ + "VAR": int64(5), + }), + FieldSpec: types.FieldSpec{Path: "data"}, + }, + }, + "null input": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dep +data: + FOO: null`, + expectedError: "obj '' at path 'data/FOO': invalid type encountered 0", + filter: Filter{ + MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}), + FieldSpec: types.FieldSpec{Path: "data/FOO"}, + }, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + _, err := filtertest_test.RunFilterE(t, tc.input, tc.filter) + if !assert.EqualError(t, err, tc.expectedError) { + t.FailNow() + } + }) + } +} diff --git a/api/go.sum b/api/go.sum index 42307ebb7..3fb81672a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -239,6 +239,7 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -438,6 +439,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -469,6 +471,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -499,6 +502,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -573,6 +577,7 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= diff --git a/api/internal/accumulator/refvartransformer.go b/api/internal/accumulator/refvartransformer.go index bda417046..ae3667a70 100644 --- a/api/internal/accumulator/refvartransformer.go +++ b/api/internal/accumulator/refvartransformer.go @@ -4,13 +4,12 @@ package accumulator import ( - "fmt" - expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion" + "sigs.k8s.io/kustomize/api/filters/refvar" "sigs.k8s.io/kustomize/api/resmap" - "sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filtersutil" ) type refVarTransformer struct { @@ -31,59 +30,6 @@ func newRefVarTransformer( } } -// replaceVars accepts as 'in' a string, or string array, which can have -// embedded instances of $VAR style variables, e.g. a container command string. -// The function returns the string with the variables expanded to their final -// values. -func (rv *refVarTransformer) replaceVars(in interface{}) (interface{}, error) { - switch vt := in.(type) { - case []interface{}: - var xs []interface{} - for _, a := range in.([]interface{}) { - x, ok := a.(string) - if !ok { - return nil, fmt.Errorf("expected array of strings, found %v", in) - } - xs = append(xs, expansion2.Expand(x, rv.mappingFunc)) - } - return xs, nil - case map[string]interface{}: - inMap := in.(map[string]interface{}) - xs := make(map[string]interface{}, len(inMap)) - for k, v := range inMap { - s, ok := v.(string) - if !ok { - // This field can not contain a $(VAR) since it is not - // of string type. For instance .spec.replicas: 3 in - // a Deployment object - xs[k] = v - } else { - // This field can potentially contains a $(VAR) since it is - // of string type. For instance .spec.replicas: $(REPLICAS) - // in a Deployment object - xs[k] = expansion2.Expand(s, rv.mappingFunc) - } - } - return xs, nil - case interface{}: - s, ok := in.(string) - if !ok { - // This field can not contain a $(VAR) since it is not of string type. - return in, nil - } - // This field can potentially contain a $(VAR) since it is - // of string type. - return expansion2.Expand(s, rv.mappingFunc), nil - // staticcheck erroneously claims that `case nil` - // is unreachable here, so suppressing it. - //nolint:staticcheck - case nil: - return nil, nil - default: - return "", fmt.Errorf("invalid type encountered %T", vt) - } -} - // UnusedVars returns slice of Var names that were unused // after a Transform run. func (rv *refVarTransformer) UnusedVars() []string { @@ -104,12 +50,12 @@ func (rv *refVarTransformer) Transform(m resmap.ResMap) error { rv.replacementCounts, rv.varMap) for _, res := range m.Resources() { for _, fieldSpec := range rv.fieldSpecs { - if res.OrgId().IsSelected(&fieldSpec.Gvk) { - if err := transform.MutateField( - res.Map(), fieldSpec.PathSlice(), - false, rv.replaceVars); err != nil { - return err - } + err := filtersutil.ApplyToJSON(refvar.Filter{ + MappingFunc: rv.mappingFunc, + FieldSpec: fieldSpec, + }, res) + if err != nil { + return err } } } diff --git a/api/internal/accumulator/refvartransformer_test.go b/api/internal/accumulator/refvartransformer_test.go index ac899f9f3..afd1eed1d 100644 --- a/api/internal/accumulator/refvartransformer_test.go +++ b/api/internal/accumulator/refvartransformer_test.go @@ -44,7 +44,6 @@ func TestRefVarTransformer(t *testing.T) { {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/map"}, {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"}, {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"}, - {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"}, {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"}, }, res: resmaptest_test.NewRmBuilder( @@ -63,7 +62,7 @@ func TestRefVarTransformer(t *testing.T) { "item4": "$(BAZ)+$(BAZ)", "item5": "$(BOO)", "item6": "if $(BOO)", - "item7": 2019, + "item7": int64(2019), }, "slice": []interface{}{ "$(FOO)", @@ -74,8 +73,7 @@ func TestRefVarTransformer(t *testing.T) { "if $(BOO)", }, "interface": "$(FOO)", - "nil": nil, - "num": 2019, + "num": int64(2019), }}).ResMap(), }, expected: expected{ @@ -95,7 +93,7 @@ func TestRefVarTransformer(t *testing.T) { "item4": "5+5", "item5": true, "item6": "if true", - "item7": 2019, + "item7": int64(2019), }, "slice": []interface{}{ "replacementForFoo", @@ -106,8 +104,7 @@ func TestRefVarTransformer(t *testing.T) { "if true", }, "interface": "replacementForFoo", - "nil": nil, - "num": 2019, + "num": int64(2019), }}).ResMap(), unused: []string{"BAR"}, }, @@ -131,7 +128,29 @@ func TestRefVarTransformer(t *testing.T) { "slice": []interface{}{5}, // noticeably *not* a []string }}).ResMap(), }, - errMessage: "expected array of strings, found [5]", + errMessage: `obj '{"apiVersion": "v1", "data": {"slice": [5]}, "kind": "ConfigMap", "metadata": {"name": "cm1"}} +' at path 'data/slice': invalid value type expect a string`, + }, + { + description: "var replacement panic in nil", + given: given{ + varMap: map[string]interface{}{}, + fs: []types.FieldSpec{ + {Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"}, + }, + res: resmaptest_test.NewRmBuilder( + t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())). + Add(map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "cm1", + }, + "data": map[string]interface{}{ + "nil": nil, // noticeably *not* a []string + }}).ResMap(), + }, + errMessage: `obj '' at path 'data/nil': invalid type encountered 0`, }, } diff --git a/api/testutils/filtertest/runfilter.go b/api/testutils/filtertest/runfilter.go index aea5901fb..2cf775311 100644 --- a/api/testutils/filtertest/runfilter.go +++ b/api/testutils/filtertest/runfilter.go @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/kustomize/kyaml/kio" ) -func RunFilter(t *testing.T, input string, f kio.Filter) string { +func run(input string, f kio.Filter) (string, error) { var out bytes.Buffer rw := kio.ByteReadWriter{ Reader: bytes.NewBufferString(input), @@ -23,8 +23,26 @@ func RunFilter(t *testing.T, input string, f kio.Filter) string { Filters: []kio.Filter{f}, Outputs: []kio.Writer{&rw}, }.Execute() + if err != nil { + return "", err + } + return out.String(), nil +} + +// RunFilter runs filter and panic if there is error +func RunFilter(t *testing.T, input string, f kio.Filter) string { + output, err := run(input, f) if !assert.NoError(t, err) { t.FailNow() } - return out.String() + return output +} + +// RunFilterE runs filter and return error if there is +func RunFilterE(t *testing.T, input string, f kio.Filter) (string, error) { + output, err := run(input, f) + if err != nil { + return "", err + } + return output, nil } diff --git a/kustomize/go.mod b/kustomize/go.mod index b1e2d19a2..61174f699 100644 --- a/kustomize/go.mod +++ b/kustomize/go.mod @@ -12,7 +12,10 @@ require ( sigs.k8s.io/yaml v1.2.0 ) -replace sigs.k8s.io/kustomize/api v0.5.1 => ../api +replace ( + sigs.k8s.io/kustomize/api v0.5.1 => ../api + sigs.k8s.io/kustomize/kyaml v0.4.1 => ../kyaml +) exclude ( github.com/russross/blackfriday v2.0.0+incompatible