1
2
3
4 package target
5
6 import (
7 "encoding/json"
8 "fmt"
9 "os"
10 "strings"
11
12 "sigs.k8s.io/kustomize/api/ifc"
13 "sigs.k8s.io/kustomize/api/internal/accumulator"
14 "sigs.k8s.io/kustomize/api/internal/builtins"
15 "sigs.k8s.io/kustomize/api/internal/kusterr"
16 load "sigs.k8s.io/kustomize/api/internal/loader"
17 "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
18 "sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
19 "sigs.k8s.io/kustomize/api/internal/plugins/loader"
20 "sigs.k8s.io/kustomize/api/internal/utils"
21 "sigs.k8s.io/kustomize/api/konfig"
22 "sigs.k8s.io/kustomize/api/resmap"
23 "sigs.k8s.io/kustomize/api/resource"
24 "sigs.k8s.io/kustomize/api/types"
25 "sigs.k8s.io/kustomize/kyaml/errors"
26 "sigs.k8s.io/kustomize/kyaml/openapi"
27 "sigs.k8s.io/yaml"
28 )
29
30
31 type KustTarget struct {
32 kustomization *types.Kustomization
33 kustFileName string
34 ldr ifc.Loader
35 validator ifc.Validator
36 rFactory *resmap.Factory
37 pLdr *loader.Loader
38 origin *resource.Origin
39 }
40
41
42 func NewKustTarget(
43 ldr ifc.Loader,
44 validator ifc.Validator,
45 rFactory *resmap.Factory,
46 pLdr *loader.Loader) *KustTarget {
47 return &KustTarget{
48 ldr: ldr,
49 validator: validator,
50 rFactory: rFactory,
51 pLdr: pLdr.LoaderWithWorkingDir(ldr.Root()),
52 }
53 }
54
55
56 func (kt *KustTarget) Load() error {
57 content, kustFileName, err := LoadKustFile(kt.ldr)
58 if err != nil {
59 return err
60 }
61
62 var k types.Kustomization
63 if err := k.Unmarshal(content); err != nil {
64 return err
65 }
66
67
68 if warningMessages := k.CheckDeprecatedFields(); warningMessages != nil {
69 for _, msg := range *warningMessages {
70 fmt.Fprintf(os.Stderr, "%v\n", msg)
71 }
72 }
73
74 k.FixKustomization()
75
76
77 if err := k.CheckEmpty(); err != nil {
78 return err
79 }
80
81 errs := k.EnforceFields()
82 if len(errs) > 0 {
83 return fmt.Errorf(
84 "Failed to read kustomization file under %s:\n"+
85 strings.Join(errs, "\n"), kt.ldr.Root())
86 }
87 kt.kustomization = &k
88 kt.kustFileName = kustFileName
89 return nil
90 }
91
92
93 func (kt *KustTarget) Kustomization() types.Kustomization {
94 var result types.Kustomization
95 b, _ := json.Marshal(*kt.kustomization)
96 json.Unmarshal(b, &result)
97 return result
98 }
99
100 func LoadKustFile(ldr ifc.Loader) ([]byte, string, error) {
101 var content []byte
102 match := 0
103 var kustFileName string
104 for _, kf := range konfig.RecognizedKustomizationFileNames() {
105 c, err := ldr.Load(kf)
106 if err == nil {
107 match += 1
108 content = c
109 kustFileName = kf
110 }
111 }
112 switch match {
113 case 0:
114 return nil, "", NewErrMissingKustomization(ldr.Root())
115 case 1:
116 return content, kustFileName, nil
117 default:
118 return nil, "", fmt.Errorf(
119 "Found multiple kustomization files under: %s\n", ldr.Root())
120 }
121 }
122
123
124
125 func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
126 return kt.makeCustomizedResMap()
127 }
128
129 func (kt *KustTarget) makeCustomizedResMap() (resmap.ResMap, error) {
130 var origin *resource.Origin
131 if len(kt.kustomization.BuildMetadata) != 0 {
132 origin = &resource.Origin{}
133 }
134 kt.origin = origin
135 ra, err := kt.AccumulateTarget()
136 if err != nil {
137 return nil, err
138 }
139
140
141
142
143 err = kt.addHashesToNames(ra)
144 if err != nil {
145 return nil, err
146 }
147
148
149
150 err = ra.FixBackReferences()
151 if err != nil {
152 return nil, err
153 }
154
155
156 err = ra.ResolveVars()
157 if err != nil {
158 return nil, err
159 }
160
161 err = kt.IgnoreLocal(ra)
162 if err != nil {
163 return nil, err
164 }
165
166 return ra.ResMap(), nil
167 }
168
169 func (kt *KustTarget) addHashesToNames(
170 ra *accumulator.ResAccumulator) error {
171 p := builtins.NewHashTransformerPlugin()
172 err := kt.configureBuiltinPlugin(p, nil, builtinhelpers.HashTransformer)
173 if err != nil {
174 return err
175 }
176 return ra.Transform(p)
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 func (kt *KustTarget) AccumulateTarget() (
193 ra *accumulator.ResAccumulator, err error) {
194 return kt.accumulateTarget(accumulator.MakeEmptyAccumulator())
195 }
196
197
198
199 func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
200 resRa *accumulator.ResAccumulator, err error) {
201 ra, err = kt.accumulateResources(ra, kt.kustomization.Resources)
202 if err != nil {
203 return nil, errors.WrapPrefixf(err, "accumulating resources")
204 }
205 tConfig, err := builtinconfig.MakeTransformerConfig(
206 kt.ldr, kt.kustomization.Configurations)
207 if err != nil {
208 return nil, err
209 }
210 err = ra.MergeConfig(tConfig)
211 if err != nil {
212 return nil, errors.WrapPrefixf(
213 err, "merging config %v", tConfig)
214 }
215 crdTc, err := accumulator.LoadConfigFromCRDs(kt.ldr, kt.kustomization.Crds)
216 if err != nil {
217 return nil, errors.WrapPrefixf(
218 err, "loading CRDs %v", kt.kustomization.Crds)
219 }
220 err = ra.MergeConfig(crdTc)
221 if err != nil {
222 return nil, errors.WrapPrefixf(
223 err, "merging CRDs %v", crdTc)
224 }
225 err = kt.runGenerators(ra)
226 if err != nil {
227 return nil, err
228 }
229
230
231
232 ra, err = kt.accumulateComponents(ra, kt.kustomization.Components)
233 if err != nil {
234 return nil, errors.WrapPrefixf(err, "accumulating components")
235 }
236
237 err = kt.runTransformers(ra)
238 if err != nil {
239 return nil, err
240 }
241 err = kt.runValidators(ra)
242 if err != nil {
243 return nil, err
244 }
245 err = ra.MergeVars(kt.kustomization.Vars)
246 if err != nil {
247 return nil, errors.WrapPrefixf(
248 err, "merging vars %v", kt.kustomization.Vars)
249 }
250 return ra, nil
251 }
252
253
254 func (kt *KustTarget) IgnoreLocal(ra *accumulator.ResAccumulator) error {
255 rf := kt.rFactory.RF()
256 if rf.IncludeLocalConfigs {
257 return nil
258 }
259 remainRes, err := rf.DropLocalNodes(ra.ResMap().ToRNodeSlice())
260 if err != nil {
261 return err
262 }
263 return ra.Intersection(kt.rFactory.FromResourceSlice(remainRes))
264 }
265
266 func (kt *KustTarget) runGenerators(
267 ra *accumulator.ResAccumulator) error {
268 var generators []*resmap.GeneratorWithProperties
269 gs, err := kt.configureBuiltinGenerators()
270 if err != nil {
271 return err
272 }
273 generators = append(generators, gs...)
274
275 gs, err = kt.configureExternalGenerators()
276 if err != nil {
277 return errors.WrapPrefixf(err, "loading generator plugins")
278 }
279 generators = append(generators, gs...)
280 for i, g := range generators {
281 resMap, err := g.Generate()
282 if err != nil {
283 return err
284 }
285 if resMap != nil {
286 err = resMap.AddOriginAnnotation(generators[i].Origin)
287 if err != nil {
288 return errors.WrapPrefixf(err, "adding origin annotations for generator %v", g)
289 }
290 }
291 err = ra.AbsorbAll(resMap)
292 if err != nil {
293 return errors.WrapPrefixf(err, "merging from generator %v", g)
294 }
295 }
296 return nil
297 }
298
299 func (kt *KustTarget) configureExternalGenerators() (
300 []*resmap.GeneratorWithProperties, error) {
301 ra := accumulator.MakeEmptyAccumulator()
302 var generatorPaths []string
303 for _, p := range kt.kustomization.Generators {
304
305 rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
306 if err != nil {
307
308 generatorPaths = append(generatorPaths, p)
309 continue
310 }
311
312 if kt.origin != nil {
313 resources := rm.Resources()
314 for _, r := range resources {
315 r.SetOrigin(kt.origin.Append(kt.kustFileName))
316 rm.Replace(r)
317 }
318 }
319 if err = ra.AppendAll(rm); err != nil {
320 return nil, errors.WrapPrefixf(err, "configuring external generator")
321 }
322 }
323 ra, err := kt.accumulateResources(ra, generatorPaths)
324 if err != nil {
325 return nil, err
326 }
327 return kt.pLdr.LoadGenerators(kt.ldr, kt.validator, ra.ResMap())
328 }
329
330 func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
331 var r []*resmap.TransformerWithProperties
332 tConfig := ra.GetTransformerConfig()
333 lts, err := kt.configureBuiltinTransformers(tConfig)
334 if err != nil {
335 return err
336 }
337 r = append(r, lts...)
338 lts, err = kt.configureExternalTransformers(kt.kustomization.Transformers)
339 if err != nil {
340 return err
341 }
342 r = append(r, lts...)
343 return ra.Transform(newMultiTransformer(r))
344 }
345
346 func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]*resmap.TransformerWithProperties, error) {
347 ra := accumulator.MakeEmptyAccumulator()
348 var transformerPaths []string
349 for _, p := range transformers {
350
351 rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
352 if err != nil {
353
354 transformerPaths = append(transformerPaths, p)
355 continue
356 }
357
358 if kt.origin != nil {
359 resources := rm.Resources()
360 for _, r := range resources {
361 r.SetOrigin(kt.origin.Append(kt.kustFileName))
362 rm.Replace(r)
363 }
364 }
365
366 if err = ra.AppendAll(rm); err != nil {
367 return nil, errors.WrapPrefixf(err, "configuring external transformer")
368 }
369 }
370 ra, err := kt.accumulateResources(ra, transformerPaths)
371 if err != nil {
372 return nil, err
373 }
374 return kt.pLdr.LoadTransformers(kt.ldr, kt.validator, ra.ResMap())
375 }
376
377 func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error {
378 validators, err := kt.configureExternalTransformers(kt.kustomization.Validators)
379 if err != nil {
380 return err
381 }
382 for _, v := range validators {
383
384 orignal := ra.ResMap().DeepCopy()
385 err = v.Transform(ra.ResMap())
386 if err != nil {
387 return err
388 }
389 newMap := ra.ResMap().DeepCopy()
390 if err = kt.removeValidatedByLabel(newMap); err != nil {
391 return err
392 }
393 if err = orignal.ErrorIfNotEqualSets(newMap); err != nil {
394 return fmt.Errorf("validator shouldn't modify the resource map: %v", err)
395 }
396 }
397 return nil
398 }
399
400 func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) error {
401 resources := rm.Resources()
402 for _, r := range resources {
403 labels := r.GetLabels()
404 if _, found := labels[konfig.ValidatedByLabelKey]; !found {
405 continue
406 }
407 delete(labels, konfig.ValidatedByLabelKey)
408 if err := r.SetLabels(labels); err != nil {
409 return err
410 }
411 }
412 return nil
413 }
414
415
416
417 func (kt *KustTarget) accumulateResources(
418 ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
419 for _, path := range paths {
420
421 if errF := kt.accumulateFile(ra, path); errF != nil {
422
423 if errors.Is(errF, load.ErrHTTP) {
424 return nil, errF
425 }
426 ldr, err := kt.ldr.New(path)
427 if err != nil {
428
429
430
431
432
433
434
435 if kusterr.IsMalformedYAMLError(errF) && !utils.IsErrTimeout(err) {
436 return nil, errF
437 }
438 return nil, errors.WrapPrefixf(
439 err, "accumulation err='%s'", errF.Error())
440 }
441
442 origin := kt.origin.Copy()
443 if kt.origin != nil {
444 kt.origin = kt.origin.Append(path)
445 ra, err = kt.accumulateDirectory(ra, ldr, false)
446
447 kt.origin = &origin
448 } else {
449 ra, err = kt.accumulateDirectory(ra, ldr, false)
450 }
451 if err != nil {
452 if kusterr.IsMalformedYAMLError(errF) {
453 return nil, errF
454 }
455 return nil, errors.WrapPrefixf(
456 err, "accumulation err='%s'", errF.Error())
457 }
458 }
459 }
460 return ra, nil
461 }
462
463
464
465 func (kt *KustTarget) accumulateComponents(
466 ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
467 for _, path := range paths {
468
469 ldr, errL := kt.ldr.New(path)
470 if errL != nil {
471 return nil, fmt.Errorf("loader.New %q", errL)
472 }
473 var errD error
474
475 origin := kt.origin.Copy()
476 if kt.origin != nil {
477 kt.origin = kt.origin.Append(path)
478 ra, errD = kt.accumulateDirectory(ra, ldr, true)
479
480 kt.origin = &origin
481 } else {
482 ra, errD = kt.accumulateDirectory(ra, ldr, true)
483 }
484 if errD != nil {
485 return nil, fmt.Errorf("accumulateDirectory: %q", errD)
486 }
487 }
488 return ra, nil
489 }
490
491 func (kt *KustTarget) accumulateDirectory(
492 ra *accumulator.ResAccumulator, ldr ifc.Loader, isComponent bool) (*accumulator.ResAccumulator, error) {
493 defer ldr.Cleanup()
494 subKt := NewKustTarget(ldr, kt.validator, kt.rFactory, kt.pLdr)
495 err := subKt.Load()
496 if err != nil {
497 return nil, errors.WrapPrefixf(
498 err, "couldn't make target for path '%s'", ldr.Root())
499 }
500 subKt.kustomization.BuildMetadata = kt.kustomization.BuildMetadata
501 subKt.origin = kt.origin
502 var bytes []byte
503 if openApiPath, exists := subKt.Kustomization().OpenAPI["path"]; exists {
504 bytes, err = ldr.Load(openApiPath)
505 if err != nil {
506 return nil, err
507 }
508 }
509 err = openapi.SetSchema(subKt.Kustomization().OpenAPI, bytes, false)
510 if err != nil {
511 return nil, err
512 }
513 if isComponent && subKt.kustomization.Kind != types.ComponentKind {
514 return nil, fmt.Errorf(
515 "expected kind '%s' for path '%s' but got '%s'", types.ComponentKind, ldr.Root(), subKt.kustomization.Kind)
516 } else if !isComponent && subKt.kustomization.Kind == types.ComponentKind {
517 return nil, fmt.Errorf(
518 "expected kind != '%s' for path '%s'", types.ComponentKind, ldr.Root())
519 }
520
521 var subRa *accumulator.ResAccumulator
522 if isComponent {
523
524 subRa, err = subKt.accumulateTarget(ra)
525 ra = accumulator.MakeEmptyAccumulator()
526 } else {
527
528
529 subRa, err = subKt.AccumulateTarget()
530 }
531 if err != nil {
532 return nil, errors.WrapPrefixf(
533 err, "recursed accumulation of path '%s'", ldr.Root())
534 }
535 err = ra.MergeAccumulator(subRa)
536 if err != nil {
537 return nil, errors.WrapPrefixf(
538 err, "recursed merging from path '%s'", ldr.Root())
539 }
540 return ra, nil
541 }
542
543 func (kt *KustTarget) accumulateFile(
544 ra *accumulator.ResAccumulator, path string) error {
545 resources, err := kt.rFactory.FromFile(kt.ldr, path)
546 if err != nil {
547 return errors.WrapPrefixf(err, "accumulating resources from '%s'", path)
548 }
549 if kt.origin != nil {
550 originAnno, err := kt.origin.Append(path).String()
551 if err != nil {
552 return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
553 }
554 err = resources.AnnotateAll(utils.OriginAnnotationKey, originAnno)
555 if err != nil || originAnno == "" {
556 return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
557 }
558 }
559 err = ra.AppendAll(resources)
560 if err != nil {
561 return errors.WrapPrefixf(err, "merging resources from '%s'", path)
562 }
563 return nil
564 }
565
566 func (kt *KustTarget) configureBuiltinPlugin(
567 p resmap.Configurable, c interface{}, bpt builtinhelpers.BuiltinPluginType) (err error) {
568 var y []byte
569 if c != nil {
570 y, err = yaml.Marshal(c)
571 if err != nil {
572 return errors.WrapPrefixf(
573 err, "builtin %s marshal", bpt)
574 }
575 }
576 err = p.Config(
577 resmap.NewPluginHelpers(
578 kt.ldr, kt.validator, kt.rFactory, kt.pLdr.Config()),
579 y)
580 if err != nil {
581 return errors.WrapPrefixf(
582 err, "trouble configuring builtin %s with config: `\n%s`", bpt, string(y))
583 }
584 return nil
585 }
586
View as plain text