mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 02:20:53 +00:00
Merge pull request #4431 from sdowell/implement-trackable-filters
Implement trackable filters
This commit is contained in:
@@ -16,32 +16,15 @@ import (
|
|||||||
|
|
||||||
var annosFs = builtinconfig.MakeDefaultConfig().CommonAnnotations
|
var annosFs = builtinconfig.MakeDefaultConfig().CommonAnnotations
|
||||||
|
|
||||||
type setEntryArg struct {
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
Tag string
|
|
||||||
NodePath []string
|
|
||||||
}
|
|
||||||
|
|
||||||
var setEntryArgs []setEntryArg
|
|
||||||
|
|
||||||
func setEntryCallbackStub(key, value, tag string, node *yaml.RNode) {
|
|
||||||
setEntryArgs = append(setEntryArgs, setEntryArg{
|
|
||||||
Key: key,
|
|
||||||
Value: value,
|
|
||||||
Tag: tag,
|
|
||||||
NodePath: node.FieldPath(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAnnotations_Filter(t *testing.T) {
|
func TestAnnotations_Filter(t *testing.T) {
|
||||||
|
mutationTrackStub := filtertest_test.MutationTrackerStub{}
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
filter Filter
|
filter Filter
|
||||||
fsslice types.FsSlice
|
fsslice types.FsSlice
|
||||||
setEntryCallback func(key, value, tag string, node *yaml.RNode)
|
setEntryCallback func(key, value, tag string, node *yaml.RNode)
|
||||||
expectedSetEntryArgs []setEntryArg
|
expectedSetEntryArgs []filtertest_test.SetValueArg
|
||||||
}{
|
}{
|
||||||
"add": {
|
"add": {
|
||||||
input: `
|
input: `
|
||||||
@@ -261,14 +244,14 @@ spec:
|
|||||||
"b": "b1",
|
"b": "b1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setEntryCallback: setEntryCallbackStub,
|
setEntryCallback: mutationTrackStub.MutationTracker,
|
||||||
fsslice: []types.FieldSpec{
|
fsslice: []types.FieldSpec{
|
||||||
{
|
{
|
||||||
Path: "spec/template/metadata/annotations",
|
Path: "spec/template/metadata/annotations",
|
||||||
CreateIfNotPresent: true,
|
CreateIfNotPresent: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedSetEntryArgs: []setEntryArg{
|
expectedSetEntryArgs: []filtertest_test.SetValueArg{
|
||||||
{
|
{
|
||||||
Key: "a",
|
Key: "a",
|
||||||
Value: "a1",
|
Value: "a1",
|
||||||
@@ -298,7 +281,7 @@ spec:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
setEntryArgs = nil
|
mutationTrackStub.Reset()
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
filter := tc.filter
|
filter := tc.filter
|
||||||
filter.WithMutationTracker(tc.setEntryCallback)
|
filter.WithMutationTracker(tc.setEntryCallback)
|
||||||
@@ -308,7 +291,7 @@ spec:
|
|||||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !assert.Equal(t, tc.expectedSetEntryArgs, setEntryArgs) {
|
if !assert.Equal(t, tc.expectedSetEntryArgs, mutationTrackStub.SetValueArgs()) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,32 +13,15 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type setValueArg struct {
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
Tag string
|
|
||||||
PrevValue string
|
|
||||||
}
|
|
||||||
|
|
||||||
var setValueArgs []setValueArg
|
|
||||||
|
|
||||||
func setValueCallbackStub(key, value, tag string, node *yaml.RNode) {
|
|
||||||
setValueArgs = append(setValueArgs, setValueArg{
|
|
||||||
Key: key,
|
|
||||||
Value: value,
|
|
||||||
Tag: tag,
|
|
||||||
PrevValue: node.YNode().Value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImageTagUpdater_Filter(t *testing.T) {
|
func TestImageTagUpdater_Filter(t *testing.T) {
|
||||||
|
mutationTrackerStub := filtertest.MutationTrackerStub{}
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
filter Filter
|
filter Filter
|
||||||
fsSlice types.FsSlice
|
fsSlice types.FsSlice
|
||||||
setValueCallback func(key, value, tag string, node *yaml.RNode)
|
setValueCallback func(key, value, tag string, node *yaml.RNode)
|
||||||
expectedSetValueArgs []setValueArg
|
expectedSetValueArgs []filtertest.SetValueArg
|
||||||
}{
|
}{
|
||||||
"ignore CustomResourceDefinition": {
|
"ignore CustomResourceDefinition": {
|
||||||
input: `
|
input: `
|
||||||
@@ -747,30 +730,30 @@ spec:
|
|||||||
Path: "spec/template/spec/initContainers[]/image",
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setValueCallback: setValueCallbackStub,
|
setValueCallback: mutationTrackerStub.MutationTracker,
|
||||||
expectedSetValueArgs: []setValueArg{
|
expectedSetValueArgs: []filtertest.SetValueArg{
|
||||||
{
|
{
|
||||||
Value: "busybox:v3",
|
Value: "busybox:v3",
|
||||||
PrevValue: "nginx:1.7.9",
|
NodePath: []string{"spec", "template", "spec", "containers", "image"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: "busybox:v3",
|
Value: "busybox:v3",
|
||||||
PrevValue: "nginx:latest",
|
NodePath: []string{"spec", "template", "spec", "containers", "image"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: "busybox:v3",
|
Value: "busybox:v3",
|
||||||
PrevValue: "nginx",
|
NodePath: []string{"spec", "template", "spec", "initContainers", "image"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: "busybox:v3",
|
Value: "busybox:v3",
|
||||||
PrevValue: "nginx@sha256:111111111111111111",
|
NodePath: []string{"spec", "template", "spec", "initContainers", "image"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
setValueArgs = nil
|
mutationTrackerStub.Reset()
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
filter := tc.filter
|
filter := tc.filter
|
||||||
filter.WithMutationTracker(tc.setValueCallback)
|
filter.WithMutationTracker(tc.setValueCallback)
|
||||||
@@ -780,7 +763,7 @@ spec:
|
|||||||
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
assert.Equal(t, tc.expectedSetValueArgs, setValueArgs)
|
assert.Equal(t, tc.expectedSetValueArgs, mutationTrackerStub.SetValueArgs())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,31 +14,14 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type setEntryArg struct {
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
Tag string
|
|
||||||
NodePath []string
|
|
||||||
}
|
|
||||||
|
|
||||||
var setEntryArgs []setEntryArg
|
|
||||||
|
|
||||||
func setEntryCallbackStub(key, value, tag string, node *yaml.RNode) {
|
|
||||||
setEntryArgs = append(setEntryArgs, setEntryArg{
|
|
||||||
Key: key,
|
|
||||||
Value: value,
|
|
||||||
Tag: tag,
|
|
||||||
NodePath: node.FieldPath(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLabels_Filter(t *testing.T) {
|
func TestLabels_Filter(t *testing.T) {
|
||||||
|
mutationTrackerStub := filtertest_test.MutationTrackerStub{}
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
filter Filter
|
filter Filter
|
||||||
setEntryCallback func(key, value, tag string, node *yaml.RNode)
|
setEntryCallback func(key, value, tag string, node *yaml.RNode)
|
||||||
expectedSetEntryArgs []setEntryArg
|
expectedSetEntryArgs []filtertest_test.SetValueArg
|
||||||
}{
|
}{
|
||||||
"add": {
|
"add": {
|
||||||
input: `
|
input: `
|
||||||
@@ -458,8 +441,8 @@ a:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setEntryCallback: setEntryCallbackStub,
|
setEntryCallback: mutationTrackerStub.MutationTracker,
|
||||||
expectedSetEntryArgs: []setEntryArg{
|
expectedSetEntryArgs: []filtertest_test.SetValueArg{
|
||||||
{
|
{
|
||||||
Key: "mage",
|
Key: "mage",
|
||||||
Value: "yennefer",
|
Value: "yennefer",
|
||||||
@@ -477,7 +460,7 @@ a:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
setEntryArgs = nil
|
mutationTrackerStub.Reset()
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
tc.filter.WithMutationTracker(tc.setEntryCallback)
|
tc.filter.WithMutationTracker(tc.setEntryCallback)
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
@@ -485,7 +468,7 @@ a:
|
|||||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !assert.Equal(t, tc.expectedSetEntryArgs, setEntryArgs) {
|
if !assert.Equal(t, tc.expectedSetEntryArgs, mutationTrackerStub.SetValueArgs()) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -18,9 +18,17 @@ type Filter struct {
|
|||||||
|
|
||||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
|
|
||||||
|
trackableSetter filtersutil.TrackableSetter
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
var _ kio.TrackableFilter = &Filter{}
|
||||||
|
|
||||||
|
// WithMutationTracker registers a callback which will be invoked each time a field is mutated
|
||||||
|
func (ns *Filter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) {
|
||||||
|
ns.trackableSetter.WithMutationTracker(callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
|
||||||
@@ -44,7 +52,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: filtersutil.SetScalar(ns.Namespace),
|
SetValue: ns.trackableSetter.SetScalar(ns.Namespace),
|
||||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||||
CreateTag: yaml.NodeTagString,
|
CreateTag: yaml.NodeTagString,
|
||||||
})
|
})
|
||||||
@@ -77,7 +85,7 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
|||||||
FsSlice: []types.FieldSpec{
|
FsSlice: []types.FieldSpec{
|
||||||
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
|
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
|
||||||
},
|
},
|
||||||
SetValue: filtersutil.SetScalar(ns.Namespace),
|
SetValue: ns.trackableSetter.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)
|
||||||
@@ -123,11 +131,15 @@ func (ns Filter) roleBindingHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set the namespace for the default account
|
// set the namespace for the default account
|
||||||
v := yaml.NewScalarRNode(ns.Namespace)
|
node, err := o.Pipe(
|
||||||
return o.PipeE(
|
|
||||||
yaml.LookupCreate(yaml.ScalarNode, "namespace"),
|
yaml.LookupCreate(yaml.ScalarNode, "namespace"),
|
||||||
yaml.FieldSetter{Value: v},
|
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns.trackableSetter.SetScalar(ns.Namespace)(node)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
"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"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mutationTrackerStub = filtertest_test.MutationTrackerStub{}
|
||||||
|
|
||||||
var tests = []TestCase{
|
var tests = []TestCase{
|
||||||
{
|
{
|
||||||
name: "add",
|
name: "add",
|
||||||
@@ -283,6 +286,72 @@ a:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "mutation tracker",
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
subjects:
|
||||||
|
- name: default
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c: bar
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
subjects:
|
||||||
|
- name: default
|
||||||
|
namespace: bar
|
||||||
|
metadata:
|
||||||
|
namespace: bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c: bar
|
||||||
|
`,
|
||||||
|
filter: namespace.Filter{Namespace: "bar"},
|
||||||
|
fsslice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "a/b/c",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutationTracker: mutationTrackerStub.MutationTracker,
|
||||||
|
expectedSetValueArgs: []filtertest_test.SetValueArg{
|
||||||
|
{
|
||||||
|
Value: "bar",
|
||||||
|
NodePath: []string{"metadata", "namespace"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "bar",
|
||||||
|
NodePath: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "bar",
|
||||||
|
NodePath: []string{"metadata", "namespace"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "bar",
|
||||||
|
NodePath: []string{"namespace"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "bar",
|
||||||
|
NodePath: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
@@ -291,13 +360,17 @@ type TestCase struct {
|
|||||||
expected string
|
expected string
|
||||||
filter namespace.Filter
|
filter namespace.Filter
|
||||||
fsslice types.FsSlice
|
fsslice types.FsSlice
|
||||||
|
mutationTracker func(key, value, tag string, node *yaml.RNode)
|
||||||
|
expectedSetValueArgs []filtertest_test.SetValueArg
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = builtinconfig.MakeDefaultConfig()
|
var config = builtinconfig.MakeDefaultConfig()
|
||||||
|
|
||||||
func TestNamespace_Filter(t *testing.T) {
|
func TestNamespace_Filter(t *testing.T) {
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
|
mutationTrackerStub.Reset()
|
||||||
test := tests[i]
|
test := tests[i]
|
||||||
|
test.filter.WithMutationTracker(test.mutationTracker)
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
test.filter.FsSlice = append(config.NameSpace, test.fsslice...)
|
test.filter.FsSlice = append(config.NameSpace, test.fsslice...)
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
@@ -306,6 +379,7 @@ func TestNamespace_Filter(t *testing.T) {
|
|||||||
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
assert.Equal(t, test.expectedSetValueArgs, mutationTrackerStub.SetValueArgs())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,17 @@ type Filter struct {
|
|||||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||||
|
|
||||||
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
|
|
||||||
|
trackableSetter filtersutil.TrackableSetter
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
var _ kio.TrackableFilter = &Filter{}
|
||||||
|
|
||||||
|
// WithMutationTracker registers a callback which will be invoked each time a field is mutated
|
||||||
|
func (f *Filter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) {
|
||||||
|
f.trackableSetter.WithMutationTracker(callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
||||||
@@ -37,6 +45,6 @@ func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f Filter) evaluateField(node *yaml.RNode) error {
|
func (f Filter) evaluateField(node *yaml.RNode) error {
|
||||||
return filtersutil.SetScalar(fmt.Sprintf(
|
return f.trackableSetter.SetScalar(fmt.Sprintf(
|
||||||
"%s%s", f.Prefix, node.YNode().Value))(node)
|
"%s%s", f.Prefix, node.YNode().Value))(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/filters/prefix"
|
"sigs.k8s.io/kustomize/api/filters/prefix"
|
||||||
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"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mutationTrackerStub = filtertest_test.MutationTrackerStub{}
|
||||||
|
|
||||||
var tests = map[string]TestCase{
|
var tests = map[string]TestCase{
|
||||||
"prefix": {
|
"prefix": {
|
||||||
input: `
|
input: `
|
||||||
@@ -83,17 +86,61 @@ a:
|
|||||||
FieldSpec: types.FieldSpec{Path: "a/b/c"},
|
FieldSpec: types.FieldSpec{Path: "a/b/c"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mutation tracker": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: foo-instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: foo-instance
|
||||||
|
`,
|
||||||
|
filter: prefix.Filter{
|
||||||
|
Prefix: "foo-",
|
||||||
|
FieldSpec: types.FieldSpec{Path: "metadata/name"},
|
||||||
|
},
|
||||||
|
mutationTracker: mutationTrackerStub.MutationTracker,
|
||||||
|
expectedSetValueArgs: []filtertest_test.SetValueArg{
|
||||||
|
{
|
||||||
|
Value: "foo-instance",
|
||||||
|
NodePath: []string{"metadata", "name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "foo-instance",
|
||||||
|
NodePath: []string{"metadata", "name"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter prefix.Filter
|
filter prefix.Filter
|
||||||
|
mutationTracker func(key, value, tag string, node *yaml.RNode)
|
||||||
|
expectedSetValueArgs []filtertest_test.SetValueArg
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
for name := range tests {
|
for name := range tests {
|
||||||
|
mutationTrackerStub.Reset()
|
||||||
test := tests[name]
|
test := tests[name]
|
||||||
|
test.filter.WithMutationTracker(test.mutationTracker)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(test.expected),
|
strings.TrimSpace(test.expected),
|
||||||
@@ -101,6 +148,7 @@ func TestFilter(t *testing.T) {
|
|||||||
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
assert.Equal(t, test.expectedSetValueArgs, mutationTrackerStub.SetValueArgs())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,17 @@ import (
|
|||||||
type Filter struct {
|
type Filter struct {
|
||||||
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||||
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
|
|
||||||
|
trackableSetter filtersutil.TrackableSetter
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
var _ kio.TrackableFilter = &Filter{}
|
||||||
|
|
||||||
|
// WithMutationTracker registers a callback which will be invoked each time a field is mutated
|
||||||
|
func (rc *Filter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) {
|
||||||
|
rc.trackableSetter.WithMutationTracker(callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
|
||||||
@@ -33,5 +41,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 filtersutil.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
|
return rc.trackableSetter.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,17 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
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"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
|
mutationTrackerStub := filtertest_test.MutationTrackerStub{}
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter Filter
|
filter Filter
|
||||||
|
mutationTracker func(key, value, tag string, node *yaml.RNode)
|
||||||
|
expectedSetValueArgs []filtertest_test.SetValueArg
|
||||||
}{
|
}{
|
||||||
"update field": {
|
"update field": {
|
||||||
input: `
|
input: `
|
||||||
@@ -161,9 +164,43 @@ spec:
|
|||||||
FieldSpec: types.FieldSpec{Path: "spec/template/replicas"},
|
FieldSpec: types.FieldSpec{Path: "spec/template/replicas"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"mutation tracker": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 5
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 42
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Replica: types.Replica{
|
||||||
|
Name: "dep",
|
||||||
|
Count: 42,
|
||||||
|
},
|
||||||
|
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
|
||||||
|
},
|
||||||
|
mutationTracker: mutationTrackerStub.MutationTracker,
|
||||||
|
expectedSetValueArgs: []filtertest_test.SetValueArg{
|
||||||
|
{
|
||||||
|
Value: "42",
|
||||||
|
NodePath: []string{"spec", "replicas"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
|
mutationTrackerStub.Reset()
|
||||||
|
tc.filter.WithMutationTracker(tc.mutationTracker)
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(tc.expected),
|
strings.TrimSpace(tc.expected),
|
||||||
@@ -171,6 +208,7 @@ spec:
|
|||||||
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
assert.Equal(t, tc.expectedSetValueArgs, mutationTrackerStub.SetValueArgs())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,17 @@ type Filter struct {
|
|||||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||||
|
|
||||||
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
|
|
||||||
|
trackableSetter filtersutil.TrackableSetter
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
var _ kio.TrackableFilter = &Filter{}
|
||||||
|
|
||||||
|
// WithMutationTracker registers a callback which will be invoked each time a field is mutated
|
||||||
|
func (f *Filter) WithMutationTracker(callback func(key, value, tag string, node *yaml.RNode)) {
|
||||||
|
f.trackableSetter.WithMutationTracker(callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
||||||
@@ -37,6 +45,6 @@ func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f Filter) evaluateField(node *yaml.RNode) error {
|
func (f Filter) evaluateField(node *yaml.RNode) error {
|
||||||
return filtersutil.SetScalar(fmt.Sprintf(
|
return f.trackableSetter.SetScalar(fmt.Sprintf(
|
||||||
"%s%s", node.YNode().Value, f.Suffix))(node)
|
"%s%s", node.YNode().Value, f.Suffix))(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/filters/suffix"
|
"sigs.k8s.io/kustomize/api/filters/suffix"
|
||||||
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"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mutationTrackerStub = filtertest_test.MutationTrackerStub{}
|
||||||
|
|
||||||
var tests = map[string]TestCase{
|
var tests = map[string]TestCase{
|
||||||
"suffix": {
|
"suffix": {
|
||||||
input: `
|
input: `
|
||||||
@@ -83,17 +86,61 @@ a:
|
|||||||
FieldSpec: types.FieldSpec{Path: "a/b/c"},
|
FieldSpec: types.FieldSpec{Path: "a/b/c"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mutation tracker": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance-foo
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance-foo
|
||||||
|
`,
|
||||||
|
filter: suffix.Filter{
|
||||||
|
Suffix: "-foo",
|
||||||
|
FieldSpec: types.FieldSpec{Path: "metadata/name"},
|
||||||
|
},
|
||||||
|
mutationTracker: mutationTrackerStub.MutationTracker,
|
||||||
|
expectedSetValueArgs: []filtertest_test.SetValueArg{
|
||||||
|
{
|
||||||
|
Value: "instance-foo",
|
||||||
|
NodePath: []string{"metadata", "name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "instance-foo",
|
||||||
|
NodePath: []string{"metadata", "name"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter suffix.Filter
|
filter suffix.Filter
|
||||||
|
mutationTracker func(key, value, tag string, node *yaml.RNode)
|
||||||
|
expectedSetValueArgs []filtertest_test.SetValueArg
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
for name := range tests {
|
for name := range tests {
|
||||||
|
mutationTrackerStub.Reset()
|
||||||
test := tests[name]
|
test := tests[name]
|
||||||
|
test.filter.WithMutationTracker(test.mutationTracker)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(test.expected),
|
strings.TrimSpace(test.expected),
|
||||||
@@ -101,6 +148,7 @@ func TestFilter(t *testing.T) {
|
|||||||
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
filtertest_test.RunFilter(t, test.input, test.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
assert.Equal(t, test.expectedSetValueArgs, mutationTrackerStub.SetValueArgs())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func run(input string, f kio.Filter) (string, error) {
|
func run(input string, f kio.Filter) (string, error) {
|
||||||
@@ -46,3 +47,32 @@ func RunFilterE(t *testing.T, input string, f kio.Filter) (string, error) {
|
|||||||
}
|
}
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SetValueArg struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
Tag string
|
||||||
|
NodePath []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MutationTrackerStub to help stub a mutation tracker for kio.TrackableFilter
|
||||||
|
type MutationTrackerStub struct {
|
||||||
|
setValueArgs []SetValueArg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mts *MutationTrackerStub) MutationTracker(key, value, tag string, node *yaml.RNode) {
|
||||||
|
mts.setValueArgs = append(mts.setValueArgs, SetValueArg{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
Tag: tag,
|
||||||
|
NodePath: node.FieldPath(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mts *MutationTrackerStub) SetValueArgs() []SetValueArg {
|
||||||
|
return mts.setValueArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mts *MutationTrackerStub) Reset() {
|
||||||
|
mts.setValueArgs = nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user