mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
feat: Add SetEntryCallback to annotations filter
Add a configurable callback that is invoked each time an annotation is applied by the annotations filter. This is useful for scenarios such as tracking annotations as they are applied. Issues: GoogleContainerTools/kpt#2448
This commit is contained in:
@@ -19,10 +19,25 @@ type Filter struct {
|
|||||||
|
|
||||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
// FsSlice contains the FieldSpecs to locate the namespace field
|
||||||
FsSlice types.FsSlice
|
FsSlice types.FsSlice
|
||||||
|
|
||||||
|
// SetEntryCallback is invoked each time an annotation is applied
|
||||||
|
// Example use cases:
|
||||||
|
// - Tracking all paths where annotations have been applied
|
||||||
|
SetEntryCallback func(key, value, tag string, node *yaml.RNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
|
func (f Filter) setEntry(key, value, tag string) filtersutil.SetFn {
|
||||||
|
baseSetEntryFunc := filtersutil.SetEntry(key, value, tag)
|
||||||
|
return func(node *yaml.RNode) error {
|
||||||
|
if f.SetEntryCallback != nil {
|
||||||
|
f.SetEntryCallback(key, value, tag, node)
|
||||||
|
}
|
||||||
|
return baseSetEntryFunc(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
keys := yaml.SortedMapKeys(f.Annotations)
|
keys := yaml.SortedMapKeys(f.Annotations)
|
||||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||||
@@ -30,7 +45,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: filtersutil.SetEntry(
|
SetValue: f.setEntry(
|
||||||
k, f.Annotations[k], yaml.NodeTagString),
|
k, f.Annotations[k], yaml.NodeTagString),
|
||||||
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
|
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
|
||||||
CreateTag: yaml.NodeTagMap,
|
CreateTag: yaml.NodeTagMap,
|
||||||
|
|||||||
@@ -11,16 +11,36 @@ 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 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) {
|
||||||
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
|
||||||
|
expectedSetEntryArgs []setEntryArg
|
||||||
}{
|
}{
|
||||||
"add": {
|
"add": {
|
||||||
input: `
|
input: `
|
||||||
@@ -210,9 +230,74 @@ metadata:
|
|||||||
"b": "b1",
|
"b": "b1",
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// test usage of SetEntryCallback
|
||||||
|
"set_entry_callback": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
a: a1
|
||||||
|
b: b1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
a: a1
|
||||||
|
b: b1
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Annotations: annoMap{
|
||||||
|
"a": "a1",
|
||||||
|
"b": "b1",
|
||||||
|
},
|
||||||
|
SetEntryCallback: setEntryCallbackStub,
|
||||||
|
},
|
||||||
|
fsslice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/metadata/annotations",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSetEntryArgs: []setEntryArg{
|
||||||
|
{
|
||||||
|
Key: "a",
|
||||||
|
Value: "a1",
|
||||||
|
Tag: "!!str",
|
||||||
|
NodePath: []string{"metadata", "annotations"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "a",
|
||||||
|
Value: "a1",
|
||||||
|
Tag: "!!str",
|
||||||
|
NodePath: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "b",
|
||||||
|
Value: "b1",
|
||||||
|
Tag: "!!str",
|
||||||
|
NodePath: []string{"metadata", "annotations"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "b",
|
||||||
|
Value: "b1",
|
||||||
|
Tag: "!!str",
|
||||||
|
NodePath: []string{"spec", "template", "metadata", "annotations"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
|
setEntryArgs = nil
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
filter := tc.filter
|
filter := tc.filter
|
||||||
filter.FsSlice = append(annosFs, tc.fsslice...)
|
filter.FsSlice = append(annosFs, tc.fsslice...)
|
||||||
@@ -221,6 +306,9 @@ metadata:
|
|||||||
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) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user