1
2
3
4 package resource
5
6 import (
7 "fmt"
8 "log"
9 "strings"
10
11 "sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
12 "sigs.k8s.io/kustomize/api/ifc"
13 "sigs.k8s.io/kustomize/api/internal/utils"
14 "sigs.k8s.io/kustomize/api/types"
15 "sigs.k8s.io/kustomize/kyaml/kio"
16 "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
17 "sigs.k8s.io/kustomize/kyaml/resid"
18 kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
19 "sigs.k8s.io/yaml"
20 )
21
22
23
24 type Resource struct {
25 kyaml.RNode
26 refVarNames []string
27 }
28
29 var BuildAnnotations = []string{
30 utils.BuildAnnotationPreviousKinds,
31 utils.BuildAnnotationPreviousNames,
32 utils.BuildAnnotationPrefixes,
33 utils.BuildAnnotationSuffixes,
34 utils.BuildAnnotationPreviousNamespaces,
35 utils.BuildAnnotationAllowNameChange,
36 utils.BuildAnnotationAllowKindChange,
37 utils.BuildAnnotationsRefBy,
38 utils.BuildAnnotationsGenBehavior,
39 utils.BuildAnnotationsGenAddHashSuffix,
40
41 kioutil.PathAnnotation,
42 kioutil.IndexAnnotation,
43 kioutil.SeqIndentAnnotation,
44 kioutil.IdAnnotation,
45 kioutil.InternalAnnotationsMigrationResourceIDAnnotation,
46
47 kioutil.LegacyPathAnnotation,
48 kioutil.LegacyIndexAnnotation,
49 kioutil.LegacyIdAnnotation,
50 }
51
52 func (r *Resource) ResetRNode(incoming *Resource) {
53 r.RNode = *incoming.Copy()
54 }
55
56 func (r *Resource) GetGvk() resid.Gvk {
57 return resid.GvkFromNode(&r.RNode)
58 }
59
60 func (r *Resource) Hash(h ifc.KustHasher) (string, error) {
61 return h.Hash(&r.RNode)
62 }
63
64 func (r *Resource) SetGvk(gvk resid.Gvk) {
65 r.SetKind(gvk.Kind)
66 r.SetApiVersion(gvk.ApiVersion())
67 }
68
69 func (r *Resource) GetOrigin() (*Origin, error) {
70 annotations := r.GetAnnotations()
71 originAnnotations, ok := annotations[utils.OriginAnnotationKey]
72 if !ok {
73 return nil, nil
74 }
75 var origin Origin
76 if err := yaml.Unmarshal([]byte(originAnnotations), &origin); err != nil {
77 return nil, err
78 }
79 return &origin, nil
80 }
81
82 func (r *Resource) SetOrigin(origin *Origin) error {
83 annotations := r.GetAnnotations()
84 if origin == nil {
85 delete(annotations, utils.OriginAnnotationKey)
86 } else {
87 originStr, err := origin.String()
88 if err != nil {
89 return err
90 }
91 annotations[utils.OriginAnnotationKey] = originStr
92 }
93 return r.SetAnnotations(annotations)
94 }
95
96 func (r *Resource) GetTransformations() (Transformations, error) {
97 annotations := r.GetAnnotations()
98 transformerAnnotations, ok := annotations[utils.TransformerAnnotationKey]
99 if !ok {
100 return nil, nil
101 }
102 var transformations Transformations
103 if err := yaml.Unmarshal([]byte(transformerAnnotations), &transformations); err != nil {
104 return nil, err
105 }
106 return transformations, nil
107 }
108
109 func (r *Resource) AddTransformation(origin *Origin) error {
110 annotations := r.GetAnnotations()
111 transformations, err := r.GetTransformations()
112 if err != nil {
113 return err
114 }
115 if transformations == nil {
116 transformations = Transformations{}
117 }
118 transformations = append(transformations, origin)
119 transformationStr, err := transformations.String()
120 if err != nil {
121 return err
122 }
123 annotations[utils.TransformerAnnotationKey] = transformationStr
124 return r.SetAnnotations(annotations)
125 }
126
127 func (r *Resource) ClearTransformations() error {
128 annotations := r.GetAnnotations()
129 delete(annotations, utils.TransformerAnnotationKey)
130 return r.SetAnnotations(annotations)
131 }
132
133
134
135
136 type ResCtx interface {
137 AddNamePrefix(p string)
138 AddNameSuffix(s string)
139 GetNamePrefixes() []string
140 GetNameSuffixes() []string
141 }
142
143
144
145 type ResCtxMatcher func(ResCtx) bool
146
147
148 func (r *Resource) DeepCopy() *Resource {
149 rc := &Resource{
150 RNode: *r.Copy(),
151 }
152 rc.copyKustomizeSpecificFields(r)
153 return rc
154 }
155
156
157
158
159
160
161
162 func (r *Resource) CopyMergeMetaDataFieldsFrom(other *Resource) error {
163 if err := r.SetLabels(
164 mergeStringMaps(other.GetLabels(), r.GetLabels())); err != nil {
165 return fmt.Errorf("copyMerge cannot set labels - %w", err)
166 }
167
168 ra := r.GetAnnotations()
169 _, enableNameSuffixHash := ra[utils.BuildAnnotationsGenAddHashSuffix]
170 merged := mergeStringMapsWithBuildAnnotations(other.GetAnnotations(), ra)
171 if !enableNameSuffixHash {
172 delete(merged, utils.BuildAnnotationsGenAddHashSuffix)
173 }
174 if err := r.SetAnnotations(merged); err != nil {
175 return fmt.Errorf("copyMerge cannot set annotations - %w", err)
176 }
177
178 if err := r.SetName(other.GetName()); err != nil {
179 return fmt.Errorf("copyMerge cannot set name - %w", err)
180 }
181 if err := r.SetNamespace(other.GetNamespace()); err != nil {
182 return fmt.Errorf("copyMerge cannot set namespace - %w", err)
183 }
184 r.copyKustomizeSpecificFields(other)
185 return nil
186 }
187
188 func (r *Resource) copyKustomizeSpecificFields(other *Resource) {
189 r.refVarNames = copyStringSlice(other.refVarNames)
190 }
191
192 func (r *Resource) MergeDataMapFrom(o *Resource) {
193 r.SetDataMap(mergeStringMaps(o.GetDataMap(), r.GetDataMap()))
194 }
195
196 func (r *Resource) MergeBinaryDataMapFrom(o *Resource) {
197 r.SetBinaryDataMap(mergeStringMaps(o.GetBinaryDataMap(), r.GetBinaryDataMap()))
198 }
199
200 func (r *Resource) ErrIfNotEquals(o *Resource) error {
201 meYaml, err := r.AsYAML()
202 if err != nil {
203 return err
204 }
205 otherYaml, err := o.AsYAML()
206 if err != nil {
207 return err
208 }
209 if !r.ReferencesEqual(o) {
210 return fmt.Errorf(
211 `unequal references - self:
212 %sreferenced by: %s
213 --- other:
214 %sreferenced by: %s
215 `, meYaml, r.GetRefBy(), otherYaml, o.GetRefBy())
216 }
217 if string(meYaml) != string(otherYaml) {
218 return fmt.Errorf(`--- self:
219 %s
220 --- other:
221 %s
222 `, meYaml, otherYaml)
223 }
224 return nil
225 }
226
227 func (r *Resource) ReferencesEqual(other *Resource) bool {
228 setSelf := make(map[resid.ResId]bool)
229 setOther := make(map[resid.ResId]bool)
230 for _, ref := range other.GetRefBy() {
231 setOther[ref] = true
232 }
233 for _, ref := range r.GetRefBy() {
234 if _, ok := setOther[ref]; !ok {
235 return false
236 }
237 setSelf[ref] = true
238 }
239 return len(setSelf) == len(setOther)
240 }
241
242 func copyStringSlice(s []string) []string {
243 if s == nil {
244 return nil
245 }
246 c := make([]string, len(s))
247 copy(c, s)
248 return c
249 }
250
251
252 func (r *Resource) AddNamePrefix(p string) {
253 r.appendCsvAnnotation(utils.BuildAnnotationPrefixes, p)
254 }
255
256
257 func (r *Resource) AddNameSuffix(s string) {
258 r.appendCsvAnnotation(utils.BuildAnnotationSuffixes, s)
259 }
260
261 func (r *Resource) appendCsvAnnotation(name, value string) {
262 if value == "" {
263 return
264 }
265 currentValue := r.getCsvAnnotation(name)
266 newValue := strings.Join(append(currentValue, value), ",")
267 if err := r.RNode.PipeE(kyaml.SetAnnotation(name, newValue)); err != nil {
268 panic(err)
269 }
270 }
271
272
273 func (r *Resource) GetNamePrefixes() []string {
274 return r.getCsvAnnotation(utils.BuildAnnotationPrefixes)
275 }
276
277
278 func (r *Resource) GetNameSuffixes() []string {
279 return r.getCsvAnnotation(utils.BuildAnnotationSuffixes)
280 }
281
282 func (r *Resource) getCsvAnnotation(name string) []string {
283 annotations := r.GetAnnotations()
284 if _, ok := annotations[name]; !ok {
285 return nil
286 }
287 return strings.Split(annotations[name], ",")
288 }
289
290
291
292
293
294
295
296
297
298 func (r *Resource) PrefixesSuffixesEquals(o ResCtx, allowEmpty bool) bool {
299 if allowEmpty {
300 eitherPrefixEmpty := len(r.GetNamePrefixes()) == 0 || len(o.GetNamePrefixes()) == 0
301 eitherSuffixEmpty := len(r.GetNameSuffixes()) == 0 || len(o.GetNameSuffixes()) == 0
302
303 return (eitherPrefixEmpty || utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes())) &&
304 (eitherSuffixEmpty || utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes()))
305 } else {
306 return utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes()) &&
307 utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes())
308 }
309 }
310
311
312
313
314 func (r *Resource) RemoveBuildAnnotations() {
315 annotations := r.GetAnnotations()
316 if len(annotations) == 0 {
317 return
318 }
319 for _, a := range BuildAnnotations {
320 delete(annotations, a)
321 }
322 if err := r.SetAnnotations(annotations); err != nil {
323 panic(err)
324 }
325 }
326
327 func (r *Resource) setPreviousId(ns string, n string, k string) *Resource {
328 r.appendCsvAnnotation(utils.BuildAnnotationPreviousNames, n)
329 r.appendCsvAnnotation(utils.BuildAnnotationPreviousNamespaces, ns)
330 r.appendCsvAnnotation(utils.BuildAnnotationPreviousKinds, k)
331 return r
332 }
333
334
335 func (r *Resource) AllowNameChange() {
336 r.enable(utils.BuildAnnotationAllowNameChange)
337 }
338
339
340 func (r *Resource) NameChangeAllowed() bool {
341 return r.isEnabled(utils.BuildAnnotationAllowNameChange)
342 }
343
344
345 func (r *Resource) AllowKindChange() {
346 r.enable(utils.BuildAnnotationAllowKindChange)
347 }
348
349
350 func (r *Resource) KindChangeAllowed() bool {
351 return r.isEnabled(utils.BuildAnnotationAllowKindChange)
352 }
353
354 func (r *Resource) isEnabled(annoKey string) bool {
355 annotations := r.GetAnnotations()
356 v, ok := annotations[annoKey]
357 return ok && v == utils.Enabled
358 }
359
360 func (r *Resource) enable(annoKey string) {
361 annotations := r.GetAnnotations()
362 annotations[annoKey] = utils.Enabled
363 if err := r.SetAnnotations(annotations); err != nil {
364 panic(err)
365 }
366 }
367
368
369 func (r *Resource) String() string {
370 bs, err := r.MarshalJSON()
371 if err != nil {
372 return "<" + err.Error() + ">"
373 }
374 return strings.TrimSpace(string(bs))
375 }
376
377
378
379 func (r *Resource) AsYAML() ([]byte, error) {
380 json, err := r.MarshalJSON()
381 if err != nil {
382 return nil, err
383 }
384 return yaml.JSONToYAML(json)
385 }
386
387
388 func (r *Resource) MustYaml() string {
389 yml, err := r.AsYAML()
390 if err != nil {
391 log.Fatal(err)
392 }
393 return string(yml)
394 }
395
396
397 func (r *Resource) Behavior() types.GenerationBehavior {
398 annotations := r.GetAnnotations()
399 if v, ok := annotations[utils.BuildAnnotationsGenBehavior]; ok {
400 return types.NewGenerationBehavior(v)
401 }
402 return types.NewGenerationBehavior("")
403 }
404
405
406 func (r *Resource) SetBehavior(behavior types.GenerationBehavior) {
407 annotations := r.GetAnnotations()
408 annotations[utils.BuildAnnotationsGenBehavior] = behavior.String()
409 if err := r.SetAnnotations(annotations); err != nil {
410 panic(err)
411 }
412 }
413
414
415
416 func (r *Resource) NeedHashSuffix() bool {
417 return r.isEnabled(utils.BuildAnnotationsGenAddHashSuffix)
418 }
419
420
421
422 func (r *Resource) EnableHashSuffix() {
423 r.enable(utils.BuildAnnotationsGenAddHashSuffix)
424 }
425
426
427
428 func (r *Resource) OrgId() resid.ResId {
429 ids := r.PrevIds()
430 if len(ids) > 0 {
431 return ids[0]
432 }
433 return r.CurId()
434 }
435
436
437
438
439
440
441
442 func (r *Resource) PrevIds() []resid.ResId {
443 prevIds, err := utils.PrevIds(&r.RNode)
444 if err != nil {
445
446 panic(err)
447 }
448 return prevIds
449 }
450
451
452 func (r *Resource) StorePreviousId() {
453 id := r.CurId()
454 r.setPreviousId(id.EffectiveNamespace(), id.Name, id.Kind)
455 }
456
457
458
459
460 func (r *Resource) CurId() resid.ResId {
461 return resid.NewResIdWithNamespace(
462 r.GetGvk(), r.GetName(), r.GetNamespace())
463 }
464
465
466 func (r *Resource) GetRefBy() []resid.ResId {
467 var resIds []resid.ResId
468 asStrings := r.getCsvAnnotation(utils.BuildAnnotationsRefBy)
469 for _, s := range asStrings {
470 resIds = append(resIds, resid.FromString(s))
471 }
472 return resIds
473 }
474
475
476
477 func (r *Resource) AppendRefBy(id fmt.Stringer) {
478 r.appendCsvAnnotation(utils.BuildAnnotationsRefBy, id.String())
479 }
480
481
482 func (r *Resource) GetRefVarNames() []string {
483 return r.refVarNames
484 }
485
486
487 func (r *Resource) AppendRefVarName(variable types.Var) {
488 r.refVarNames = append(r.refVarNames, variable.Name)
489 }
490
491
492 func (r *Resource) ApplySmPatch(patch *Resource) error {
493 n, ns, k := r.GetName(), r.GetNamespace(), r.GetKind()
494 if patch.NameChangeAllowed() || patch.KindChangeAllowed() {
495 r.StorePreviousId()
496 }
497 if err := r.ApplyFilter(patchstrategicmerge.Filter{
498 Patch: &patch.RNode,
499 }); err != nil {
500 return err
501 }
502 if r.IsNilOrEmpty() {
503 return nil
504 }
505 if !patch.KindChangeAllowed() {
506 r.SetKind(k)
507 }
508 if !patch.NameChangeAllowed() {
509 r.SetName(n)
510 }
511 r.SetNamespace(ns)
512 return nil
513 }
514
515 func (r *Resource) ApplyFilter(f kio.Filter) error {
516 l, err := f.Filter([]*kyaml.RNode{&r.RNode})
517 if len(l) == 0 {
518
519
520 r.SetYNode(nil)
521 }
522 return err
523 }
524
525 func mergeStringMaps(maps ...map[string]string) map[string]string {
526 result := map[string]string{}
527 for _, m := range maps {
528 for key, value := range m {
529 result[key] = value
530 }
531 }
532 return result
533 }
534
535 func mergeStringMapsWithBuildAnnotations(maps ...map[string]string) map[string]string {
536 result := mergeStringMaps(maps...)
537 for i := range BuildAnnotations {
538 if len(maps) > 0 {
539 if v, ok := maps[0][BuildAnnotations[i]]; ok {
540 result[BuildAnnotations[i]] = v
541 continue
542 }
543 }
544 delete(result, BuildAnnotations[i])
545 }
546 return result
547 }
548
View as plain text