sigs.k8s.io/cluster-api@v1.7.1/internal/controllers/machineset/machineset_preflight_test.go (about)

     1  /*
     2  Copyright 2023 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 machineset
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  	corev1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  	utilfeature "k8s.io/component-base/featuregate/testing"
    27  	"k8s.io/utils/ptr"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    30  
    31  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    32  	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
    33  	"sigs.k8s.io/cluster-api/feature"
    34  	"sigs.k8s.io/cluster-api/internal/contract"
    35  	"sigs.k8s.io/cluster-api/internal/test/builder"
    36  )
    37  
    38  func TestMachineSetReconciler_runPreflightChecks(t *testing.T) {
    39  	ns := "ns1"
    40  
    41  	controlPlaneWithNoVersion := builder.ControlPlane(ns, "cp1").Build()
    42  
    43  	controlPlaneWithInvalidVersion := builder.ControlPlane(ns, "cp1").
    44  		WithVersion("v1.25.6.0").Build()
    45  
    46  	controlPlaneProvisioning := builder.ControlPlane(ns, "cp1").
    47  		WithVersion("v1.25.6").Build()
    48  
    49  	controlPlaneUpgrading := builder.ControlPlane(ns, "cp1").
    50  		WithVersion("v1.26.2").
    51  		WithStatusFields(map[string]interface{}{
    52  			"status.version": "v1.25.2",
    53  		}).
    54  		Build()
    55  
    56  	controlPlaneStable := builder.ControlPlane(ns, "cp1").
    57  		WithVersion("v1.26.2").
    58  		WithStatusFields(map[string]interface{}{
    59  			"status.version": "v1.26.2",
    60  		}).
    61  		Build()
    62  
    63  	controlPlaneStable128 := builder.ControlPlane(ns, "cp1").
    64  		WithVersion("v1.28.0").
    65  		WithStatusFields(map[string]interface{}{
    66  			"status.version": "v1.28.0",
    67  		}).
    68  		Build()
    69  
    70  	t.Run("should run preflight checks if the feature gate is enabled", func(t *testing.T) {
    71  		defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachineSetPreflightChecks, true)()
    72  
    73  		tests := []struct {
    74  			name         string
    75  			cluster      *clusterv1.Cluster
    76  			controlPlane *unstructured.Unstructured
    77  			machineSet   *clusterv1.MachineSet
    78  			wantPass     bool
    79  			wantErr      bool
    80  		}{
    81  			{
    82  				name:       "should pass if cluster has no control plane",
    83  				cluster:    &clusterv1.Cluster{},
    84  				machineSet: &clusterv1.MachineSet{},
    85  				wantPass:   true,
    86  			},
    87  			{
    88  				name: "should pass if the control plane version is not defined",
    89  				cluster: &clusterv1.Cluster{
    90  					ObjectMeta: metav1.ObjectMeta{
    91  						Namespace: ns,
    92  					},
    93  					Spec: clusterv1.ClusterSpec{
    94  						ControlPlaneRef: contract.ObjToRef(controlPlaneWithNoVersion),
    95  					},
    96  				},
    97  				controlPlane: controlPlaneWithNoVersion,
    98  				machineSet:   &clusterv1.MachineSet{},
    99  				wantPass:     true,
   100  			},
   101  			{
   102  				name: "should error if the control plane version is invalid",
   103  				cluster: &clusterv1.Cluster{
   104  					ObjectMeta: metav1.ObjectMeta{
   105  						Namespace: ns,
   106  					},
   107  					Spec: clusterv1.ClusterSpec{
   108  						ControlPlaneRef: contract.ObjToRef(controlPlaneWithInvalidVersion),
   109  					},
   110  				},
   111  				controlPlane: controlPlaneWithInvalidVersion,
   112  				machineSet:   &clusterv1.MachineSet{},
   113  				wantErr:      true,
   114  			},
   115  			{
   116  				name: "should pass if all preflight checks are skipped",
   117  				cluster: &clusterv1.Cluster{
   118  					ObjectMeta: metav1.ObjectMeta{
   119  						Namespace: ns,
   120  					},
   121  					Spec: clusterv1.ClusterSpec{
   122  						ControlPlaneRef: contract.ObjToRef(controlPlaneUpgrading),
   123  					},
   124  				},
   125  				controlPlane: controlPlaneUpgrading,
   126  				machineSet: &clusterv1.MachineSet{
   127  					ObjectMeta: metav1.ObjectMeta{
   128  						Namespace: ns,
   129  						Annotations: map[string]string{
   130  							clusterv1.MachineSetSkipPreflightChecksAnnotation: string(clusterv1.MachineSetPreflightCheckAll),
   131  						},
   132  					},
   133  				},
   134  				wantPass: true,
   135  			},
   136  			{
   137  				name: "control plane preflight check: should fail if the control plane is provisioning",
   138  				cluster: &clusterv1.Cluster{
   139  					ObjectMeta: metav1.ObjectMeta{
   140  						Namespace: ns,
   141  					},
   142  					Spec: clusterv1.ClusterSpec{
   143  						ControlPlaneRef: contract.ObjToRef(controlPlaneProvisioning),
   144  					},
   145  				},
   146  				controlPlane: controlPlaneProvisioning,
   147  				machineSet:   &clusterv1.MachineSet{},
   148  				wantPass:     false,
   149  			},
   150  			{
   151  				name: "control plane preflight check: should fail if the control plane is upgrading",
   152  				cluster: &clusterv1.Cluster{
   153  					ObjectMeta: metav1.ObjectMeta{
   154  						Namespace: ns,
   155  					},
   156  					Spec: clusterv1.ClusterSpec{
   157  						ControlPlaneRef: contract.ObjToRef(controlPlaneUpgrading),
   158  					},
   159  				},
   160  				controlPlane: controlPlaneUpgrading,
   161  				machineSet:   &clusterv1.MachineSet{},
   162  				wantPass:     false,
   163  			},
   164  			{
   165  				name: "control plane preflight check: should pass if the control plane is upgrading but the preflight check is skipped",
   166  				cluster: &clusterv1.Cluster{
   167  					ObjectMeta: metav1.ObjectMeta{
   168  						Namespace: ns,
   169  					},
   170  					Spec: clusterv1.ClusterSpec{
   171  						ControlPlaneRef: contract.ObjToRef(controlPlaneUpgrading),
   172  					},
   173  				},
   174  				controlPlane: controlPlaneUpgrading,
   175  				machineSet: &clusterv1.MachineSet{
   176  					ObjectMeta: metav1.ObjectMeta{
   177  						Namespace: ns,
   178  						Annotations: map[string]string{
   179  							clusterv1.MachineSetSkipPreflightChecksAnnotation: string(clusterv1.MachineSetPreflightCheckControlPlaneIsStable),
   180  						},
   181  					},
   182  					Spec: clusterv1.MachineSetSpec{
   183  						Template: clusterv1.MachineTemplateSpec{
   184  							Spec: clusterv1.MachineSpec{
   185  								Version:   ptr.To("v1.26.2"),
   186  								Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{Kind: "KubeadmConfigTemplate"}},
   187  							},
   188  						},
   189  					},
   190  				},
   191  				wantPass: true,
   192  			},
   193  			{
   194  				name: "control plane preflight check: should pass if the control plane is stable",
   195  				cluster: &clusterv1.Cluster{
   196  					ObjectMeta: metav1.ObjectMeta{
   197  						Namespace: ns,
   198  					},
   199  					Spec: clusterv1.ClusterSpec{
   200  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   201  					},
   202  				},
   203  				controlPlane: controlPlaneStable,
   204  				machineSet:   &clusterv1.MachineSet{},
   205  				wantPass:     true,
   206  			},
   207  			{
   208  				name: "should pass if the machine set version is not defined",
   209  				cluster: &clusterv1.Cluster{
   210  					ObjectMeta: metav1.ObjectMeta{
   211  						Namespace: ns,
   212  					},
   213  					Spec: clusterv1.ClusterSpec{
   214  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   215  					},
   216  				},
   217  				controlPlane: controlPlaneStable,
   218  				machineSet: &clusterv1.MachineSet{
   219  					ObjectMeta: metav1.ObjectMeta{
   220  						Namespace: ns,
   221  					},
   222  					Spec: clusterv1.MachineSetSpec{},
   223  				},
   224  				wantPass: true,
   225  			},
   226  			{
   227  				name: "should error if the machine set version is invalid",
   228  				cluster: &clusterv1.Cluster{
   229  					ObjectMeta: metav1.ObjectMeta{
   230  						Namespace: ns,
   231  					},
   232  					Spec: clusterv1.ClusterSpec{
   233  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   234  					},
   235  				},
   236  				controlPlane: controlPlaneStable,
   237  				machineSet: &clusterv1.MachineSet{
   238  					ObjectMeta: metav1.ObjectMeta{
   239  						Namespace: ns,
   240  					},
   241  					Spec: clusterv1.MachineSetSpec{
   242  						Template: clusterv1.MachineTemplateSpec{
   243  							Spec: clusterv1.MachineSpec{
   244  								Version: ptr.To("v1.27.0.0"),
   245  							},
   246  						},
   247  					},
   248  				},
   249  				wantErr: true,
   250  			},
   251  			{
   252  				name: "kubernetes version preflight check: should fail if the machine set minor version is greater than control plane minor version",
   253  				cluster: &clusterv1.Cluster{
   254  					ObjectMeta: metav1.ObjectMeta{
   255  						Namespace: ns,
   256  					},
   257  					Spec: clusterv1.ClusterSpec{
   258  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   259  					},
   260  				},
   261  				controlPlane: controlPlaneStable,
   262  				machineSet: &clusterv1.MachineSet{
   263  					ObjectMeta: metav1.ObjectMeta{
   264  						Namespace: ns,
   265  					},
   266  					Spec: clusterv1.MachineSetSpec{
   267  						Template: clusterv1.MachineTemplateSpec{
   268  							Spec: clusterv1.MachineSpec{
   269  								Version: ptr.To("v1.27.0"),
   270  							},
   271  						},
   272  					},
   273  				},
   274  				wantPass: false,
   275  			},
   276  			{
   277  				name: "kubernetes version preflight check: should fail if the machine set minor version is 4 older than control plane minor version for >= v1.28",
   278  				cluster: &clusterv1.Cluster{
   279  					ObjectMeta: metav1.ObjectMeta{
   280  						Namespace: ns,
   281  					},
   282  					Spec: clusterv1.ClusterSpec{
   283  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable128),
   284  					},
   285  				},
   286  				controlPlane: controlPlaneStable128,
   287  				machineSet: &clusterv1.MachineSet{
   288  					ObjectMeta: metav1.ObjectMeta{
   289  						Namespace: ns,
   290  					},
   291  					Spec: clusterv1.MachineSetSpec{
   292  						Template: clusterv1.MachineTemplateSpec{
   293  							Spec: clusterv1.MachineSpec{
   294  								Version: ptr.To("v1.24.0"),
   295  							},
   296  						},
   297  					},
   298  				},
   299  				wantPass: false,
   300  			},
   301  			{
   302  				name: "kubernetes version preflight check: should fail if the machine set minor version is 3 older than control plane minor version for < v1.28",
   303  				cluster: &clusterv1.Cluster{
   304  					ObjectMeta: metav1.ObjectMeta{
   305  						Namespace: ns,
   306  					},
   307  					Spec: clusterv1.ClusterSpec{
   308  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   309  					},
   310  				},
   311  				controlPlane: controlPlaneStable,
   312  				machineSet: &clusterv1.MachineSet{
   313  					ObjectMeta: metav1.ObjectMeta{
   314  						Namespace: ns,
   315  					},
   316  					Spec: clusterv1.MachineSetSpec{
   317  						Template: clusterv1.MachineTemplateSpec{
   318  							Spec: clusterv1.MachineSpec{
   319  								Version: ptr.To("v1.23.0"),
   320  							},
   321  						},
   322  					},
   323  				},
   324  				wantPass: false,
   325  			},
   326  			{
   327  				name: "kubernetes version preflight check: should pass if the machine set minor version is greater than control plane minor version but the preflight check is skipped",
   328  				cluster: &clusterv1.Cluster{
   329  					ObjectMeta: metav1.ObjectMeta{
   330  						Namespace: ns,
   331  					},
   332  					Spec: clusterv1.ClusterSpec{
   333  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   334  					},
   335  				},
   336  				controlPlane: controlPlaneStable,
   337  				machineSet: &clusterv1.MachineSet{
   338  					ObjectMeta: metav1.ObjectMeta{
   339  						Namespace: ns,
   340  						Annotations: map[string]string{
   341  							clusterv1.MachineSetSkipPreflightChecksAnnotation: string(clusterv1.MachineSetPreflightCheckKubernetesVersionSkew),
   342  						},
   343  					},
   344  					Spec: clusterv1.MachineSetSpec{
   345  						Template: clusterv1.MachineTemplateSpec{
   346  							Spec: clusterv1.MachineSpec{
   347  								Version: ptr.To("v1.27.0"),
   348  							},
   349  						},
   350  					},
   351  				},
   352  				wantPass: true,
   353  			},
   354  			{
   355  				name: "kubernetes version preflight check: should pass if the machine set minor version and control plane version conform to kubernetes version skew policy >= v1.28",
   356  				cluster: &clusterv1.Cluster{
   357  					ObjectMeta: metav1.ObjectMeta{
   358  						Namespace: ns,
   359  					},
   360  					Spec: clusterv1.ClusterSpec{
   361  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable128),
   362  					},
   363  				},
   364  				controlPlane: controlPlaneStable128,
   365  				machineSet: &clusterv1.MachineSet{
   366  					ObjectMeta: metav1.ObjectMeta{
   367  						Namespace: ns,
   368  					},
   369  					Spec: clusterv1.MachineSetSpec{
   370  						Template: clusterv1.MachineTemplateSpec{
   371  							Spec: clusterv1.MachineSpec{
   372  								Version: ptr.To("v1.25.0"),
   373  							},
   374  						},
   375  					},
   376  				},
   377  				wantPass: true,
   378  			},
   379  			{
   380  				name: "kubernetes version preflight check: should pass if the machine set minor version and control plane version conform to kubernetes version skew policy < v1.28",
   381  				cluster: &clusterv1.Cluster{
   382  					ObjectMeta: metav1.ObjectMeta{
   383  						Namespace: ns,
   384  					},
   385  					Spec: clusterv1.ClusterSpec{
   386  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   387  					},
   388  				},
   389  				controlPlane: controlPlaneStable,
   390  				machineSet: &clusterv1.MachineSet{
   391  					ObjectMeta: metav1.ObjectMeta{
   392  						Namespace: ns,
   393  					},
   394  					Spec: clusterv1.MachineSetSpec{
   395  						Template: clusterv1.MachineTemplateSpec{
   396  							Spec: clusterv1.MachineSpec{
   397  								Version: ptr.To("v1.24.0"),
   398  							},
   399  						},
   400  					},
   401  				},
   402  				wantPass: true,
   403  			},
   404  			{
   405  				name: "kubeadm version preflight check: should fail if the machine set version is not equal (major+minor) to control plane version when using kubeadm bootstrap provider",
   406  				cluster: &clusterv1.Cluster{
   407  					ObjectMeta: metav1.ObjectMeta{
   408  						Namespace: ns,
   409  					},
   410  					Spec: clusterv1.ClusterSpec{
   411  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   412  					},
   413  				},
   414  				controlPlane: controlPlaneStable,
   415  				machineSet: &clusterv1.MachineSet{
   416  					ObjectMeta: metav1.ObjectMeta{
   417  						Namespace: ns,
   418  					},
   419  					Spec: clusterv1.MachineSetSpec{
   420  						Template: clusterv1.MachineTemplateSpec{
   421  							Spec: clusterv1.MachineSpec{
   422  								Version: ptr.To("v1.25.5"),
   423  								Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{
   424  									APIVersion: bootstrapv1.GroupVersion.String(),
   425  									Kind:       "KubeadmConfigTemplate",
   426  								}},
   427  							},
   428  						},
   429  					},
   430  				},
   431  				wantPass: false,
   432  			},
   433  			{
   434  				name: "kubeadm version preflight check: should pass if the machine set is not using kubeadm bootstrap provider",
   435  				cluster: &clusterv1.Cluster{
   436  					ObjectMeta: metav1.ObjectMeta{
   437  						Namespace: ns,
   438  					},
   439  					Spec: clusterv1.ClusterSpec{
   440  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   441  					},
   442  				},
   443  				controlPlane: controlPlaneStable,
   444  				machineSet: &clusterv1.MachineSet{
   445  					ObjectMeta: metav1.ObjectMeta{
   446  						Namespace: ns,
   447  					},
   448  					Spec: clusterv1.MachineSetSpec{
   449  						Template: clusterv1.MachineTemplateSpec{
   450  							Spec: clusterv1.MachineSpec{
   451  								Version: ptr.To("v1.25.0"),
   452  							},
   453  						},
   454  					},
   455  				},
   456  				wantPass: true,
   457  			},
   458  			{
   459  				name: "kubeadm version preflight check: should pass if the machine set version and control plane version do not conform to kubeadm version skew policy but the preflight check is skipped",
   460  				cluster: &clusterv1.Cluster{
   461  					ObjectMeta: metav1.ObjectMeta{
   462  						Namespace: ns,
   463  					},
   464  					Spec: clusterv1.ClusterSpec{
   465  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   466  					},
   467  				},
   468  				controlPlane: controlPlaneStable,
   469  				machineSet: &clusterv1.MachineSet{
   470  					ObjectMeta: metav1.ObjectMeta{
   471  						Namespace: ns,
   472  						Annotations: map[string]string{
   473  							clusterv1.MachineSetSkipPreflightChecksAnnotation: "foobar," + string(clusterv1.MachineSetPreflightCheckKubeadmVersionSkew),
   474  						},
   475  					},
   476  					Spec: clusterv1.MachineSetSpec{
   477  						Template: clusterv1.MachineTemplateSpec{
   478  							Spec: clusterv1.MachineSpec{
   479  								Version: ptr.To("v1.25.0"),
   480  								Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{
   481  									APIVersion: bootstrapv1.GroupVersion.String(),
   482  									Kind:       "KubeadmConfigTemplate",
   483  								}},
   484  							},
   485  						},
   486  					},
   487  				},
   488  				wantPass: true,
   489  			},
   490  			{
   491  				name: "kubeadm version preflight check: should pass if the machine set version and control plane version conform to kubeadm version skew when using kubeadm bootstrap provider",
   492  				cluster: &clusterv1.Cluster{
   493  					ObjectMeta: metav1.ObjectMeta{
   494  						Namespace: ns,
   495  					},
   496  					Spec: clusterv1.ClusterSpec{
   497  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   498  					},
   499  				},
   500  				controlPlane: controlPlaneStable,
   501  				machineSet: &clusterv1.MachineSet{
   502  					ObjectMeta: metav1.ObjectMeta{
   503  						Namespace: ns,
   504  					},
   505  					Spec: clusterv1.MachineSetSpec{
   506  						Template: clusterv1.MachineTemplateSpec{
   507  							Spec: clusterv1.MachineSpec{
   508  								Version: ptr.To("v1.26.2"),
   509  								Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{
   510  									APIVersion: bootstrapv1.GroupVersion.String(),
   511  									Kind:       "KubeadmConfigTemplate",
   512  								}},
   513  							},
   514  						},
   515  					},
   516  				},
   517  				wantPass: true,
   518  			},
   519  			{
   520  				name: "kubeadm version preflight check: should error if the bootstrap ref APIVersion is invalid",
   521  				cluster: &clusterv1.Cluster{
   522  					ObjectMeta: metav1.ObjectMeta{
   523  						Namespace: ns,
   524  					},
   525  					Spec: clusterv1.ClusterSpec{
   526  						ControlPlaneRef: contract.ObjToRef(controlPlaneStable),
   527  					},
   528  				},
   529  				controlPlane: controlPlaneStable,
   530  				machineSet: &clusterv1.MachineSet{
   531  					ObjectMeta: metav1.ObjectMeta{
   532  						Namespace: ns,
   533  					},
   534  					Spec: clusterv1.MachineSetSpec{
   535  						Template: clusterv1.MachineTemplateSpec{
   536  							Spec: clusterv1.MachineSpec{
   537  								Version: ptr.To("v1.26.2"),
   538  								Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{
   539  									APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1/invalid",
   540  									Kind:       "KubeadmConfigTemplate",
   541  								}},
   542  							},
   543  						},
   544  					},
   545  				},
   546  				wantErr: true,
   547  			},
   548  		}
   549  
   550  		for _, tt := range tests {
   551  			t.Run(tt.name, func(t *testing.T) {
   552  				g := NewWithT(t)
   553  				objs := []client.Object{}
   554  				if tt.controlPlane != nil {
   555  					objs = append(objs, tt.controlPlane)
   556  				}
   557  				fakeClient := fake.NewClientBuilder().WithObjects(objs...).Build()
   558  				r := &Reconciler{
   559  					Client:                    fakeClient,
   560  					UnstructuredCachingClient: fakeClient,
   561  				}
   562  				result, _, err := r.runPreflightChecks(ctx, tt.cluster, tt.machineSet, "")
   563  				if tt.wantErr {
   564  					g.Expect(err).To(HaveOccurred())
   565  				} else {
   566  					g.Expect(err).ToNot(HaveOccurred())
   567  					g.Expect(result.IsZero()).To(Equal(tt.wantPass))
   568  				}
   569  			})
   570  		}
   571  	})
   572  
   573  	t.Run("should not run the preflight checks if the feature gate is disabled", func(t *testing.T) {
   574  		defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachineSetPreflightChecks, false)()
   575  
   576  		g := NewWithT(t)
   577  		cluster := &clusterv1.Cluster{
   578  			ObjectMeta: metav1.ObjectMeta{
   579  				Namespace: ns,
   580  			},
   581  			Spec: clusterv1.ClusterSpec{
   582  				ControlPlaneRef: contract.ObjToRef(controlPlaneUpgrading),
   583  			},
   584  		}
   585  		controlPlane := controlPlaneUpgrading
   586  		machineSet := &clusterv1.MachineSet{
   587  			ObjectMeta: metav1.ObjectMeta{
   588  				Namespace: ns,
   589  			},
   590  			Spec: clusterv1.MachineSetSpec{
   591  				Template: clusterv1.MachineTemplateSpec{
   592  					Spec: clusterv1.MachineSpec{
   593  						Version: ptr.To("v1.26.0"),
   594  						Bootstrap: clusterv1.Bootstrap{ConfigRef: &corev1.ObjectReference{
   595  							APIVersion: bootstrapv1.GroupVersion.String(),
   596  							Kind:       "KubeadmConfigTemplate",
   597  						}},
   598  					},
   599  				},
   600  			},
   601  		}
   602  		fakeClient := fake.NewClientBuilder().WithObjects(controlPlane).Build()
   603  		r := &Reconciler{Client: fakeClient}
   604  		result, _, err := r.runPreflightChecks(ctx, cluster, machineSet, "")
   605  		g.Expect(err).ToNot(HaveOccurred())
   606  		g.Expect(result.IsZero()).To(BeTrue())
   607  	})
   608  }