diff --git a/controlplane/kubeadm/api/v1alpha3/conversion.go b/controlplane/kubeadm/api/v1alpha3/conversion.go index 7edfab18c211..033262a0b240 100644 --- a/controlplane/kubeadm/api/v1alpha3/conversion.go +++ b/controlplane/kubeadm/api/v1alpha3/conversion.go @@ -19,7 +19,6 @@ package v1alpha3 import ( apiconversion "k8s.io/apimachinery/pkg/conversion" "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha4" - utilconversion "sigs.k8s.io/cluster-api/util/conversion" "sigs.k8s.io/controller-runtime/pkg/conversion" ) @@ -38,6 +37,7 @@ func (src *KubeadmControlPlane) ConvertTo(destRaw conversion.Hub) error { } dest.Spec.RolloutStrategy = restored.Spec.RolloutStrategy + dest.Spec.MachineTemplate.ObjectMeta = restored.Spec.MachineTemplate.ObjectMeta return nil } @@ -69,10 +69,12 @@ func (dest *KubeadmControlPlaneList) ConvertFrom(srcRaw conversion.Hub) error { func Convert_v1alpha4_KubeadmControlPlaneSpec_To_v1alpha3_KubeadmControlPlaneSpec(in *v1alpha4.KubeadmControlPlaneSpec, out *KubeadmControlPlaneSpec, s apiconversion.Scope) error { out.UpgradeAfter = in.RolloutAfter + out.InfrastructureTemplate = in.MachineTemplate.InfrastructureRef return autoConvert_v1alpha4_KubeadmControlPlaneSpec_To_v1alpha3_KubeadmControlPlaneSpec(in, out, s) } func Convert_v1alpha3_KubeadmControlPlaneSpec_To_v1alpha4_KubeadmControlPlaneSpec(in *KubeadmControlPlaneSpec, out *v1alpha4.KubeadmControlPlaneSpec, s apiconversion.Scope) error { out.RolloutAfter = in.UpgradeAfter + out.MachineTemplate.InfrastructureRef = in.InfrastructureTemplate return autoConvert_v1alpha3_KubeadmControlPlaneSpec_To_v1alpha4_KubeadmControlPlaneSpec(in, out, s) } diff --git a/controlplane/kubeadm/api/v1alpha3/webhook_test.go b/controlplane/kubeadm/api/v1alpha3/webhook_test.go index b6991fce6702..07579b77d28b 100644 --- a/controlplane/kubeadm/api/v1alpha3/webhook_test.go +++ b/controlplane/kubeadm/api/v1alpha3/webhook_test.go @@ -34,11 +34,12 @@ import ( func TestKubeadmControlPlaneConversion(t *testing.T) { g := NewWithT(t) + ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("conversion-webhook-%s", util.RandomString(5))) g.Expect(err).ToNot(HaveOccurred()) infraMachineTemplateName := fmt.Sprintf("test-machinetemplate-%s", util.RandomString(5)) controlPlaneName := fmt.Sprintf("test-controlpane-%s", util.RandomString(5)) - controlPane := &KubeadmControlPlane{ + controlPlane := &KubeadmControlPlane{ ObjectMeta: metav1.ObjectMeta{ Name: controlPlaneName, Namespace: ns.Name, @@ -86,8 +87,8 @@ func TestKubeadmControlPlaneConversion(t *testing.T) { }, } - g.Expect(testEnv.Create(ctx, controlPane)).To(Succeed()) + g.Expect(testEnv.Create(ctx, controlPlane)).To(Succeed()) defer func(do ...client.Object) { g.Expect(testEnv.Cleanup(ctx, do...)).To(Succeed()) - }(ns, controlPane) + }(ns, controlPlane) } diff --git a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_types.go b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_types.go index c32bb75ae135..87e3a15bb202 100644 --- a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_types.go +++ b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_types.go @@ -58,9 +58,9 @@ type KubeadmControlPlaneSpec struct { // Version defines the desired Kubernetes version. Version string `json:"version"` - // InfrastructureTemplate is a required reference to a custom resource - // offered by an infrastructure provider. - InfrastructureTemplate corev1.ObjectReference `json:"infrastructureTemplate"` + // MachineTemplate contains information about how machines + // should be shaped when creating or updating a control plane. + MachineTemplate KubeadmControlPlaneMachineTemplate `json:"machineTemplate"` // KubeadmConfigSpec is a KubeadmConfigSpec // to use for initializing and joining machines to the control plane. @@ -85,6 +85,17 @@ type KubeadmControlPlaneSpec struct { RolloutStrategy *RolloutStrategy `json:"rolloutStrategy,omitempty"` } +type KubeadmControlPlaneMachineTemplate struct { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + ObjectMeta clusterv1.ObjectMeta `json:"metadata,omitempty"` + + // InfrastructureRef is a required reference to a custom resource + // offered by an infrastructure provider. + InfrastructureRef corev1.ObjectReference `json:"infrastructureRef"` +} + // RolloutStrategy describes how to replace existing machines // with new ones. type RolloutStrategy struct { diff --git a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook.go b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook.go index 0361aa5c3dcc..7e3da35dc6c5 100644 --- a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook.go +++ b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook.go @@ -54,8 +54,8 @@ func (in *KubeadmControlPlane) Default() { in.Spec.Replicas = &replicas } - if in.Spec.InfrastructureTemplate.Namespace == "" { - in.Spec.InfrastructureTemplate.Namespace = in.Namespace + if in.Spec.MachineTemplate.InfrastructureRef.Namespace == "" { + in.Spec.MachineTemplate.InfrastructureRef.Namespace = in.Namespace } if !strings.HasPrefix(in.Spec.Version, "v") { @@ -112,7 +112,7 @@ const ( // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type. func (in *KubeadmControlPlane) ValidateUpdate(old runtime.Object) error { // add a * to indicate everything beneath is ok. - // For example, {"spec", "*"} will allow any path under "spec" to change, such as spec.infrastructureTemplate.name + // For example, {"spec", "*"} will allow any path under "spec" to change. allowedPaths := [][]string{ {"metadata", "*"}, {spec, kubeadmConfigSpec, clusterConfiguration, "etcd", "local", "imageRepository"}, @@ -130,7 +130,8 @@ func (in *KubeadmControlPlane) ValidateUpdate(old runtime.Object) error { {spec, kubeadmConfigSpec, files}, {spec, kubeadmConfigSpec, "verbosity"}, {spec, kubeadmConfigSpec, users}, - {spec, "infrastructureTemplate", "name"}, + {spec, "machineTemplate", "metadata"}, + {spec, "machineTemplate", "infrastructureRef", "name"}, {spec, "replicas"}, {spec, "version"}, {spec, "rolloutAfter"}, @@ -274,12 +275,32 @@ func (in *KubeadmControlPlane) validateCommon() (allErrs field.ErrorList) { } } - if in.Spec.InfrastructureTemplate.Namespace != in.Namespace { + if in.Spec.MachineTemplate.InfrastructureRef.APIVersion == "" { allErrs = append( allErrs, field.Invalid( - field.NewPath("spec", "infrastructureTemplate", "namespace"), - in.Spec.InfrastructureTemplate.Namespace, + field.NewPath("spec", "machineTemplate", "infrastructure", "apiVersion"), + in.Spec.MachineTemplate.InfrastructureRef.APIVersion, + "cannot be empty", + ), + ) + } + if in.Spec.MachineTemplate.InfrastructureRef.Kind == "" { + allErrs = append( + allErrs, + field.Invalid( + field.NewPath("spec", "machineTemplate", "infrastructure", "kind"), + in.Spec.MachineTemplate.InfrastructureRef.Kind, + "cannot be empty", + ), + ) + } + if in.Spec.MachineTemplate.InfrastructureRef.Namespace != in.Namespace { + allErrs = append( + allErrs, + field.Invalid( + field.NewPath("spec", "machineTemplate", "infrastructure", "namespace"), + in.Spec.MachineTemplate.InfrastructureRef.Namespace, "must match metadata.namespace", ), ) diff --git a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook_test.go b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook_test.go index aa1b89a21cfd..6c3cba83a7c9 100644 --- a/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook_test.go +++ b/controlplane/kubeadm/api/v1alpha4/kubeadm_control_plane_webhook_test.go @@ -37,20 +37,29 @@ func TestKubeadmControlPlaneDefault(t *testing.T) { Namespace: "foo", }, Spec: KubeadmControlPlaneSpec{ - Version: "v1.18.3", - InfrastructureTemplate: corev1.ObjectReference{}, - RolloutStrategy: &RolloutStrategy{}, + Version: "v1.18.3", + MachineTemplate: KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, + RolloutStrategy: &RolloutStrategy{}, }, } updateDefaultingValidationKCP := kcp.DeepCopy() updateDefaultingValidationKCP.Spec.Version = "v1.18.3" - updateDefaultingValidationKCP.Spec.InfrastructureTemplate = corev1.ObjectReference{ - Namespace: "foo", + updateDefaultingValidationKCP.Spec.MachineTemplate.InfrastructureRef = corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + Namespace: "foo", } t.Run("for KubeadmControlPLane", utildefaulting.DefaultValidateTest(updateDefaultingValidationKCP)) kcp.Default() - g.Expect(kcp.Spec.InfrastructureTemplate.Namespace).To(Equal(kcp.Namespace)) + g.Expect(kcp.Spec.MachineTemplate.InfrastructureRef.Namespace).To(Equal(kcp.Namespace)) g.Expect(kcp.Spec.Version).To(Equal("v1.18.3")) g.Expect(kcp.Spec.RolloutStrategy.Type).To(Equal(RollingUpdateStrategyType)) g.Expect(kcp.Spec.RolloutStrategy.RollingUpdate.MaxSurge.IntVal).To(Equal(int32(1))) @@ -63,9 +72,13 @@ func TestKubeadmControlPlaneValidateCreate(t *testing.T) { Namespace: "foo", }, Spec: KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Namespace: "foo", - Name: "infraTemplate", + MachineTemplate: KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Namespace: "foo", + Name: "infraTemplate", + }, }, Replicas: pointer.Int32Ptr(1), Version: "v1.19.0", @@ -84,7 +97,7 @@ func TestKubeadmControlPlaneValidateCreate(t *testing.T) { invalidMaxSurge.Spec.RolloutStrategy.RollingUpdate.MaxSurge.IntVal = int32(3) invalidNamespace := valid.DeepCopy() - invalidNamespace.Spec.InfrastructureTemplate.Namespace = "bar" + invalidNamespace.Spec.MachineTemplate.InfrastructureRef.Namespace = "bar" missingReplicas := valid.DeepCopy() missingReplicas.Spec.Replicas = nil @@ -190,9 +203,13 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { Namespace: "foo", }, Spec: KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Namespace: "foo", - Name: "infraTemplate", + MachineTemplate: KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Namespace: "foo", + Name: "infraTemplate", + }, }, Replicas: pointer.Int32Ptr(1), RolloutStrategy: &RolloutStrategy{ @@ -300,7 +317,7 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { }, }, } - validUpdate.Spec.InfrastructureTemplate.Name = "orange" + validUpdate.Spec.MachineTemplate.InfrastructureRef.Name = "orange" validUpdate.Spec.Replicas = pointer.Int32Ptr(5) now := metav1.NewTime(time.Now()) validUpdate.Spec.RolloutAfter = &now @@ -312,7 +329,7 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) { scaleToEven.Spec.Replicas = pointer.Int32Ptr(2) invalidNamespace := before.DeepCopy() - invalidNamespace.Spec.InfrastructureTemplate.Namespace = "bar" + invalidNamespace.Spec.MachineTemplate.InfrastructureRef.Namespace = "bar" missingReplicas := before.DeepCopy() missingReplicas.Spec.Replicas = nil @@ -804,9 +821,13 @@ func TestKubeadmControlPlaneValidateUpdateAfterDefaulting(t *testing.T) { }, Spec: KubeadmControlPlaneSpec{ Version: "v1.19.0", - InfrastructureTemplate: corev1.ObjectReference{ - Namespace: "foo", - Name: "infraTemplate", + MachineTemplate: KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Namespace: "foo", + Name: "infraTemplate", + }, }, }, } @@ -836,7 +857,7 @@ func TestKubeadmControlPlaneValidateUpdateAfterDefaulting(t *testing.T) { g.Expect(err).To(HaveOccurred()) } else { g.Expect(err).To(Succeed()) - g.Expect(tt.kcp.Spec.InfrastructureTemplate.Namespace).To(Equal(tt.before.Namespace)) + g.Expect(tt.kcp.Spec.MachineTemplate.InfrastructureRef.Namespace).To(Equal(tt.before.Namespace)) g.Expect(tt.kcp.Spec.Version).To(Equal("v1.19.0")) g.Expect(tt.kcp.Spec.RolloutStrategy.Type).To(Equal(RollingUpdateStrategyType)) g.Expect(tt.kcp.Spec.RolloutStrategy.RollingUpdate.MaxSurge.IntVal).To(Equal(int32(1))) diff --git a/controlplane/kubeadm/controllers/controller.go b/controlplane/kubeadm/controllers/controller.go index 3a27a7c77da3..5f20401a4dcd 100644 --- a/controlplane/kubeadm/controllers/controller.go +++ b/controlplane/kubeadm/controllers/controller.go @@ -235,7 +235,7 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster * log.Info("Reconcile KubeadmControlPlane") // Make sure to reconcile the external infrastructure reference. - if err := r.reconcileExternalReference(ctx, cluster, kcp.Spec.InfrastructureTemplate); err != nil { + if err := r.reconcileExternalReference(ctx, cluster, &kcp.Spec.MachineTemplate.InfrastructureRef); err != nil { return ctrl.Result{}, err } diff --git a/controlplane/kubeadm/controllers/controller_test.go b/controlplane/kubeadm/controllers/controller_test.go index 1558c2a6a0e3..c9a8f94211fc 100644 --- a/controlplane/kubeadm/controllers/controller_test.go +++ b/controlplane/kubeadm/controllers/controller_test.go @@ -211,6 +211,14 @@ func TestReconcileNoClusterOwnerRef(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "UnknownInfraMachine", + APIVersion: "test/v1alpha1", + Name: "foo", + Namespace: "test", + }, + }, }, } kcp.Default() @@ -241,6 +249,14 @@ func TestReconcileNoKCP(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "UnknownInfraMachine", + APIVersion: "test/v1alpha1", + Name: "foo", + Namespace: "test", + }, + }, }, } @@ -271,6 +287,14 @@ func TestReconcileNoCluster(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "UnknownInfraMachine", + APIVersion: "test/v1alpha1", + Name: "foo", + Namespace: "test", + }, + }, }, } kcp.Default() @@ -312,6 +336,14 @@ func TestReconcilePaused(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "UnknownInfraMachine", + APIVersion: "test/v1alpha1", + Name: "foo", + Namespace: "test", + }, + }, }, } kcp.Default() @@ -357,6 +389,14 @@ func TestReconcileClusterNoEndpoints(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "UnknownInfraMachine", + APIVersion: "test/v1alpha1", + Name: "foo", + Namespace: "test", + }, + }, }, } kcp.Default() @@ -419,7 +459,7 @@ func TestKubeadmControlPlaneReconciler_adoption(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), }, Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ @@ -482,7 +522,7 @@ func TestKubeadmControlPlaneReconciler_adoption(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), }, Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ @@ -590,7 +630,7 @@ func TestKubeadmControlPlaneReconciler_adoption(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), }, Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ @@ -647,7 +687,7 @@ func TestKubeadmControlPlaneReconciler_adoption(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "test0", - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), }, Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ @@ -731,11 +771,13 @@ func TestReconcileInitializeControlPlane(t *testing.T) { Spec: controlplanev1.KubeadmControlPlaneSpec{ Replicas: nil, Version: "v1.16.6", - InfrastructureTemplate: corev1.ObjectReference{ - Kind: genericMachineTemplate.GetKind(), - APIVersion: genericMachineTemplate.GetAPIVersion(), - Name: genericMachineTemplate.GetName(), - Namespace: cluster.Namespace, + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: genericMachineTemplate.GetKind(), + APIVersion: genericMachineTemplate.GetAPIVersion(), + Name: genericMachineTemplate.GetName(), + Namespace: cluster.Namespace, + }, }, KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{}, }, @@ -1322,11 +1364,13 @@ func createClusterWithControlPlane() (*clusterv1.Cluster, *controlplanev1.Kubead }, }, Spec: controlplanev1.KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Kind: "GenericMachineTemplate", - Namespace: namespace, - Name: "infra-foo", - APIVersion: "generic.io/v1", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "GenericMachineTemplate", + Namespace: namespace, + Name: "infra-foo", + APIVersion: "generic.io/v1", + }, }, Replicas: pointer.Int32Ptr(int32(3)), Version: "v1.16.6", @@ -1380,7 +1424,7 @@ func createMachineNodePair(name string, cluster *clusterv1.Cluster, kcp *control ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(kcp, controlplanev1.GroupVersion.WithKind("KubeadmControlPlane")), }, diff --git a/controlplane/kubeadm/controllers/helpers.go b/controlplane/kubeadm/controllers/helpers.go index cac2d01ccd45..f536396f239d 100644 --- a/controlplane/kubeadm/controllers/helpers.go +++ b/controlplane/kubeadm/controllers/helpers.go @@ -120,12 +120,12 @@ func (r *KubeadmControlPlaneReconciler) adoptKubeconfigSecret(ctx context.Contex return nil } -func (r *KubeadmControlPlaneReconciler) reconcileExternalReference(ctx context.Context, cluster *clusterv1.Cluster, ref corev1.ObjectReference) error { +func (r *KubeadmControlPlaneReconciler) reconcileExternalReference(ctx context.Context, cluster *clusterv1.Cluster, ref *corev1.ObjectReference) error { if !strings.HasSuffix(ref.Kind, external.TemplateSuffix) { return nil } - obj, err := external.Get(ctx, r.Client, &ref, cluster.Namespace) + obj, err := external.Get(ctx, r.Client, ref, cluster.Namespace) if err != nil { return err } @@ -162,11 +162,12 @@ func (r *KubeadmControlPlaneReconciler) cloneConfigsAndGenerateMachine(ctx conte // Clone the infrastructure template infraRef, err := external.CloneTemplate(ctx, &external.CloneTemplateInput{ Client: r.Client, - TemplateRef: &kcp.Spec.InfrastructureTemplate, + TemplateRef: &kcp.Spec.MachineTemplate.InfrastructureRef, Namespace: kcp.Namespace, OwnerRef: infraCloneOwner, ClusterName: cluster.Name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), + Annotations: kcp.Spec.MachineTemplate.ObjectMeta.Annotations, }) if err != nil { // Safe to return early here since no resources have been created yet. @@ -237,7 +238,8 @@ func (r *KubeadmControlPlaneReconciler) generateKubeadmConfig(ctx context.Contex ObjectMeta: metav1.ObjectMeta{ Name: names.SimpleNameGenerator.GenerateName(kcp.Name + "-"), Namespace: kcp.Namespace, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), + Annotations: kcp.Spec.MachineTemplate.ObjectMeta.Annotations, OwnerReferences: []metav1.OwnerReference{owner}, }, Spec: *spec, @@ -261,9 +263,10 @@ func (r *KubeadmControlPlaneReconciler) generateKubeadmConfig(ctx context.Contex func (r *KubeadmControlPlaneReconciler) generateMachine(ctx context.Context, kcp *controlplanev1.KubeadmControlPlane, cluster *clusterv1.Cluster, infraRef, bootstrapRef *corev1.ObjectReference, failureDomain *string) error { machine := &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ - Name: names.SimpleNameGenerator.GenerateName(kcp.Name + "-"), - Namespace: kcp.Namespace, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Name: names.SimpleNameGenerator.GenerateName(kcp.Name + "-"), + Namespace: kcp.Namespace, + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), + Annotations: kcp.Spec.MachineTemplate.ObjectMeta.Annotations, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(kcp, controlplanev1.GroupVersion.WithKind("KubeadmControlPlane")), }, diff --git a/controlplane/kubeadm/controllers/helpers_test.go b/controlplane/kubeadm/controllers/helpers_test.go index 53adfe86e67d..602359c17de5 100644 --- a/controlplane/kubeadm/controllers/helpers_test.go +++ b/controlplane/kubeadm/controllers/helpers_test.go @@ -357,11 +357,13 @@ func TestCloneConfigsAndGenerateMachine(t *testing.T) { Namespace: cluster.Namespace, }, Spec: controlplanev1.KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Kind: genericMachineTemplate.GetKind(), - APIVersion: genericMachineTemplate.GetAPIVersion(), - Name: genericMachineTemplate.GetName(), - Namespace: cluster.Namespace, + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: genericMachineTemplate.GetKind(), + APIVersion: genericMachineTemplate.GetAPIVersion(), + Name: genericMachineTemplate.GetName(), + Namespace: cluster.Namespace, + }, }, Version: "v1.16.6", }, @@ -439,11 +441,13 @@ func TestCloneConfigsAndGenerateMachineFail(t *testing.T) { Namespace: cluster.Namespace, }, Spec: controlplanev1.KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Kind: genericMachineTemplate.GetKind(), - APIVersion: genericMachineTemplate.GetAPIVersion(), - Name: genericMachineTemplate.GetName(), - Namespace: cluster.Namespace, + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: genericMachineTemplate.GetKind(), + APIVersion: genericMachineTemplate.GetAPIVersion(), + Name: genericMachineTemplate.GetName(), + Namespace: cluster.Namespace, + }, }, Version: "v1.16.6", }, @@ -461,7 +465,7 @@ func TestCloneConfigsAndGenerateMachineFail(t *testing.T) { } // Try to break Infra Cloning - kcp.Spec.InfrastructureTemplate.Name = "something_invalid" + kcp.Spec.MachineTemplate.InfrastructureRef.Name = "something_invalid" g.Expect(r.cloneConfigsAndGenerateMachine(ctx, cluster, kcp, bootstrapSpec, nil)).To(HaveOccurred()) g.Expect(&kcp.GetConditions()[0]).Should(conditions.HaveSameStateOf(&clusterv1.Condition{ Type: controlplanev1.MachinesCreatedCondition, diff --git a/controlplane/kubeadm/controllers/status_test.go b/controlplane/kubeadm/controllers/status_test.go index a6ec08c25270..446586119b4f 100644 --- a/controlplane/kubeadm/controllers/status_test.go +++ b/controlplane/kubeadm/controllers/status_test.go @@ -56,6 +56,13 @@ func TestKubeadmControlPlaneReconciler_updateStatusNoMachines(t *testing.T) { }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, }, } kcp.Default() @@ -105,6 +112,13 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesNotReady(t *testin }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, }, } kcp.Default() @@ -163,6 +177,13 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesReady(t *testing.T }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, }, } kcp.Default() @@ -229,6 +250,13 @@ func TestKubeadmControlPlaneReconciler_updateStatusMachinesReadyMixed(t *testing }, Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, }, } kcp.Default() @@ -295,6 +323,13 @@ func TestKubeadmControlPlaneReconciler_machinesCreatedIsIsTrueEvenWhenTheNodesAr Spec: controlplanev1.KubeadmControlPlaneSpec{ Version: "v1.16.6", Replicas: pointer.Int32Ptr(3), + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + APIVersion: "test/v1alpha1", + Kind: "UnknownInfraMachine", + Name: "foo", + }, + }, }, } kcp.Default() diff --git a/controlplane/kubeadm/controllers/upgrade_test.go b/controlplane/kubeadm/controllers/upgrade_test.go index a79c61b919aa..d09fca800247 100644 --- a/controlplane/kubeadm/controllers/upgrade_test.go +++ b/controlplane/kubeadm/controllers/upgrade_test.go @@ -153,7 +153,7 @@ func TestKubeadmControlPlaneReconciler_RolloutStrategy_ScaleDown(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: name, - Labels: internal.ControlPlaneLabelsForCluster(cluster.Name), + Labels: internal.ControlPlaneMachineLabelsForCluster(kcp, cluster.Name), }, Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ diff --git a/controlplane/kubeadm/internal/cluster_labels.go b/controlplane/kubeadm/internal/cluster_labels.go index f67b7c3825db..4adffc6b948e 100644 --- a/controlplane/kubeadm/internal/cluster_labels.go +++ b/controlplane/kubeadm/internal/cluster_labels.go @@ -18,12 +18,18 @@ package internal import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha4" ) -// ControlPlaneLabelsForCluster returns a set of labels to add to a control plane machine for this specific cluster. -func ControlPlaneLabelsForCluster(clusterName string) map[string]string { - return map[string]string{ - clusterv1.ClusterLabelName: clusterName, - clusterv1.MachineControlPlaneLabelName: "", +// ControlPlaneMachineLabelsForCluster returns a set of labels to add to a control plane machine for this specific cluster. +func ControlPlaneMachineLabelsForCluster(kcp *controlplanev1.KubeadmControlPlane, clusterName string) map[string]string { + labels := kcp.Spec.MachineTemplate.ObjectMeta.Labels + if labels == nil { + labels = map[string]string{} } + + // Always force these labels over the ones coming from the spec. + labels[clusterv1.ClusterLabelName] = clusterName + labels[clusterv1.MachineControlPlaneLabelName] = "" + return labels } diff --git a/controlplane/kubeadm/internal/control_plane.go b/controlplane/kubeadm/internal/control_plane.go index 9b943f433be7..29b6ba5bdf82 100644 --- a/controlplane/kubeadm/internal/control_plane.go +++ b/controlplane/kubeadm/internal/control_plane.go @@ -107,9 +107,9 @@ func (c *ControlPlane) Version() *string { return &c.KCP.Spec.Version } -// InfrastructureTemplate returns the KubeadmControlPlane's infrastructure template. -func (c *ControlPlane) InfrastructureTemplate() *corev1.ObjectReference { - return &c.KCP.Spec.InfrastructureTemplate +// MachineInfrastructureTemplateRef returns the KubeadmControlPlane's infrastructure template for Machines. +func (c *ControlPlane) MachineInfrastructureTemplateRef() *corev1.ObjectReference { + return &c.KCP.Spec.MachineTemplate.InfrastructureRef } // AsOwnerReference returns an owner reference to the KubeadmControlPlane. @@ -205,7 +205,8 @@ func (c *ControlPlane) GenerateKubeadmConfig(spec *bootstrapv1.KubeadmConfigSpec ObjectMeta: metav1.ObjectMeta{ Name: names.SimpleNameGenerator.GenerateName(c.KCP.Name + "-"), Namespace: c.KCP.Namespace, - Labels: ControlPlaneLabelsForCluster(c.Cluster.Name), + Labels: ControlPlaneMachineLabelsForCluster(c.KCP, c.Cluster.Name), + Annotations: c.KCP.Spec.MachineTemplate.ObjectMeta.Annotations, OwnerReferences: []metav1.OwnerReference{owner}, }, Spec: *spec, @@ -217,9 +218,10 @@ func (c *ControlPlane) GenerateKubeadmConfig(spec *bootstrapv1.KubeadmConfigSpec func (c *ControlPlane) NewMachine(infraRef, bootstrapRef *corev1.ObjectReference, failureDomain *string) *clusterv1.Machine { return &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ - Name: names.SimpleNameGenerator.GenerateName(c.KCP.Name + "-"), - Namespace: c.KCP.Namespace, - Labels: ControlPlaneLabelsForCluster(c.Cluster.Name), + Name: names.SimpleNameGenerator.GenerateName(c.KCP.Name + "-"), + Namespace: c.KCP.Namespace, + Labels: ControlPlaneMachineLabelsForCluster(c.KCP, c.Cluster.Name), + Annotations: c.KCP.Spec.MachineTemplate.ObjectMeta.Annotations, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(c.KCP, controlplanev1.GroupVersion.WithKind("KubeadmControlPlane")), }, @@ -261,7 +263,7 @@ func (c *ControlPlane) MachinesNeedingRollout() collections.Machines { // Machines that are scheduled for rollout (KCP.Spec.RolloutAfter set, the RolloutAfter deadline is expired, and the machine was created before the deadline). collections.ShouldRolloutAfter(&c.reconciliationTime, c.KCP.Spec.RolloutAfter), // Machines that do not match with KCP config. - collections.Not(MatchesKCPConfiguration(c.infraResources, c.kubeadmConfigs, c.KCP)), + collections.Not(MatchesMachineSpec(c.infraResources, c.kubeadmConfigs, c.KCP)), ) } diff --git a/controlplane/kubeadm/internal/filters.go b/controlplane/kubeadm/internal/filters.go index b2b5da9f6f56..85c5faabc674 100644 --- a/controlplane/kubeadm/internal/filters.go +++ b/controlplane/kubeadm/internal/filters.go @@ -25,12 +25,16 @@ import ( bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha4" controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha4" "sigs.k8s.io/cluster-api/util/collections" + "sigs.k8s.io/controller-runtime/pkg/client" ) -// MatchesKCPConfiguration returns a filter to find all machines that matches with KCP config and do not require any rollout. +// MatchesMachineSpec returns a filter to find all machines that matches with KCP config and do not require any rollout. // Kubernetes version, infrastructure template, and KubeadmConfig field need to be equivalent. -func MatchesKCPConfiguration(infraConfigs map[string]*unstructured.Unstructured, machineConfigs map[string]*bootstrapv1.KubeadmConfig, kcp *controlplanev1.KubeadmControlPlane) func(machine *clusterv1.Machine) bool { +func MatchesMachineSpec(infraConfigs map[string]*unstructured.Unstructured, machineConfigs map[string]*bootstrapv1.KubeadmConfig, kcp *controlplanev1.KubeadmControlPlane) func(machine *clusterv1.Machine) bool { return collections.And( + func(machine *clusterv1.Machine) bool { + return matchMachineTemplateMetadata(kcp, machine) + }, collections.MatchesKubernetesVersion(kcp.Spec.Version), MatchesKubeadmBootstrapConfig(machineConfigs, kcp), MatchesTemplateClonedFrom(infraConfigs, kcp), @@ -59,8 +63,13 @@ func MatchesTemplateClonedFrom(infraConfigs map[string]*unstructured.Unstructure } // Check if the machine's infrastructure reference has been created from the current KCP infrastructure template. - if clonedFromName != kcp.Spec.InfrastructureTemplate.Name || - clonedFromGroupKind != kcp.Spec.InfrastructureTemplate.GroupVersionKind().GroupKind().String() { + if clonedFromName != kcp.Spec.MachineTemplate.InfrastructureRef.Name || + clonedFromGroupKind != kcp.Spec.MachineTemplate.InfrastructureRef.GroupVersionKind().GroupKind().String() { + return false + } + + // Check if the machine template metadata matches with the infrastructure object. + if !matchMachineTemplateMetadata(kcp, infraObj) { return false } return true @@ -79,10 +88,29 @@ func MatchesKubeadmBootstrapConfig(machineConfigs map[string]*bootstrapv1.Kubead return false } + bootstrapRef := machine.Spec.Bootstrap.ConfigRef + if bootstrapRef == nil { + // Missing bootstrap reference should not be considered as unmatching. + // This is a safety precaution to avoid selecting machines that are broken, which in the future should be remediated separately. + return true + } + + machineConfig, found := machineConfigs[machine.Name] + if !found { + // Return true here because failing to get KubeadmConfig should not be considered as unmatching. + // This is a safety precaution to avoid rolling out machines if the client or the api-server is misbehaving. + return true + } + + // Check if the machine template metadata matches with the infrastructure object. + if !matchMachineTemplateMetadata(kcp, machineConfig) { + return false + } + // Check if KCP and machine InitConfiguration or JoinConfiguration matches // NOTE: only one between init configuration and join configuration is set on a machine, depending // on the fact that the machine was the initial control plane node or a joining control plane node. - return matchInitOrJoinConfiguration(machineConfigs, kcp, machine) + return matchInitOrJoinConfiguration(machineConfig, kcp) } } @@ -122,16 +150,8 @@ func matchClusterConfiguration(kcp *controlplanev1.KubeadmControlPlane, machine // matchInitOrJoinConfiguration verifies if KCP and machine InitConfiguration or JoinConfiguration matches. // NOTE: By extension this method takes care of detecting changes in other fields of the KubeadmConfig configuration (e.g. Files, Mounts etc.) -func matchInitOrJoinConfiguration(machineConfigs map[string]*bootstrapv1.KubeadmConfig, kcp *controlplanev1.KubeadmControlPlane, machine *clusterv1.Machine) bool { - bootstrapRef := machine.Spec.Bootstrap.ConfigRef - if bootstrapRef == nil { - // Missing bootstrap reference should not be considered as unmatching. - // This is a safety precaution to avoid selecting machines that are broken, which in the future should be remediated separately. - return true - } - - machineConfig, found := machineConfigs[machine.Name] - if !found { +func matchInitOrJoinConfiguration(machineConfig *bootstrapv1.KubeadmConfig, kcp *controlplanev1.KubeadmControlPlane) bool { + if machineConfig == nil { // Return true here because failing to get KubeadmConfig should not be considered as unmatching. // This is a safety precaution to avoid rolling out machines if the client or the api-server is misbehaving. return true @@ -212,3 +232,30 @@ func cleanupConfigFields(kcpConfig *bootstrapv1.KubeadmConfigSpec, machineConfig machineConfig.Spec.JoinConfiguration.TypeMeta = kcpConfig.JoinConfiguration.TypeMeta } } + +// matchMachineTemplateMetadata matches the machine template object meta information, +// specifically annotations and labels, against an object. +func matchMachineTemplateMetadata(kcp *controlplanev1.KubeadmControlPlane, obj client.Object) bool { + // Check if annotations and labels match. + if !isSubsetMapOf(kcp.Spec.MachineTemplate.ObjectMeta.Annotations, obj.GetAnnotations()) { + return false + } + if !isSubsetMapOf(kcp.Spec.MachineTemplate.ObjectMeta.Labels, obj.GetLabels()) { + return false + } + return true +} + +func isSubsetMapOf(base map[string]string, existing map[string]string) bool { +loopBase: + for key, value := range base { + for existingKey, existingValue := range existing { + if existingKey == key && existingValue == value { + continue loopBase + } + } + // Return false right away if a key value pair wasn't found. + return false + } + return true +} diff --git a/controlplane/kubeadm/internal/filters_test.go b/controlplane/kubeadm/internal/filters_test.go index 454705130441..16d7c12e1dd3 100644 --- a/controlplane/kubeadm/internal/filters_test.go +++ b/controlplane/kubeadm/internal/filters_test.go @@ -273,20 +273,12 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { t.Run("returns true if the machine does not have a bootstrap config", func(t *testing.T) { g := NewWithT(t) kcp := &controlplanev1.KubeadmControlPlane{} - m := &clusterv1.Machine{} - g.Expect(matchInitOrJoinConfiguration(nil, kcp, m)).To(BeTrue()) + g.Expect(matchInitOrJoinConfiguration(nil, kcp)).To(BeTrue()) }) t.Run("returns true if the there are problems reading the bootstrap config", func(t *testing.T) { g := NewWithT(t) kcp := &controlplanev1.KubeadmControlPlane{} - m := &clusterv1.Machine{ - Spec: clusterv1.MachineSpec{ - Bootstrap: clusterv1.Bootstrap{ - ConfigRef: &corev1.ObjectReference{}, - }, - }, - } - g.Expect(matchInitOrJoinConfiguration(nil, kcp, m)).To(BeTrue()) + g.Expect(matchInitOrJoinConfiguration(nil, kcp)).To(BeTrue()) }) t.Run("returns true if InitConfiguration is equal", func(t *testing.T) { g := NewWithT(t) @@ -334,7 +326,7 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { }, }, } - g.Expect(matchInitOrJoinConfiguration(machineConfigs, kcp, m)).To(BeTrue()) + g.Expect(matchInitOrJoinConfiguration(machineConfigs[m.Name], kcp)).To(BeTrue()) }) t.Run("returns false if InitConfiguration is NOT equal", func(t *testing.T) { g := NewWithT(t) @@ -386,7 +378,7 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { }, }, } - g.Expect(matchInitOrJoinConfiguration(machineConfigs, kcp, m)).To(BeFalse()) + g.Expect(matchInitOrJoinConfiguration(machineConfigs[m.Name], kcp)).To(BeFalse()) }) t.Run("returns true if JoinConfiguration is equal", func(t *testing.T) { g := NewWithT(t) @@ -434,7 +426,7 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { }, }, } - g.Expect(matchInitOrJoinConfiguration(machineConfigs, kcp, m)).To(BeTrue()) + g.Expect(matchInitOrJoinConfiguration(machineConfigs[m.Name], kcp)).To(BeTrue()) }) t.Run("returns false if JoinConfiguration is NOT equal", func(t *testing.T) { g := NewWithT(t) @@ -486,7 +478,7 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { }, }, } - g.Expect(matchInitOrJoinConfiguration(machineConfigs, kcp, m)).To(BeFalse()) + g.Expect(matchInitOrJoinConfiguration(machineConfigs[m.Name], kcp)).To(BeFalse()) }) t.Run("returns false if some other configurations are not equal", func(t *testing.T) { g := NewWithT(t) @@ -535,7 +527,7 @@ func TestMatchInitOrJoinConfiguration(t *testing.T) { }, }, } - g.Expect(matchInitOrJoinConfiguration(machineConfigs, kcp, m)).To(BeFalse()) + g.Expect(matchInitOrJoinConfiguration(machineConfigs[m.Name], kcp)).To(BeFalse()) }) } @@ -842,6 +834,94 @@ func TestMatchesKubeadmBootstrapConfig(t *testing.T) { f := MatchesKubeadmBootstrapConfig(machineConfigs, kcp) g.Expect(f(m)).To(BeFalse()) }) + t.Run("should match on labels and annotations", func(t *testing.T) { + kcp := &controlplanev1.KubeadmControlPlane{ + Spec: controlplanev1.KubeadmControlPlaneSpec{ + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + ObjectMeta: clusterv1.ObjectMeta{ + Annotations: map[string]string{ + "test": "annotation", + }, + Labels: map[string]string{ + "test": "labels", + }, + }, + }, + KubeadmConfigSpec: bootstrapv1.KubeadmConfigSpec{ + ClusterConfiguration: &bootstrapv1.ClusterConfiguration{}, + InitConfiguration: &bootstrapv1.InitConfiguration{}, + JoinConfiguration: &bootstrapv1.JoinConfiguration{}, + }, + }, + } + m := &clusterv1.Machine{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmConfig", + APIVersion: clusterv1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test", + }, + Spec: clusterv1.MachineSpec{ + Bootstrap: clusterv1.Bootstrap{ + ConfigRef: &corev1.ObjectReference{ + Kind: "KubeadmConfig", + Namespace: "default", + Name: "test", + APIVersion: bootstrapv1.GroupVersion.String(), + }, + }, + }, + } + machineConfigs := map[string]*bootstrapv1.KubeadmConfig{ + m.Name: { + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmConfig", + APIVersion: bootstrapv1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test", + }, + Spec: bootstrapv1.KubeadmConfigSpec{ + JoinConfiguration: &bootstrapv1.JoinConfiguration{}, + }, + }, + } + + t.Run("by returning false if neither labels or annotations match", func(t *testing.T) { + g := NewWithT(t) + machineConfigs[m.Name].Annotations = nil + machineConfigs[m.Name].Labels = nil + f := MatchesKubeadmBootstrapConfig(machineConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning false if only labels don't match", func(t *testing.T) { + g := NewWithT(t) + machineConfigs[m.Name].Annotations = kcp.Spec.MachineTemplate.ObjectMeta.Annotations + machineConfigs[m.Name].Labels = nil + f := MatchesKubeadmBootstrapConfig(machineConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning false if only annotations don't match", func(t *testing.T) { + g := NewWithT(t) + machineConfigs[m.Name].Annotations = nil + machineConfigs[m.Name].Labels = kcp.Spec.MachineTemplate.ObjectMeta.Labels + f := MatchesKubeadmBootstrapConfig(machineConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning true if both labels and annotations match", func(t *testing.T) { + g := NewWithT(t) + machineConfigs[m.Name].Labels = kcp.Spec.MachineTemplate.ObjectMeta.Labels + machineConfigs[m.Name].Annotations = kcp.Spec.MachineTemplate.ObjectMeta.Annotations + f := MatchesKubeadmBootstrapConfig(machineConfigs, kcp) + g.Expect(f(m)).To(BeTrue()) + }) + }) } func TestMatchesTemplateClonedFrom(t *testing.T) { @@ -869,6 +949,101 @@ func TestMatchesTemplateClonedFrom(t *testing.T) { MatchesTemplateClonedFrom(map[string]*unstructured.Unstructured{}, kcp)(machine), ).To(BeTrue()) }) + + t.Run("matches labels or annotations", func(t *testing.T) { + kcp := &controlplanev1.KubeadmControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: controlplanev1.KubeadmControlPlaneSpec{ + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + ObjectMeta: clusterv1.ObjectMeta{ + Annotations: map[string]string{ + "test": "annotation", + }, + Labels: map[string]string{ + "test": "labels", + }, + }, + InfrastructureRef: corev1.ObjectReference{ + Kind: "GenericMachineTemplate", + Namespace: "default", + Name: "infra-foo", + APIVersion: "generic.io/v1", + }, + }, + }, + } + m := &clusterv1.Machine{ + Spec: clusterv1.MachineSpec{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "GenericMachine", + Namespace: "default", + Name: "infra-foo", + APIVersion: "generic.io/v1", + }, + }, + } + + infraConfigs := map[string]*unstructured.Unstructured{ + m.Name: { + Object: map[string]interface{}{ + "kind": "InfrastructureMachine", + "apiVersion": "infrastructure.cluster.x-k8s.io/v1alpha4", + "metadata": map[string]interface{}{ + "name": "infra-config1", + "namespace": "default", + }, + }, + }, + } + + t.Run("by returning false if neither labels or annotations match", func(t *testing.T) { + g := NewWithT(t) + infraConfigs[m.Name].SetAnnotations(map[string]string{ + clusterv1.TemplateClonedFromNameAnnotation: "infra-foo", + clusterv1.TemplateClonedFromGroupKindAnnotation: "GenericMachineTemplate.generic.io", + }) + infraConfigs[m.Name].SetLabels(nil) + f := MatchesTemplateClonedFrom(infraConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning false if only labels don't match", func(t *testing.T) { + g := NewWithT(t) + infraConfigs[m.Name].SetAnnotations(map[string]string{ + clusterv1.TemplateClonedFromNameAnnotation: "infra-foo", + clusterv1.TemplateClonedFromGroupKindAnnotation: "GenericMachineTemplate.generic.io", + "test": "annotation", + }) + infraConfigs[m.Name].SetLabels(nil) + f := MatchesTemplateClonedFrom(infraConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning false if only annotations don't match", func(t *testing.T) { + g := NewWithT(t) + infraConfigs[m.Name].SetAnnotations(map[string]string{ + clusterv1.TemplateClonedFromNameAnnotation: "infra-foo", + clusterv1.TemplateClonedFromGroupKindAnnotation: "GenericMachineTemplate.generic.io", + }) + infraConfigs[m.Name].SetLabels(kcp.Spec.MachineTemplate.ObjectMeta.Labels) + f := MatchesTemplateClonedFrom(infraConfigs, kcp) + g.Expect(f(m)).To(BeFalse()) + }) + + t.Run("by returning true if both labels and annotations match", func(t *testing.T) { + g := NewWithT(t) + infraConfigs[m.Name].SetAnnotations(map[string]string{ + clusterv1.TemplateClonedFromNameAnnotation: "infra-foo", + clusterv1.TemplateClonedFromGroupKindAnnotation: "GenericMachineTemplate.generic.io", + "test": "annotation", + }) + infraConfigs[m.Name].SetLabels(kcp.Spec.MachineTemplate.ObjectMeta.Labels) + f := MatchesTemplateClonedFrom(infraConfigs, kcp) + g.Expect(f(m)).To(BeTrue()) + }) + }) } func TestMatchesTemplateClonedFrom_WithClonedFromAnnotations(t *testing.T) { @@ -877,11 +1052,13 @@ func TestMatchesTemplateClonedFrom_WithClonedFromAnnotations(t *testing.T) { Namespace: "default", }, Spec: controlplanev1.KubeadmControlPlaneSpec{ - InfrastructureTemplate: corev1.ObjectReference{ - Kind: "GenericMachineTemplate", - Namespace: "default", - Name: "infra-foo", - APIVersion: "generic.io/v1", + MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{ + InfrastructureRef: corev1.ObjectReference{ + Kind: "GenericMachineTemplate", + Namespace: "default", + Name: "infra-foo", + APIVersion: "generic.io/v1", + }, }, }, } diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml index 0d15fb6d9e85..fad8fa1279ee 100644 --- a/test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml +++ b/test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml @@ -52,10 +52,11 @@ metadata: kcp-adoption.step2: "" spec: replicas: ${CONTROL_PLANE_MACHINE_COUNT} - infrastructureTemplate: - kind: DockerMachineTemplate - apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 - name: "${CLUSTER_NAME}-control-plane" + machineTemplate: + infrastructureRef: + kind: DockerMachineTemplate + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 + name: "${CLUSTER_NAME}-control-plane" kubeadmConfigSpec: clusterConfiguration: controllerManager: diff --git a/test/infrastructure/docker/examples/machine-pool.yaml b/test/infrastructure/docker/examples/machine-pool.yaml index bf9d521008be..e23052ee60a0 100644 --- a/test/infrastructure/docker/examples/machine-pool.yaml +++ b/test/infrastructure/docker/examples/machine-pool.yaml @@ -30,11 +30,12 @@ metadata: spec: replicas: 1 version: v1.19.1 - infrastructureTemplate: - apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 - kind: DockerMachineTemplate - name: controlplane - namespace: default + machineTemplate: + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 + kind: DockerMachineTemplate + name: controlplane + namespace: default kubeadmConfigSpec: clusterConfiguration: controllerManager: diff --git a/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml b/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml index eb79ebc01177..833269a3a177 100644 --- a/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml +++ b/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml @@ -45,11 +45,12 @@ metadata: spec: replicas: 1 version: v1.19.1 - infrastructureTemplate: - apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 - kind: DockerMachineTemplate - name: controlplane - namespace: default + machineTemplate: + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 + kind: DockerMachineTemplate + name: controlplane + namespace: default kubeadmConfigSpec: clusterConfiguration: apiServer: diff --git a/test/infrastructure/docker/examples/simple-cluster.yaml b/test/infrastructure/docker/examples/simple-cluster.yaml index 64d4c8599782..fad1e78db4c5 100644 --- a/test/infrastructure/docker/examples/simple-cluster.yaml +++ b/test/infrastructure/docker/examples/simple-cluster.yaml @@ -45,11 +45,12 @@ metadata: spec: replicas: 1 version: v1.19.1 - infrastructureTemplate: - apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 - kind: DockerMachineTemplate - name: controlplane - namespace: default + machineTemplate: + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 + kind: DockerMachineTemplate + name: controlplane + namespace: default kubeadmConfigSpec: clusterConfiguration: apiServer: diff --git a/test/infrastructure/docker/templates/cluster-template-development.yaml b/test/infrastructure/docker/templates/cluster-template-development.yaml index 55d50aca7644..9706b2f28c4b 100644 --- a/test/infrastructure/docker/templates/cluster-template-development.yaml +++ b/test/infrastructure/docker/templates/cluster-template-development.yaml @@ -46,11 +46,12 @@ metadata: namespace: "${NAMESPACE}" spec: replicas: ${CONTROL_PLANE_MACHINE_COUNT} - infrastructureTemplate: - kind: DockerMachineTemplate - apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 - name: "${CLUSTER_NAME}-control-plane" - namespace: "${NAMESPACE}" + machineTemplate: + infrastructureRef: + kind: DockerMachineTemplate + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4 + name: "${CLUSTER_NAME}-control-plane" + namespace: "${NAMESPACE}" kubeadmConfigSpec: clusterConfiguration: controllerManager: