Switch prefix transformer to kyaml.

This commit is contained in:
jregan
2020-07-17 14:48:36 -07:00
parent ac1c31c82b
commit 71b7b00bd8
22 changed files with 622 additions and 473 deletions

View File

@@ -5,31 +5,27 @@ package builtins
import ( import (
"errors" "errors"
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
// Add the given prefix and suffix to the field. // Add the given prefix and suffix to the field.
type PrefixSuffixTransformerPlugin struct { type PrefixSuffixTransformerPlugin struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"` Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
} }
// Not placed in a file yet due to lack of demand. // A Gvk skip list for prefix/suffix modification.
var prefixSuffixFieldSpecsToSkip = []types.FieldSpec{ // hard coded for now - eventually should be part of config.
{ var prefixSuffixFieldSpecsToSkip = types.FsSlice{
Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}, {Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}},
}, {Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}},
{
Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"},
},
} }
func (p *PrefixSuffixTransformerPlugin) Config( func (p *PrefixSuffixTransformerPlugin) Config(
@@ -48,29 +44,24 @@ func (p *PrefixSuffixTransformerPlugin) Config(
} }
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error { func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
// Even if both the Prefix and Suffix are empty we want // Even if both the Prefix and Suffix are empty we want
// to proceed with the transformation. This allows to add contextual // to proceed with the transformation. This allows to add contextual
// information to the resources (AddNamePrefix and AddNameSuffix). // information to the resources (AddNamePrefix and AddNameSuffix).
for _, r := range m.Resources() { for _, r := range m.Resources() {
// TODO: move this test into the filter (i.e. make a better filter)
if p.shouldSkip(r.OrgId()) { if p.shouldSkip(r.OrgId()) {
// Don't change the actual definition
// of a CRD.
continue continue
} }
id := r.OrgId() id := r.OrgId()
// current default configuration contains // current default configuration contains
// only one entry: "metadata/name" with no GVK // only one entry: "metadata/name" with no GVK
for _, path := range p.FieldSpecs { for _, fs := range p.FieldSpecs {
if !id.IsSelected(&path.Gvk) { // TODO: this is redundant to filter (but needed for now)
// With the currrent default configuration, if !id.IsSelected(&fs.Gvk) {
// because no Gvk is specified, so a wild
// card
continue continue
} }
// TODO: move this test into the filter.
if smellsLikeANameChange(&path) { if smellsLikeANameChange(&fs) {
// "metadata/name" is the only field. // "metadata/name" is the only field.
// this will add a prefix and a suffix // this will add a prefix and a suffix
// to the resource even if those are // to the resource even if those are
@@ -78,15 +69,11 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
r.AddNamePrefix(p.Prefix) r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix) r.AddNameSuffix(p.Suffix)
} }
err := filtersutil.ApplyToJSON(prefixsuffix.Filter{
// the addPrefixSuffix method will not Prefix: p.Prefix,
// change the name if both the prefix and suffix Suffix: p.Suffix,
// are empty. FieldSpec: fs,
err := transform.MutateField( }, r)
r.Map(),
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil { if err != nil {
return err return err
} }
@@ -99,8 +86,7 @@ func smellsLikeANameChange(fs *types.FieldSpec) bool {
return fs.Path == "metadata/name" return fs.Path == "metadata/name"
} }
func (p *PrefixSuffixTransformerPlugin) shouldSkip( func (p *PrefixSuffixTransformerPlugin) shouldSkip(id resid.ResId) bool {
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip { for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) { if id.IsSelected(&path.Gvk) {
return true return true
@@ -109,15 +95,6 @@ func (p *PrefixSuffixTransformerPlugin) shouldSkip(
return false return false
} }
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)
if !ok {
return nil, fmt.Errorf("%#v is expected to be %T", in, s)
}
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
}
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin { func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
return &PrefixSuffixTransformerPlugin{} return &PrefixSuffixTransformerPlugin{}
} }

View File

@@ -30,7 +30,7 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for _, k := range keys { for _, k := range keys {
if err := node.PipeE(fsslice.Filter{ if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice, FsSlice: f.FsSlice,
SetValue: fsslice.SetEntry(k, f.Annotations[k], yaml.StringTag), SetValue: filtersutil.SetEntry(k, f.Annotations[k], yaml.StringTag),
CreateKind: yaml.MappingNode, // Annotations are MappingNodes. CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
CreateTag: "!!map", CreateTag: "!!map",
}); err != nil { }); err != nil {

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package fieldspec contains a yaml.Filter to modify a resource
// that matches the FieldSpec.
package fieldspec

View File

@@ -0,0 +1,61 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fieldspec_test
import (
"bytes"
"log"
"os"
. "sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func ExampleFilter() {
in := &kio.ByteReader{
Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`),
}
fltr := Filter{
CreateKind: yaml.ScalarNode,
SetValue: filtersutil.SetScalar("green"),
FieldSpec: types.FieldSpec{Path: "a/b", CreateIfNotPresent: true},
}
err := kio.Pipeline{
Inputs: []kio.Reader{in},
Filters: []kio.Filter{kio.FilterAll(fltr)},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// a:
// b: green
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// a:
// b: green
}

View File

@@ -1,24 +1,27 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package fsslice package fieldspec
import ( import (
"strings" "strings"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
// fieldSpecFilter applies a single fieldSpec to a single object var _ yaml.Filter = Filter{}
// fieldSpecFilter stores internal state and should not be reused
type fieldSpecFilter struct { // Filter applies a single fieldSpec to a single object
// Filter stores internal state and should not be reused
type Filter struct {
// FieldSpec contains the path to the value to set. // FieldSpec contains the path to the value to set.
FieldSpec types.FieldSpec `yaml:"fieldSpec"` FieldSpec types.FieldSpec `yaml:"fieldSpec"`
// Set the field using this function // Set the field using this function
SetValue SetFn SetValue filtersutil.SetFn
// CreateKind defines the type of node to create if the field is not found // CreateKind defines the type of node to create if the field is not found
CreateKind yaml.Kind CreateKind yaml.Kind
@@ -29,7 +32,7 @@ type fieldSpecFilter struct {
path []string path []string
} }
func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) { func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
// check if the FieldSpec applies to the object // check if the FieldSpec applies to the object
if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil { if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil {
return obj, errors.Wrap(err) return obj, errors.Wrap(err)
@@ -43,7 +46,7 @@ func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
return obj, nil return obj, nil
} }
func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error { func (fltr Filter) filter(obj *yaml.RNode) error {
if len(fltr.path) == 0 { if len(fltr.path) == 0 {
// found the field -- set its value // found the field -- set its value
return fltr.SetValue(obj) return fltr.SetValue(obj)
@@ -60,7 +63,7 @@ func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error {
} }
// field calls filter on the field matching the next path element // field calls filter on the field matching the next path element
func (fltr fieldSpecFilter) field(obj *yaml.RNode) error { func (fltr Filter) field(obj *yaml.RNode) error {
fieldName, isSeq := isSequenceField(fltr.path[0]) fieldName, isSeq := isSequenceField(fltr.path[0])
// lookup the field matching the next path element // lookup the field matching the next path element
@@ -104,9 +107,9 @@ func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
} }
// seq calls filter on all sequence elements // seq calls filter on all sequence elements
func (fltr fieldSpecFilter) seq(obj *yaml.RNode) error { func (fltr Filter) seq(obj *yaml.RNode) error {
if err := obj.VisitElements(func(node *yaml.RNode) error { if err := obj.VisitElements(func(node *yaml.RNode) error {
// recurse on each element -- re-allocating a fieldSpecFilter is // recurse on each element -- re-allocating a Filter is
// not strictly required, but is more consistent with field // not strictly required, but is more consistent with field
// and less likely to have side effects // and less likely to have side effects
// keep the entire path -- it does not contain parts for sequences // keep the entire path -- it does not contain parts for sequences

View File

@@ -0,0 +1,380 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fieldspec_test
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type TestCase struct {
name string
input string
expected string
filter fieldspec.Filter
fieldSpec string
error string
}
var tests = []TestCase{
{
name: "update",
fieldSpec: `
path: a/b
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-kind-not-match",
fieldSpec: `
path: a/b
group: foo
kind: Bar1
`,
input: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-group-not-match",
fieldSpec: `
path: a/b
group: foo1
kind: Bar
`,
input: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-version-not-match",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "bad-version",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "bad-meta",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
error: "missing Resource metadata",
},
{
name: "miss-match-type",
fieldSpec: `
path: a/b/c
kind: Bar
`,
input: `
kind: Bar
a:
b: a
`,
error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node",
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "add",
fieldSpec: `
path: a/b/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {b: {c: {d: e}}}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "update-in-sequence",
fieldSpec: `
path: a/b[]/c/d
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: a
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
// Don't create a sequence
{
name: "empty-sequence-no-create",
fieldSpec: `
path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
// Create a new field for an element in a sequence
{
name: "empty-sequence-create",
fieldSpec: `
path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {d: e}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "group v1",
fieldSpec: `
path: a/b
group: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "version v1",
fieldSpec: `
path: a/b
version: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
a:
b: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
}
func TestFilter_Filter(t *testing.T) {
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(test.fieldSpec), &test.filter.FieldSpec)
if !assert.NoError(t, err) {
t.FailNow()
}
out := &bytes.Buffer{}
rw := &kio.ByteReadWriter{
Reader: bytes.NewBufferString(test.input),
Writer: out,
OmitReaderAnnotations: true,
}
// run the filter
err = kio.Pipeline{
Inputs: []kio.Reader{rw},
Filters: []kio.Filter{kio.FilterAll(test.filter)},
Outputs: []kio.Writer{rw},
}.Execute()
if test.error != "" {
if !assert.EqualError(t, err, test.error) {
t.FailNow()
}
// stop rest of test
return
}
if !assert.NoError(t, err) {
t.FailNow()
}
// check results
if !assert.Equal(t,
strings.TrimSpace(test.expected),
strings.TrimSpace(out.String())) {
t.FailNow()
}
})
}
}

View File

@@ -1,6 +1,6 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package fsslice package fieldspec
import ( import (
"strings" "strings"

View File

@@ -1,6 +1,6 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package fsslice package fieldspec
import ( import (
"strings" "strings"

View File

@@ -0,0 +1,33 @@
package filtersutil
import (
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SetFn is a function that accepts an RNode to possibly modify.
type SetFn func(*yaml.RNode) error
// SetScalar returns a SetFn to set a scalar value
func SetScalar(value string) SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{StringValue: value})
}
}
// SetEntry returns a SetFn to set an entry in a map
func SetEntry(key, value, tag string) SetFn {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Value: value,
Tag: tag,
}
if tag == yaml.StringTag && yaml.IsYaml1_1NonString(n) {
n.Style = yaml.DoubleQuotedStyle
}
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{
Name: key,
Value: yaml.NewRNode(n),
})
}
}

View File

@@ -1,6 +1,6 @@
// Copyright 2020 The Kubernetes Authors. // Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package fsslice contains a yaml.Filter to modify a resource using an // Package fsslice contains a yaml.Filter to modify a resource if
// FsSlice to identify fields to be updated within the resource. // it matches one or more FieldSpec entries.
package fsslice package fsslice

View File

@@ -8,6 +8,7 @@ import (
"log" "log"
"os" "os"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -30,7 +31,7 @@ metadata:
} }
fltr := fsslice.Filter{ fltr := fsslice.Filter{
CreateKind: yaml.ScalarNode, CreateKind: yaml.ScalarNode,
SetValue: fsslice.SetScalar("green"), SetValue: filtersutil.SetScalar("green"),
FsSlice: []types.FieldSpec{ FsSlice: []types.FieldSpec{
{Path: "a/b", CreateIfNotPresent: true}, {Path: "a/b", CreateIfNotPresent: true},
}, },

View File

@@ -4,48 +4,22 @@
package fsslice package fsslice
import ( import (
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
// SetFn sets a value
type SetFn func(*yaml.RNode) error
// SetScalar returns a SetFn to set a scalar value
func SetScalar(value string) SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{StringValue: value})
}
}
// SetEntry returns a SetFn to set an entry in a map
func SetEntry(key, value, tag string) SetFn {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Value: value,
Tag: tag,
}
if tag == yaml.StringTag && yaml.IsYaml1_1NonString(n) {
n.Style = yaml.DoubleQuotedStyle
}
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{
Name: key,
Value: yaml.NewRNode(n),
})
}
}
var _ yaml.Filter = Filter{} var _ yaml.Filter = Filter{}
// Filter uses an FsSlice to modify fields on a single object // Filter ranges over an FsSlice to modify fields on a single object.
// An FsSlice is a range of FieldSpecs. A FieldSpec is a GVK plus a path.
type Filter struct { type Filter struct {
// FieldSpecList list of FieldSpecs to set // FieldSpecList list of FieldSpecs to set
FsSlice types.FsSlice `yaml:"fsSlice"` FsSlice types.FsSlice `yaml:"fsSlice"`
// SetValue is called on each field that matches one of the FieldSpecs // SetValue is called on each field that matches one of the FieldSpecs
SetValue SetFn SetValue filtersutil.SetFn
// CreateKind is used to create fields that do not exist // CreateKind is used to create fields that do not exist
CreateKind yaml.Kind CreateKind yaml.Kind
@@ -59,7 +33,7 @@ func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
// apply this FieldSpec // apply this FieldSpec
// create a new filter for each iteration because they // create a new filter for each iteration because they
// store internal state about the field paths // store internal state about the field paths
_, err := (&fieldSpecFilter{ _, err := (&fieldspec.Filter{
FieldSpec: fltr.FsSlice[i], FieldSpec: fltr.FsSlice[i],
SetValue: fltr.SetValue, SetValue: fltr.SetValue,
CreateKind: fltr.CreateKind, CreateKind: fltr.CreateKind,

View File

@@ -9,335 +9,77 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/filtersutil"
. "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
type TestCase struct { type TestCase struct {
name string
input string input string
expected string expected string
filter fsslice.Filter filter Filter
fsSlice string fsSlice string
error string error string
} }
var tests = []TestCase{ var tests = map[string]TestCase{
{ "empty": {
name: "update",
fsSlice: ` fsSlice: `
- path: a/b
group: foo
kind: Bar
`, `,
input: ` input: `
apiVersion: foo/v1beta1 apiVersion: foo/v1
kind: Bar kind: Bar
a:
b: c
`, `,
expected: ` expected: `
apiVersion: foo/v1beta1 apiVersion: foo/v1
kind: Bar kind: Bar
a:
b: e
`, `,
filter: fsslice.Filter{ filter: Filter{
SetValue: fsslice.SetScalar("e"), SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-kind-not-match",
fsSlice: `
- path: a/b
group: foo
kind: Bar1
`,
input: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "update-group-not-match",
fsSlice: `
- path: a/b
group: foo1
kind: Bar
`,
input: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "update-version-not-match",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "bad-version",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "bad-meta",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
error: "missing Resource metadata",
},
{
name: "miss-match-type",
fsSlice: `
- path: a/b/c
kind: Bar
`,
input: `
kind: Bar
a:
b: a
`,
error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node",
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "add",
fsSlice: `
- path: a/b/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {b: {c: {d: e}}}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode, CreateKind: yaml.ScalarNode,
}, },
}, },
"two": {
{
name: "update-in-sequence",
fsSlice: `
- path: a/b[]/c/d
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: a
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: e
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
// Don't create a sequence
{
name: "empty-sequence-no-create",
fsSlice: `
- path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
// Create a new field for an element in a sequence
{
name: "empty-sequence-create",
fsSlice: `
- path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {d: e}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "group v1",
fsSlice: ` fsSlice: `
- path: a/b - path: a/b
group: v1 group: foo
version: v1
create: true create: true
kind: Bar kind: Bar
`, - path: q/r[]/s/t
input: ` group: foo
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "version v1",
fsSlice: `
- path: a/b
version: v1 version: v1
create: true create: true
kind: Bar kind: Bar
`, `,
input: ` input: `
apiVersion: v1 apiVersion: foo/v1
kind: Bar kind: Bar
q:
r:
- s: {}
`, `,
expected: ` expected: `
apiVersion: v1 apiVersion: foo/v1
kind: Bar kind: Bar
q:
r:
- s: {t: e}
a: a:
b: e b: e
`, `,
filter: fsslice.Filter{ filter: Filter{
SetValue: fsslice.SetScalar("e"), SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode, CreateKind: yaml.ScalarNode,
}, },
}, },
} }
func TestFilter_Filter(t *testing.T) { func TestFilter(t *testing.T) {
for i := range tests { for name := range tests {
test := tests[i] test := tests[name]
t.Run(test.name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice) err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice)
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()

View File

@@ -4,6 +4,7 @@
package imagetag package imagetag
import ( import (
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -35,7 +36,7 @@ func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
return node, nil return node, nil
} }
func updateImageTagFn(imageTag types.Image) fsslice.SetFn { func updateImageTagFn(imageTag types.Image) filtersutil.SetFn {
return func(node *yaml.RNode) error { return func(node *yaml.RNode) error {
return node.PipeE(imageTagUpdater{ return node.PipeE(imageTagUpdater{
ImageTag: imageTag, ImageTag: imageTag,

View File

@@ -31,7 +31,7 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for _, k := range keys { for _, k := range keys {
if err := node.PipeE(fsslice.Filter{ if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice, FsSlice: f.FsSlice,
SetValue: fsslice.SetEntry(k, f.Labels[k], yaml.StringTag), SetValue: filtersutil.SetEntry(k, f.Labels[k], yaml.StringTag),
CreateKind: yaml.MappingNode, // Labels are MappingNodes. CreateKind: yaml.MappingNode, // Labels are MappingNodes.
CreateTag: "!!map", CreateTag: "!!map",
}); err != nil { }); err != nil {

View File

@@ -4,6 +4,8 @@
package namespace package namespace
import ( import (
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -42,7 +44,7 @@ func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// transformations based on data -- :) // transformations based on data -- :)
err := node.PipeE(fsslice.Filter{ err := node.PipeE(fsslice.Filter{
FsSlice: ns.FsSlice, FsSlice: ns.FsSlice,
SetValue: fsslice.SetScalar(ns.Namespace), SetValue: filtersutil.SetScalar(ns.Namespace),
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
CreateTag: yaml.StringTag, CreateTag: yaml.StringTag,
}) })
@@ -73,7 +75,7 @@ func (ns Filter) hacks(obj *yaml.RNode) error {
// if they are cluster scoped through either an annotation on the resources, // if they are cluster scoped through either an annotation on the resources,
// or through inlined OpenAPI on the resource as a YAML comment. // or through inlined OpenAPI on the resource as a YAML comment.
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error { func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
gvk := fsslice.GetGVK(meta) gvk := fieldspec.GetGVK(meta)
if !gvk.IsNamespaceableKind() { if !gvk.IsNamespaceableKind() {
return nil return nil
} }
@@ -81,7 +83,7 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) erro
FsSlice: []types.FieldSpec{ FsSlice: []types.FieldSpec{
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true}, {Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
}, },
SetValue: fsslice.SetScalar(ns.Namespace), SetValue: filtersutil.SetScalar(ns.Namespace),
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
} }
_, err := f.Filter(obj) _, err := f.Filter(obj)

View File

@@ -9,12 +9,11 @@ import (
"os" "os"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix" "sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
) )
func ExampleFilter() { func ExampleFilter() {
fss := builtinconfig.MakeDefaultConfig().NamePrefix
err := kio.Pipeline{ err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(` Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1 apiVersion: example.com/v1
@@ -27,7 +26,8 @@ kind: Bar
metadata: metadata:
name: instance name: instance
`)}}, `)}},
Filters: []kio.Filter{prefixsuffix.Filter{Prefix: "baz-", FsSlice: fss}}, Filters: []kio.Filter{prefixsuffix.Filter{
Prefix: "baz-", FieldSpec: types.FieldSpec{Path: "metadata/name"}}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute() }.Execute()
if err != nil { if err != nil {

View File

@@ -6,7 +6,8 @@ package prefixsuffix
import ( import (
"fmt" "fmt"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
@@ -17,28 +18,26 @@ type Filter struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"` Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
} }
var _ kio.Filter = Filter{} var _ kio.Filter = Filter{}
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes) return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
} }
// Run runs the filter on a single node rather than a slice func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) { err := node.PipeE(fieldspec.Filter{
// transformations based on data -- :) FieldSpec: f.FieldSpec,
err := node.PipeE(fsslice.Filter{ SetValue: f.evaluateField,
FsSlice: ns.FsSlice,
SetValue: ns.set,
CreateKind: yaml.ScalarNode, // Name is a ScalarNode CreateKind: yaml.ScalarNode, // Name is a ScalarNode
CreateTag: yaml.StringTag, CreateTag: yaml.StringTag,
}) })
return node, err return node, err
} }
func (ns Filter) set(node *yaml.RNode) error { func (f Filter) evaluateField(node *yaml.RNode) error {
return fsslice.SetScalar(fmt.Sprintf( return filtersutil.SetScalar(fmt.Sprintf(
"%s%s%s", ns.Prefix, node.YNode().Value, ns.Suffix))(node) "%s%s%s", f.Prefix, node.YNode().Value, f.Suffix))(node)
} }

View File

@@ -9,14 +9,12 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix" "sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
) )
var tests = []TestCase{ var tests = map[string]TestCase{
{ "prefix": {
name: "prefix",
input: ` input: `
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Foo kind: Foo
@@ -40,10 +38,10 @@ metadata:
name: foo-instance name: foo-instance
`, `,
filter: prefixsuffix.Filter{Prefix: "foo-"}, filter: prefixsuffix.Filter{Prefix: "foo-"},
fs: types.FieldSpec{Path: "metadata/name"},
}, },
{ "suffix": {
name: "suffix",
input: ` input: `
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Foo kind: Foo
@@ -67,10 +65,10 @@ metadata:
name: instance-foo name: instance-foo
`, `,
filter: prefixsuffix.Filter{Suffix: "-foo"}, filter: prefixsuffix.Filter{Suffix: "-foo"},
fs: types.FieldSpec{Path: "metadata/name"},
}, },
{ "prefix-suffix": {
name: "prefix-suffix",
input: ` input: `
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Foo kind: Foo
@@ -94,10 +92,10 @@ metadata:
name: bar-instance-foo name: bar-instance-foo
`, `,
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"}, filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
fs: types.FieldSpec{Path: "metadata/name"},
}, },
{ "data-fieldspecs": {
name: "data-fieldspecs",
input: ` input: `
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Foo kind: Foo
@@ -119,7 +117,7 @@ a:
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Foo kind: Foo
metadata: metadata:
name: foo-instance name: instance
a: a:
b: b:
c: foo-d c: foo-d
@@ -127,35 +125,28 @@ a:
apiVersion: example.com/v1 apiVersion: example.com/v1
kind: Bar kind: Bar
metadata: metadata:
name: foo-instance name: instance
a: a:
b: b:
c: foo-d c: foo-d
`, `,
filter: prefixsuffix.Filter{Prefix: "foo-"}, filter: prefixsuffix.Filter{Prefix: "foo-"},
fsslice: []types.FieldSpec{ fs: types.FieldSpec{Path: "a/b/c"},
{
Path: "a/b/c",
},
},
}, },
} }
type TestCase struct { type TestCase struct {
name string
input string input string
expected string expected string
filter prefixsuffix.Filter filter prefixsuffix.Filter
fsslice types.FsSlice fs types.FieldSpec
} }
var config = builtinconfig.MakeDefaultConfig()
func TestFilter(t *testing.T) { func TestFilter(t *testing.T) {
for i := range tests { for name := range tests {
test := tests[i] test := tests[name]
t.Run(test.name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
test.filter.FsSlice = append(config.NamePrefix, test.fsslice...) test.filter.FieldSpec = test.fs
if !assert.Equal(t, if !assert.Equal(t,
strings.TrimSpace(test.expected), strings.TrimSpace(test.expected),
strings.TrimSpace( strings.TrimSpace(

View File

@@ -3,6 +3,7 @@ package replicacount
import ( import (
"strconv" "strconv"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
@@ -45,5 +46,5 @@ func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
} }
func (rc Filter) set(node *yaml.RNode) error { func (rc Filter) set(node *yaml.RNode) error {
return fsslice.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node) return filtersutil.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
} }

View File

@@ -6,34 +6,30 @@ package main
import ( import (
"errors" "errors"
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
// Add the given prefix and suffix to the field. // Add the given prefix and suffix to the field.
type plugin struct { type plugin struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"` Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"` Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
} }
//noinspection GoUnusedGlobalVariable //noinspection GoUnusedGlobalVariable
var KustomizePlugin plugin var KustomizePlugin plugin
// Not placed in a file yet due to lack of demand. // A Gvk skip list for prefix/suffix modification.
var prefixSuffixFieldSpecsToSkip = []types.FieldSpec{ // hard coded for now - eventually should be part of config.
{ var prefixSuffixFieldSpecsToSkip = types.FsSlice{
Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}, {Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}},
}, {Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}},
{
Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"},
},
} }
func (p *plugin) Config( func (p *plugin) Config(
@@ -52,29 +48,24 @@ func (p *plugin) Config(
} }
func (p *plugin) Transform(m resmap.ResMap) error { func (p *plugin) Transform(m resmap.ResMap) error {
// Even if both the Prefix and Suffix are empty we want // Even if both the Prefix and Suffix are empty we want
// to proceed with the transformation. This allows to add contextual // to proceed with the transformation. This allows to add contextual
// information to the resources (AddNamePrefix and AddNameSuffix). // information to the resources (AddNamePrefix and AddNameSuffix).
for _, r := range m.Resources() { for _, r := range m.Resources() {
// TODO: move this test into the filter (i.e. make a better filter)
if p.shouldSkip(r.OrgId()) { if p.shouldSkip(r.OrgId()) {
// Don't change the actual definition
// of a CRD.
continue continue
} }
id := r.OrgId() id := r.OrgId()
// current default configuration contains // current default configuration contains
// only one entry: "metadata/name" with no GVK // only one entry: "metadata/name" with no GVK
for _, path := range p.FieldSpecs { for _, fs := range p.FieldSpecs {
if !id.IsSelected(&path.Gvk) { // TODO: this is redundant to filter (but needed for now)
// With the currrent default configuration, if !id.IsSelected(&fs.Gvk) {
// because no Gvk is specified, so a wild
// card
continue continue
} }
// TODO: move this test into the filter.
if smellsLikeANameChange(&path) { if smellsLikeANameChange(&fs) {
// "metadata/name" is the only field. // "metadata/name" is the only field.
// this will add a prefix and a suffix // this will add a prefix and a suffix
// to the resource even if those are // to the resource even if those are
@@ -82,15 +73,11 @@ func (p *plugin) Transform(m resmap.ResMap) error {
r.AddNamePrefix(p.Prefix) r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix) r.AddNameSuffix(p.Suffix)
} }
err := filtersutil.ApplyToJSON(prefixsuffix.Filter{
// the addPrefixSuffix method will not Prefix: p.Prefix,
// change the name if both the prefix and suffix Suffix: p.Suffix,
// are empty. FieldSpec: fs,
err := transform.MutateField( }, r)
r.Map(),
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil { if err != nil {
return err return err
} }
@@ -103,8 +90,7 @@ func smellsLikeANameChange(fs *types.FieldSpec) bool {
return fs.Path == "metadata/name" return fs.Path == "metadata/name"
} }
func (p *plugin) shouldSkip( func (p *plugin) shouldSkip(id resid.ResId) bool {
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip { for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) { if id.IsSelected(&path.Gvk) {
return true return true
@@ -112,12 +98,3 @@ func (p *plugin) shouldSkip(
} }
return false return false
} }
func (p *plugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)
if !ok {
return nil, fmt.Errorf("%#v is expected to be %T", in, s)
}
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
}

View File

@@ -4,6 +4,7 @@ go 1.14
require ( require (
sigs.k8s.io/kustomize/api v0.5.1 sigs.k8s.io/kustomize/api v0.5.1
sigs.k8s.io/kustomize/kyaml v0.4.1
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )