1
2
3
4 package krusty_test
5
6 import (
7 "fmt"
8 "strings"
9 "testing"
10
11 "sigs.k8s.io/kustomize/api/internal/loader"
12 "sigs.k8s.io/kustomize/api/konfig"
13 kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
14 )
15
16 type FileGen func(kusttest_test.Harness)
17
18 func writeC(path string, content string) FileGen {
19 return func(th kusttest_test.Harness) {
20 th.WriteC(path, content)
21 }
22 }
23
24 func writeF(path string, content string) FileGen {
25 return func(th kusttest_test.Harness) {
26 th.WriteF(path, content)
27 }
28 }
29
30 func writeK(path string, content string) FileGen {
31 return func(th kusttest_test.Harness) {
32 th.WriteK(path, content)
33 }
34 }
35
36 func writeTestBase(th kusttest_test.Harness) {
37 th.WriteK("base", `
38 resources:
39 - deploy.yaml
40 configMapGenerator:
41 - name: my-configmap
42 literals:
43 - testValue=purple
44 - otherValue=green
45 `)
46 th.WriteF("base/deploy.yaml", `
47 apiVersion: v1
48 kind: Deployment
49 metadata:
50 name: storefront
51 spec:
52 replicas: 1
53 `)
54 }
55
56 func writeTestComponent(th kusttest_test.Harness) {
57 th.WriteC("comp", `
58 namePrefix: comp-
59 replicas:
60 - name: storefront
61 count: 3
62 resources:
63 - stub.yaml
64 configMapGenerator:
65 - name: my-configmap
66 behavior: merge
67 literals:
68 - testValue=blue
69 - compValue=red
70 `)
71 th.WriteF("comp/stub.yaml", `
72 apiVersion: v1
73 kind: Deployment
74 metadata:
75 name: stub
76 spec:
77 replicas: 1
78 `)
79 }
80
81 func writeOverlayProd(th kusttest_test.Harness) {
82 th.WriteK("prod", `
83 resources:
84 - ../base
85 - db
86
87 components:
88 - ../comp
89 `)
90 writeDB(th)
91 }
92
93 func writeDB(th kusttest_test.Harness) {
94 deployment("db", "prod/db")(th)
95 }
96
97 func deployment(name string, path string) FileGen {
98 return writeF(path, fmt.Sprintf(`
99 apiVersion: v1
100 kind: Deployment
101 metadata:
102 name: %s
103 spec:
104 type: Logical
105 `, name))
106 }
107
108 func TestComponent(t *testing.T) {
109 testCases := map[string]struct {
110 input []FileGen
111 runPath string
112 expectedOutput string
113 }{
114
115
116 "basic-component": {
117 input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd},
118 runPath: "prod",
119 expectedOutput: `
120 apiVersion: v1
121 kind: Deployment
122 metadata:
123 name: comp-storefront
124 spec:
125 replicas: 3
126 ---
127 apiVersion: v1
128 data:
129 compValue: red
130 otherValue: green
131 testValue: blue
132 kind: ConfigMap
133 metadata:
134 name: comp-my-configmap-97647ckcmg
135 ---
136 apiVersion: v1
137 kind: Deployment
138 metadata:
139 name: comp-db
140 spec:
141 type: Logical
142 ---
143 apiVersion: v1
144 kind: Deployment
145 metadata:
146 name: comp-stub
147 spec:
148 replicas: 1
149 `,
150 },
151 "multiple-components": {
152 input: []FileGen{writeTestBase, writeTestComponent, writeDB,
153 writeC("additionalcomp", `
154 configMapGenerator:
155 - name: my-configmap
156 behavior: merge
157 literals:
158 - otherValue=orange
159 `),
160 writeK("prod", `
161 resources:
162 - ../base
163 - db
164
165 components:
166 - ../comp
167 - ../additionalcomp
168 `),
169 },
170 runPath: "prod",
171 expectedOutput: `
172 apiVersion: v1
173 kind: Deployment
174 metadata:
175 name: comp-storefront
176 spec:
177 replicas: 3
178 ---
179 apiVersion: v1
180 data:
181 compValue: red
182 otherValue: orange
183 testValue: blue
184 kind: ConfigMap
185 metadata:
186 name: comp-my-configmap-g486mb229k
187 ---
188 apiVersion: v1
189 kind: Deployment
190 metadata:
191 name: comp-db
192 spec:
193 type: Logical
194 ---
195 apiVersion: v1
196 kind: Deployment
197 metadata:
198 name: comp-stub
199 spec:
200 replicas: 1
201 `,
202 },
203 "nested-components": {
204 input: []FileGen{writeTestBase, writeTestComponent, writeDB,
205 writeC("additionalcomp", `
206 components:
207 - ../comp
208 configMapGenerator:
209 - name: my-configmap
210 behavior: merge
211 literals:
212 - otherValue=orange
213 `),
214 writeK("prod", `
215 resources:
216 - ../base
217 - db
218
219 components:
220 - ../additionalcomp
221 `),
222 },
223 runPath: "prod",
224 expectedOutput: `
225 apiVersion: v1
226 kind: Deployment
227 metadata:
228 name: comp-storefront
229 spec:
230 replicas: 3
231 ---
232 apiVersion: v1
233 data:
234 compValue: red
235 otherValue: orange
236 testValue: blue
237 kind: ConfigMap
238 metadata:
239 name: comp-my-configmap-g486mb229k
240 ---
241 apiVersion: v1
242 kind: Deployment
243 metadata:
244 name: comp-db
245 spec:
246 type: Logical
247 ---
248 apiVersion: v1
249 kind: Deployment
250 metadata:
251 name: comp-stub
252 spec:
253 replicas: 1
254 `,
255 },
256
257
258 "basic-component-with-repeated-base": {
259 input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd,
260 writeK("repeated", `
261 resources:
262 - ../base
263 - ../prod
264 `),
265 },
266 runPath: "repeated",
267 expectedOutput: `
268 apiVersion: v1
269 kind: Deployment
270 metadata:
271 name: storefront
272 spec:
273 replicas: 1
274 ---
275 apiVersion: v1
276 data:
277 otherValue: green
278 testValue: purple
279 kind: ConfigMap
280 metadata:
281 name: my-configmap-9cd648hm8f
282 ---
283 apiVersion: v1
284 kind: Deployment
285 metadata:
286 name: comp-storefront
287 spec:
288 replicas: 3
289 ---
290 apiVersion: v1
291 data:
292 compValue: red
293 otherValue: green
294 testValue: blue
295 kind: ConfigMap
296 metadata:
297 name: comp-my-configmap-97647ckcmg
298 ---
299 apiVersion: v1
300 kind: Deployment
301 metadata:
302 name: comp-db
303 spec:
304 type: Logical
305 ---
306 apiVersion: v1
307 kind: Deployment
308 metadata:
309 name: comp-stub
310 spec:
311 replicas: 1
312 `,
313 },
314 "applying-component-directly-should-be-same-as-kustomization": {
315 input: []FileGen{writeTestBase, writeTestComponent,
316 writeC("direct-component", `
317 resources:
318 - ../base
319 configMapGenerator:
320 - name: my-configmap
321 behavior: merge
322 literals:
323 - compValue=red
324 - testValue=blue
325 `),
326 },
327 runPath: "direct-component",
328 expectedOutput: `
329 apiVersion: v1
330 kind: Deployment
331 metadata:
332 name: storefront
333 spec:
334 replicas: 1
335 ---
336 apiVersion: v1
337 data:
338 compValue: red
339 otherValue: green
340 testValue: blue
341 kind: ConfigMap
342 metadata:
343 name: my-configmap-97647ckcmg
344 `,
345 },
346 "missing-optional-component-api-version": {
347 input: []FileGen{writeTestBase, writeOverlayProd,
348 writeF("comp/"+konfig.DefaultKustomizationFileName(), `
349 kind: Component
350 configMapGenerator:
351 - name: my-configmap
352 behavior: merge
353 literals:
354 - otherValue=orange
355 `),
356 },
357 runPath: "prod",
358 expectedOutput: `
359 apiVersion: v1
360 kind: Deployment
361 metadata:
362 name: storefront
363 spec:
364 replicas: 1
365 ---
366 apiVersion: v1
367 data:
368 otherValue: orange
369 testValue: purple
370 kind: ConfigMap
371 metadata:
372 name: my-configmap-6hhdg8gkdg
373 ---
374 apiVersion: v1
375 kind: Deployment
376 metadata:
377 name: db
378 spec:
379 type: Logical
380 `,
381 },
382
383
384 "components-can-add-the-same-base-if-the-first-renames-resources": {
385 input: []FileGen{writeTestBase,
386 deployment("proxy", "comp-a/proxy.yaml"),
387 writeC("comp-a", `
388 resources:
389 - ../base
390
391 nameSuffix: "-a"
392 `),
393 writeC("comp-b", `
394 resources:
395 - ../base
396
397 nameSuffix: "-b"
398 `),
399 writeK("prod", `
400 components:
401 - ../comp-a
402 - ../comp-b`),
403 },
404 runPath: "prod",
405 expectedOutput: `
406 apiVersion: v1
407 kind: Deployment
408 metadata:
409 name: storefront-a-b
410 spec:
411 replicas: 1
412 ---
413 apiVersion: v1
414 data:
415 otherValue: green
416 testValue: purple
417 kind: ConfigMap
418 metadata:
419 name: my-configmap-a-b-9cd648hm8f
420 ---
421 apiVersion: v1
422 kind: Deployment
423 metadata:
424 name: storefront-b
425 spec:
426 replicas: 1
427 ---
428 apiVersion: v1
429 data:
430 otherValue: green
431 testValue: purple
432 kind: ConfigMap
433 metadata:
434 name: my-configmap-b-9cd648hm8f
435 `,
436 },
437
438 "multiple-bases-can-add-the-same-component-if-it-doesn-not-define-named-entities": {
439 input: []FileGen{
440 writeC("comp", `
441 namespace: prod
442 `),
443 writeK("base-a", `
444 resources:
445 - proxy.yaml
446
447 components:
448 - ../comp
449 `),
450 deployment("proxy-a", "base-a/proxy.yaml"),
451 writeK("base-b", `
452 resources:
453 - proxy.yaml
454
455 components:
456 - ../comp
457 `),
458 deployment("proxy-b", "base-b/proxy.yaml"),
459 writeK("prod", `
460 resources:
461 - proxy.yaml
462 - ../base-a
463 - ../base-b
464 `),
465 deployment("proxy-prod", "prod/proxy.yaml"),
466 },
467 runPath: "prod",
468
469
470 expectedOutput: `
471 apiVersion: v1
472 kind: Deployment
473 metadata:
474 name: proxy-prod
475 spec:
476 type: Logical
477 ---
478 apiVersion: v1
479 kind: Deployment
480 metadata:
481 name: proxy-a
482 namespace: prod
483 spec:
484 type: Logical
485 ---
486 apiVersion: v1
487 kind: Deployment
488 metadata:
489 name: proxy-b
490 namespace: prod
491 spec:
492 type: Logical
493 `,
494 },
495 }
496
497 for tn, tc := range testCases {
498 t.Run(tn, func(t *testing.T) {
499 th := kusttest_test.MakeHarness(t)
500 for _, f := range tc.input {
501 f(th)
502 }
503 m := th.Run(tc.runPath, th.MakeDefaultOptions())
504 th.AssertActualEqualsExpected(m, tc.expectedOutput)
505 })
506 }
507 }
508
509 func TestComponentErrors(t *testing.T) {
510 testCases := map[string]struct {
511 input []FileGen
512 runPath string
513 expectedError string
514 }{
515 "components-cannot-be-added-to-resources": {
516 input: []FileGen{writeTestBase, writeTestComponent,
517 writeK("compinres", `
518 resources:
519 - ../base
520 - ../comp
521 `),
522 },
523 runPath: "compinres",
524 expectedError: "expected kind != 'Component' for path '/comp'",
525 },
526 "kustomizations-cannot-be-added-to-components": {
527 input: []FileGen{writeTestBase, writeTestComponent,
528 writeK("kustincomponents", `
529 components:
530 - ../base
531 - ../comp
532 `),
533 },
534 runPath: "kustincomponents",
535 expectedError: "accumulating components: accumulateDirectory: \"expected kind 'Component' for path " +
536 "'/base' but got 'Kustomization'",
537 },
538 "files-cannot-be-added-to-components-list": {
539 input: []FileGen{writeTestBase,
540 writeF("filesincomponents/stub.yaml", `
541 apiVersion: v1
542 kind: Deployment
543 metadata:
544 name: stub
545 spec:
546 replicas: 1
547 `),
548 writeK("filesincomponents", `
549 components:
550 - stub.yaml
551 - ../comp
552 `),
553 },
554 runPath: "filesincomponents",
555 expectedError: fmt.Sprintf("%s: '%s'", loader.ErrRtNotDir.Error(), "/filesincomponents/stub.yaml"),
556 },
557 "invalid-component-api-version": {
558 input: []FileGen{writeTestBase, writeOverlayProd,
559 writeF("comp/"+konfig.DefaultKustomizationFileName(), `
560 apiVersion: kustomize.config.k8s.io/v1beta1
561 kind: Component
562 configMapGenerator:
563 - name: my-configmap
564 behavior: merge
565 literals:
566 - otherValue=orange
567 `),
568 },
569 runPath: "prod",
570 expectedError: "apiVersion for Component should be kustomize.config.k8s.io/v1alpha1",
571 },
572 "components-cannot-add-the-same-resource": {
573 input: []FileGen{writeTestBase,
574 writeC("comp-a", `
575 resources:
576 - proxy.yaml
577 `),
578 deployment("proxy", "comp-a/proxy.yaml"),
579 writeC("comp-b", `
580 resources:
581 - proxy.yaml
582 `),
583 deployment("proxy", "comp-b/proxy.yaml"),
584 writeK("prod", `
585 resources:
586 - ../base
587
588 components:
589 - ../comp-a
590 - ../comp-b`),
591 },
592 runPath: "prod",
593 expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
594 },
595 "components-cannot-add-the-same-base": {
596 input: []FileGen{writeTestBase,
597 deployment("proxy", "comp-a/proxy.yaml"),
598 writeC("comp-a", `
599 resources:
600 - ../base
601 `),
602 writeC("comp-b", `
603 resources:
604 - ../base
605 `),
606 writeK("prod", `
607 components:
608 - ../comp-a
609 - ../comp-b`),
610 },
611 runPath: "prod",
612 expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/storefront.[noNs]",
613 },
614 "components-cannot-add-bases-containing-the-same-resource": {
615 input: []FileGen{writeTestBase,
616 writeC("comp-a", `
617 resources:
618 - ../base-a
619 `),
620 writeK("base-a", `
621 resources:
622 - proxy.yaml
623 `),
624 deployment("proxy", "base-a/proxy.yaml"),
625 writeC("comp-b", `
626 resources:
627 - ../base-b
628 `),
629 writeK("base-b", `
630 resources:
631 - proxy.yaml
632 `),
633 deployment("proxy", "base-b/proxy.yaml"),
634 writeK("prod", `
635 resources:
636 - ../base
637
638 components:
639 - ../comp-a
640 - ../comp-b`),
641 },
642 runPath: "prod",
643 expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
644 },
645 }
646
647 for tn, tc := range testCases {
648 t.Run(tn, func(t *testing.T) {
649 th := kusttest_test.MakeHarness(t)
650 for _, f := range tc.input {
651 f(th)
652 }
653 err := th.RunWithErr(tc.runPath, th.MakeDefaultOptions())
654 if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
655 t.Fatalf("unexpected error: %s", err)
656 }
657 })
658 }
659 }
660
661 func TestOrderOfAccumulatedComponent(t *testing.T) {
662 tests := map[string]struct {
663 input []FileGen
664 expectedOutput string
665 }{
666 "components_using_a_generated_resource_by_configMapGenerator": {
667 input: []FileGen{
668 writeK("", `
669 resources:
670 - resource.yaml
671 components:
672 - components
673 configMapGenerator:
674 - name: generated-resource
675 literals:
676 - key=value
677 options:
678 disableNameSuffixHash: true`),
679 writeF("resource.yaml", `
680 apiVersion: v1
681 kind: ConfigMap
682 metadata:
683 name: config-from-resources
684 data:
685 foo: bar`),
686 writeC("/components", `
687 apiVersion: kustomize.config.k8s.io/v1alpha1
688 kind: Component
689 nameSuffix: -suffix
690 `),
691 },
692 expectedOutput: `
693 apiVersion: v1
694 data:
695 foo: bar
696 kind: ConfigMap
697 metadata:
698 name: config-from-resources-suffix
699 ---
700 apiVersion: v1
701 data:
702 key: value
703 kind: ConfigMap
704 metadata:
705 name: generated-resource-suffix
706 `},
707 "components_are_applied_before_replacements_transformer_applied": {
708 input: []FileGen{
709 writeK("", `
710 resources:
711 - resource.yaml
712 components:
713 - components
714 replacements:
715 - source:
716 kind: Pod
717 name: myapp-pod
718 fieldPath: metadata.namespace
719 targets:
720 - select:
721 kind: Pod
722 name: myapp-pod
723 fieldPaths:
724 - spec.containers.[name=myapp-container].env.[name=CURRENT_POD_NAMESPACE].value`),
725 writeF("resource.yaml", `
726 apiVersion: v1
727 kind: Pod
728 metadata:
729 name: myapp-pod
730 namespace: dev-assa
731 spec:
732 containers:
733 - image: busybox
734 name: myapp-container
735 env:
736 - name: CURRENT_POD_NAMESPACE
737 value: "$(PLACEHOLDER)"`),
738 writeC("/components", `
739 apiVersion: kustomize.config.k8s.io/v1alpha1
740 kind: Component
741 namespace: kustomize-namespace`),
742 },
743 expectedOutput: `
744 apiVersion: v1
745 kind: Pod
746 metadata:
747 name: myapp-pod
748 namespace: kustomize-namespace
749 spec:
750 containers:
751 - env:
752 - name: CURRENT_POD_NAMESPACE
753 value: kustomize-namespace
754 image: busybox
755 name: myapp-container
756 `},
757 }
758
759 for testName, test := range tests {
760 t.Run(testName, func(t *testing.T) {
761 th := kusttest_test.MakeHarness(t)
762 for _, f := range test.input {
763 f(th)
764 }
765 m := th.Run(".", th.MakeDefaultOptions())
766 th.AssertActualEqualsExpected(m, test.expectedOutput)
767 })
768 }
769 }
770
View as plain text