diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go index 240143a8d34b..22cf8913adbd 100644 --- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go +++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go @@ -92,11 +92,17 @@ func TestKubeadmConfigReconciler_MachineToBootstrapMapFuncReturn(t *testing.T) { // Reconcile returns early if the kubeadm config is ready because it should never re-generate bootstrap data. func TestKubeadmConfigReconciler_Reconcile_ReturnEarlyIfKubeadmConfigIsReady(t *testing.T) { g := NewWithT(t) - + cluster := builder.Cluster(metav1.NamespaceDefault, "cluster1").Build() + cluster.Status.InfrastructureReady = true + machine := builder.Machine(metav1.NamespaceDefault, "m1").WithClusterName("cluster1").Build() config := newKubeadmConfig(metav1.NamespaceDefault, "cfg") + addKubeadmConfigToMachine(config, machine) + config.Status.Ready = true objects := []client.Object{ + cluster, + machine, config, } myclient := fake.NewClientBuilder().WithObjects(objects...).Build() @@ -117,7 +123,7 @@ func TestKubeadmConfigReconciler_Reconcile_ReturnEarlyIfKubeadmConfigIsReady(t * g.Expect(result.RequeueAfter).To(Equal(time.Duration(0))) } -// Reconcile returns early if the kubeadm config is ready because it should never re-generate bootstrap data. +// Reconcile should update owner references on bootstrap secrets on creation and update. func TestKubeadmConfigReconciler_TestSecretOwnerReferenceReconciliation(t *testing.T) { g := NewWithT(t) @@ -249,14 +255,20 @@ func TestKubeadmConfigReconciler_Reconcile_ReturnNilIfReferencedMachineIsNotFoun // If the machine has bootstrap data secret reference, there is no need to generate more bootstrap data. func TestKubeadmConfigReconciler_Reconcile_ReturnEarlyIfMachineHasDataSecretName(t *testing.T) { g := NewWithT(t) + cluster := builder.Cluster(metav1.NamespaceDefault, "cluster1").Build() + cluster.Status.InfrastructureReady = true + machine := builder.Machine(metav1.NamespaceDefault, "machine"). WithVersion("v1.19.1"). + WithClusterName("cluster1"). WithBootstrapTemplate(bootstrapbuilder.KubeadmConfig(metav1.NamespaceDefault, "cfg").Unstructured()). Build() machine.Spec.Bootstrap.DataSecretName = pointer.String("something") config := newKubeadmConfig(metav1.NamespaceDefault, "cfg") + addKubeadmConfigToMachine(config, machine) objects := []client.Object{ + cluster, machine, config, } @@ -273,9 +285,12 @@ func TestKubeadmConfigReconciler_Reconcile_ReturnEarlyIfMachineHasDataSecretName }, } result, err := k.Reconcile(ctx, request) + actual := &bootstrapv1.KubeadmConfig{} + g.Expect(myclient.Get(ctx, client.ObjectKey{Namespace: config.Namespace, Name: config.Name}, actual)).To(Succeed()) g.Expect(err).NotTo(HaveOccurred()) g.Expect(result.Requeue).To(BeFalse()) g.Expect(result.RequeueAfter).To(Equal(time.Duration(0))) + assertHasTrueCondition(g, myclient, request, bootstrapv1.DataSecretAvailableCondition) } func TestKubeadmConfigReconciler_ReturnEarlyIfClusterInfraNotReady(t *testing.T) { @@ -328,35 +343,7 @@ func TestKubeadmConfigReconciler_Reconcile_ReturnEarlyIfMachineHasNoCluster(t *t WithBootstrapTemplate(bootstrapbuilder.KubeadmConfig(metav1.NamespaceDefault, "cfg").Unstructured()). Build() config := newKubeadmConfig(metav1.NamespaceDefault, "cfg") - - objects := []client.Object{ - machine, - config, - } - myclient := fake.NewClientBuilder().WithObjects(objects...).Build() - - k := &KubeadmConfigReconciler{ - Client: myclient, - } - - request := ctrl.Request{ - NamespacedName: client.ObjectKey{ - Namespace: metav1.NamespaceDefault, - Name: "cfg", - }, - } - _, err := k.Reconcile(ctx, request) - g.Expect(err).NotTo(HaveOccurred()) -} - -// This does not expect an error, hoping the machine gets updated with a cluster. -func TestKubeadmConfigReconciler_Reconcile_ReturnNilIfMachineDoesNotHaveAssociatedCluster(t *testing.T) { - g := NewWithT(t) - machine := builder.Machine(metav1.NamespaceDefault, "machine"). - WithVersion("v1.19.1"). - WithBootstrapTemplate(bootstrapbuilder.KubeadmConfig(metav1.NamespaceDefault, "cfg").Unstructured()). - Build() - config := newKubeadmConfig(metav1.NamespaceDefault, "cfg") + addKubeadmConfigToMachine(config, machine) objects := []client.Object{ machine, @@ -390,6 +377,7 @@ func TestKubeadmConfigReconciler_Reconcile_ReturnNilIfAssociatedClusterIsNotFoun Build() config := newKubeadmConfig(metav1.NamespaceDefault, "cfg") + addKubeadmConfigToMachine(config, machine) objects := []client.Object{ // intentionally omitting cluster machine, @@ -430,7 +418,7 @@ func TestKubeadmConfigReconciler_Reconcile_RequeueJoiningNodesIfControlPlaneNotI objects []client.Object }{ { - name: "requeue worker when control plane is not yet initialiezd", + name: "requeue worker when control plane is not yet initialized", request: ctrl.Request{ NamespacedName: client.ObjectKey{ Namespace: workerJoinConfig.Namespace, @@ -482,11 +470,19 @@ func TestKubeadmConfigReconciler_Reconcile_RequeueJoiningNodesIfControlPlaneNotI func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T) { g := NewWithT(t) + configName := "control-plane-init-cfg" cluster := builder.Cluster(metav1.NamespaceDefault, "cluster").Build() + cluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{Host: "validhost", Port: 6443} cluster.Status.InfrastructureReady = true + conditions.MarkTrue(cluster, clusterv1.ControlPlaneInitializedCondition) controlPlaneInitMachine := newControlPlaneMachine(cluster, "control-plane-init-machine") - controlPlaneInitConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine.Namespace, "control-plane-init-cfg") + controlPlaneInitConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine.Namespace, configName) + controlPlaneInitConfig.Spec.JoinConfiguration = &bootstrapv1.JoinConfiguration{} + controlPlaneInitConfig.Spec.JoinConfiguration.Discovery.BootstrapToken = &bootstrapv1.BootstrapTokenDiscovery{ + CACertHashes: []string{"...."}, + } + addKubeadmConfigToMachine(controlPlaneInitConfig, controlPlaneInitMachine) objects := []client.Object{ @@ -499,8 +495,9 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T) myclient := fake.NewClientBuilder().WithObjects(objects...).Build() k := &KubeadmConfigReconciler{ - Client: myclient, - KubeadmInitLock: &myInitLocker{}, + Client: myclient, + KubeadmInitLock: &myInitLocker{}, + remoteClientGetter: fakeremote.NewClusterClient, } request := ctrl.Request{ @@ -509,6 +506,9 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T) Name: "control-plane-init-cfg", }, } + s := &corev1.Secret{} + g.Expect(myclient.Get(ctx, client.ObjectKey{Namespace: metav1.NamespaceDefault, Name: configName}, s)).ToNot(Succeed()) + result, err := k.Reconcile(ctx, request) g.Expect(err).NotTo(HaveOccurred()) g.Expect(result.Requeue).To(BeFalse()) @@ -522,6 +522,9 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T) assertHasTrueCondition(g, myclient, request, bootstrapv1.CertificatesAvailableCondition) assertHasTrueCondition(g, myclient, request, bootstrapv1.DataSecretAvailableCondition) + // Expect the Secret to exist, and for it to contain some data under the "value" key. + g.Expect(myclient.Get(ctx, client.ObjectKey{Namespace: metav1.NamespaceDefault, Name: configName}, s)).To(Succeed()) + g.Expect(len(s.Data["value"])).To(BeNumerically(">", 0)) // Ensure that we don't fail trying to refresh any bootstrap tokens _, err = k.Reconcile(ctx, request) g.Expect(err).NotTo(HaveOccurred()) @@ -561,11 +564,15 @@ func TestKubeadmConfigReconciler_Reconcile_ErrorIfJoiningControlPlaneHasInvalidC request := ctrl.Request{ NamespacedName: client.ObjectKey{ Namespace: metav1.NamespaceDefault, - Name: "control-plane-join-cfg", + Name: controlPlaneJoinConfig.Name, }, } _, err := k.Reconcile(ctx, request) g.Expect(err).NotTo(HaveOccurred()) + actualConfig := &bootstrapv1.KubeadmConfig{} + g.Expect(myclient.Get(ctx, client.ObjectKey{Namespace: controlPlaneJoinConfig.Namespace, Name: controlPlaneJoinConfig.Name}, actualConfig)).To(Succeed()) + assertHasTrueCondition(g, myclient, request, bootstrapv1.DataSecretAvailableCondition) + assertHasTrueCondition(g, myclient, request, bootstrapv1.CertificatesAvailableCondition) } // If there is no APIEndpoint but everything is ready then requeue in hopes of a new APIEndpoint showing up eventually. @@ -607,9 +614,16 @@ func TestKubeadmConfigReconciler_Reconcile_RequeueIfControlPlaneIsMissingAPIEndp g.Expect(err).NotTo(HaveOccurred()) g.Expect(result.Requeue).To(BeFalse()) g.Expect(result.RequeueAfter).To(Equal(10 * time.Second)) + + actualConfig := &bootstrapv1.KubeadmConfig{} + g.Expect(myclient.Get(ctx, client.ObjectKey{Namespace: workerJoinConfig.Namespace, Name: workerJoinConfig.Name}, actualConfig)).To(Succeed()) + + // At this point the DataSecretAvailableCondition should not be set. CertificatesAvailableCondition should be true. + g.Expect(conditions.Get(actualConfig, bootstrapv1.DataSecretAvailableCondition)).To(BeNil()) + assertHasTrueCondition(g, myclient, request, bootstrapv1.CertificatesAvailableCondition) } -func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) { +func TestReconcileIfJoinCertificatesAvailableConditioninNodesAndControlPlaneIsReady(t *testing.T) { cluster := builder.Cluster(metav1.NamespaceDefault, "cluster").Build() cluster.Status.InfrastructureReady = true conditions.MarkTrue(cluster, clusterv1.ControlPlaneInitializedCondition) @@ -1848,6 +1862,17 @@ func TestKubeadmConfigReconciler_Reconcile_ExactlyOneControlPlaneMachineInitiali g.Expect(err).NotTo(HaveOccurred()) g.Expect(result.Requeue).To(BeFalse()) g.Expect(result.RequeueAfter).To(Equal(30 * time.Second)) + confList := &bootstrapv1.KubeadmConfigList{} + g.Expect(myclient.List(ctx, confList)).To(Succeed()) + for _, c := range confList.Items { + // Ensure the DataSecretName is only set for controlPlaneInitConfigFirst. + if c.Name == controlPlaneInitConfigFirst.Name { + g.Expect(*c.Status.DataSecretName).To(Not(BeEmpty())) + } + if c.Name == controlPlaneInitConfigSecond.Name { + g.Expect(c.Status.DataSecretName).To(BeNil()) + } + } } // Patch should be applied if there is an error in reconcile. @@ -2252,6 +2277,10 @@ func addKubeadmConfigToMachine(config *bootstrapv1.KubeadmConfig, machine *clust }, } + if machine.Spec.Bootstrap.ConfigRef == nil { + machine.Spec.Bootstrap.ConfigRef = &corev1.ObjectReference{} + } + machine.Spec.Bootstrap.ConfigRef.Name = config.Name machine.Spec.Bootstrap.ConfigRef.Namespace = config.Namespace }