diff --git a/api/filters/namespace/namespace.go b/api/filters/namespace/namespace.go index e554600bc..85484bf70 100644 --- a/api/filters/namespace/namespace.go +++ b/api/filters/namespace/namespace.go @@ -18,9 +18,17 @@ type Filter struct { // FsSlice contains the FieldSpecs to locate the namespace field FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` + + trackableSetter filtersutil.TrackableSetter } 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) { 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 -- :) err := node.PipeE(fsslice.Filter{ FsSlice: ns.FsSlice, - SetValue: filtersutil.SetScalar(ns.Namespace), + SetValue: ns.trackableSetter.SetScalar(ns.Namespace), CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode CreateTag: yaml.NodeTagString, }) @@ -77,7 +85,7 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error { FsSlice: []types.FieldSpec{ {Path: types.MetadataNamespacePath, CreateIfNotPresent: true}, }, - SetValue: filtersutil.SetScalar(ns.Namespace), + SetValue: ns.trackableSetter.SetScalar(ns.Namespace), CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode } _, 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 - v := yaml.NewScalarRNode(ns.Namespace) - return o.PipeE( + node, err := o.Pipe( yaml.LookupCreate(yaml.ScalarNode, "namespace"), - yaml.FieldSetter{Value: v}, ) + if err != nil { + return err + } + + return ns.trackableSetter.SetScalar(ns.Namespace)(node) + }) return err diff --git a/api/filters/namespace/namespace_test.go b/api/filters/namespace/namespace_test.go index e9854811e..302abe035 100644 --- a/api/filters/namespace/namespace_test.go +++ b/api/filters/namespace/namespace_test.go @@ -12,8 +12,11 @@ import ( "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/yaml" ) +var mutationTrackerStub = filtertest_test.MutationTrackerStub{} + var tests = []TestCase{ { name: "add", @@ -283,21 +286,91 @@ 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 { - name string - input string - expected string - filter namespace.Filter - fsslice types.FsSlice + name string + input string + expected string + filter namespace.Filter + fsslice types.FsSlice + mutationTracker func(key, value, tag string, node *yaml.RNode) + expectedSetValueArgs []filtertest_test.SetValueArg } var config = builtinconfig.MakeDefaultConfig() func TestNamespace_Filter(t *testing.T) { for i := range tests { + mutationTrackerStub.Reset() test := tests[i] + test.filter.WithMutationTracker(test.mutationTracker) t.Run(test.name, func(t *testing.T) { test.filter.FsSlice = append(config.NameSpace, test.fsslice...) if !assert.Equal(t, @@ -306,6 +379,7 @@ func TestNamespace_Filter(t *testing.T) { filtertest_test.RunFilter(t, test.input, test.filter))) { t.FailNow() } + assert.Equal(t, test.expectedSetValueArgs, mutationTrackerStub.SetValueArgs()) }) } }