1
16
17 package config
18
19 import (
20 "fmt"
21 "reflect"
22 "testing"
23 "time"
24
25 "github.com/google/go-cmp/cmp"
26 "github.com/lithammer/dedent"
27
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/version"
31 apimachineryversion "k8s.io/apimachinery/pkg/version"
32
33 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
34 kubeadmapiv1old "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
35 kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
36 "k8s.io/kubernetes/cmd/kubeadm/app/constants"
37 kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
38 )
39
40 const KubeadmGroupName = "kubeadm.k8s.io"
41
42 func TestValidateSupportedVersion(t *testing.T) {
43 tests := []struct {
44 gv schema.GroupVersion
45 allowDeprecated bool
46 allowExperimental bool
47 expectedErr bool
48 }{
49 {
50 gv: schema.GroupVersion{
51 Group: KubeadmGroupName,
52 Version: "v1alpha1",
53 },
54 expectedErr: true,
55 },
56 {
57 gv: schema.GroupVersion{
58 Group: KubeadmGroupName,
59 Version: "v1alpha2",
60 },
61 expectedErr: true,
62 },
63 {
64 gv: schema.GroupVersion{
65 Group: KubeadmGroupName,
66 Version: "v1alpha3",
67 },
68 expectedErr: true,
69 },
70 {
71 gv: schema.GroupVersion{
72 Group: KubeadmGroupName,
73 Version: "v1beta1",
74 },
75 expectedErr: true,
76 },
77 {
78 gv: schema.GroupVersion{
79 Group: KubeadmGroupName,
80 Version: "v1beta2",
81 },
82 expectedErr: true,
83 },
84 {
85 gv: schema.GroupVersion{
86 Group: KubeadmGroupName,
87 Version: "v1beta3",
88 },
89 },
90 {
91 gv: schema.GroupVersion{
92 Group: "foo.k8s.io",
93 Version: "v1",
94 },
95 },
96 {
97 gv: schema.GroupVersion{
98 Group: KubeadmGroupName,
99 Version: "v1beta4",
100 },
101 allowExperimental: true,
102 },
103 {
104 gv: schema.GroupVersion{
105 Group: KubeadmGroupName,
106 Version: "v1beta4",
107 },
108 expectedErr: true,
109 },
110 }
111
112 for _, rt := range tests {
113 t.Run(fmt.Sprintf("%s/allowDeprecated:%t", rt.gv, rt.allowDeprecated), func(t *testing.T) {
114 err := validateSupportedVersion(rt.gv, rt.allowDeprecated, rt.allowExperimental)
115 if rt.expectedErr && err == nil {
116 t.Error("unexpected success")
117 } else if !rt.expectedErr && err != nil {
118 t.Errorf("unexpected failure: %v", err)
119 }
120 })
121 }
122 }
123
124 func TestLowercaseSANs(t *testing.T) {
125 tests := []struct {
126 name string
127 in []string
128 out []string
129 }{
130 {
131 name: "empty struct",
132 },
133 {
134 name: "already lowercase",
135 in: []string{"example.k8s.io"},
136 out: []string{"example.k8s.io"},
137 },
138 {
139 name: "ip addresses and uppercase",
140 in: []string{"EXAMPLE.k8s.io", "10.100.0.1"},
141 out: []string{"example.k8s.io", "10.100.0.1"},
142 },
143 {
144 name: "punycode and uppercase",
145 in: []string{"xn--7gq663byk9a.xn--fiqz9s", "ANOTHEREXAMPLE.k8s.io"},
146 out: []string{"xn--7gq663byk9a.xn--fiqz9s", "anotherexample.k8s.io"},
147 },
148 }
149
150 for _, test := range tests {
151 t.Run(test.name, func(t *testing.T) {
152 cfg := &kubeadmapiv1.ClusterConfiguration{
153 APIServer: kubeadmapiv1.APIServer{
154 CertSANs: test.in,
155 },
156 }
157
158 LowercaseSANs(cfg.APIServer.CertSANs)
159
160 if len(cfg.APIServer.CertSANs) != len(test.out) {
161 t.Fatalf("expected %d elements, got %d", len(test.out), len(cfg.APIServer.CertSANs))
162 }
163
164 for i, expected := range test.out {
165 if cfg.APIServer.CertSANs[i] != expected {
166 t.Errorf("expected element %d to be %q, got %q", i, expected, cfg.APIServer.CertSANs[i])
167 }
168 }
169 })
170 }
171 }
172
173 func TestVerifyAPIServerBindAddress(t *testing.T) {
174 tests := []struct {
175 name string
176 address string
177 expectedError bool
178 }{
179 {
180 name: "valid address: IPV4",
181 address: "192.168.0.1",
182 },
183 {
184 name: "valid address: IPV6",
185 address: "2001:db8:85a3::8a2e:370:7334",
186 },
187 {
188 name: "valid address 127.0.0.1",
189 address: "127.0.0.1",
190 expectedError: false,
191 },
192 {
193 name: "invalid address: not a global unicast 0.0.0.0",
194 address: "0.0.0.0",
195 expectedError: true,
196 },
197 {
198 name: "invalid address: not a global unicast ::",
199 address: "::",
200 expectedError: true,
201 },
202 {
203 name: "invalid address: cannot parse IPV4",
204 address: "255.255.255.255.255",
205 expectedError: true,
206 },
207 {
208 name: "invalid address: cannot parse IPV6",
209 address: "2a00:800::2a00:800:10102a00",
210 expectedError: true,
211 },
212 }
213
214 for _, test := range tests {
215 t.Run(test.name, func(t *testing.T) {
216 if err := VerifyAPIServerBindAddress(test.address); (err != nil) != test.expectedError {
217 t.Errorf("expected error: %v, got %v, error: %v", test.expectedError, (err != nil), err)
218 }
219 })
220 }
221 }
222
223
224
225
226
227 func TestMigrateOldConfig(t *testing.T) {
228 var (
229 gv = kubeadmapiv1old.SchemeGroupVersion.String()
230 gvExperimental = kubeadmapiv1.SchemeGroupVersion.String()
231 )
232 tests := []struct {
233 name string
234 oldCfg string
235 expectedKinds []string
236 expectErr bool
237 allowExperimental bool
238 }{
239 {
240 name: "empty file produces empty result",
241 oldCfg: "",
242 expectErr: false,
243 },
244 {
245 name: "bad config produces error",
246 oldCfg: dedent.Dedent(fmt.Sprintf(`
247 apiVersion: %s
248 `, gv)),
249 expectErr: true,
250 },
251 {
252 name: "unknown API produces error",
253 oldCfg: dedent.Dedent(fmt.Sprintf(`
254 apiVersion: %s
255 kind: Foo
256 `, gv)),
257 expectErr: true,
258 },
259 {
260 name: "InitConfiguration only gets migrated",
261 oldCfg: dedent.Dedent(fmt.Sprintf(`
262 apiVersion: %s
263 kind: InitConfiguration
264 `, gv)),
265 expectedKinds: []string{
266 constants.InitConfigurationKind,
267 constants.ClusterConfigurationKind,
268 },
269 expectErr: false,
270 },
271 {
272 name: "ClusterConfiguration only gets migrated",
273 oldCfg: dedent.Dedent(fmt.Sprintf(`
274 apiVersion: %s
275 kind: ClusterConfiguration
276 `, gv)),
277 expectedKinds: []string{
278 constants.InitConfigurationKind,
279 constants.ClusterConfigurationKind,
280 },
281 expectErr: false,
282 },
283 {
284 name: "JoinConfiguration only gets migrated",
285 oldCfg: dedent.Dedent(fmt.Sprintf(`
286 apiVersion: %s
287 kind: JoinConfiguration
288 discovery:
289 bootstrapToken:
290 token: abcdef.0123456789abcdef
291 apiServerEndpoint: kube-apiserver:6443
292 unsafeSkipCAVerification: true
293 `, gv)),
294 expectedKinds: []string{
295 constants.JoinConfigurationKind,
296 },
297 expectErr: false,
298 },
299 {
300 name: "Init + Cluster Configurations are migrated",
301 oldCfg: dedent.Dedent(fmt.Sprintf(`
302 apiVersion: %s
303 kind: InitConfiguration
304 ---
305 apiVersion: %[1]s
306 kind: ClusterConfiguration
307 `, gv)),
308 expectedKinds: []string{
309 constants.InitConfigurationKind,
310 constants.ClusterConfigurationKind,
311 },
312 expectErr: false,
313 },
314 {
315 name: "Init + Join Configurations are migrated",
316 oldCfg: dedent.Dedent(fmt.Sprintf(`
317 apiVersion: %s
318 kind: InitConfiguration
319 ---
320 apiVersion: %[1]s
321 kind: JoinConfiguration
322 discovery:
323 bootstrapToken:
324 token: abcdef.0123456789abcdef
325 apiServerEndpoint: kube-apiserver:6443
326 unsafeSkipCAVerification: true
327 `, gv)),
328 expectedKinds: []string{
329 constants.InitConfigurationKind,
330 constants.ClusterConfigurationKind,
331 constants.JoinConfigurationKind,
332 },
333 expectErr: false,
334 },
335 {
336 name: "Cluster + Join Configurations are migrated",
337 oldCfg: dedent.Dedent(fmt.Sprintf(`
338 apiVersion: %s
339 kind: ClusterConfiguration
340 ---
341 apiVersion: %[1]s
342 kind: JoinConfiguration
343 discovery:
344 bootstrapToken:
345 token: abcdef.0123456789abcdef
346 apiServerEndpoint: kube-apiserver:6443
347 unsafeSkipCAVerification: true
348 `, gv)),
349 expectedKinds: []string{
350 constants.InitConfigurationKind,
351 constants.ClusterConfigurationKind,
352 constants.JoinConfigurationKind,
353 },
354 expectErr: false,
355 },
356 {
357 name: "Init + Cluster + Join Configurations are migrated",
358 oldCfg: dedent.Dedent(fmt.Sprintf(`
359 apiVersion: %s
360 kind: InitConfiguration
361 ---
362 apiVersion: %[1]s
363 kind: ClusterConfiguration
364 ---
365 apiVersion: %[1]s
366 kind: JoinConfiguration
367 discovery:
368 bootstrapToken:
369 token: abcdef.0123456789abcdef
370 apiServerEndpoint: kube-apiserver:6443
371 unsafeSkipCAVerification: true
372 `, gv)),
373 expectedKinds: []string{
374 constants.InitConfigurationKind,
375 constants.ClusterConfigurationKind,
376 constants.JoinConfigurationKind,
377 },
378 expectErr: false,
379 },
380 {
381 name: "component configs are not migrated",
382 oldCfg: dedent.Dedent(fmt.Sprintf(`
383 apiVersion: %s
384 kind: InitConfiguration
385 ---
386 apiVersion: %[1]s
387 kind: ClusterConfiguration
388 ---
389 apiVersion: %[1]s
390 kind: JoinConfiguration
391 discovery:
392 bootstrapToken:
393 token: abcdef.0123456789abcdef
394 apiServerEndpoint: kube-apiserver:6443
395 unsafeSkipCAVerification: true
396 ---
397 apiVersion: kubeproxy.config.k8s.io/v1alpha1
398 kind: KubeProxyConfiguration
399 ---
400 apiVersion: kubelet.config.k8s.io/v1beta1
401 kind: KubeletConfiguration
402 `, gv)),
403 expectedKinds: []string{
404 constants.InitConfigurationKind,
405 constants.ClusterConfigurationKind,
406 constants.JoinConfigurationKind,
407 },
408 expectErr: false,
409 },
410 {
411 name: "ClusterConfiguration gets migrated from experimental API",
412 oldCfg: dedent.Dedent(fmt.Sprintf(`
413 apiVersion: %s
414 kind: ClusterConfiguration
415 `, gvExperimental)),
416 expectedKinds: []string{
417 constants.InitConfigurationKind,
418 constants.ClusterConfigurationKind,
419 },
420 allowExperimental: true,
421 expectErr: false,
422 },
423 {
424 name: "ClusterConfiguration from experimental API cannot be migrated",
425 oldCfg: dedent.Dedent(fmt.Sprintf(`
426 apiVersion: %s
427 kind: ClusterConfiguration
428 `, gvExperimental)),
429 allowExperimental: false,
430 expectErr: true,
431 },
432 {
433 name: "ResetConfiguration gets migrated from experimental API",
434 oldCfg: dedent.Dedent(fmt.Sprintf(`
435 apiVersion: %s
436 kind: ResetConfiguration
437 force: true
438 cleanupTmpDir: true
439 criSocket: unix:///var/run/containerd/containerd.sock
440 certificatesDir: /etc/kubernetes/pki
441 `, gvExperimental)),
442 expectedKinds: []string{
443 constants.ResetConfigurationKind,
444 },
445 allowExperimental: true,
446 expectErr: false,
447 },
448 {
449 name: "ResetConfiguration from experimental API cannot be migrated",
450 oldCfg: dedent.Dedent(fmt.Sprintf(`
451 apiVersion: %s
452 kind: ResetConfiguration
453 `, gvExperimental)),
454 allowExperimental: false,
455 expectErr: true,
456 },
457 }
458
459 for _, test := range tests {
460 t.Run(test.name, func(t *testing.T) {
461 b, err := MigrateOldConfig([]byte(test.oldCfg), test.allowExperimental, defaultEmptyMigrateMutators())
462 if test.expectErr {
463 if err == nil {
464 t.Fatalf("unexpected success:\n%s", b)
465 }
466 } else {
467 if err != nil {
468 t.Fatalf("unexpected failure: %v", err)
469 }
470 gvks, err := kubeadmutil.GroupVersionKindsFromBytes(b)
471 if err != nil {
472 t.Fatalf("unexpected error returned by GroupVersionKindsFromBytes: %v", err)
473 }
474 if len(gvks) != len(test.expectedKinds) {
475 t.Fatalf("length mismatch between resulting gvks and expected kinds:\n\tlen(gvks)=%d\n\tlen(expectedKinds)=%d",
476 len(gvks), len(test.expectedKinds))
477 }
478 for _, expectedKind := range test.expectedKinds {
479 if !kubeadmutil.GroupVersionKindsHasKind(gvks, expectedKind) {
480 t.Fatalf("migration failed to produce config kind: %s", expectedKind)
481 }
482 }
483 expectedGV := gv
484 if test.allowExperimental {
485 expectedGV = gvExperimental
486 }
487 for _, gvk := range gvks {
488 if gvk.GroupVersion().String() != expectedGV {
489 t.Errorf("GV mismatch, expected GV: %s, got GV: %s", expectedGV, gvk.GroupVersion().String())
490 }
491 }
492 }
493 })
494 }
495 }
496
497
498
499
500
501 func TestValidateConfig(t *testing.T) {
502 var (
503 gv = kubeadmapiv1old.SchemeGroupVersion.String()
504 gvExperimental = kubeadmapiv1.SchemeGroupVersion.String()
505 )
506 tests := []struct {
507 name string
508 cfg string
509 expectedError bool
510 allowExperimental bool
511 }{
512 {
513 name: "invalid subdomain",
514 cfg: dedent.Dedent(fmt.Sprintf(`
515 apiVersion: %s
516 kind: InitConfiguration
517 name: foo bar # not a valid subdomain
518 `, gv)),
519 expectedError: true,
520 },
521 {
522 name: "unknown API GVK",
523 cfg: dedent.Dedent(`
524 apiVersion: foo/bar # not a valid GroupVersion
525 kind: zzz # not a valid Kind
526 `),
527 expectedError: true,
528 },
529 {
530 name: "legacy API GVK",
531 cfg: dedent.Dedent(`
532 apiVersion: kubeadm.k8s.io/v1beta1 # legacy API
533 kind: InitConfiguration
534 `),
535 expectedError: true,
536 },
537 {
538 name: "unknown field",
539 cfg: dedent.Dedent(fmt.Sprintf(`
540 apiVersion: %s
541 kind: InitConfiguration
542 foo: bar
543 `, gv)),
544 expectedError: true,
545 },
546 {
547 name: "valid",
548 cfg: dedent.Dedent(fmt.Sprintf(`
549 apiVersion: %s
550 kind: InitConfiguration
551 `, gv)),
552 expectedError: false,
553 },
554 {
555 name: "valid: experimental API",
556 cfg: dedent.Dedent(fmt.Sprintf(`
557 apiVersion: %s
558 kind: InitConfiguration
559 `, gvExperimental)),
560 expectedError: false,
561 allowExperimental: true,
562 },
563 {
564 name: "invalid: experimental API",
565 cfg: dedent.Dedent(fmt.Sprintf(`
566 apiVersion: %s
567 kind: InitConfiguration
568 `, gvExperimental)),
569 expectedError: true,
570 allowExperimental: false,
571 },
572 {
573 name: "valid ResetConfiguration",
574 cfg: dedent.Dedent(fmt.Sprintf(`
575 apiVersion: %s
576 kind: ResetConfiguration
577 force: true
578 `, gvExperimental)),
579 expectedError: false,
580 allowExperimental: true,
581 },
582 {
583 name: "invalid field in ResetConfiguration",
584 cfg: dedent.Dedent(fmt.Sprintf(`
585 apiVersion: %s
586 kind: ResetConfiguration
587 foo: bar
588 `, gvExperimental)),
589 expectedError: true,
590 allowExperimental: true,
591 },
592 {
593 name: "experimental API is not allowed in ResetConfiguration",
594 cfg: dedent.Dedent(fmt.Sprintf(`
595 apiVersion: %s
596 kind: ResetConfiguration
597 `, gvExperimental)),
598 expectedError: true,
599 allowExperimental: false,
600 },
601 }
602
603 for _, test := range tests {
604 t.Run(test.name, func(t *testing.T) {
605 err := ValidateConfig([]byte(test.cfg), test.allowExperimental)
606 if (err != nil) != test.expectedError {
607 t.Fatalf("expected error: %v, got: %v, error: %v", test.expectedError, (err != nil), err)
608 }
609 })
610 }
611 }
612
613 func TestIsKubeadmPrereleaseVersion(t *testing.T) {
614 validVersionInfo := &apimachineryversion.Info{Major: "1", GitVersion: "v1.23.0-alpha.1"}
615 tests := []struct {
616 name string
617 versionInfo *apimachineryversion.Info
618 k8sVersion *version.Version
619 mcpVersion *version.Version
620 expectedResult bool
621 }{
622 {
623 name: "invalid versionInfo",
624 versionInfo: &apimachineryversion.Info{},
625 expectedResult: false,
626 },
627 {
628 name: "kubeadm is not a prerelease version",
629 versionInfo: &apimachineryversion.Info{Major: "1", GitVersion: "v1.23.0"},
630 expectedResult: false,
631 },
632 {
633 name: "mcpVersion is equal to k8sVersion",
634 versionInfo: validVersionInfo,
635 k8sVersion: version.MustParseSemantic("v1.21.0"),
636 mcpVersion: version.MustParseSemantic("v1.21.0"),
637 expectedResult: true,
638 },
639 {
640 name: "k8sVersion is 1 MINOR version older than mcpVersion",
641 versionInfo: validVersionInfo,
642 k8sVersion: version.MustParseSemantic("v1.21.0"),
643 mcpVersion: version.MustParseSemantic("v1.22.0"),
644 expectedResult: true,
645 },
646 {
647 name: "k8sVersion is 2 MINOR versions older than mcpVersion",
648 versionInfo: validVersionInfo,
649 k8sVersion: version.MustParseSemantic("v1.21.0"),
650 mcpVersion: version.MustParseSemantic("v1.23.0"),
651 expectedResult: false,
652 },
653 }
654
655 for _, tc := range tests {
656 t.Run(tc.name, func(t *testing.T) {
657 result := isKubeadmPrereleaseVersion(tc.versionInfo, tc.k8sVersion, tc.mcpVersion)
658 if result != tc.expectedResult {
659 t.Errorf("expected result: %v, got %v", tc.expectedResult, result)
660 }
661 })
662 }
663 }
664
665 func TestNormalizeKubernetesVersion(t *testing.T) {
666 validVersion := fmt.Sprintf("v%v", constants.MinimumControlPlaneVersion)
667 validCIVersion := fmt.Sprintf("%s%s", constants.CIKubernetesVersionPrefix, validVersion)
668 tests := []struct {
669 name string
670 cfg *kubeadmapi.ClusterConfiguration
671 expectedCfg *kubeadmapi.ClusterConfiguration
672 expectErr bool
673 }{
674 {
675 name: "normal version, default image repository",
676 cfg: &kubeadmapi.ClusterConfiguration{
677 KubernetesVersion: validVersion,
678 ImageRepository: kubeadmapiv1.DefaultImageRepository,
679 },
680 expectedCfg: &kubeadmapi.ClusterConfiguration{
681 KubernetesVersion: validVersion,
682 CIKubernetesVersion: "",
683 ImageRepository: kubeadmapiv1.DefaultImageRepository,
684 CIImageRepository: "",
685 },
686 expectErr: false,
687 },
688 {
689 name: "normal version, custom image repository",
690 cfg: &kubeadmapi.ClusterConfiguration{
691 KubernetesVersion: validVersion,
692 ImageRepository: "custom.repository",
693 },
694 expectedCfg: &kubeadmapi.ClusterConfiguration{
695 KubernetesVersion: validVersion,
696 CIKubernetesVersion: "",
697 ImageRepository: "custom.repository",
698 CIImageRepository: "",
699 },
700 expectErr: false,
701 },
702 {
703 name: "ci version, default image repository",
704 cfg: &kubeadmapi.ClusterConfiguration{
705 KubernetesVersion: validCIVersion,
706 ImageRepository: kubeadmapiv1.DefaultImageRepository,
707 },
708 expectedCfg: &kubeadmapi.ClusterConfiguration{
709 KubernetesVersion: validVersion,
710 CIKubernetesVersion: validCIVersion,
711 ImageRepository: kubeadmapiv1.DefaultImageRepository,
712 CIImageRepository: constants.DefaultCIImageRepository,
713 },
714 expectErr: false,
715 },
716 {
717 name: "ci version, custom image repository",
718 cfg: &kubeadmapi.ClusterConfiguration{
719 KubernetesVersion: validCIVersion,
720 ImageRepository: "custom.repository",
721 },
722 expectedCfg: &kubeadmapi.ClusterConfiguration{
723 KubernetesVersion: validVersion,
724 CIKubernetesVersion: validCIVersion,
725 ImageRepository: "custom.repository",
726 CIImageRepository: "",
727 },
728 expectErr: false,
729 },
730 {
731 name: "unsupported old version",
732 cfg: &kubeadmapi.ClusterConfiguration{
733 KubernetesVersion: "v0.0.0",
734 ImageRepository: kubeadmapiv1.DefaultImageRepository,
735 },
736 expectedCfg: &kubeadmapi.ClusterConfiguration{
737 KubernetesVersion: "v0.0.0",
738 CIKubernetesVersion: "",
739 ImageRepository: kubeadmapiv1.DefaultImageRepository,
740 CIImageRepository: "",
741 },
742 expectErr: true,
743 },
744 }
745
746 for _, tc := range tests {
747 t.Run(tc.name, func(t *testing.T) {
748 err := NormalizeKubernetesVersion(tc.cfg)
749 if !reflect.DeepEqual(tc.cfg, tc.expectedCfg) {
750 t.Errorf("expected ClusterConfiguration: %#v, got %#v", tc.expectedCfg, tc.cfg)
751 }
752 if !tc.expectErr && err != nil {
753 t.Errorf("unexpected failure: %v", err)
754 }
755 })
756 }
757 }
758
759
760 func TestDefaultMigrateMutators(t *testing.T) {
761 tests := []struct {
762 name string
763 mutators migrateMutators
764 input []any
765 expected []any
766 expectedDiff bool
767 expectedError bool
768 }{
769 {
770 name: "mutate InitConfiguration",
771 mutators: defaultMigrateMutators(),
772 input: []any{&kubeadmapi.InitConfiguration{
773 ClusterConfiguration: kubeadmapi.ClusterConfiguration{
774 APIServer: kubeadmapi.APIServer{
775 TimeoutForControlPlane: &metav1.Duration{
776 Duration: 1234 * time.Millisecond,
777 },
778 },
779 },
780 Timeouts: &kubeadmapi.Timeouts{
781 ControlPlaneComponentHealthCheck: &metav1.Duration{},
782 },
783 }},
784 expected: []any{&kubeadmapi.InitConfiguration{
785 Timeouts: &kubeadmapi.Timeouts{
786 ControlPlaneComponentHealthCheck: &metav1.Duration{
787 Duration: 1234 * time.Millisecond,
788 },
789 },
790 }},
791 },
792 {
793 name: "mutate JoinConfiguration",
794 mutators: defaultMigrateMutators(),
795 input: []any{&kubeadmapi.JoinConfiguration{
796 Discovery: kubeadmapi.Discovery{
797 Timeout: &metav1.Duration{
798 Duration: 1234 * time.Microsecond,
799 },
800 },
801 Timeouts: &kubeadmapi.Timeouts{
802 Discovery: &metav1.Duration{},
803 },
804 }},
805 expected: []any{&kubeadmapi.JoinConfiguration{
806 Timeouts: &kubeadmapi.Timeouts{
807 Discovery: &metav1.Duration{
808 Duration: 1234 * time.Microsecond,
809 },
810 },
811 }},
812 },
813 {
814 name: "diff when mutating InitConfiguration",
815 mutators: defaultMigrateMutators(),
816 input: []any{&kubeadmapi.InitConfiguration{
817 ClusterConfiguration: kubeadmapi.ClusterConfiguration{
818 APIServer: kubeadmapi.APIServer{
819 TimeoutForControlPlane: &metav1.Duration{
820 Duration: 1234 * time.Millisecond,
821 },
822 },
823 },
824 Timeouts: &kubeadmapi.Timeouts{
825 ControlPlaneComponentHealthCheck: &metav1.Duration{},
826 },
827 }},
828 expected: []any{&kubeadmapi.InitConfiguration{
829 Timeouts: &kubeadmapi.Timeouts{
830 ControlPlaneComponentHealthCheck: &metav1.Duration{
831 Duration: 1 * time.Millisecond,
832 },
833 },
834 }},
835 expectedDiff: true,
836 },
837 {
838 name: "expect an error for a missing mutator",
839 mutators: migrateMutators{},
840 input: []any{&kubeadmapi.ResetConfiguration{}},
841 expectedError: true,
842 },
843 }
844
845 for _, tc := range tests {
846 t.Run(tc.name, func(t *testing.T) {
847 err := tc.mutators.mutate(tc.input)
848 if (err != nil) != tc.expectedError {
849 t.Fatalf("expected error: %v, got: %v, error: %v", tc.expectedError, (err != nil), err)
850 }
851 if err != nil {
852 return
853 }
854 diff := cmp.Diff(tc.expected, tc.input)
855 if (len(diff) > 0) != tc.expectedDiff {
856 t.Fatalf("got a diff with the expected config (-want,+got):\n%s", diff)
857 }
858 })
859 }
860 }
861
862 func TestIsKubeadmConfigPresent(t *testing.T) {
863 var tcases = []struct {
864 name string
865 gvkmap kubeadmapi.DocumentMap
866 expected bool
867 }{
868 {
869 name: " Wrong Group value",
870 gvkmap: kubeadmapi.DocumentMap{
871 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: []byte(`kind: Foo`),
872 },
873 expected: false,
874 },
875 {
876 name: "Empty Group value",
877 gvkmap: kubeadmapi.DocumentMap{
878 {Group: "", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
879 },
880 expected: false,
881 },
882 {
883 name: "Nil value",
884 gvkmap: nil,
885 expected: false,
886 },
887 {
888 name: "Correct Group value 1",
889 gvkmap: kubeadmapi.DocumentMap{
890 {Group: "kubeadm.k8s.io", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
891 },
892 expected: true,
893 },
894 {
895 name: "Correct Group value 2",
896 gvkmap: kubeadmapi.DocumentMap{
897 {Group: kubeadmapi.GroupName, Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
898 },
899 expected: true,
900 },
901 }
902 for _, tt := range tcases {
903 t.Run(tt.name, func(t *testing.T) {
904 if isKubeadmConfigPresent(tt.gvkmap) != tt.expected {
905 t.Error("unexpected result")
906 }
907 })
908 }
909 }
910
View as plain text