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  }