...
1
2
3
4 package fieldspec
5
6 import (
7 "fmt"
8 "strings"
9
10 "sigs.k8s.io/kustomize/api/filters/filtersutil"
11 "sigs.k8s.io/kustomize/api/types"
12 "sigs.k8s.io/kustomize/kyaml/errors"
13 "sigs.k8s.io/kustomize/kyaml/resid"
14 "sigs.k8s.io/kustomize/kyaml/utils"
15 "sigs.k8s.io/kustomize/kyaml/yaml"
16 )
17
18 var _ yaml.Filter = Filter{}
19
20
21
22
23
24
25
26
27
28
29
30
31 type Filter struct {
32
33 FieldSpec types.FieldSpec `yaml:"fieldSpec"`
34
35
36 SetValue filtersutil.SetFn
37
38
39 CreateKind yaml.Kind
40
41 CreateTag string
42
43
44 path []string
45 }
46
47 func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
48
49 if match := isMatchGVK(fltr.FieldSpec, obj); !match {
50 return obj, nil
51 }
52 fltr.path = utils.PathSplitter(fltr.FieldSpec.Path, "/")
53 if err := fltr.filter(obj); err != nil {
54 return nil, errors.WrapPrefixf(err,
55 "considering field '%s' of object %s", fltr.FieldSpec.Path, resid.FromRNode(obj))
56 }
57 return obj, nil
58 }
59
60
61 func (fltr Filter) filter(obj *yaml.RNode) error {
62 if len(fltr.path) == 0 {
63
64 return fltr.SetValue(obj)
65 }
66 if obj.IsTaggedNull() || obj.IsNil() {
67 return nil
68 }
69 switch obj.YNode().Kind {
70 case yaml.SequenceNode:
71 return fltr.handleSequence(obj)
72 case yaml.MappingNode:
73 return fltr.handleMap(obj)
74 case yaml.AliasNode:
75 return fltr.filter(yaml.NewRNode(obj.YNode().Alias))
76 default:
77 return errors.Errorf("expected sequence or mapping node")
78 }
79 }
80
81
82 func (fltr Filter) handleMap(obj *yaml.RNode) error {
83 fieldName, isSeq := isSequenceField(fltr.path[0])
84 if fieldName == "" {
85 return fmt.Errorf("cannot set or create an empty field name")
86 }
87
88 var operation yaml.Filter
89 var kind yaml.Kind
90 tag := yaml.NodeTagEmpty
91 switch {
92 case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
93
94 operation = yaml.Lookup(fieldName)
95 if isSeq {
96
97
98 kind = yaml.SequenceNode
99 }
100 case len(fltr.path) <= 1:
101
102 operation = yaml.LookupCreate(fltr.CreateKind, fieldName)
103 kind = fltr.CreateKind
104 tag = fltr.CreateTag
105 default:
106
107 operation = yaml.LookupCreate(yaml.MappingNode, fieldName)
108 kind = yaml.MappingNode
109 tag = yaml.NodeTagMap
110 }
111
112
113 field, err := obj.Pipe(operation)
114 if err != nil {
115 return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
116 }
117 if field == nil {
118
119 return nil
120 }
121
122
123
124
125 if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
126 field.YNode().Kind = kind
127 field.YNode().Tag = tag
128 }
129
130
131 var next = fltr
132
133 next.path = fltr.path[1:]
134 return next.filter(field)
135 }
136
137
138 func (fltr Filter) handleSequence(obj *yaml.RNode) error {
139 if err := obj.VisitElements(func(node *yaml.RNode) error {
140
141 node.AppendToFieldPath(obj.FieldPath()...)
142
143
144
145
146 return fltr.filter(node)
147 }); err != nil {
148 return errors.WrapPrefixf(err,
149 "visit traversal on path: %v", fltr.path)
150 }
151 return nil
152 }
153
154
155
156 func isSequenceField(name string) (string, bool) {
157 shorter := strings.TrimSuffix(name, "[]")
158 return shorter, shorter != name
159 }
160
161
162 func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) bool {
163 if kind := obj.GetKind(); fs.Kind != "" && fs.Kind != kind {
164
165 return false
166 }
167
168
169 group, version := resid.ParseGroupVersion(obj.GetApiVersion())
170
171 if fs.Group != "" && fs.Group != group {
172
173 return false
174 }
175
176 if fs.Version != "" && fs.Version != version {
177
178 return false
179 }
180
181 return true
182 }
183
View as plain text