sigs.k8s.io/cluster-api@v1.6.3/internal/webhooks/clusterclass_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package webhooks 18 19 import ( 20 "strings" 21 "testing" 22 "time" 23 24 . "github.com/onsi/gomega" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 utilfeature "k8s.io/component-base/featuregate/testing" 29 "k8s.io/utils/pointer" 30 ctrl "sigs.k8s.io/controller-runtime" 31 "sigs.k8s.io/controller-runtime/pkg/client" 32 "sigs.k8s.io/controller-runtime/pkg/client/fake" 33 34 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 35 "sigs.k8s.io/cluster-api/api/v1beta1/index" 36 "sigs.k8s.io/cluster-api/feature" 37 "sigs.k8s.io/cluster-api/internal/test/builder" 38 "sigs.k8s.io/cluster-api/internal/webhooks/util" 39 ) 40 41 var ( 42 ctx = ctrl.SetupSignalHandler() 43 fakeScheme = runtime.NewScheme() 44 ) 45 46 func init() { 47 _ = clusterv1.AddToScheme(fakeScheme) 48 } 49 50 func TestClusterClassDefaultNamespaces(t *testing.T) { 51 // NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses. 52 // Enabling the feature flag temporarily for this test. 53 defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)() 54 55 namespace := "default" 56 57 in := builder.ClusterClass(namespace, "class1"). 58 WithInfrastructureClusterTemplate( 59 builder.InfrastructureClusterTemplate("", "infra1").Build()). 60 WithControlPlaneTemplate( 61 builder.ControlPlaneTemplate("", "cp1"). 62 Build()). 63 WithControlPlaneInfrastructureMachineTemplate( 64 builder.InfrastructureMachineTemplate("", "cpInfra1"). 65 Build()). 66 WithWorkerMachineDeploymentClasses( 67 *builder.MachineDeploymentClass("aa"). 68 WithInfrastructureTemplate( 69 builder.InfrastructureMachineTemplate("", "infra1").Build()). 70 WithBootstrapTemplate( 71 builder.BootstrapTemplate("", "bootstrap1").Build()). 72 Build()). 73 Build() 74 75 fakeClient := fake.NewClientBuilder(). 76 WithScheme(fakeScheme). 77 WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName). 78 Build() 79 80 // Create the webhook and add the fakeClient as its client. 81 webhook := &ClusterClass{Client: fakeClient} 82 t.Run("for ClusterClass", util.CustomDefaultValidateTest(ctx, in, webhook)) 83 84 g := NewWithT(t) 85 g.Expect(webhook.Default(ctx, in)).To(Succeed()) 86 87 // Namespace defaulted on references 88 g.Expect(in.Spec.Infrastructure.Ref.Namespace).To(Equal(namespace)) 89 g.Expect(in.Spec.ControlPlane.Ref.Namespace).To(Equal(namespace)) 90 g.Expect(in.Spec.ControlPlane.MachineInfrastructure.Ref.Namespace).To(Equal(namespace)) 91 for i := range in.Spec.Workers.MachineDeployments { 92 g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Bootstrap.Ref.Namespace).To(Equal(namespace)) 93 g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace)) 94 } 95 } 96 97 func TestClusterClassValidationFeatureGated(t *testing.T) { 98 // NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses. 99 100 tests := []struct { 101 name string 102 in *clusterv1.ClusterClass 103 old *clusterv1.ClusterClass 104 expectErr bool 105 }{ 106 { 107 name: "creation should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)", 108 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 109 WithInfrastructureClusterTemplate( 110 builder.InfrastructureClusterTemplate("", "infra1").Build()). 111 WithControlPlaneTemplate( 112 builder.ControlPlaneTemplate("", "cp1"). 113 Build()). 114 WithControlPlaneInfrastructureMachineTemplate( 115 builder.InfrastructureMachineTemplate("", "cpInfra1"). 116 Build()). 117 WithWorkerMachineDeploymentClasses( 118 *builder.MachineDeploymentClass("aa"). 119 WithInfrastructureTemplate( 120 builder.InfrastructureMachineTemplate("", "infra1").Build()). 121 WithBootstrapTemplate( 122 builder.BootstrapTemplate("", "bootstrap1").Build()). 123 Build()). 124 Build(), 125 expectErr: true, 126 }, 127 { 128 name: "update should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)", 129 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 130 WithInfrastructureClusterTemplate( 131 builder.InfrastructureClusterTemplate("", "infra1").Build()). 132 WithControlPlaneTemplate( 133 builder.ControlPlaneTemplate("", "cp1"). 134 Build()). 135 WithControlPlaneInfrastructureMachineTemplate( 136 builder.InfrastructureMachineTemplate("", "cpInfra1"). 137 Build()). 138 WithWorkerMachineDeploymentClasses( 139 *builder.MachineDeploymentClass("aa"). 140 WithInfrastructureTemplate( 141 builder.InfrastructureMachineTemplate("", "infra1").Build()). 142 WithBootstrapTemplate( 143 builder.BootstrapTemplate("", "bootstrap1").Build()). 144 Build()). 145 Build(), 146 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 147 WithInfrastructureClusterTemplate( 148 builder.InfrastructureClusterTemplate("", "infra1").Build()). 149 WithControlPlaneTemplate( 150 builder.ControlPlaneTemplate("", "cp1"). 151 Build()). 152 WithControlPlaneInfrastructureMachineTemplate( 153 builder.InfrastructureMachineTemplate("", "cpInfra1"). 154 Build()). 155 WithWorkerMachineDeploymentClasses( 156 *builder.MachineDeploymentClass("aa"). 157 WithInfrastructureTemplate( 158 builder.InfrastructureMachineTemplate("", "infra1").Build()). 159 WithBootstrapTemplate( 160 builder.BootstrapTemplate("", "bootstrap1").Build()). 161 Build()). 162 Build(), 163 expectErr: true, 164 }, 165 } 166 167 for _, tt := range tests { 168 t.Run(tt.name, func(t *testing.T) { 169 g := NewWithT(t) 170 webhook := &ClusterClass{} 171 err := webhook.validate(ctx, tt.old, tt.in) 172 if tt.expectErr { 173 g.Expect(err).To(HaveOccurred()) 174 return 175 } 176 g.Expect(err).ToNot(HaveOccurred()) 177 }) 178 } 179 } 180 181 func TestClusterClassValidation(t *testing.T) { 182 // NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses. 183 // Enabling the feature flag temporarily for this test. 184 defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)() 185 186 ref := &corev1.ObjectReference{ 187 APIVersion: "group.test.io/foo", 188 Kind: "barTemplate", 189 Name: "baz", 190 Namespace: "default", 191 } 192 refBadTemplate := &corev1.ObjectReference{ 193 APIVersion: "group.test.io/foo", 194 Kind: "bar", 195 Name: "baz", 196 Namespace: "default", 197 } 198 refBadAPIVersion := &corev1.ObjectReference{ 199 APIVersion: "group/test.io/v1/foo", 200 Kind: "barTemplate", 201 Name: "baz", 202 Namespace: "default", 203 } 204 incompatibleRef := &corev1.ObjectReference{ 205 APIVersion: "group.test.io/foo", 206 Kind: "another-barTemplate", 207 Name: "baz", 208 Namespace: "default", 209 } 210 compatibleRef := &corev1.ObjectReference{ 211 APIVersion: "group.test.io/another-foo", 212 Kind: "barTemplate", 213 Name: "another-baz", 214 Namespace: "default", 215 } 216 217 tests := []struct { 218 name string 219 in *clusterv1.ClusterClass 220 old *clusterv1.ClusterClass 221 expectErr bool 222 }{ 223 224 /* 225 CREATE Tests 226 */ 227 228 { 229 name: "create pass", 230 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 231 WithInfrastructureClusterTemplate( 232 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 233 WithControlPlaneTemplate( 234 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 235 Build()). 236 WithControlPlaneInfrastructureMachineTemplate( 237 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 238 Build()). 239 WithWorkerMachineDeploymentClasses( 240 *builder.MachineDeploymentClass("aa"). 241 WithInfrastructureTemplate( 242 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 243 WithBootstrapTemplate( 244 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 245 Build(), 246 *builder.MachineDeploymentClass("bb"). 247 WithInfrastructureTemplate( 248 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 249 WithBootstrapTemplate( 250 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 251 Build()). 252 Build(), 253 expectErr: false, 254 }, 255 256 // empty name in ref tests 257 { 258 name: "create fail infrastructureCluster has empty name", 259 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 260 WithInfrastructureClusterTemplate( 261 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "").Build()). 262 WithControlPlaneTemplate( 263 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 264 Build()). 265 Build(), 266 expectErr: true, 267 }, 268 { 269 name: "create fail controlPlane class has empty name", 270 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 271 WithInfrastructureClusterTemplate( 272 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 273 WithControlPlaneTemplate( 274 builder.ControlPlaneTemplate(metav1.NamespaceDefault, ""). 275 Build()). 276 Build(), 277 expectErr: true, 278 }, 279 { 280 name: "create fail control plane class machineInfrastructure has empty name", 281 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 282 WithInfrastructureClusterTemplate( 283 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 284 WithControlPlaneTemplate( 285 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 286 Build()). 287 WithControlPlaneInfrastructureMachineTemplate( 288 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, ""). 289 Build()). 290 Build(), 291 expectErr: true, 292 }, 293 { 294 name: "create fail machineDeployment Bootstrap has empty name", 295 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 296 WithInfrastructureClusterTemplate( 297 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 298 WithControlPlaneTemplate( 299 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 300 Build()). 301 WithControlPlaneInfrastructureMachineTemplate( 302 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 303 Build()). 304 WithWorkerMachineDeploymentClasses( 305 *builder.MachineDeploymentClass("aa"). 306 WithInfrastructureTemplate( 307 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 308 WithBootstrapTemplate( 309 builder.BootstrapTemplate(metav1.NamespaceDefault, "").Build()). 310 Build()). 311 Build(), 312 expectErr: true, 313 }, 314 { 315 name: "create fail machineDeployment Infrastructure has empty name", 316 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 317 WithInfrastructureClusterTemplate( 318 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 319 WithControlPlaneTemplate( 320 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 321 Build()). 322 WithControlPlaneInfrastructureMachineTemplate( 323 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 324 Build()). 325 WithWorkerMachineDeploymentClasses( 326 *builder.MachineDeploymentClass("aa"). 327 WithInfrastructureTemplate( 328 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "").Build()). 329 WithBootstrapTemplate( 330 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap").Build()). 331 Build()). 332 Build(), 333 expectErr: true, 334 }, 335 336 // inconsistent namespace in ref tests 337 { 338 name: "create fail if InfrastructureCluster has inconsistent namespace", 339 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 340 WithInfrastructureClusterTemplate( 341 builder.InfrastructureClusterTemplate("WrongNamespace", "infra1").Build()). 342 WithControlPlaneTemplate( 343 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 344 Build()). 345 WithControlPlaneInfrastructureMachineTemplate( 346 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 347 Build()). 348 Build(), 349 expectErr: true, 350 }, 351 { 352 name: "create fail if controlPlane has inconsistent namespace", 353 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 354 WithInfrastructureClusterTemplate( 355 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 356 WithControlPlaneTemplate( 357 builder.ControlPlaneTemplate("WrongNamespace", "cp1"). 358 Build()). 359 WithControlPlaneInfrastructureMachineTemplate( 360 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 361 Build()). 362 Build(), 363 expectErr: true, 364 }, 365 { 366 name: "create fail if controlPlane machineInfrastructure has inconsistent namespace", 367 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 368 WithInfrastructureClusterTemplate( 369 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 370 WithControlPlaneTemplate( 371 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 372 Build()). 373 WithControlPlaneInfrastructureMachineTemplate( 374 builder.InfrastructureMachineTemplate("WrongNamespace", "cpInfra1"). 375 Build()). 376 Build(), 377 expectErr: true, 378 }, 379 { 380 name: "create fail if machineDeployment / bootstrap has inconsistent namespace", 381 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 382 WithInfrastructureClusterTemplate( 383 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 384 WithControlPlaneTemplate( 385 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 386 Build()). 387 WithControlPlaneInfrastructureMachineTemplate( 388 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 389 Build()). 390 WithWorkerMachineDeploymentClasses( 391 *builder.MachineDeploymentClass("aa"). 392 WithInfrastructureTemplate( 393 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 394 WithBootstrapTemplate( 395 builder.BootstrapTemplate("WrongNamespace", "bootstrap1").Build()). 396 Build()). 397 Build(), 398 expectErr: true, 399 }, 400 { 401 name: "create fail if machineDeployment / infrastructure has inconsistent namespace", 402 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 403 WithInfrastructureClusterTemplate( 404 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 405 WithControlPlaneTemplate( 406 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 407 Build()). 408 WithControlPlaneInfrastructureMachineTemplate( 409 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 410 Build()). 411 WithWorkerMachineDeploymentClasses( 412 *builder.MachineDeploymentClass("aa"). 413 WithInfrastructureTemplate( 414 builder.InfrastructureMachineTemplate("WrongNamespace", "infra1").Build()). 415 WithBootstrapTemplate( 416 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 417 Build()). 418 Build(), 419 expectErr: true, 420 }, 421 422 // bad template in ref tests 423 { 424 name: "create fail if bad template in InfrastructureCluster", 425 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 426 WithInfrastructureClusterTemplate( 427 refToUnstructured(refBadTemplate)). 428 WithControlPlaneTemplate( 429 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 430 Build()). 431 WithControlPlaneInfrastructureMachineTemplate( 432 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 433 Build()). 434 Build(), 435 old: nil, 436 expectErr: true, 437 }, 438 { 439 name: "create fail if bad template in controlPlane machineInfrastructure", 440 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 441 WithInfrastructureClusterTemplate( 442 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 443 WithControlPlaneTemplate( 444 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 445 Build()). 446 WithControlPlaneInfrastructureMachineTemplate( 447 refToUnstructured(refBadTemplate)). 448 Build(), 449 old: nil, 450 expectErr: true, 451 }, 452 { 453 name: "create fail if bad template in ControlPlane", 454 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 455 WithInfrastructureClusterTemplate( 456 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 457 WithControlPlaneTemplate( 458 refToUnstructured(refBadTemplate)). 459 WithControlPlaneInfrastructureMachineTemplate( 460 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 461 Build()). 462 Build(), 463 old: nil, 464 expectErr: true, 465 }, 466 { 467 name: "create fail if bad template in machineDeployment Bootstrap", 468 469 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 470 WithInfrastructureClusterTemplate( 471 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 472 WithControlPlaneTemplate( 473 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 474 Build()). 475 WithControlPlaneInfrastructureMachineTemplate( 476 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 477 Build()). 478 WithWorkerMachineDeploymentClasses( 479 *builder.MachineDeploymentClass("aa"). 480 WithInfrastructureTemplate( 481 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 482 WithBootstrapTemplate( 483 refToUnstructured(refBadTemplate)). 484 Build()). 485 Build(), 486 old: nil, 487 expectErr: true, 488 }, 489 { 490 name: "create fail if bad template in machineDeployment Infrastructure", 491 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 492 WithInfrastructureClusterTemplate( 493 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 494 WithControlPlaneTemplate( 495 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 496 Build()). 497 WithControlPlaneInfrastructureMachineTemplate( 498 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 499 Build()). 500 WithWorkerMachineDeploymentClasses( 501 *builder.MachineDeploymentClass("aa"). 502 WithInfrastructureTemplate( 503 refToUnstructured(refBadTemplate)). 504 WithBootstrapTemplate( 505 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 506 Build()). 507 Build(), 508 old: nil, 509 expectErr: true, 510 }, 511 512 // bad apiVersion in ref tests 513 { 514 name: "create fail with a bad APIVersion for template in InfrastructureCluster", 515 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 516 WithInfrastructureClusterTemplate( 517 refToUnstructured(refBadAPIVersion)). 518 WithControlPlaneTemplate( 519 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 520 Build()). 521 WithControlPlaneInfrastructureMachineTemplate( 522 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 523 Build()). 524 Build(), 525 old: nil, 526 expectErr: true, 527 }, 528 { 529 name: "create fail with a bad APIVersion for template in controlPlane machineInfrastructure", 530 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 531 WithInfrastructureClusterTemplate( 532 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 533 WithControlPlaneTemplate( 534 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 535 Build()). 536 WithControlPlaneInfrastructureMachineTemplate( 537 refToUnstructured(refBadAPIVersion)). 538 Build(), 539 old: nil, 540 expectErr: true, 541 }, 542 { 543 name: "create fail with a bad APIVersion for template in ControlPlane", 544 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 545 WithInfrastructureClusterTemplate( 546 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 547 WithControlPlaneTemplate( 548 refToUnstructured(refBadAPIVersion)). 549 WithControlPlaneInfrastructureMachineTemplate( 550 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 551 Build()). 552 Build(), 553 old: nil, 554 expectErr: true, 555 }, 556 { 557 name: "create fail with a bad APIVersion for template in machineDeployment Bootstrap", 558 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 559 WithInfrastructureClusterTemplate( 560 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 561 WithControlPlaneTemplate( 562 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 563 Build()). 564 WithControlPlaneInfrastructureMachineTemplate( 565 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 566 Build()). 567 WithWorkerMachineDeploymentClasses( 568 *builder.MachineDeploymentClass("aa"). 569 WithInfrastructureTemplate( 570 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 571 WithBootstrapTemplate( 572 refToUnstructured(refBadAPIVersion)). 573 Build()). 574 Build(), 575 old: nil, 576 expectErr: true, 577 }, 578 { 579 name: "create fail with a bad APIVersion for template in machineDeployment Infrastructure", 580 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 581 WithInfrastructureClusterTemplate( 582 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 583 WithControlPlaneTemplate( 584 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 585 Build()). 586 WithControlPlaneInfrastructureMachineTemplate( 587 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 588 Build()). 589 WithWorkerMachineDeploymentClasses( 590 *builder.MachineDeploymentClass("aa"). 591 WithInfrastructureTemplate( 592 refToUnstructured(refBadAPIVersion)). 593 WithBootstrapTemplate( 594 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 595 Build()). 596 Build(), 597 old: nil, 598 expectErr: true, 599 }, 600 601 // create test 602 { 603 name: "create fail if duplicated machineDeploymentClasses", 604 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 605 WithInfrastructureClusterTemplate( 606 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 607 WithControlPlaneTemplate( 608 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 609 Build()). 610 WithControlPlaneInfrastructureMachineTemplate( 611 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 612 Build()). 613 WithWorkerMachineDeploymentClasses( 614 *builder.MachineDeploymentClass("aa"). 615 WithInfrastructureTemplate( 616 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 617 WithBootstrapTemplate( 618 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(), 619 *builder.MachineDeploymentClass("aa"). 620 WithInfrastructureTemplate( 621 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 622 WithBootstrapTemplate( 623 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 624 Build()). 625 Build(), 626 expectErr: true, 627 }, 628 { 629 name: "create pass if valid machineHealthCheck defined for ControlPlane with MachineInfrastructure set", 630 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 631 WithInfrastructureClusterTemplate( 632 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 633 WithControlPlaneTemplate( 634 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 635 Build()). 636 WithControlPlaneInfrastructureMachineTemplate( 637 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 638 Build()). 639 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{ 640 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 641 { 642 Type: corev1.NodeReady, 643 Status: corev1.ConditionUnknown, 644 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 645 }, 646 }, 647 NodeStartupTimeout: &metav1.Duration{ 648 Duration: time.Duration(6000000000000)}}). 649 Build(), 650 }, 651 { 652 name: "create fail if MachineHealthCheck defined for ControlPlane with MachineInfrastructure unset", 653 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 654 WithInfrastructureClusterTemplate( 655 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 656 WithControlPlaneTemplate( 657 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 658 Build()). 659 // No ControlPlaneMachineInfrastructure makes this an invalid creation request. 660 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{ 661 NodeStartupTimeout: &metav1.Duration{ 662 Duration: time.Duration(6000000000000)}}). 663 Build(), 664 expectErr: true, 665 }, 666 { 667 name: "create fail if ControlPlane MachineHealthCheck does not define UnhealthyConditions", 668 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 669 WithInfrastructureClusterTemplate( 670 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 671 WithControlPlaneTemplate( 672 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 673 Build()). 674 WithControlPlaneInfrastructureMachineTemplate( 675 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 676 Build()). 677 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{ 678 NodeStartupTimeout: &metav1.Duration{ 679 Duration: time.Duration(6000000000000)}}). 680 Build(), 681 expectErr: true, 682 }, 683 { 684 name: "create pass if MachineDeployment MachineHealthCheck is valid", 685 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 686 WithInfrastructureClusterTemplate( 687 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 688 WithControlPlaneTemplate( 689 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 690 Build()). 691 WithWorkerMachineDeploymentClasses( 692 *builder.MachineDeploymentClass("aa"). 693 WithInfrastructureTemplate( 694 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 695 WithBootstrapTemplate( 696 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 697 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{ 698 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 699 { 700 Type: corev1.NodeReady, 701 Status: corev1.ConditionUnknown, 702 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 703 }, 704 }, 705 NodeStartupTimeout: &metav1.Duration{ 706 Duration: time.Duration(6000000000000)}}). 707 Build()). 708 Build(), 709 }, 710 { 711 name: "create fail if MachineDeployment MachineHealthCheck NodeStartUpTimeout is too short", 712 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 713 WithInfrastructureClusterTemplate( 714 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 715 WithControlPlaneTemplate( 716 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 717 Build()). 718 WithWorkerMachineDeploymentClasses( 719 *builder.MachineDeploymentClass("aa"). 720 WithInfrastructureTemplate( 721 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 722 WithBootstrapTemplate( 723 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 724 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{ 725 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 726 { 727 Type: corev1.NodeReady, 728 Status: corev1.ConditionUnknown, 729 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 730 }, 731 }, 732 NodeStartupTimeout: &metav1.Duration{ 733 // nodeStartupTimeout is too short here - 600ns. 734 Duration: time.Duration(600)}}). 735 Build()). 736 Build(), 737 expectErr: true, 738 }, 739 { 740 name: "create fail if MachineDeployment MachineHealthCheck does not define UnhealthyConditions", 741 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 742 WithInfrastructureClusterTemplate( 743 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 744 WithControlPlaneTemplate( 745 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 746 Build()). 747 WithWorkerMachineDeploymentClasses( 748 *builder.MachineDeploymentClass("aa"). 749 WithInfrastructureTemplate( 750 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 751 WithBootstrapTemplate( 752 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 753 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{ 754 NodeStartupTimeout: &metav1.Duration{ 755 Duration: time.Duration(6000000000000)}}). 756 Build()). 757 Build(), 758 expectErr: true, 759 }, 760 761 /* 762 UPDATE Tests 763 */ 764 765 { 766 name: "update pass in case of no changes", 767 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 768 WithInfrastructureClusterTemplate( 769 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 770 WithControlPlaneTemplate( 771 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 772 Build()). 773 WithControlPlaneInfrastructureMachineTemplate( 774 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 775 Build()). 776 WithWorkerMachineDeploymentClasses( 777 *builder.MachineDeploymentClass("aa"). 778 WithInfrastructureTemplate( 779 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 780 WithBootstrapTemplate( 781 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 782 Build()). 783 Build(), 784 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 785 WithInfrastructureClusterTemplate( 786 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 787 WithControlPlaneTemplate( 788 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 789 Build()). 790 WithControlPlaneInfrastructureMachineTemplate( 791 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 792 Build()). 793 WithWorkerMachineDeploymentClasses( 794 *builder.MachineDeploymentClass("aa"). 795 WithInfrastructureTemplate( 796 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 797 WithBootstrapTemplate( 798 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 799 Build()). 800 Build(), 801 expectErr: false, 802 }, 803 { 804 name: "update pass if infrastructureCluster changes in a compatible way", 805 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 806 WithInfrastructureClusterTemplate( 807 refToUnstructured(ref)). 808 WithControlPlaneTemplate( 809 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 810 Build()). 811 WithControlPlaneInfrastructureMachineTemplate( 812 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 813 Build()). 814 WithWorkerMachineDeploymentClasses( 815 *builder.MachineDeploymentClass("aa"). 816 WithInfrastructureTemplate( 817 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 818 WithBootstrapTemplate( 819 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 820 Build()). 821 Build(), 822 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 823 WithInfrastructureClusterTemplate( 824 refToUnstructured(compatibleRef)). 825 WithControlPlaneTemplate( 826 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 827 Build()). 828 WithControlPlaneInfrastructureMachineTemplate( 829 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 830 Build()). 831 WithWorkerMachineDeploymentClasses( 832 *builder.MachineDeploymentClass("aa"). 833 WithInfrastructureTemplate( 834 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 835 WithBootstrapTemplate( 836 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 837 Build()). 838 Build(), 839 expectErr: false, 840 }, 841 { 842 name: "update fails if infrastructureCluster changes in an incompatible way", 843 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 844 WithInfrastructureClusterTemplate( 845 refToUnstructured(ref)). 846 WithControlPlaneTemplate( 847 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 848 Build()). 849 WithControlPlaneInfrastructureMachineTemplate( 850 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 851 Build()). 852 WithWorkerMachineDeploymentClasses( 853 *builder.MachineDeploymentClass("aa"). 854 WithInfrastructureTemplate( 855 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 856 WithBootstrapTemplate( 857 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 858 Build()). 859 Build(), 860 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 861 WithInfrastructureClusterTemplate( 862 refToUnstructured(incompatibleRef)). 863 WithControlPlaneTemplate( 864 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 865 Build()). 866 WithControlPlaneInfrastructureMachineTemplate( 867 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 868 Build()). 869 WithWorkerMachineDeploymentClasses( 870 *builder.MachineDeploymentClass("aa"). 871 WithInfrastructureTemplate( 872 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 873 WithBootstrapTemplate( 874 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 875 Build()). 876 Build(), 877 expectErr: true, 878 }, 879 { 880 name: "update pass if controlPlane changes in a compatible way", 881 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 882 WithInfrastructureClusterTemplate( 883 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 884 WithControlPlaneTemplate( 885 refToUnstructured(ref)). 886 WithControlPlaneInfrastructureMachineTemplate( 887 refToUnstructured(ref)). 888 WithWorkerMachineDeploymentClasses( 889 *builder.MachineDeploymentClass("aa"). 890 WithInfrastructureTemplate( 891 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 892 WithBootstrapTemplate( 893 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 894 Build()). 895 Build(), 896 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 897 WithInfrastructureClusterTemplate( 898 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 899 WithControlPlaneTemplate( 900 refToUnstructured(compatibleRef)). 901 WithControlPlaneInfrastructureMachineTemplate( 902 refToUnstructured(compatibleRef)). 903 WithWorkerMachineDeploymentClasses( 904 *builder.MachineDeploymentClass("aa"). 905 WithInfrastructureTemplate( 906 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 907 WithBootstrapTemplate( 908 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 909 Build()). 910 Build(), 911 expectErr: false, 912 }, 913 { 914 name: "update fails if controlPlane changes in an incompatible way (controlPlane template)", 915 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 916 WithInfrastructureClusterTemplate( 917 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 918 WithControlPlaneTemplate( 919 refToUnstructured(ref)). 920 WithControlPlaneInfrastructureMachineTemplate( 921 refToUnstructured(ref)). 922 WithWorkerMachineDeploymentClasses( 923 *builder.MachineDeploymentClass("aa"). 924 WithInfrastructureTemplate( 925 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 926 WithBootstrapTemplate( 927 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 928 Build()). 929 Build(), 930 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 931 WithInfrastructureClusterTemplate( 932 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 933 WithControlPlaneTemplate( 934 refToUnstructured(incompatibleRef)). 935 WithControlPlaneInfrastructureMachineTemplate( 936 refToUnstructured(compatibleRef)). 937 WithWorkerMachineDeploymentClasses( 938 *builder.MachineDeploymentClass("aa"). 939 WithInfrastructureTemplate( 940 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 941 WithBootstrapTemplate( 942 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 943 Build()). 944 Build(), 945 expectErr: true, 946 }, 947 { 948 name: "update fails if controlPlane changes in an incompatible way (controlPlane infrastructureMachineTemplate)", 949 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 950 WithInfrastructureClusterTemplate( 951 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 952 WithControlPlaneTemplate( 953 refToUnstructured(ref)). 954 WithControlPlaneInfrastructureMachineTemplate( 955 refToUnstructured(ref)). 956 WithWorkerMachineDeploymentClasses( 957 *builder.MachineDeploymentClass("aa"). 958 WithInfrastructureTemplate( 959 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 960 WithBootstrapTemplate( 961 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 962 Build()). 963 Build(), 964 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 965 WithInfrastructureClusterTemplate( 966 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 967 WithControlPlaneTemplate( 968 refToUnstructured(compatibleRef)). 969 WithControlPlaneInfrastructureMachineTemplate( 970 refToUnstructured(incompatibleRef)). 971 WithWorkerMachineDeploymentClasses( 972 *builder.MachineDeploymentClass("aa"). 973 WithInfrastructureTemplate( 974 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 975 WithBootstrapTemplate( 976 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 977 Build()). 978 Build(), 979 expectErr: true, 980 }, 981 { 982 name: "update pass if a machine deployment changes in a compatible way", 983 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 984 WithInfrastructureClusterTemplate( 985 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 986 WithControlPlaneTemplate( 987 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 988 Build()). 989 WithControlPlaneInfrastructureMachineTemplate( 990 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 991 Build()). 992 WithWorkerMachineDeploymentClasses( 993 *builder.MachineDeploymentClass("aa"). 994 WithInfrastructureTemplate( 995 refToUnstructured(ref)). 996 WithBootstrapTemplate( 997 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 998 Build()). 999 Build(), 1000 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1001 WithInfrastructureClusterTemplate( 1002 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1003 WithControlPlaneTemplate( 1004 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1005 Build()). 1006 WithControlPlaneInfrastructureMachineTemplate( 1007 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1008 Build()). 1009 WithWorkerMachineDeploymentClasses( 1010 *builder.MachineDeploymentClass("aa"). 1011 WithInfrastructureTemplate( 1012 refToUnstructured(compatibleRef)). 1013 WithBootstrapTemplate( 1014 refToUnstructured(incompatibleRef)). 1015 Build()). 1016 Build(), 1017 expectErr: false, 1018 }, 1019 { 1020 name: "update fails a machine deployment changes in an incompatible way", 1021 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1022 WithInfrastructureClusterTemplate( 1023 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1024 WithControlPlaneTemplate( 1025 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1026 Build()). 1027 WithControlPlaneInfrastructureMachineTemplate( 1028 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1029 Build()). 1030 WithWorkerMachineDeploymentClasses( 1031 *builder.MachineDeploymentClass("aa"). 1032 WithInfrastructureTemplate( 1033 refToUnstructured(ref)). 1034 WithBootstrapTemplate( 1035 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1036 Build()). 1037 Build(), 1038 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1039 WithInfrastructureClusterTemplate( 1040 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1041 WithControlPlaneTemplate( 1042 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1043 Build()). 1044 WithControlPlaneInfrastructureMachineTemplate( 1045 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1046 Build()). 1047 WithWorkerMachineDeploymentClasses( 1048 *builder.MachineDeploymentClass("aa"). 1049 WithInfrastructureTemplate( 1050 refToUnstructured(incompatibleRef)). 1051 WithBootstrapTemplate( 1052 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1053 Build()). 1054 Build(), 1055 expectErr: true, 1056 }, 1057 { 1058 name: "update pass if a machine deployment class gets added", 1059 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1060 WithInfrastructureClusterTemplate( 1061 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1062 WithControlPlaneTemplate( 1063 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1064 Build()). 1065 WithControlPlaneInfrastructureMachineTemplate( 1066 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1067 Build()). 1068 WithWorkerMachineDeploymentClasses( 1069 *builder.MachineDeploymentClass("aa"). 1070 WithInfrastructureTemplate( 1071 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1072 WithBootstrapTemplate( 1073 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1074 Build()). 1075 Build(), 1076 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1077 WithInfrastructureClusterTemplate( 1078 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1079 WithControlPlaneTemplate( 1080 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1081 Build()). 1082 WithControlPlaneInfrastructureMachineTemplate( 1083 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1084 Build()). 1085 WithWorkerMachineDeploymentClasses( 1086 *builder.MachineDeploymentClass("aa"). 1087 WithInfrastructureTemplate( 1088 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1089 WithBootstrapTemplate( 1090 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1091 Build(), 1092 *builder.MachineDeploymentClass("BB"). 1093 WithInfrastructureTemplate( 1094 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1095 WithBootstrapTemplate( 1096 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1097 Build()). 1098 Build(), 1099 expectErr: false, 1100 }, 1101 { 1102 name: "update fails if a duplicated deployment class gets added", 1103 old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1104 WithInfrastructureClusterTemplate( 1105 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1106 WithControlPlaneTemplate( 1107 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1108 Build()). 1109 WithControlPlaneInfrastructureMachineTemplate( 1110 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1111 Build()). 1112 WithWorkerMachineDeploymentClasses( 1113 *builder.MachineDeploymentClass("aa"). 1114 WithInfrastructureTemplate( 1115 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1116 WithBootstrapTemplate( 1117 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1118 Build()). 1119 Build(), 1120 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1121 WithInfrastructureClusterTemplate( 1122 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1123 WithControlPlaneTemplate( 1124 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1125 Build()). 1126 WithControlPlaneInfrastructureMachineTemplate( 1127 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1128 Build()). 1129 WithWorkerMachineDeploymentClasses( 1130 *builder.MachineDeploymentClass("aa"). 1131 WithInfrastructureTemplate( 1132 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1133 WithBootstrapTemplate( 1134 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(), 1135 *builder.MachineDeploymentClass("aa"). 1136 WithInfrastructureTemplate( 1137 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1138 WithBootstrapTemplate( 1139 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1140 Build()). 1141 Build(), 1142 expectErr: true, 1143 }, 1144 { 1145 name: "should return error for invalid labels and annotations", 1146 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1147 WithInfrastructureClusterTemplate( 1148 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1149 WithControlPlaneTemplate( 1150 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1151 Build()). 1152 WithControlPlaneInfrastructureMachineTemplate( 1153 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1154 Build()). 1155 WithWorkerMachineDeploymentClasses( 1156 *builder.MachineDeploymentClass("aa"). 1157 WithInfrastructureTemplate( 1158 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1159 WithBootstrapTemplate( 1160 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1161 WithLabels(invalidLabels()). 1162 WithAnnotations(invalidAnnotations()). 1163 Build()). 1164 WithControlPlaneMetadata(invalidLabels(), invalidAnnotations()). 1165 Build(), 1166 expectErr: true, 1167 }, 1168 { 1169 name: "should not return error for valid namingStrategy.template", 1170 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1171 WithInfrastructureClusterTemplate( 1172 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1173 WithControlPlaneTemplate( 1174 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1175 Build()). 1176 WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: pointer.String("{{ .cluster.name }}-cp-{{ .random }}")}). 1177 WithControlPlaneInfrastructureMachineTemplate( 1178 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1179 Build()). 1180 WithWorkerMachineDeploymentClasses( 1181 *builder.MachineDeploymentClass("aa"). 1182 WithInfrastructureTemplate( 1183 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1184 WithBootstrapTemplate( 1185 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1186 WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: pointer.String("{{ .cluster.name }}-md-{{ .machineDeployment.topologyName }}-{{ .random }}")}). 1187 Build()). 1188 WithWorkerMachinePoolClasses( 1189 *builder.MachinePoolClass("bb"). 1190 WithInfrastructureTemplate( 1191 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()). 1192 WithBootstrapTemplate( 1193 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()). 1194 WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: pointer.String("{{ .cluster.name }}-md-{{ .machinePool.topologyName }}-{{ .random }}")}). 1195 Build()). 1196 Build(), 1197 expectErr: false, 1198 }, 1199 { 1200 name: "should return error for invalid ControlPlane namingStrategy.template", 1201 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1202 WithInfrastructureClusterTemplate( 1203 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1204 WithControlPlaneTemplate( 1205 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1206 Build()). 1207 WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: pointer.String("template-cp-{{ .invalidkey }}")}). 1208 WithControlPlaneInfrastructureMachineTemplate( 1209 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1210 Build()). 1211 Build(), 1212 expectErr: true, 1213 }, 1214 { 1215 name: "should return error for ControlPlane namingStrategy.template when the generated name does not conform to RFC 1123", 1216 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1217 WithInfrastructureClusterTemplate( 1218 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1219 WithControlPlaneTemplate( 1220 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1221 Build()). 1222 WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: pointer.String("template-cp-{{ .cluster.name }}-")}). 1223 WithControlPlaneInfrastructureMachineTemplate( 1224 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1225 Build()). 1226 Build(), 1227 expectErr: true, 1228 }, 1229 { 1230 name: "should return error for invalid MachineDeployment namingStrategy.template", 1231 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1232 WithInfrastructureClusterTemplate( 1233 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1234 WithControlPlaneTemplate( 1235 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1236 Build()). 1237 WithControlPlaneInfrastructureMachineTemplate( 1238 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1239 Build()). 1240 WithWorkerMachineDeploymentClasses( 1241 *builder.MachineDeploymentClass("aa"). 1242 WithInfrastructureTemplate( 1243 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1244 WithBootstrapTemplate( 1245 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1246 WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: pointer.String("template-md-{{ .cluster.name")}). 1247 Build()). 1248 Build(), 1249 expectErr: true, 1250 }, 1251 { 1252 name: "should return error for invalid MachineDeployment namingStrategy.template when the generated name does not conform to RFC 1123", 1253 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1254 WithInfrastructureClusterTemplate( 1255 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1256 WithControlPlaneTemplate( 1257 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1258 Build()). 1259 WithControlPlaneInfrastructureMachineTemplate( 1260 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1261 Build()). 1262 WithWorkerMachineDeploymentClasses( 1263 *builder.MachineDeploymentClass("aa"). 1264 WithInfrastructureTemplate( 1265 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1266 WithBootstrapTemplate( 1267 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1268 WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: pointer.String("template-md-{{ .cluster.name }}-")}). 1269 Build()). 1270 Build(), 1271 expectErr: true, 1272 }, 1273 { 1274 name: "should return error for invalid MachinePool namingStrategy.template", 1275 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1276 WithInfrastructureClusterTemplate( 1277 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1278 WithControlPlaneTemplate( 1279 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1280 Build()). 1281 WithControlPlaneInfrastructureMachineTemplate( 1282 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1283 Build()). 1284 WithWorkerMachinePoolClasses( 1285 *builder.MachinePoolClass("bb"). 1286 WithInfrastructureTemplate( 1287 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()). 1288 WithBootstrapTemplate( 1289 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()). 1290 WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: pointer.String("template-mp-{{ .cluster.name")}). 1291 Build()). 1292 Build(), 1293 expectErr: true, 1294 }, 1295 { 1296 name: "should return error for invalid MachinePool namingStrategy.template when the generated name does not conform to RFC 1123", 1297 in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1298 WithInfrastructureClusterTemplate( 1299 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1300 WithControlPlaneTemplate( 1301 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1302 Build()). 1303 WithControlPlaneInfrastructureMachineTemplate( 1304 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). 1305 Build()). 1306 WithWorkerMachinePoolClasses( 1307 *builder.MachinePoolClass("bb"). 1308 WithInfrastructureTemplate( 1309 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()). 1310 WithBootstrapTemplate( 1311 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()). 1312 WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: pointer.String("template-mp-{{ .cluster.name }}-")}). 1313 Build()). 1314 Build(), 1315 expectErr: true, 1316 }, 1317 } 1318 1319 for _, tt := range tests { 1320 t.Run(tt.name, func(t *testing.T) { 1321 g := NewWithT(t) 1322 1323 // Sets up the fakeClient for the test case. 1324 fakeClient := fake.NewClientBuilder(). 1325 WithScheme(fakeScheme). 1326 WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName). 1327 Build() 1328 1329 // Create the webhook and add the fakeClient as its client. 1330 webhook := &ClusterClass{Client: fakeClient} 1331 err := webhook.validate(ctx, tt.old, tt.in) 1332 if tt.expectErr { 1333 g.Expect(err).To(HaveOccurred()) 1334 return 1335 } 1336 g.Expect(err).ToNot(HaveOccurred()) 1337 }) 1338 } 1339 } 1340 1341 func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { 1342 // NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses. 1343 // Enabling the feature flag temporarily for this test. 1344 defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)() 1345 1346 tests := []struct { 1347 name string 1348 oldClusterClass *clusterv1.ClusterClass 1349 newClusterClass *clusterv1.ClusterClass 1350 clusters []client.Object 1351 expectErr bool 1352 }{ 1353 { 1354 name: "pass if a MachineDeploymentClass not in use gets removed", 1355 clusters: []client.Object{ 1356 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1357 WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). 1358 WithTopology( 1359 builder.ClusterTopology(). 1360 WithClass("class1"). 1361 WithMachineDeployment( 1362 builder.MachineDeploymentTopology("workers1"). 1363 WithClass("bb"). 1364 Build(), 1365 ). 1366 Build()). 1367 Build(), 1368 }, 1369 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1370 WithInfrastructureClusterTemplate( 1371 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1372 WithControlPlaneTemplate( 1373 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1374 Build()). 1375 WithWorkerMachineDeploymentClasses( 1376 *builder.MachineDeploymentClass("aa"). 1377 WithInfrastructureTemplate( 1378 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1379 WithBootstrapTemplate( 1380 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1381 Build(), 1382 *builder.MachineDeploymentClass("bb"). 1383 WithInfrastructureTemplate( 1384 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1385 WithBootstrapTemplate( 1386 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1387 Build()). 1388 Build(), 1389 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1390 WithInfrastructureClusterTemplate( 1391 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1392 WithControlPlaneTemplate( 1393 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1394 Build()). 1395 WithWorkerMachineDeploymentClasses( 1396 *builder.MachineDeploymentClass("bb"). 1397 WithInfrastructureTemplate( 1398 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1399 WithBootstrapTemplate( 1400 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1401 Build()). 1402 Build(), 1403 expectErr: false, 1404 }, 1405 { 1406 name: "error if a MachineDeploymentClass in use gets removed", 1407 clusters: []client.Object{ 1408 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1409 WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). 1410 WithTopology( 1411 builder.ClusterTopology(). 1412 WithClass("class1"). 1413 WithMachineDeployment( 1414 builder.MachineDeploymentTopology("workers1"). 1415 WithClass("bb"). 1416 Build(), 1417 ). 1418 Build()). 1419 Build(), 1420 }, 1421 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1422 WithInfrastructureClusterTemplate( 1423 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1424 WithControlPlaneTemplate( 1425 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1426 Build()). 1427 WithWorkerMachineDeploymentClasses( 1428 *builder.MachineDeploymentClass("aa"). 1429 WithInfrastructureTemplate( 1430 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1431 WithBootstrapTemplate( 1432 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1433 Build(), 1434 *builder.MachineDeploymentClass("bb"). 1435 WithInfrastructureTemplate( 1436 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1437 WithBootstrapTemplate( 1438 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1439 Build()). 1440 Build(), 1441 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1442 WithInfrastructureClusterTemplate( 1443 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1444 WithControlPlaneTemplate( 1445 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1446 Build()). 1447 WithWorkerMachineDeploymentClasses( 1448 *builder.MachineDeploymentClass("aa"). 1449 WithInfrastructureTemplate( 1450 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1451 WithBootstrapTemplate( 1452 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1453 Build()). 1454 Build(), 1455 expectErr: true, 1456 }, 1457 { 1458 name: "error if many MachineDeploymentClasses, used in multiple Clusters using the modified ClusterClass, are removed", 1459 clusters: []client.Object{ 1460 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1461 WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). 1462 WithTopology( 1463 builder.ClusterTopology(). 1464 WithClass("class1"). 1465 WithMachineDeployment( 1466 builder.MachineDeploymentTopology("workers1"). 1467 WithClass("bb"). 1468 Build(), 1469 ). 1470 WithMachineDeployment( 1471 builder.MachineDeploymentTopology("workers2"). 1472 WithClass("aa"). 1473 Build(), 1474 ). 1475 Build()). 1476 Build(), 1477 builder.Cluster(metav1.NamespaceDefault, "cluster2"). 1478 WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). 1479 WithTopology( 1480 builder.ClusterTopology(). 1481 WithClass("class1"). 1482 WithMachineDeployment( 1483 builder.MachineDeploymentTopology("workers1"). 1484 WithClass("aa"). 1485 Build(), 1486 ). 1487 WithMachineDeployment( 1488 builder.MachineDeploymentTopology("workers2"). 1489 WithClass("aa"). 1490 Build(), 1491 ). 1492 Build()). 1493 Build(), 1494 builder.Cluster(metav1.NamespaceDefault, "cluster3"). 1495 WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). 1496 WithTopology( 1497 builder.ClusterTopology(). 1498 WithClass("class1"). 1499 WithMachineDeployment( 1500 builder.MachineDeploymentTopology("workers1"). 1501 WithClass("bb"). 1502 Build(), 1503 ). 1504 Build()). 1505 Build(), 1506 }, 1507 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1508 WithInfrastructureClusterTemplate( 1509 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1510 WithControlPlaneTemplate( 1511 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1512 Build()). 1513 WithWorkerMachineDeploymentClasses( 1514 *builder.MachineDeploymentClass("aa"). 1515 WithInfrastructureTemplate( 1516 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1517 WithBootstrapTemplate( 1518 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1519 Build(), 1520 *builder.MachineDeploymentClass("bb"). 1521 WithInfrastructureTemplate( 1522 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1523 WithBootstrapTemplate( 1524 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1525 Build()). 1526 Build(), 1527 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1528 WithInfrastructureClusterTemplate( 1529 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1530 WithControlPlaneTemplate( 1531 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1532 Build()). 1533 WithWorkerMachineDeploymentClasses( 1534 *builder.MachineDeploymentClass("bb"). 1535 WithInfrastructureTemplate( 1536 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1537 WithBootstrapTemplate( 1538 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1539 Build()). 1540 Build(), 1541 expectErr: true, 1542 }, 1543 { 1544 name: "error if a control plane MachineHealthCheck that is in use by a cluster is removed", 1545 clusters: []client.Object{ 1546 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1547 WithTopology(builder.ClusterTopology(). 1548 WithClass("clusterclass1"). 1549 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{ 1550 Enable: pointer.Bool(true), 1551 }). 1552 Build()). 1553 Build(), 1554 }, 1555 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1556 WithInfrastructureClusterTemplate( 1557 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1558 WithControlPlaneTemplate( 1559 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1560 Build()). 1561 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{ 1562 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 1563 { 1564 Type: corev1.NodeReady, 1565 Status: corev1.ConditionUnknown, 1566 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 1567 }, 1568 }, 1569 }). 1570 Build(), 1571 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1572 WithInfrastructureClusterTemplate( 1573 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1574 WithControlPlaneTemplate( 1575 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1576 Build()). 1577 Build(), 1578 expectErr: true, 1579 }, 1580 { 1581 name: "pass if a control plane MachineHealthCheck is removed but no cluster enforces it", 1582 clusters: []client.Object{ 1583 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1584 WithTopology(builder.ClusterTopology(). 1585 WithClass("clusterclass1"). 1586 Build()). 1587 Build(), 1588 }, 1589 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1590 WithInfrastructureClusterTemplate( 1591 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1592 WithControlPlaneTemplate( 1593 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1594 Build()). 1595 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{}). 1596 Build(), 1597 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1598 WithInfrastructureClusterTemplate( 1599 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1600 WithControlPlaneTemplate( 1601 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1602 Build()). 1603 Build(), 1604 expectErr: false, 1605 }, 1606 { 1607 name: "pass if a control plane MachineHealthCheck is removed when clusters are not using it (clusters have overrides in topology)", 1608 clusters: []client.Object{ 1609 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1610 WithTopology(builder.ClusterTopology(). 1611 WithClass("clusterclass1"). 1612 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{ 1613 Enable: pointer.Bool(true), 1614 MachineHealthCheckClass: clusterv1.MachineHealthCheckClass{ 1615 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 1616 { 1617 Type: corev1.NodeReady, 1618 Status: corev1.ConditionUnknown, 1619 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 1620 }, 1621 }, 1622 }, 1623 }). 1624 Build()). 1625 Build(), 1626 }, 1627 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1628 WithInfrastructureClusterTemplate( 1629 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1630 WithControlPlaneTemplate( 1631 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1632 Build()). 1633 WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{}). 1634 Build(), 1635 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1636 WithInfrastructureClusterTemplate( 1637 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1638 WithControlPlaneTemplate( 1639 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1640 Build()). 1641 Build(), 1642 expectErr: false, 1643 }, 1644 { 1645 name: "error if a MachineDeployment MachineHealthCheck that is in use by a cluster is removed", 1646 clusters: []client.Object{ 1647 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1648 WithTopology(builder.ClusterTopology(). 1649 WithClass("clusterclass1"). 1650 WithMachineDeployment(builder.MachineDeploymentTopology("md1"). 1651 WithClass("mdclass1"). 1652 WithMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{ 1653 Enable: pointer.Bool(true), 1654 }). 1655 Build()). 1656 Build()). 1657 Build(), 1658 }, 1659 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1660 WithInfrastructureClusterTemplate( 1661 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1662 WithControlPlaneTemplate( 1663 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1664 Build()). 1665 WithWorkerMachineDeploymentClasses( 1666 *builder.MachineDeploymentClass("mdclass1"). 1667 WithInfrastructureTemplate( 1668 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1669 WithBootstrapTemplate( 1670 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1671 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}). 1672 Build(), 1673 ). 1674 Build(), 1675 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1676 WithInfrastructureClusterTemplate( 1677 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1678 WithControlPlaneTemplate( 1679 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1680 Build()). 1681 WithWorkerMachineDeploymentClasses( 1682 *builder.MachineDeploymentClass("mdclass1"). 1683 WithInfrastructureTemplate( 1684 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1685 WithBootstrapTemplate( 1686 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1687 Build(), 1688 ). 1689 Build(), 1690 expectErr: true, 1691 }, 1692 { 1693 name: "pass if a MachineDeployment MachineHealthCheck is removed but no cluster enforces it", 1694 clusters: []client.Object{ 1695 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1696 WithTopology(builder.ClusterTopology(). 1697 WithClass("clusterclass1"). 1698 WithMachineDeployment(builder.MachineDeploymentTopology("md1"). 1699 WithClass("mdclass1"). 1700 Build()). 1701 Build()). 1702 Build(), 1703 }, 1704 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1705 WithInfrastructureClusterTemplate( 1706 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1707 WithControlPlaneTemplate( 1708 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1709 Build()). 1710 WithWorkerMachineDeploymentClasses( 1711 *builder.MachineDeploymentClass("mdclass1"). 1712 WithInfrastructureTemplate( 1713 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1714 WithBootstrapTemplate( 1715 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1716 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}). 1717 Build(), 1718 ). 1719 Build(), 1720 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1721 WithInfrastructureClusterTemplate( 1722 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1723 WithControlPlaneTemplate( 1724 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1725 Build()). 1726 WithWorkerMachineDeploymentClasses( 1727 *builder.MachineDeploymentClass("mdclass1"). 1728 WithInfrastructureTemplate( 1729 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1730 WithBootstrapTemplate( 1731 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1732 Build(), 1733 ). 1734 Build(), 1735 expectErr: false, 1736 }, 1737 { 1738 name: "pass if a MachineDeployment MachineHealthCheck is removed when clusters are not using it (clusters have overrides in topology)", 1739 clusters: []client.Object{ 1740 builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1741 WithTopology(builder.ClusterTopology(). 1742 WithClass("clusterclass1"). 1743 WithMachineDeployment(builder.MachineDeploymentTopology("md1"). 1744 WithClass("mdclass1"). 1745 WithMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{ 1746 Enable: pointer.Bool(true), 1747 MachineHealthCheckClass: clusterv1.MachineHealthCheckClass{ 1748 UnhealthyConditions: []clusterv1.UnhealthyCondition{ 1749 { 1750 Type: corev1.NodeReady, 1751 Status: corev1.ConditionUnknown, 1752 Timeout: metav1.Duration{Duration: 5 * time.Minute}, 1753 }, 1754 }, 1755 }, 1756 }). 1757 Build()). 1758 Build()). 1759 Build(), 1760 }, 1761 oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1762 WithInfrastructureClusterTemplate( 1763 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1764 WithControlPlaneTemplate( 1765 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1766 Build()). 1767 WithWorkerMachineDeploymentClasses( 1768 *builder.MachineDeploymentClass("mdclass1"). 1769 WithInfrastructureTemplate( 1770 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1771 WithBootstrapTemplate( 1772 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1773 WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}). 1774 Build(), 1775 ). 1776 Build(), 1777 newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1"). 1778 WithInfrastructureClusterTemplate( 1779 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). 1780 WithControlPlaneTemplate( 1781 builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). 1782 Build()). 1783 WithWorkerMachineDeploymentClasses( 1784 *builder.MachineDeploymentClass("mdclass1"). 1785 WithInfrastructureTemplate( 1786 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1787 WithBootstrapTemplate( 1788 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1789 Build(), 1790 ). 1791 Build(), 1792 expectErr: false, 1793 }, 1794 } 1795 1796 for _, tt := range tests { 1797 t.Run(tt.name, func(t *testing.T) { 1798 g := NewWithT(t) 1799 1800 // Sets up the fakeClient for the test case. 1801 fakeClient := fake.NewClientBuilder(). 1802 WithScheme(fakeScheme). 1803 WithObjects(tt.clusters...). 1804 WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName). 1805 Build() 1806 1807 // Create the webhook and add the fakeClient as its client. 1808 webhook := &ClusterClass{Client: fakeClient} 1809 err := webhook.validate(ctx, tt.oldClusterClass, tt.newClusterClass) 1810 if tt.expectErr { 1811 g.Expect(err).To(HaveOccurred()) 1812 return 1813 } 1814 g.Expect(err).ToNot(HaveOccurred()) 1815 }) 1816 } 1817 } 1818 1819 func invalidLabels() map[string]string { 1820 return map[string]string{ 1821 "foo": "$invalid-key", 1822 "bar": strings.Repeat("a", 64) + "too-long-value", 1823 "/invalid-key": "foo", 1824 } 1825 } 1826 1827 func invalidAnnotations() map[string]string { 1828 return map[string]string{ 1829 "/invalid-key": "foo", 1830 } 1831 }