sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/internal/test/fake_objects.go (about) 1 /* 2 Copyright 2019 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 test 18 19 import ( 20 "fmt" 21 "strings" 22 23 corev1 "k8s.io/api/core/v1" 24 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 25 "k8s.io/apimachinery/pkg/api/meta" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 28 "k8s.io/apimachinery/pkg/types" 29 "k8s.io/klog/v2" 30 "k8s.io/utils/ptr" 31 "sigs.k8s.io/controller-runtime/pkg/client" 32 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 33 34 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 35 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 36 fakebootstrap "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/bootstrap" 37 fakecontrolplane "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/controlplane" 38 fakeexternal "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/external" 39 fakeinfrastructure "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test/providers/infrastructure" 40 addonsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1" 41 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 42 "sigs.k8s.io/cluster-api/internal/test/builder" 43 "sigs.k8s.io/cluster-api/util" 44 ) 45 46 type FakeCluster struct { 47 namespace string 48 name string 49 controlPlane *FakeControlPlane 50 machinePools []*FakeMachinePool 51 machineDeployments []*FakeMachineDeployment 52 machineSets []*FakeMachineSet 53 machines []*FakeMachine 54 withCloudConfigSecret bool 55 withCredentialSecret bool 56 topologyClass *string 57 } 58 59 // NewFakeCluster return a FakeCluster that can generate a cluster object, all its own ancillary objects: 60 // - the clusterInfrastructure object 61 // - the kubeconfig secret object (if there is no a control plane object) 62 // - a user defined ca secret 63 // and all the objects for the defined FakeControlPlane, FakeMachinePools, FakeMachineDeployments, FakeMachineSets, FakeMachines 64 // Nb. if there is no a control plane object, the first FakeMachine gets a generated sa secret. 65 func NewFakeCluster(namespace, name string) *FakeCluster { 66 return &FakeCluster{ 67 namespace: namespace, 68 name: name, 69 } 70 } 71 72 func (f *FakeCluster) WithControlPlane(fakeControlPlane *FakeControlPlane) *FakeCluster { 73 f.controlPlane = fakeControlPlane 74 return f 75 } 76 77 func (f *FakeCluster) WithMachinePools(fakeMachinePool ...*FakeMachinePool) *FakeCluster { 78 f.machinePools = append(f.machinePools, fakeMachinePool...) 79 return f 80 } 81 82 func (f *FakeCluster) WithCloudConfigSecret() *FakeCluster { 83 f.withCloudConfigSecret = true 84 return f 85 } 86 87 func (f *FakeCluster) WithCredentialSecret() *FakeCluster { 88 f.withCredentialSecret = true 89 return f 90 } 91 92 func (f *FakeCluster) WithMachineDeployments(fakeMachineDeployment ...*FakeMachineDeployment) *FakeCluster { 93 f.machineDeployments = append(f.machineDeployments, fakeMachineDeployment...) 94 return f 95 } 96 97 func (f *FakeCluster) WithMachineSets(fakeMachineSet ...*FakeMachineSet) *FakeCluster { 98 f.machineSets = append(f.machineSets, fakeMachineSet...) 99 return f 100 } 101 102 func (f *FakeCluster) WithMachines(fakeMachine ...*FakeMachine) *FakeCluster { 103 f.machines = append(f.machines, fakeMachine...) 104 return f 105 } 106 107 func (f *FakeCluster) WithTopologyClass(class string) *FakeCluster { 108 f.topologyClass = &class 109 return f 110 } 111 112 func (f *FakeCluster) Objs() []client.Object { 113 clusterInfrastructure := &fakeinfrastructure.GenericInfrastructureCluster{ 114 TypeMeta: metav1.TypeMeta{ 115 APIVersion: fakeinfrastructure.GroupVersion.String(), 116 Kind: "GenericInfrastructureCluster", 117 }, 118 ObjectMeta: metav1.ObjectMeta{ 119 Name: f.name, 120 Namespace: f.namespace, 121 // OwnerReferences: cluster, Added by the cluster controller (see below) -- RECONCILED 122 // Labels: cluster.x-k8s.io/cluster-name=cluster, Added by the cluster controller (see below) -- RECONCILED 123 }, 124 } 125 126 cluster := &clusterv1.Cluster{ 127 TypeMeta: metav1.TypeMeta{ 128 Kind: "Cluster", 129 APIVersion: clusterv1.GroupVersion.String(), 130 }, 131 ObjectMeta: metav1.ObjectMeta{ 132 Name: f.name, 133 Namespace: f.namespace, 134 // Labels: cluster.x-k8s.io/cluster-name=cluster MISSING?? 135 }, 136 Spec: clusterv1.ClusterSpec{ 137 InfrastructureRef: &corev1.ObjectReference{ 138 APIVersion: clusterInfrastructure.APIVersion, 139 Kind: clusterInfrastructure.Kind, 140 Name: clusterInfrastructure.Name, 141 Namespace: clusterInfrastructure.Namespace, 142 }, 143 }, 144 } 145 146 if f.topologyClass != nil { 147 cluster.Spec.Topology = &clusterv1.Topology{Class: *f.topologyClass} 148 } 149 150 // Ensure the cluster gets a UID to be used by dependant objects for creating OwnerReferences. 151 setUID(cluster) 152 153 clusterInfrastructure.SetOwnerReferences([]metav1.OwnerReference{ 154 { 155 APIVersion: cluster.APIVersion, 156 Kind: cluster.Kind, 157 Name: cluster.Name, 158 UID: cluster.UID, 159 }, 160 }) 161 clusterInfrastructure.SetLabels(map[string]string{ 162 clusterv1.ClusterNameLabel: cluster.Name, 163 }) 164 165 caSecret := &corev1.Secret{ // provided by the user -- ** NOT RECONCILED ** 166 TypeMeta: metav1.TypeMeta{ 167 Kind: "Secret", 168 APIVersion: "v1", 169 }, 170 ObjectMeta: metav1.ObjectMeta{ 171 Name: f.name + "-ca", 172 Namespace: f.namespace, 173 }, 174 } 175 176 objs := []client.Object{ 177 cluster, 178 clusterInfrastructure, 179 caSecret, 180 } 181 182 if f.withCloudConfigSecret { 183 cloudSecret := &corev1.Secret{ // provided by the user -- ** NOT RECONCILED ** 184 TypeMeta: metav1.TypeMeta{ 185 Kind: "Secret", 186 APIVersion: "v1", 187 }, 188 ObjectMeta: metav1.ObjectMeta{ 189 Name: f.name + "-cloud-config", 190 Namespace: f.namespace, 191 }, 192 } 193 194 cloudSecret.SetLabels(map[string]string{ 195 clusterctlv1.ClusterctlMoveLabel: "", 196 }) 197 objs = append(objs, cloudSecret) 198 } 199 200 if f.withCredentialSecret { 201 credentialSecret := &corev1.Secret{ // provided by the user -- ** NOT RECONCILED ** 202 TypeMeta: metav1.TypeMeta{ 203 Kind: "Secret", 204 APIVersion: "v1", 205 }, 206 ObjectMeta: metav1.ObjectMeta{ 207 Name: f.name + "-credentials", 208 Namespace: f.namespace, 209 }, 210 } 211 credentialSecret.SetOwnerReferences([]metav1.OwnerReference{ 212 { 213 APIVersion: cluster.APIVersion, 214 Kind: cluster.Kind, 215 Name: cluster.Name, 216 UID: cluster.UID, 217 }, 218 }) 219 objs = append(objs, credentialSecret) 220 } 221 222 // if the cluster has a control plane object 223 if f.controlPlane != nil { 224 // Adds the objects for the controlPlane 225 objs = append(objs, f.controlPlane.Objs(cluster)...) 226 } else { 227 // Adds the kubeconfig object generated by the cluster controller -- ** NOT RECONCILED ** 228 kubeconfigSecret := &corev1.Secret{ 229 TypeMeta: metav1.TypeMeta{ 230 Kind: "Secret", 231 APIVersion: "v1", 232 }, 233 ObjectMeta: metav1.ObjectMeta{ 234 Name: f.name + "-kubeconfig", 235 Namespace: f.namespace, 236 OwnerReferences: []metav1.OwnerReference{ 237 { 238 APIVersion: cluster.APIVersion, 239 Kind: cluster.Kind, 240 Name: cluster.Name, 241 UID: cluster.UID, 242 }, 243 }, 244 // Labels: cluster.x-k8s.io/cluster-name=cluster MISSING?? 245 }, 246 } 247 objs = append(objs, kubeconfigSecret) 248 } 249 250 // Adds the objects for the machinePools 251 for _, machinePool := range f.machinePools { 252 objs = append(objs, machinePool.Objs(cluster)...) 253 } 254 255 // Adds the objects for the machineDeployments 256 for _, machineDeployment := range f.machineDeployments { 257 objs = append(objs, machineDeployment.Objs(cluster)...) 258 } 259 260 // Adds the objects for the machineSets directly attached to the cluster 261 for _, machineSet := range f.machineSets { 262 objs = append(objs, machineSet.Objs(cluster, nil)...) 263 } 264 265 // Adds the objects for the machines directly attached to the cluster 266 // Nb. In case there is no control plane, the first machine is arbitrarily used to simulate the generation of certificates Secrets implemented by the bootstrap controller. 267 for i, machine := range f.machines { 268 generateCerts := false 269 if f.controlPlane == nil && i == 0 { 270 generateCerts = true 271 } 272 objs = append(objs, machine.Objs(cluster, generateCerts, nil, nil, nil)...) 273 } 274 275 // Ensure all the objects gets UID. 276 // Nb. This adds UID to all the objects; it does not change the UID explicitly sets in advance for the objects involved in the object graphs. 277 for _, o := range objs { 278 setUID(o) 279 } 280 281 return objs 282 } 283 284 type FakeControlPlane struct { 285 name string 286 machines []*FakeMachine 287 } 288 289 // NewFakeControlPlane return a FakeControlPlane that can generate a controlPlane object, all its own ancillary objects: 290 // - the controlPlaneInfrastructure template object 291 // - the kubeconfig secret object 292 // - a generated sa secret 293 // and all the objects for the defined FakeMachines. 294 func NewFakeControlPlane(name string) *FakeControlPlane { 295 return &FakeControlPlane{ 296 name: name, 297 } 298 } 299 300 func (f *FakeControlPlane) WithMachines(fakeMachine ...*FakeMachine) *FakeControlPlane { 301 f.machines = append(f.machines, fakeMachine...) 302 return f 303 } 304 305 func (f *FakeControlPlane) Objs(cluster *clusterv1.Cluster) []client.Object { 306 controlPlaneInfrastructure := &fakeinfrastructure.GenericInfrastructureMachineTemplate{ 307 TypeMeta: metav1.TypeMeta{ 308 APIVersion: fakeinfrastructure.GroupVersion.String(), 309 Kind: "GenericInfrastructureMachineTemplate", 310 }, 311 ObjectMeta: metav1.ObjectMeta{ 312 Name: f.name, 313 Namespace: cluster.Namespace, 314 OwnerReferences: []metav1.OwnerReference{ // Added by the control plane controller (see below) -- RECONCILED 315 { 316 APIVersion: clusterv1.GroupVersion.String(), 317 Kind: "Cluster", 318 Name: cluster.Name, 319 UID: cluster.UID, 320 }, 321 }, 322 // Labels: MISSING 323 }, 324 } 325 326 controlPlane := &fakecontrolplane.GenericControlPlane{ 327 TypeMeta: metav1.TypeMeta{ 328 APIVersion: fakecontrolplane.GroupVersion.String(), 329 Kind: "GenericControlPlane", 330 }, 331 ObjectMeta: metav1.ObjectMeta{ 332 Name: f.name, 333 Namespace: cluster.Namespace, 334 OwnerReferences: []metav1.OwnerReference{ // Added by the control plane controller (see below) -- RECONCILED 335 { 336 APIVersion: clusterv1.GroupVersion.String(), 337 Kind: "Cluster", 338 Name: cluster.Name, 339 UID: cluster.UID, 340 }, 341 }, 342 Labels: map[string]string{ // cluster.x-k8s.io/cluster-name=cluster, Added by the control plane controller (see below) -- RECONCILED 343 clusterv1.ClusterNameLabel: cluster.Name, 344 }, 345 }, 346 Spec: fakecontrolplane.GenericControlPlaneSpec{ 347 MachineTemplate: fakecontrolplane.GenericMachineTemplate{ 348 InfrastructureRef: corev1.ObjectReference{ 349 APIVersion: controlPlaneInfrastructure.APIVersion, 350 Kind: controlPlaneInfrastructure.Kind, 351 Namespace: controlPlaneInfrastructure.Namespace, 352 Name: controlPlaneInfrastructure.Name, 353 }, 354 }, 355 }, 356 } 357 358 // Ensure the controlPlane gets a UID to be used by dependant objects for creating OwnerReferences. 359 setUID(controlPlane) 360 361 // sets the reference from the cluster to the plane object 362 cluster.Spec.ControlPlaneRef = &corev1.ObjectReference{ 363 APIVersion: controlPlane.APIVersion, 364 Kind: controlPlane.Kind, 365 Namespace: controlPlane.Namespace, 366 Name: controlPlane.Name, 367 } 368 369 // Adds the kubeconfig object generated by the control plane controller -- ** NOT RECONCILED ** 370 kubeconfigSecret := &corev1.Secret{ 371 TypeMeta: metav1.TypeMeta{ 372 Kind: "Secret", 373 APIVersion: "v1", 374 }, 375 ObjectMeta: metav1.ObjectMeta{ 376 Name: cluster.GetName() + "-kubeconfig", 377 Namespace: cluster.GetNamespace(), 378 // Labels: cluster.x-k8s.io/cluster-name=cluster MISSING?? 379 }, 380 } 381 kubeconfigSecret.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(controlPlane, controlPlane.GroupVersionKind())}) 382 383 // Adds one of the certificate secret object generated by the control plane controller -- ** NOT RECONCILED ** 384 saSecret := &corev1.Secret{ 385 TypeMeta: metav1.TypeMeta{ 386 Kind: "Secret", 387 APIVersion: "v1", 388 }, 389 ObjectMeta: metav1.ObjectMeta{ 390 Name: cluster.GetName() + "-sa", 391 Namespace: cluster.GetNamespace(), 392 // Labels: cluster.x-k8s.io/cluster-name=cluster MISSING?? 393 }, 394 } 395 saSecret.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(controlPlane, controlPlane.GroupVersionKind())}) 396 397 objs := []client.Object{ 398 controlPlane, 399 controlPlaneInfrastructure, 400 kubeconfigSecret, 401 saSecret, 402 } 403 404 // Adds the objects for the machines controlled by the controlPlane 405 for _, machine := range f.machines { 406 objs = append(objs, machine.Objs(cluster, false, nil, nil, controlPlane)...) 407 } 408 409 return objs 410 } 411 412 type FakeMachinePool struct { 413 name string 414 bootstrapConfig *clusterv1.Bootstrap 415 machines []*FakeMachine 416 } 417 418 // NewFakeMachinePool return a FakeMachinePool that can generate a MachinePool object, all its own ancillary objects: 419 // - the machinePoolInfrastructure object 420 // - the machinePoolBootstrap object. 421 func NewFakeMachinePool(name string) *FakeMachinePool { 422 return &FakeMachinePool{ 423 name: name, 424 } 425 } 426 427 func (f *FakeMachinePool) WithStaticBootstrapConfig() *FakeMachinePool { 428 f.bootstrapConfig = NewStaticBootstrapConfig(f.name) 429 return f 430 } 431 432 func (f *FakeMachinePool) WithMachines(fakeMachine ...*FakeMachine) *FakeMachinePool { 433 f.machines = append(f.machines, fakeMachine...) 434 return f 435 } 436 437 func (f *FakeMachinePool) Objs(cluster *clusterv1.Cluster) []client.Object { 438 machinePoolInfrastructure := &fakeinfrastructure.GenericInfrastructureMachineTemplate{ 439 TypeMeta: metav1.TypeMeta{ 440 APIVersion: fakeinfrastructure.GroupVersion.String(), 441 Kind: "GenericInfrastructureMachineTemplate", 442 }, 443 ObjectMeta: metav1.ObjectMeta{ 444 Name: f.name, 445 Namespace: cluster.Namespace, 446 OwnerReferences: []metav1.OwnerReference{ // Added by the machinePool controller (mirrors machinePool.spec.ClusterName) -- RECONCILED 447 { 448 APIVersion: clusterv1.GroupVersion.String(), 449 Kind: "Cluster", 450 Name: cluster.Name, 451 UID: cluster.UID, 452 }, 453 }, 454 // Labels: MISSING 455 }, 456 } 457 458 machinePoolBootstrap := &fakebootstrap.GenericBootstrapConfigTemplate{ 459 TypeMeta: metav1.TypeMeta{ 460 APIVersion: fakebootstrap.GroupVersion.String(), 461 Kind: "GenericBootstrapConfigTemplate", 462 }, 463 ObjectMeta: metav1.ObjectMeta{ 464 Name: f.name, 465 Namespace: cluster.Namespace, 466 OwnerReferences: []metav1.OwnerReference{ // Added by the machinePool controller (mirrors machinePool.spec.ClusterName) -- RECONCILED 467 { 468 APIVersion: clusterv1.GroupVersion.String(), 469 Kind: "Cluster", 470 Name: cluster.Name, 471 UID: cluster.UID, 472 }, 473 }, 474 // Labels: MISSING 475 }, 476 } 477 478 bootstrapConfig := f.bootstrapConfig 479 if bootstrapConfig == nil { 480 bootstrapConfig = NewBootstrapConfigTemplate(machinePoolBootstrap) 481 } 482 483 machinePool := &expv1.MachinePool{ 484 TypeMeta: metav1.TypeMeta{ 485 Kind: "MachinePool", 486 APIVersion: expv1.GroupVersion.String(), 487 }, 488 ObjectMeta: metav1.ObjectMeta{ 489 Name: f.name, 490 Namespace: cluster.Namespace, 491 OwnerReferences: []metav1.OwnerReference{ // Added by the machinePool controller (mirrors machinePool.spec.ClusterName) -- RECONCILED 492 { 493 APIVersion: clusterv1.GroupVersion.String(), 494 Kind: "Cluster", 495 Name: cluster.Name, 496 UID: cluster.UID, 497 }, 498 }, 499 Labels: map[string]string{ 500 clusterv1.ClusterNameLabel: cluster.Name, // Added by the machinePool controller (mirrors machinePoolt.spec.ClusterName) -- RECONCILED 501 }, 502 }, 503 Spec: expv1.MachinePoolSpec{ 504 Template: clusterv1.MachineTemplateSpec{ 505 Spec: clusterv1.MachineSpec{ 506 InfrastructureRef: corev1.ObjectReference{ 507 APIVersion: machinePoolInfrastructure.APIVersion, 508 Kind: machinePoolInfrastructure.Kind, 509 Name: machinePoolInfrastructure.Name, 510 Namespace: machinePoolInfrastructure.Namespace, 511 }, 512 Bootstrap: *bootstrapConfig, 513 }, 514 }, 515 ClusterName: cluster.Name, 516 }, 517 } 518 519 // Ensure the machinePool gets a UID to be used by dependant objects for creating OwnerReferences. 520 setUID(machinePool) 521 522 objs := []client.Object{ 523 machinePool, 524 machinePoolInfrastructure, 525 } 526 527 // if the bootstrapConfig doesn't use a static secret, add the GenericBootstrapConfigTemplate to the object list 528 if bootstrapConfig.ConfigRef != nil { 529 objs = append(objs, machinePoolBootstrap) 530 } 531 532 for _, machine := range f.machines { 533 objs = append(objs, machine.Objs(cluster, false, nil, machinePool, nil)...) 534 } 535 536 return objs 537 } 538 539 func NewFakeInfrastructureTemplate(name string) *fakeinfrastructure.GenericInfrastructureMachineTemplate { 540 return &fakeinfrastructure.GenericInfrastructureMachineTemplate{ 541 TypeMeta: metav1.TypeMeta{ 542 APIVersion: fakeinfrastructure.GroupVersion.String(), 543 Kind: "GenericInfrastructureMachineTemplate", 544 }, 545 ObjectMeta: metav1.ObjectMeta{ 546 Name: name, 547 // OwnerReference Added by the machine set controller -- RECONCILED 548 // Labels: MISSING 549 }, 550 } 551 } 552 553 // NewStaticBootstrapConfig return a clusterv1.Bootstrap where 554 // - the ConfigRef is nil 555 // - the DataSecretName contains the name of the static data secret. 556 func NewStaticBootstrapConfig(name string) *clusterv1.Bootstrap { 557 return &clusterv1.Bootstrap{ 558 DataSecretName: ptr.To(name + "-bootstrap-secret"), 559 } 560 } 561 562 func NewBootstrapConfigTemplate(machineBootstrapTemplate *fakebootstrap.GenericBootstrapConfigTemplate) *clusterv1.Bootstrap { 563 return &clusterv1.Bootstrap{ 564 ConfigRef: &corev1.ObjectReference{ 565 APIVersion: machineBootstrapTemplate.APIVersion, 566 Kind: machineBootstrapTemplate.Kind, 567 Name: machineBootstrapTemplate.Name, 568 Namespace: machineBootstrapTemplate.Namespace, 569 }, 570 } 571 } 572 573 func NewBootstrapConfig(machineBootstrap *fakebootstrap.GenericBootstrapConfig) *clusterv1.Bootstrap { 574 return &clusterv1.Bootstrap{ 575 ConfigRef: &corev1.ObjectReference{ 576 APIVersion: machineBootstrap.APIVersion, 577 Kind: machineBootstrap.Kind, 578 Name: machineBootstrap.Name, 579 Namespace: machineBootstrap.Namespace, 580 }, 581 } 582 } 583 584 type FakeMachineDeployment struct { 585 name string 586 machineSets []*FakeMachineSet 587 sharedInfrastructureTemplate *fakeinfrastructure.GenericInfrastructureMachineTemplate 588 bootstrapConfig *clusterv1.Bootstrap 589 } 590 591 // NewFakeMachineDeployment return a FakeMachineDeployment that can generate a MachineDeployment object, all its own ancillary objects: 592 // - the machineDeploymentInfrastructure template object 593 // - the machineDeploymentBootstrap template object 594 // and all the objects for the defined FakeMachineSet. 595 func NewFakeMachineDeployment(name string) *FakeMachineDeployment { 596 return &FakeMachineDeployment{ 597 name: name, 598 } 599 } 600 601 func (f *FakeMachineDeployment) WithMachineSets(fakeMachineSet ...*FakeMachineSet) *FakeMachineDeployment { 602 f.machineSets = append(f.machineSets, fakeMachineSet...) 603 return f 604 } 605 606 func (f *FakeMachineDeployment) WithStaticBootstrapConfig() *FakeMachineDeployment { 607 f.bootstrapConfig = NewStaticBootstrapConfig(f.name) 608 return f 609 } 610 611 func (f *FakeMachineDeployment) WithInfrastructureTemplate(infrastructureTemplate *fakeinfrastructure.GenericInfrastructureMachineTemplate) *FakeMachineDeployment { 612 f.sharedInfrastructureTemplate = infrastructureTemplate 613 return f 614 } 615 616 func (f *FakeMachineDeployment) Objs(cluster *clusterv1.Cluster) []client.Object { 617 // infra template can be either shared or specific to the machine deployment 618 machineDeploymentInfrastructure := f.sharedInfrastructureTemplate 619 if machineDeploymentInfrastructure == nil { 620 machineDeploymentInfrastructure = NewFakeInfrastructureTemplate(f.name) 621 } 622 machineDeploymentInfrastructure.Namespace = cluster.Namespace 623 machineDeploymentInfrastructure.SetOwnerReferences(util.EnsureOwnerRef(machineDeploymentInfrastructure.GetOwnerReferences(), // Added by the machine set controller -- RECONCILED 624 metav1.OwnerReference{ 625 APIVersion: clusterv1.GroupVersion.String(), 626 Kind: "Cluster", 627 Name: cluster.Name, 628 UID: cluster.UID, 629 }, 630 )) 631 setUID(machineDeploymentInfrastructure) 632 633 machineDeploymentBootstrap := &fakebootstrap.GenericBootstrapConfigTemplate{ 634 TypeMeta: metav1.TypeMeta{ 635 APIVersion: fakebootstrap.GroupVersion.String(), 636 Kind: "GenericBootstrapConfigTemplate", 637 }, 638 ObjectMeta: metav1.ObjectMeta{ 639 Name: f.name, 640 Namespace: cluster.Namespace, 641 OwnerReferences: []metav1.OwnerReference{ // Added by the machine set controller -- RECONCILED 642 { 643 APIVersion: clusterv1.GroupVersion.String(), 644 Kind: "Cluster", 645 Name: cluster.Name, 646 UID: cluster.UID, 647 }, 648 }, 649 // Labels: MISSING 650 }, 651 } 652 653 bootstrapConfig := f.bootstrapConfig 654 if bootstrapConfig == nil { 655 bootstrapConfig = NewBootstrapConfigTemplate(machineDeploymentBootstrap) 656 } 657 658 machineDeployment := &clusterv1.MachineDeployment{ 659 TypeMeta: metav1.TypeMeta{ 660 Kind: "MachineDeployment", 661 APIVersion: clusterv1.GroupVersion.String(), 662 }, 663 ObjectMeta: metav1.ObjectMeta{ 664 Name: f.name, 665 Namespace: cluster.Namespace, 666 OwnerReferences: []metav1.OwnerReference{ // Added by the machineDeployment controller (mirrors machineDeployment.spec.ClusterName) -- RECONCILED 667 { 668 APIVersion: clusterv1.GroupVersion.String(), 669 Kind: "Cluster", 670 Name: cluster.Name, 671 UID: cluster.UID, 672 }, 673 }, 674 Labels: map[string]string{ 675 clusterv1.ClusterNameLabel: cluster.Name, // Added by the machineDeployment controller (mirrors machineDeployment.spec.ClusterName) -- RECONCILED 676 }, 677 }, 678 Spec: clusterv1.MachineDeploymentSpec{ 679 Template: clusterv1.MachineTemplateSpec{ 680 Spec: clusterv1.MachineSpec{ 681 InfrastructureRef: corev1.ObjectReference{ 682 APIVersion: machineDeploymentInfrastructure.APIVersion, 683 Kind: machineDeploymentInfrastructure.Kind, 684 Name: machineDeploymentInfrastructure.Name, 685 Namespace: machineDeploymentInfrastructure.Namespace, 686 }, 687 Bootstrap: *bootstrapConfig, 688 }, 689 }, 690 ClusterName: cluster.Name, 691 }, 692 } 693 694 // Ensure the machineDeployment gets a UID to be used by dependant objects for creating OwnerReferences. 695 setUID(machineDeployment) 696 697 objs := []client.Object{ 698 machineDeployment, 699 } 700 701 // if the bootstrapConfig doesn't use a static secret, add the GenericBootstrapConfigTemplate to the object list 702 if bootstrapConfig.ConfigRef != nil { 703 objs = append(objs, machineDeploymentBootstrap) 704 } 705 706 // if the infra template is specific to the machine deployment, add it to the object list 707 if f.sharedInfrastructureTemplate == nil { 708 objs = append(objs, machineDeploymentInfrastructure) 709 } 710 711 // Adds the objects for the machineSets 712 for _, machineSet := range f.machineSets { 713 objs = append(objs, machineSet.Objs(cluster, machineDeployment)...) 714 } 715 716 return objs 717 } 718 719 type FakeMachineSet struct { 720 name string 721 machines []*FakeMachine 722 sharedInfrastructureTemplate *fakeinfrastructure.GenericInfrastructureMachineTemplate 723 bootstrapConfig *clusterv1.Bootstrap 724 } 725 726 // NewFakeMachineSet return a FakeMachineSet that can generate a MachineSet object, all its own ancillary objects: 727 // - the machineSetInfrastructure template object (only if not controlled by a MachineDeployment) 728 // - the machineSetBootstrap template object (only if not controlled by a MachineDeployment) 729 // and all the objects for the defined FakeMachine. 730 func NewFakeMachineSet(name string) *FakeMachineSet { 731 return &FakeMachineSet{ 732 name: name, 733 } 734 } 735 736 func (f *FakeMachineSet) WithMachines(fakeMachine ...*FakeMachine) *FakeMachineSet { 737 f.machines = append(f.machines, fakeMachine...) 738 return f 739 } 740 741 func (f *FakeMachineSet) WithStaticBootstrapConfig() *FakeMachineSet { 742 f.bootstrapConfig = NewStaticBootstrapConfig(f.name) 743 return f 744 } 745 746 func (f *FakeMachineSet) WithInfrastructureTemplate(infrastructureTemplate *fakeinfrastructure.GenericInfrastructureMachineTemplate) *FakeMachineSet { 747 f.sharedInfrastructureTemplate = infrastructureTemplate 748 return f 749 } 750 751 func (f *FakeMachineSet) Objs(cluster *clusterv1.Cluster, machineDeployment *clusterv1.MachineDeployment) []client.Object { 752 machineSet := &clusterv1.MachineSet{ // Created by machineDeployment controller 753 TypeMeta: metav1.TypeMeta{ 754 Kind: "MachineSet", 755 APIVersion: clusterv1.GroupVersion.String(), 756 }, 757 ObjectMeta: metav1.ObjectMeta{ 758 Name: f.name, 759 Namespace: cluster.Namespace, 760 // Owner reference set by machineSet controller or by machineDeployment controller (see below) 761 Labels: map[string]string{ 762 clusterv1.ClusterNameLabel: cluster.Name, // Added by the machineSet controller (mirrors machineSet.spec.ClusterName) -- RECONCILED 763 }, 764 }, 765 Spec: clusterv1.MachineSetSpec{ 766 ClusterName: cluster.Name, 767 }, 768 } 769 770 // Ensure the machineSet gets a UID to be used by dependant objects for creating OwnerReferences. 771 setUID(machineSet) 772 773 objs := make([]client.Object, 0) 774 775 if machineDeployment != nil { 776 // If this machineSet belong to a machineDeployment, it is controlled by it / ownership set by the machineDeployment controller -- ** NOT RECONCILED ** 777 machineSet.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(machineDeployment, machineDeployment.GroupVersionKind())}) 778 779 // additionally the machine has ref to the same infra and bootstrap templates defined in the MachineDeployment 780 machineSet.Spec.Template.Spec.InfrastructureRef = *machineDeployment.Spec.Template.Spec.InfrastructureRef.DeepCopy() 781 machineSet.Spec.Template.Spec.Bootstrap.ConfigRef = machineDeployment.Spec.Template.Spec.Bootstrap.ConfigRef.DeepCopy() 782 783 objs = append(objs, machineSet) 784 } else { 785 // If this machineSet does not belong to a machineDeployment, it is owned by the cluster / ownership set by the machineSet controller -- RECONCILED 786 machineSet.SetOwnerReferences([]metav1.OwnerReference{{ 787 APIVersion: cluster.APIVersion, 788 Kind: cluster.Kind, 789 Name: cluster.Name, 790 UID: cluster.UID, 791 }}) 792 793 // additionally the machineSet has ref to dedicated infra and bootstrap templates 794 795 // infra template can be either shared or specific to the machine set 796 machineSetInfrastructure := f.sharedInfrastructureTemplate 797 if machineSetInfrastructure == nil { 798 machineSetInfrastructure = NewFakeInfrastructureTemplate(f.name) 799 } 800 machineSetInfrastructure.Namespace = cluster.Namespace 801 machineSetInfrastructure.OwnerReferences = append(machineSetInfrastructure.OwnerReferences, // Added by the machine set controller -- RECONCILED 802 metav1.OwnerReference{ 803 APIVersion: clusterv1.GroupVersion.String(), 804 Kind: "Cluster", 805 Name: cluster.Name, 806 UID: cluster.UID, 807 }, 808 ) 809 setUID(machineSetInfrastructure) 810 811 machineSet.Spec.Template.Spec.InfrastructureRef = corev1.ObjectReference{ 812 APIVersion: machineSetInfrastructure.APIVersion, 813 Kind: machineSetInfrastructure.Kind, 814 Name: machineSetInfrastructure.Name, 815 Namespace: machineSetInfrastructure.Namespace, 816 } 817 818 objs = append(objs, machineSet) 819 820 machineSetBootstrap := &fakebootstrap.GenericBootstrapConfigTemplate{ 821 TypeMeta: metav1.TypeMeta{ 822 APIVersion: fakebootstrap.GroupVersion.String(), 823 Kind: "GenericBootstrapConfigTemplate", 824 }, 825 ObjectMeta: metav1.ObjectMeta{ 826 Name: f.name, 827 Namespace: cluster.Namespace, 828 OwnerReferences: []metav1.OwnerReference{ // Added by the machine set controller -- RECONCILED 829 { 830 APIVersion: clusterv1.GroupVersion.String(), 831 Kind: "Cluster", 832 Name: cluster.Name, 833 UID: cluster.UID, 834 }, 835 }, 836 // Labels: MISSING 837 }, 838 } 839 840 bootstrapConfig := f.bootstrapConfig 841 if bootstrapConfig == nil { 842 bootstrapConfig = NewBootstrapConfigTemplate(machineSetBootstrap) 843 } 844 845 machineSet.Spec.Template.Spec.Bootstrap = *bootstrapConfig 846 847 // if the bootstrapConfig doesn't use a static secret, add the GenericBootstrapConfigTemplate to the object list 848 if bootstrapConfig.ConfigRef != nil { 849 objs = append(objs, machineSetBootstrap) 850 } 851 852 // if the infra template is specific to the machine set, add it to the object list 853 if f.sharedInfrastructureTemplate == nil { 854 objs = append(objs, machineSetInfrastructure) 855 } 856 } 857 858 // Adds the objects for the machines controlled by the machineSet 859 for _, machine := range f.machines { 860 objs = append(objs, machine.Objs(cluster, false, machineSet, nil, nil)...) 861 } 862 863 return objs 864 } 865 866 type FakeMachine struct { 867 name string 868 bootstrapConfig *clusterv1.Bootstrap 869 } 870 871 // NewFakeMachine return a FakeMachine that can generate a Machine object, all its own ancillary objects: 872 // - the machineInfrastructure object 873 // - the machineBootstrap object and the related bootstrapDataSecret 874 // If there is no a control plane object in the cluster, the first FakeMachine gets a generated sa secret. 875 func NewFakeMachine(name string) *FakeMachine { 876 return &FakeMachine{ 877 name: name, 878 } 879 } 880 881 func (f *FakeMachine) WithStaticBootstrapConfig() *FakeMachine { 882 f.bootstrapConfig = NewStaticBootstrapConfig(f.name) 883 return f 884 } 885 886 func (f *FakeMachine) Objs(cluster *clusterv1.Cluster, generateCerts bool, machineSet *clusterv1.MachineSet, machinePool *expv1.MachinePool, controlPlane *fakecontrolplane.GenericControlPlane) []client.Object { 887 machineInfrastructure := &fakeinfrastructure.GenericInfrastructureMachine{ 888 TypeMeta: metav1.TypeMeta{ 889 APIVersion: fakeinfrastructure.GroupVersion.String(), 890 Kind: "GenericInfrastructureMachine", 891 }, 892 ObjectMeta: metav1.ObjectMeta{ 893 Name: f.name, 894 Namespace: cluster.Namespace, 895 // OwnerReferences: machine, Added by the machine controller (see below) -- RECONCILED 896 // Labels: cluster.x-k8s.io/cluster-name=cluster, Added by the machine controller (see below) -- RECONCILED 897 }, 898 } 899 900 bootstrapDataSecretName := f.name 901 902 machineBootstrap := &fakebootstrap.GenericBootstrapConfig{ 903 TypeMeta: metav1.TypeMeta{ 904 APIVersion: fakebootstrap.GroupVersion.String(), 905 Kind: "GenericBootstrapConfig", 906 }, 907 ObjectMeta: metav1.ObjectMeta{ 908 Name: f.name, 909 Namespace: cluster.Namespace, 910 // OwnerReferences: machine, Added by the machine controller (see below) -- RECONCILED 911 // Labels: cluster.x-k8s.io/cluster-name=cluster, Added by the machine controller (see below) -- RECONCILED 912 }, 913 Status: fakebootstrap.GenericBootstrapConfigStatus{ 914 DataSecretName: &bootstrapDataSecretName, 915 }, 916 } 917 918 bootstrapConfig := f.bootstrapConfig 919 if bootstrapConfig == nil { 920 bootstrapConfig = NewBootstrapConfig(machineBootstrap) 921 bootstrapConfig.DataSecretName = &bootstrapDataSecretName 922 } 923 924 // Ensure the machineBootstrap gets a UID to be used by dependant objects for creating OwnerReferences. 925 setUID(machineBootstrap) 926 927 bootstrapDataSecret := &corev1.Secret{ // generated by the bootstrap controller -- ** NOT RECONCILED ** 928 TypeMeta: metav1.TypeMeta{ 929 Kind: "Secret", 930 APIVersion: "v1", 931 }, 932 ObjectMeta: metav1.ObjectMeta{ 933 Name: bootstrapDataSecretName, 934 Namespace: cluster.Namespace, 935 OwnerReferences: []metav1.OwnerReference{ 936 *metav1.NewControllerRef(machineBootstrap, machineBootstrap.GroupVersionKind()), 937 }, 938 Labels: map[string]string{ 939 clusterv1.ClusterNameLabel: cluster.Name, // derives from Config -(ownerRef)-> machine.spec.ClusterName 940 }, 941 }, 942 } 943 944 machine := &clusterv1.Machine{ 945 TypeMeta: metav1.TypeMeta{ 946 Kind: "Machine", 947 APIVersion: clusterv1.GroupVersion.String(), 948 }, 949 ObjectMeta: metav1.ObjectMeta{ 950 Name: f.name, 951 Namespace: cluster.Namespace, 952 // Owner reference set by machine controller or by machineSet controller (see below) 953 Labels: map[string]string{ 954 clusterv1.ClusterNameLabel: cluster.Name, // Added by the machine controller (mirrors machine.spec.ClusterName) -- RECONCILED 955 }, 956 }, 957 Spec: clusterv1.MachineSpec{ 958 InfrastructureRef: corev1.ObjectReference{ 959 APIVersion: machineInfrastructure.APIVersion, 960 Kind: machineInfrastructure.Kind, 961 Name: machineInfrastructure.Name, 962 Namespace: cluster.Namespace, 963 }, 964 ClusterName: cluster.Name, 965 }, 966 } 967 968 // Ensure the machine gets a UID to be used by dependant objects for creating OwnerReferences. 969 setUID(machine) 970 971 var additionalObjs []client.Object 972 973 switch { 974 case machineSet != nil: 975 // If this machine belong to a machineSet, it is controlled by it / ownership set by the machineSet controller -- ** NOT RECONCILED ?? ** 976 machine.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(machineSet, machineSet.GroupVersionKind())}) 977 case controlPlane != nil: 978 // If this machine belong to a controlPlane, it is controlled by it / ownership set by the controlPlane controller -- ** NOT RECONCILED ?? ** 979 machine.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(controlPlane, controlPlane.GroupVersionKind())}) 980 // Sets the MachineControlPlane Label 981 machine.Labels[clusterv1.MachineControlPlaneLabel] = "" 982 case machinePool != nil: 983 // If this machine belong to a machinePool, it is controlled by it / ownership set by the machinePool controller -- ** NOT RECONCILED ** 984 machine.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(machinePool, machinePool.GroupVersionKind())}) 985 // Sets the MachinePoolNameLabel 986 machine.Labels[clusterv1.MachinePoolNameLabel] = machinePool.Name 987 default: 988 // If this machine does not belong to a machineSet or to a control plane, it is owned by the cluster / ownership set by the machine controller -- RECONCILED 989 machine.SetOwnerReferences([]metav1.OwnerReference{{ 990 APIVersion: cluster.APIVersion, 991 Kind: cluster.Kind, 992 Name: cluster.Name, 993 UID: cluster.UID, 994 }}) 995 996 // Adds one of the certificate secret object generated by the bootstrap config controller -- ** NOT RECONCILED ** 997 if generateCerts { 998 saSecret := &corev1.Secret{ 999 TypeMeta: metav1.TypeMeta{ 1000 Kind: "Secret", 1001 APIVersion: "v1", 1002 }, 1003 ObjectMeta: metav1.ObjectMeta{ 1004 Name: cluster.GetName() + "-sa", 1005 Namespace: cluster.GetNamespace(), 1006 // Labels: cluster.x-k8s.io/cluster-name=cluster MISSING?? 1007 }, 1008 } 1009 // Set controlled by the machineBootstrap / ownership set by the bootstrap config controller -- ** NOT RECONCILED ?? ** 1010 saSecret.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(machineBootstrap, machineBootstrap.GroupVersionKind())}) 1011 1012 additionalObjs = append(additionalObjs, saSecret) 1013 } 1014 } 1015 1016 machineInfrastructure.SetOwnerReferences([]metav1.OwnerReference{ 1017 { 1018 APIVersion: machine.APIVersion, 1019 Kind: machine.Kind, 1020 Name: machine.Name, 1021 UID: machine.UID, 1022 }, 1023 }) 1024 machineInfrastructure.SetLabels(map[string]string{ 1025 clusterv1.ClusterNameLabel: machine.Spec.ClusterName, 1026 }) 1027 1028 objs := []client.Object{ 1029 machine, 1030 machineInfrastructure, 1031 } 1032 1033 if machinePool == nil { 1034 machine.Spec.Bootstrap = *bootstrapConfig 1035 if machine.Spec.Bootstrap.ConfigRef != nil { 1036 machineBootstrap.SetOwnerReferences([]metav1.OwnerReference{ 1037 { 1038 APIVersion: machine.APIVersion, 1039 Kind: machine.Kind, 1040 Name: machine.Name, 1041 UID: machine.UID, 1042 }, 1043 }) 1044 machineBootstrap.SetLabels(map[string]string{ 1045 clusterv1.ClusterNameLabel: machine.Spec.ClusterName, 1046 }) 1047 1048 objs = append(objs, bootstrapDataSecret, machineBootstrap) 1049 } 1050 } 1051 1052 objs = append(objs, additionalObjs...) 1053 1054 return objs 1055 } 1056 1057 type FakeClusterResourceSet struct { 1058 name string 1059 namespace string 1060 secrets []*corev1.Secret 1061 configMaps []*corev1.ConfigMap 1062 clusters []*clusterv1.Cluster 1063 } 1064 1065 // NewFakeClusterResourceSet return a FakeClusterResourceSet that can generate a ClusterResourceSet object, all its own ancillary objects: 1066 // - the Secret/ConfigMap defining resources 1067 // - the bindings that are created when a ClusterResourceSet is applied to a cluster. 1068 func NewFakeClusterResourceSet(namespace, name string) *FakeClusterResourceSet { 1069 return &FakeClusterResourceSet{ 1070 name: name, 1071 namespace: namespace, 1072 } 1073 } 1074 1075 func (f *FakeClusterResourceSet) WithSecret(name string) *FakeClusterResourceSet { 1076 f.secrets = append(f.secrets, &corev1.Secret{ 1077 TypeMeta: metav1.TypeMeta{ 1078 Kind: "Secret", 1079 APIVersion: "v1", 1080 }, 1081 ObjectMeta: metav1.ObjectMeta{ 1082 Name: name, 1083 Namespace: f.namespace, 1084 }, 1085 // No data are required for the sake of move tests 1086 }) 1087 return f 1088 } 1089 1090 func (f *FakeClusterResourceSet) WithConfigMap(name string) *FakeClusterResourceSet { 1091 f.configMaps = append(f.configMaps, &corev1.ConfigMap{ 1092 TypeMeta: metav1.TypeMeta{ 1093 Kind: "ConfigMap", 1094 APIVersion: "v1", 1095 }, 1096 ObjectMeta: metav1.ObjectMeta{ 1097 Name: name, 1098 Namespace: f.namespace, 1099 }, 1100 // No data are required for the sake of move tests 1101 }) 1102 return f 1103 } 1104 1105 func (f *FakeClusterResourceSet) ApplyToCluster(cluster *clusterv1.Cluster) *FakeClusterResourceSet { 1106 if f.namespace != cluster.Namespace { 1107 panic("A ClusterResourceSet can only be applied to a cluster in the same namespace") 1108 } 1109 f.clusters = append(f.clusters, cluster) 1110 return f 1111 } 1112 1113 func (f *FakeClusterResourceSet) Objs() []client.Object { 1114 crs := &addonsv1.ClusterResourceSet{ 1115 TypeMeta: metav1.TypeMeta{ 1116 Kind: "ClusterResourceSet", 1117 APIVersion: addonsv1.GroupVersion.String(), 1118 }, 1119 ObjectMeta: metav1.ObjectMeta{ 1120 Name: f.name, 1121 Namespace: f.namespace, 1122 }, 1123 Spec: addonsv1.ClusterResourceSetSpec{ 1124 Resources: []addonsv1.ResourceRef{}, 1125 }, 1126 } 1127 1128 // Ensure the ClusterResourceSet gets a UID to be used by dependant objects for creating OwnerReferences. 1129 setUID(crs) 1130 1131 objs := []client.Object{crs} 1132 1133 // Ensures all the resources of type Secret are created and listed as a ClusterResourceSet resources 1134 for i := range f.secrets { 1135 secret := f.secrets[i] 1136 1137 // secrets are owned by the ClusterResourceSet / ownership set by the ClusterResourceSet controller 1138 secret.SetOwnerReferences([]metav1.OwnerReference{{ 1139 APIVersion: crs.APIVersion, 1140 Kind: crs.Kind, 1141 Name: crs.Name, 1142 UID: crs.UID, 1143 }}) 1144 1145 crs.Spec.Resources = append(crs.Spec.Resources, addonsv1.ResourceRef{ 1146 Name: secret.Name, 1147 Kind: secret.Kind, 1148 }) 1149 1150 objs = append(objs, secret) 1151 } 1152 1153 // Ensures all the resources of type ConfigMap are created and listed as a ClusterResourceSet resources 1154 for i := range f.configMaps { 1155 configMap := f.configMaps[i] 1156 1157 // configMap are owned by the ClusterResourceSet / ownership set by the ClusterResourceSet controller 1158 configMap.SetOwnerReferences([]metav1.OwnerReference{{ 1159 APIVersion: crs.APIVersion, 1160 Kind: crs.Kind, 1161 Name: crs.Name, 1162 UID: crs.UID, 1163 }}) 1164 1165 crs.Spec.Resources = append(crs.Spec.Resources, addonsv1.ResourceRef{ 1166 Name: configMap.Name, 1167 Kind: configMap.Kind, 1168 }) 1169 1170 objs = append(objs, configMap) 1171 } 1172 1173 // Ensures all the binding with the clusters where resources are applied. 1174 for _, cluster := range f.clusters { 1175 binding := &addonsv1.ClusterResourceSetBinding{ 1176 TypeMeta: metav1.TypeMeta{ 1177 Kind: "ClusterResourceSetBinding", 1178 APIVersion: addonsv1.GroupVersion.String(), 1179 }, 1180 ObjectMeta: metav1.ObjectMeta{ 1181 Name: cluster.Name, 1182 Namespace: cluster.Namespace, 1183 }, 1184 Spec: addonsv1.ClusterResourceSetBindingSpec{ 1185 ClusterName: cluster.Name, 1186 Bindings: []*addonsv1.ResourceSetBinding{ 1187 { 1188 ClusterResourceSetName: crs.Name, 1189 }, 1190 }, 1191 }, 1192 } 1193 1194 binding.SetOwnerReferences([]metav1.OwnerReference{ 1195 // binding are owned by the ClusterResourceSet / ownership set by the ClusterResourceSet controller 1196 { 1197 APIVersion: crs.APIVersion, 1198 Kind: crs.Kind, 1199 Name: crs.Name, 1200 UID: crs.UID, 1201 }, 1202 }) 1203 1204 objs = append(objs, binding) 1205 1206 resourceSetBinding := addonsv1.ResourceSetBinding{ 1207 ClusterResourceSetName: crs.Name, 1208 Resources: []addonsv1.ResourceBinding{}, 1209 } 1210 binding.Spec.Bindings = append(binding.Spec.Bindings, &resourceSetBinding) 1211 1212 // creates map entries for each cluster/resource of type Secret 1213 for _, secret := range f.secrets { 1214 resourceSetBinding.Resources = append(resourceSetBinding.Resources, addonsv1.ResourceBinding{ResourceRef: addonsv1.ResourceRef{ 1215 Name: secret.Name, 1216 Kind: "Secret", 1217 }}) 1218 } 1219 1220 // creates map entries for each cluster/resource of type ConfigMap 1221 for _, configMap := range f.configMaps { 1222 resourceSetBinding.Resources = append(resourceSetBinding.Resources, addonsv1.ResourceBinding{ResourceRef: addonsv1.ResourceRef{ 1223 Name: configMap.Name, 1224 Kind: "ConfigMap", 1225 }}) 1226 } 1227 } 1228 1229 // Ensure all the objects gets UID. 1230 // Nb. This adds UID to all the objects; it does not change the UID explicitly sets in advance for the objects involved in the object graphs. 1231 for _, o := range objs { 1232 setUID(o) 1233 } 1234 1235 return objs 1236 } 1237 1238 type FakeExternalObject struct { 1239 name string 1240 namespace string 1241 } 1242 1243 // NewFakeExternalObject generates a new external object (a CR not related to the Cluster). 1244 func NewFakeExternalObject(namespace, name string) *FakeExternalObject { 1245 return &FakeExternalObject{ 1246 name: name, 1247 namespace: namespace, 1248 } 1249 } 1250 1251 func (f *FakeExternalObject) Objs() []client.Object { 1252 externalObj := &fakeexternal.GenericExternalObject{ 1253 TypeMeta: metav1.TypeMeta{ 1254 APIVersion: fakeexternal.GroupVersion.String(), 1255 Kind: "GenericExternalObject", 1256 }, 1257 ObjectMeta: metav1.ObjectMeta{ 1258 Name: f.name, 1259 Namespace: f.namespace, 1260 }, 1261 } 1262 setUID(externalObj) 1263 1264 return []client.Object{externalObj} 1265 } 1266 1267 type FakeClusterExternalObject struct { 1268 name string 1269 } 1270 1271 // NewFakeClusterExternalObject generates a new global external object (a CR not related to the Cluster). 1272 func NewFakeClusterExternalObject(name string) *FakeClusterExternalObject { 1273 return &FakeClusterExternalObject{ 1274 name: name, 1275 } 1276 } 1277 1278 func (f *FakeClusterExternalObject) Objs() []client.Object { 1279 externalObj := &fakeexternal.GenericClusterExternalObject{ 1280 TypeMeta: metav1.TypeMeta{ 1281 APIVersion: fakeexternal.GroupVersion.String(), 1282 Kind: "GenericClusterExternalObject", 1283 }, 1284 ObjectMeta: metav1.ObjectMeta{ 1285 Name: f.name, 1286 }, 1287 } 1288 setUID(externalObj) 1289 1290 return []client.Object{externalObj} 1291 } 1292 1293 type FakeClusterInfrastructureIdentity struct { 1294 name string 1295 secretNamespace string 1296 } 1297 1298 // NewFakeClusterInfrastructureIdentity generates a new global cluster identity object. 1299 func NewFakeClusterInfrastructureIdentity(name string) *FakeClusterInfrastructureIdentity { 1300 return &FakeClusterInfrastructureIdentity{ 1301 name: name, 1302 } 1303 } 1304 1305 func (f *FakeClusterInfrastructureIdentity) WithSecretIn(namespace string) *FakeClusterInfrastructureIdentity { 1306 f.secretNamespace = namespace 1307 return f 1308 } 1309 1310 func (f *FakeClusterInfrastructureIdentity) Objs() []client.Object { 1311 identityObj := &fakeinfrastructure.GenericClusterInfrastructureIdentity{ 1312 TypeMeta: metav1.TypeMeta{ 1313 APIVersion: fakeinfrastructure.GroupVersion.String(), 1314 Kind: "GenericClusterInfrastructureIdentity", 1315 }, 1316 ObjectMeta: metav1.ObjectMeta{ 1317 Name: f.name, 1318 }, 1319 } 1320 setUID(identityObj) 1321 objs := []client.Object{identityObj} 1322 1323 if f.secretNamespace != "" { 1324 secret := NewSecret(f.secretNamespace, fmt.Sprintf("%s-credentials", f.name)) 1325 setUID(secret) 1326 1327 secret.SetOwnerReferences(append(secret.OwnerReferences, metav1.OwnerReference{ 1328 APIVersion: identityObj.APIVersion, 1329 Kind: identityObj.Kind, 1330 Name: identityObj.Name, 1331 UID: identityObj.UID, 1332 })) 1333 objs = append(objs, secret) 1334 } 1335 1336 return objs 1337 } 1338 1339 // NewSecret generates a new secret with the given namespace and name. 1340 func NewSecret(namespace, name string) *corev1.Secret { 1341 s := &corev1.Secret{ 1342 TypeMeta: metav1.TypeMeta{ 1343 APIVersion: corev1.SchemeGroupVersion.String(), 1344 Kind: "Secret", 1345 }, 1346 ObjectMeta: metav1.ObjectMeta{ 1347 Name: name, 1348 Namespace: namespace, 1349 }, 1350 } 1351 setUID(s) 1352 return s 1353 } 1354 1355 // SelectClusterObj finds and returns a Cluster with the given name and namespace, if any. 1356 func SelectClusterObj(objs []client.Object, namespace, name string) *clusterv1.Cluster { 1357 for _, o := range objs { 1358 if o.GetObjectKind().GroupVersionKind().GroupKind() != clusterv1.GroupVersion.WithKind("Cluster").GroupKind() { 1359 continue 1360 } 1361 1362 if o.GetName() == name && o.GetNamespace() == namespace { 1363 // Converts the object to cluster 1364 // NB. Convert returns an object without version/kind, so we are enforcing those values back. 1365 cluster := &clusterv1.Cluster{} 1366 if err := FakeScheme.Convert(o, cluster, nil); err != nil { 1367 panic(fmt.Sprintf("failed to convert %s to cluster: %v", o.GetObjectKind(), err)) 1368 } 1369 cluster.APIVersion = o.GetObjectKind().GroupVersionKind().GroupVersion().String() 1370 cluster.Kind = o.GetObjectKind().GroupVersionKind().Kind 1371 return cluster 1372 } 1373 } 1374 return nil 1375 } 1376 1377 // setUID assigns a UID to the object, so test objects are uniquely identified. 1378 // NB. In order to make debugging easier we are using a human readable, deterministic string (instead of a random UID). 1379 func setUID(obj client.Object) { 1380 accessor, err := meta.Accessor(obj) 1381 if err != nil { 1382 panic(fmt.Sprintf("failed to get accessor for test object: %v", err)) 1383 } 1384 uid := fmt.Sprintf("%s, %s", obj.GetObjectKind().GroupVersionKind().String(), klog.KObj(accessor)) 1385 accessor.SetUID(types.UID(uid)) 1386 } 1387 1388 // FakeClusterCustomResourceDefinition returns a fake CRD object for the given group/versions/kind. 1389 func FakeClusterCustomResourceDefinition(group string, kind string, versions ...string) *apiextensionsv1.CustomResourceDefinition { 1390 crd := fakeCRD(group, kind, versions) 1391 crd.Spec.Scope = apiextensionsv1.ClusterScoped 1392 return crd 1393 } 1394 1395 // FakeNamespacedCustomResourceDefinition returns a fake CRD object for the given group/versions/kind. 1396 func FakeNamespacedCustomResourceDefinition(group string, kind string, versions ...string) *apiextensionsv1.CustomResourceDefinition { 1397 crd := fakeCRD(group, kind, versions) 1398 crd.Spec.Scope = apiextensionsv1.NamespaceScoped 1399 return crd 1400 } 1401 1402 func fakeCRD(group string, kind string, versions []string) *apiextensionsv1.CustomResourceDefinition { 1403 crd := &apiextensionsv1.CustomResourceDefinition{ 1404 TypeMeta: metav1.TypeMeta{ 1405 Kind: apiextensionsv1.SchemeGroupVersion.String(), 1406 APIVersion: "CustomResourceDefinition", 1407 }, 1408 ObjectMeta: metav1.ObjectMeta{ 1409 Name: fmt.Sprintf("%s.%s", strings.ToLower(kind), group), // NB. this technically should use plural(kind), but for the sake of test what really matters is to generate a unique name 1410 Labels: map[string]string{ 1411 clusterctlv1.ClusterctlLabel: "", 1412 }, 1413 }, 1414 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ // NB. the spec contains only what is strictly required by the move test 1415 Group: group, 1416 Names: apiextensionsv1.CustomResourceDefinitionNames{ 1417 Kind: kind, 1418 }, 1419 }, 1420 } 1421 1422 for i, version := range versions { 1423 // set the first version as a storage version 1424 versionObj := apiextensionsv1.CustomResourceDefinitionVersion{Name: version} 1425 if i == 0 { 1426 versionObj.Storage = true 1427 } 1428 crd.Spec.Versions = append(crd.Spec.Versions, versionObj) 1429 } 1430 return crd 1431 } 1432 1433 // FakeCRDList returns FakeCustomResourceDefinitions for all the Types used in the test object graph. 1434 func FakeCRDList() []*apiextensionsv1.CustomResourceDefinition { 1435 version := clusterv1.GroupVersion.Version 1436 1437 // Ensure CRD for external objects is set as for "force move" 1438 externalCRD := FakeNamespacedCustomResourceDefinition(fakeexternal.GroupVersion.Group, "GenericExternalObject", version) 1439 externalCRD.Labels[clusterctlv1.ClusterctlMoveLabel] = "" 1440 1441 clusterExternalCRD := FakeClusterCustomResourceDefinition(fakeexternal.GroupVersion.Group, "GenericClusterExternalObject", version) 1442 clusterExternalCRD.Labels[clusterctlv1.ClusterctlMoveLabel] = "" 1443 1444 // Ensure CRD for GenericClusterInfrastructureIdentity is set for "force move hierarchy" 1445 clusterInfrastructureIdentityCRD := FakeClusterCustomResourceDefinition(fakeinfrastructure.GroupVersion.Group, "GenericClusterInfrastructureIdentity", version) 1446 clusterInfrastructureIdentityCRD.Labels[clusterctlv1.ClusterctlMoveHierarchyLabel] = "" 1447 1448 return []*apiextensionsv1.CustomResourceDefinition{ 1449 FakeNamespacedCustomResourceDefinition(clusterv1.GroupVersion.Group, "Cluster", version), 1450 FakeNamespacedCustomResourceDefinition(clusterv1.GroupVersion.Group, "ClusterClass", version), 1451 FakeNamespacedCustomResourceDefinition(clusterv1.GroupVersion.Group, "Machine", version), 1452 FakeNamespacedCustomResourceDefinition(clusterv1.GroupVersion.Group, "MachineDeployment", version), 1453 FakeNamespacedCustomResourceDefinition(clusterv1.GroupVersion.Group, "MachineSet", version), 1454 FakeNamespacedCustomResourceDefinition(expv1.GroupVersion.Group, "MachinePool", version), 1455 FakeNamespacedCustomResourceDefinition(addonsv1.GroupVersion.Group, "ClusterResourceSet", version), 1456 FakeNamespacedCustomResourceDefinition(addonsv1.GroupVersion.Group, "ClusterResourceSetBinding", version), 1457 FakeNamespacedCustomResourceDefinition(fakecontrolplane.GroupVersion.Group, "GenericControlPlane", version), 1458 FakeNamespacedCustomResourceDefinition(fakecontrolplane.GroupVersion.Group, "GenericControlPlaneTemplate", version), 1459 FakeNamespacedCustomResourceDefinition(fakeinfrastructure.GroupVersion.Group, "GenericInfrastructureCluster", version), 1460 FakeNamespacedCustomResourceDefinition(fakeinfrastructure.GroupVersion.Group, "GenericInfrastructureClusterTemplate", version), 1461 FakeNamespacedCustomResourceDefinition(fakeinfrastructure.GroupVersion.Group, "GenericInfrastructureMachine", version), 1462 FakeNamespacedCustomResourceDefinition(fakeinfrastructure.GroupVersion.Group, "GenericInfrastructureMachineTemplate", version), 1463 FakeNamespacedCustomResourceDefinition(fakebootstrap.GroupVersion.Group, "GenericBootstrapConfig", version), 1464 FakeNamespacedCustomResourceDefinition(fakebootstrap.GroupVersion.Group, "GenericBootstrapConfigTemplate", version), 1465 externalCRD, 1466 clusterExternalCRD, 1467 clusterInfrastructureIdentityCRD, 1468 } 1469 } 1470 1471 type FakeClusterClass struct { 1472 namespace string 1473 name string 1474 infrastructureClusterTemplate *unstructured.Unstructured 1475 controlPlaneTemplate *unstructured.Unstructured 1476 controlPlaneInfrastructureMachineTemplate *unstructured.Unstructured 1477 workerMachineDeploymentClasses []*FakeMachineDeploymentClass 1478 } 1479 1480 func NewFakeClusterClass(namespace, name string) *FakeClusterClass { 1481 return &FakeClusterClass{ 1482 namespace: namespace, 1483 name: name, 1484 } 1485 } 1486 1487 func (f *FakeClusterClass) WithInfrastructureClusterTemplate(tmpl *unstructured.Unstructured) *FakeClusterClass { 1488 f.infrastructureClusterTemplate = tmpl 1489 return f 1490 } 1491 1492 func (f *FakeClusterClass) WithControlPlaneTemplate(tmpl *unstructured.Unstructured) *FakeClusterClass { 1493 f.controlPlaneTemplate = tmpl 1494 return f 1495 } 1496 1497 func (f *FakeClusterClass) WithControlPlaneInfrastructureTemplate(tmpl *unstructured.Unstructured) *FakeClusterClass { 1498 f.controlPlaneInfrastructureMachineTemplate = tmpl 1499 return f 1500 } 1501 1502 func (f *FakeClusterClass) WithWorkerMachineDeploymentClasses(classes []*FakeMachineDeploymentClass) *FakeClusterClass { 1503 f.workerMachineDeploymentClasses = classes 1504 return f 1505 } 1506 1507 func (f *FakeClusterClass) Objs() []client.Object { 1508 // objMap map where the key is the object to which the owner reference to the cluster class should be added 1509 // and the value dictates if the onwner ref needs to be added. 1510 // This map also dual functions as a way to de-duplicate and template objects that are reused. 1511 objMap := map[client.Object]bool{} 1512 1513 // If no infrastructure cluster template is provided create a generic infrastructure cluster template to use in the cluster class. 1514 if f.infrastructureClusterTemplate == nil { 1515 f.infrastructureClusterTemplate = builder.InfrastructureClusterTemplate(f.namespace, f.name).Build() 1516 } 1517 objMap[f.infrastructureClusterTemplate] = true 1518 1519 // If no controlplane template is provided create a generic controlplane template to use in the cluster class. 1520 if f.controlPlaneTemplate == nil { 1521 f.controlPlaneTemplate = builder.ControlPlaneTemplate(f.namespace, f.name).Build() 1522 } 1523 objMap[f.controlPlaneTemplate] = true 1524 1525 clusterClassBuilder := builder.ClusterClass(f.namespace, f.name). 1526 WithInfrastructureClusterTemplate(f.infrastructureClusterTemplate). 1527 WithControlPlaneTemplate(f.controlPlaneTemplate) 1528 1529 if f.controlPlaneInfrastructureMachineTemplate != nil { 1530 clusterClassBuilder.WithControlPlaneInfrastructureMachineTemplate(f.controlPlaneInfrastructureMachineTemplate) 1531 objMap[f.controlPlaneInfrastructureMachineTemplate] = true 1532 } 1533 1534 if len(f.workerMachineDeploymentClasses) > 0 { 1535 mdClasses := []clusterv1.MachineDeploymentClass{} 1536 for _, fakeMDClass := range f.workerMachineDeploymentClasses { 1537 mdClasses = append(mdClasses, *fakeMDClass.Obj()) 1538 objMap[fakeMDClass.bootstrapTemplate] = true 1539 objMap[fakeMDClass.infrastructureTemplate] = true 1540 } 1541 clusterClassBuilder.WithWorkerMachineDeploymentClasses(mdClasses...) 1542 } 1543 1544 clusterClass := clusterClassBuilder.Build() 1545 objMap[clusterClass] = false 1546 1547 for o := range objMap { 1548 setUID(o) 1549 } 1550 1551 for o, setOwnerReference := range objMap { 1552 if setOwnerReference { 1553 if err := controllerutil.SetOwnerReference(clusterClass, o, FakeScheme); err != nil { 1554 panic(err) 1555 } 1556 } 1557 } 1558 1559 objs := []client.Object{} 1560 for o := range objMap { 1561 objs = append(objs, o) 1562 } 1563 return objs 1564 } 1565 1566 type FakeMachineDeploymentClass struct { 1567 class string 1568 namespace string // Used when creating the default bootstrap and the infra machine templates 1569 infrastructureTemplate *unstructured.Unstructured 1570 bootstrapTemplate *unstructured.Unstructured 1571 } 1572 1573 func NewFakeMachineDeploymentClass(namespace, class string) *FakeMachineDeploymentClass { 1574 return &FakeMachineDeploymentClass{ 1575 class: class, 1576 namespace: namespace, 1577 } 1578 } 1579 1580 func (f *FakeMachineDeploymentClass) WithInfrastructureMachineTemplate(tmpl *unstructured.Unstructured) *FakeMachineDeploymentClass { 1581 f.infrastructureTemplate = tmpl 1582 return f 1583 } 1584 1585 func (f *FakeMachineDeploymentClass) WithBootstrapTemplate(tmpl *unstructured.Unstructured) *FakeMachineDeploymentClass { 1586 f.bootstrapTemplate = tmpl 1587 return f 1588 } 1589 1590 func (f *FakeMachineDeploymentClass) Obj() *clusterv1.MachineDeploymentClass { 1591 if f.infrastructureTemplate == nil { 1592 f.infrastructureTemplate = builder.InfrastructureMachineTemplate(f.namespace, f.class).Build() 1593 } 1594 if f.bootstrapTemplate == nil { 1595 f.bootstrapTemplate = builder.BootstrapTemplate(f.namespace, f.class).Build() 1596 } 1597 1598 return builder.MachineDeploymentClass(f.class). 1599 WithInfrastructureTemplate(f.infrastructureTemplate). 1600 WithBootstrapTemplate(f.bootstrapTemplate). 1601 Build() 1602 }