diff --git a/agent/reconciler/host_reconciler.go b/agent/reconciler/host_reconciler.go index 27ce0802b..9de9e2313 100644 --- a/agent/reconciler/host_reconciler.go +++ b/agent/reconciler/host_reconciler.go @@ -104,20 +104,6 @@ func (r *HostReconciler) reconcileNormal(ctx context.Context, byoHost *infrastru return ctrl.Result{}, nil } - if r.UseInstallerController && !conditions.IsTrue(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) { - if byoHost.Spec.InstallationSecret == nil { - logger.Info("InstallationSecret not ready") - conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded, infrastructurev1beta1.K8sInstallationSecretUnavailableReason, clusterv1.ConditionSeverityInfo, "") - return ctrl.Result{}, nil - } - err := r.executeInstallerController(ctx, byoHost) - if err != nil { - return ctrl.Result{}, err - } - r.Recorder.Event(byoHost, corev1.EventTypeNormal, "InstallScriptExecutionSucceeded", "install script executed") - conditions.MarkTrue(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) - } - if byoHost.Spec.BootstrapSecret == nil { logger.Info("BootstrapDataSecret not ready") conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded, infrastructurev1beta1.BootstrapDataSecretUnavailableReason, clusterv1.ConditionSeverityInfo, "") @@ -134,7 +120,19 @@ func (r *HostReconciler) reconcileNormal(ctx context.Context, byoHost *infrastru if r.SkipK8sInstallation { logger.Info("Skipping installation of k8s components") - } else if !r.UseInstallerController { + } else if r.UseInstallerController { + if byoHost.Spec.InstallationSecret == nil { + logger.Info("InstallationSecret not ready") + conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded, infrastructurev1beta1.K8sInstallationSecretUnavailableReason, clusterv1.ConditionSeverityInfo, "") + return ctrl.Result{}, nil + } + err := r.executeInstallerController(ctx, byoHost) + if err != nil { + return ctrl.Result{}, err + } + r.Recorder.Event(byoHost, corev1.EventTypeNormal, "InstallScriptExecutionSucceeded", "install script executed") + conditions.MarkTrue(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) + } else { err = r.installK8sComponents(ctx, byoHost) if err != nil { logger.Error(err, "error in installing k8s components") diff --git a/agent/reconciler/reconciler_test.go b/agent/reconciler/reconciler_test.go index bbce01186..73011f403 100644 --- a/agent/reconciler/reconciler_test.go +++ b/agent/reconciler/reconciler_test.go @@ -153,247 +153,6 @@ var _ = Describe("Byohost Agent Tests", func() { })) }) - Context("When use-installer-controller is set", func() { - BeforeEach(func() { - hostReconciler.UseInstallerController = true - }) - - It("should set the Reason to InstallationSecretUnavailableReason", func() { - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).ToNot(HaveOccurred()) - - updatedByoHost := &infrastructurev1beta1.ByoHost{} - err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) - Expect(err).ToNot(HaveOccurred()) - - byoHostRegistrationSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) - Expect(*byoHostRegistrationSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ - Type: infrastructurev1beta1.K8sComponentsInstallationSucceeded, - Status: corev1.ConditionFalse, - Reason: infrastructurev1beta1.K8sInstallationSecretUnavailableReason, - Severity: clusterv1.ConditionSeverityInfo, - })) - }) - - It("should return an error if we fail to load the installation secret", func() { - byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ - Kind: "Secret", - Namespace: "non-existent", - Name: "non-existent", - } - Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) - - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).To(MatchError("secrets \"non-existent\" not found")) - - // assert events - events := eventutils.CollectEvents(recorder.Events) - Expect(events).Should(ConsistOf([]string{ - fmt.Sprintf("Warning ReadInstallationSecretFailed install and uninstall script %s not found", byoHost.Spec.InstallationSecret.Name), - })) - }) - - Context("When installation secret is ready", func() { - BeforeEach(func() { - installScript := `echo "install"` - uninstallScript = `echo "uninstall"` - - installationSecret = builder.Secret(ns, "test-secret"). - WithKeyData("install", installScript). - WithKeyData("uninstall", uninstallScript). - Build() - Expect(k8sClient.Create(ctx, installationSecret)).NotTo(HaveOccurred()) - - byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ - Kind: "Secret", - Namespace: installationSecret.Namespace, - Name: installationSecret.Name, - } - - byoHost.Annotations = map[string]string{ - infrastructurev1beta1.K8sVersionAnnotation: "1.22", - infrastructurev1beta1.BundleLookupTagAnnotation: "byoh-bundle-tag", - infrastructurev1beta1.BundleLookupBaseRegistryAnnotation: "projects.blah.com", - } - - Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) - }) - - It("should return error if install script execution failed", func() { - invalidInstallationSecret := builder.Secret(ns, "invalid-test-secret"). - WithKeyData("install", "test"). - Build() - Expect(k8sClient.Create(ctx, invalidInstallationSecret)).NotTo(HaveOccurred()) - byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ - Kind: "Secret", - Namespace: invalidInstallationSecret.Namespace, - Name: invalidInstallationSecret.Name, - } - Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) - - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).To(HaveOccurred()) - - // assert events - events := eventutils.CollectEvents(recorder.Events) - Expect(events).Should(ConsistOf([]string{ - "Warning InstallScriptExecutionFailed install script execution failed", - })) - - }) - - It("should set uninstall script in byohost spec", func() { - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).NotTo(HaveOccurred()) - - updatedByoHost := &infrastructurev1beta1.ByoHost{} - err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) - Expect(err).ToNot(HaveOccurred()) - Expect(updatedByoHost.Spec.UninstallationScript).NotTo(BeNil()) - Expect(*updatedByoHost.Spec.UninstallationScript).To(Equal(uninstallScript)) - }) - - It("should set K8sComponentsInstallationSucceeded to true if Install succeeds", func() { - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).ToNot(HaveOccurred()) - - updatedByoHost := &infrastructurev1beta1.ByoHost{} - err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) - Expect(err).ToNot(HaveOccurred()) - - K8sComponentsInstallationSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) - Expect(*K8sComponentsInstallationSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ - Type: infrastructurev1beta1.K8sComponentsInstallationSucceeded, - Status: corev1.ConditionTrue, - })) - - // assert events - events := eventutils.CollectEvents(recorder.Events) - Expect(events).Should(ConsistOf([]string{ - "Normal InstallScriptExecutionSucceeded install script executed", - })) - }) - - Context("When bootstrap secret is ready", func() { - BeforeEach(func() { - secretData := `write_files: -- path: fake/path - content: blah -runCmd: -- echo 'some run command'` - - bootstrapSecret = builder.Secret(ns, "test-secret-2"). - WithData(secretData). - Build() - Expect(k8sClient.Create(ctx, bootstrapSecret)).NotTo(HaveOccurred()) - - byoHost.Spec.BootstrapSecret = &corev1.ObjectReference{ - Kind: "Secret", - Namespace: bootstrapSecret.Namespace, - Name: bootstrapSecret.Name, - } - - byoHost.Annotations = map[string]string{ - infrastructurev1beta1.K8sVersionAnnotation: "1.22", - infrastructurev1beta1.BundleLookupTagAnnotation: "byoh-bundle-tag", - infrastructurev1beta1.BundleLookupBaseRegistryAnnotation: "projects.blah.com", - } - - Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) - }) - - It("should set K8sNodeBootstrapSucceeded to false with Reason CloudInitExecutionFailedReason if the bootstrap execution fails", func() { - fakeCommandRunner.RunCmdReturns(errors.New("I failed")) - - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).To(HaveOccurred()) - - updatedByoHost := &infrastructurev1beta1.ByoHost{} - err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) - Expect(err).ToNot(HaveOccurred()) - - k8sNodeBootstrapSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded) - Expect(*k8sNodeBootstrapSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ - Type: infrastructurev1beta1.K8sNodeBootstrapSucceeded, - Status: corev1.ConditionFalse, - Reason: infrastructurev1beta1.CloudInitExecutionFailedReason, - Severity: clusterv1.ConditionSeverityError, - })) - - // assert events - events := eventutils.CollectEvents(recorder.Events) - Expect(events).Should(ConsistOf([]string{ - "Normal InstallScriptExecutionSucceeded install script executed", - "Warning BootstrapK8sNodeFailed k8s Node Bootstrap failed", - // TODO: improve test to remove this event - "Warning ResetK8sNodeFailed k8s Node Reset failed", - })) - }) - - It("should set K8sNodeBootstrapSucceeded to True if the boostrap execution succeeds", func() { - hostReconciler.K8sInstaller = fakeInstaller - result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ - NamespacedName: byoHostLookupKey, - }) - Expect(result).To(Equal(controllerruntime.Result{})) - Expect(reconcilerErr).ToNot(HaveOccurred()) - - Expect(fakeCommandRunner.RunCmdCallCount()).To(Equal(1)) - Expect(fakeFileWriter.WriteToFileCallCount()).To(Equal(1)) - - updatedByoHost := &infrastructurev1beta1.ByoHost{} - err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) - Expect(err).ToNot(HaveOccurred()) - - k8sNodeBootstrapSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded) - Expect(*k8sNodeBootstrapSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ - Type: infrastructurev1beta1.K8sNodeBootstrapSucceeded, - Status: corev1.ConditionTrue, - })) - - // assert events - events := eventutils.CollectEvents(recorder.Events) - Expect(events).Should(ConsistOf([]string{ - "Normal InstallScriptExecutionSucceeded install script executed", - "Normal BootstrapK8sNodeSucceeded k8s Node Bootstraped", - })) - }) - - AfterEach(func() { - Expect(k8sClient.Delete(ctx, bootstrapSecret)).NotTo(HaveOccurred()) - hostReconciler.SkipK8sInstallation = false - }) - }) - - AfterEach(func() { - Expect(k8sClient.Delete(ctx, installationSecret)).NotTo(HaveOccurred()) - }) - }) - - AfterEach(func() { - hostReconciler.UseInstallerController = false - }) - }) - Context("When bootstrap secret is ready", func() { BeforeEach(func() { secretData := `write_files: @@ -548,6 +307,214 @@ runCmd: Expect(fakeFileWriter.WriteToFileCallCount()).To(Equal(1)) }) + Context("When use-installer-controller is set", func() { + BeforeEach(func() { + hostReconciler.UseInstallerController = true + }) + + It("should set the Reason to InstallationSecretUnavailableReason", func() { + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).ToNot(HaveOccurred()) + + updatedByoHost := &infrastructurev1beta1.ByoHost{} + err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) + Expect(err).ToNot(HaveOccurred()) + + byoHostRegistrationSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) + Expect(*byoHostRegistrationSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ + Type: infrastructurev1beta1.K8sComponentsInstallationSucceeded, + Status: corev1.ConditionFalse, + Reason: infrastructurev1beta1.K8sInstallationSecretUnavailableReason, + Severity: clusterv1.ConditionSeverityInfo, + })) + }) + + It("should return an error if we fail to load the installation secret", func() { + byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ + Kind: "Secret", + Namespace: "non-existent", + Name: "non-existent", + } + Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) + + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).To(MatchError("secrets \"non-existent\" not found")) + + // assert events + events := eventutils.CollectEvents(recorder.Events) + Expect(events).Should(ConsistOf([]string{ + fmt.Sprintf("Warning ReadInstallationSecretFailed install and uninstall script %s not found", byoHost.Spec.InstallationSecret.Name), + })) + }) + + Context("When installation secret is ready", func() { + BeforeEach(func() { + installScript := `echo "install"` + uninstallScript = `echo "uninstall"` + + installationSecret = builder.Secret(ns, "test-secret3"). + WithKeyData("install", installScript). + WithKeyData("uninstall", uninstallScript). + Build() + Expect(k8sClient.Create(ctx, installationSecret)).NotTo(HaveOccurred()) + + byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ + Kind: "Secret", + Namespace: installationSecret.Namespace, + Name: installationSecret.Name, + } + + byoHost.Annotations = map[string]string{ + infrastructurev1beta1.K8sVersionAnnotation: "1.22", + infrastructurev1beta1.BundleLookupTagAnnotation: "byoh-bundle-tag", + infrastructurev1beta1.BundleLookupBaseRegistryAnnotation: "projects.blah.com", + } + + Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) + }) + + It("should return error if install script execution failed", func() { + invalidInstallationSecret := builder.Secret(ns, "invalid-test-secret"). + WithKeyData("install", "test"). + Build() + Expect(k8sClient.Create(ctx, invalidInstallationSecret)).NotTo(HaveOccurred()) + byoHost.Spec.InstallationSecret = &corev1.ObjectReference{ + Kind: "Secret", + Namespace: invalidInstallationSecret.Namespace, + Name: invalidInstallationSecret.Name, + } + Expect(patchHelper.Patch(ctx, byoHost, patch.WithStatusObservedGeneration{})).NotTo(HaveOccurred()) + + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).To(HaveOccurred()) + + // assert events + events := eventutils.CollectEvents(recorder.Events) + Expect(events).Should(ConsistOf([]string{ + "Warning InstallScriptExecutionFailed install script execution failed", + })) + + }) + + It("should set uninstall script in byohost spec", func() { + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).NotTo(HaveOccurred()) + + updatedByoHost := &infrastructurev1beta1.ByoHost{} + err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) + Expect(err).ToNot(HaveOccurred()) + Expect(updatedByoHost.Spec.UninstallationScript).NotTo(BeNil()) + Expect(*updatedByoHost.Spec.UninstallationScript).To(Equal(uninstallScript)) + }) + + It("should set K8sComponentsInstallationSucceeded to true if Install succeeds", func() { + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).ToNot(HaveOccurred()) + + updatedByoHost := &infrastructurev1beta1.ByoHost{} + err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) + Expect(err).ToNot(HaveOccurred()) + + K8sComponentsInstallationSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) + Expect(*K8sComponentsInstallationSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ + Type: infrastructurev1beta1.K8sComponentsInstallationSucceeded, + Status: corev1.ConditionTrue, + })) + + // assert events + events := eventutils.CollectEvents(recorder.Events) + Expect(events).Should(ConsistOf([]string{ + "Normal InstallScriptExecutionSucceeded install script executed", + "Normal BootstrapK8sNodeSucceeded k8s Node Bootstraped", + })) + }) + + It("should set K8sNodeBootstrapSucceeded to false with Reason CloudInitExecutionFailedReason if the bootstrap execution fails", func() { + fakeCommandRunner.RunCmdReturns(errors.New("I failed")) + + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).To(HaveOccurred()) + + updatedByoHost := &infrastructurev1beta1.ByoHost{} + err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) + Expect(err).ToNot(HaveOccurred()) + + k8sNodeBootstrapSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded) + Expect(*k8sNodeBootstrapSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ + Type: infrastructurev1beta1.K8sNodeBootstrapSucceeded, + Status: corev1.ConditionFalse, + Reason: infrastructurev1beta1.CloudInitExecutionFailedReason, + Severity: clusterv1.ConditionSeverityError, + })) + + // assert events + events := eventutils.CollectEvents(recorder.Events) + Expect(events).Should(ConsistOf([]string{ + "Normal InstallScriptExecutionSucceeded install script executed", + "Warning BootstrapK8sNodeFailed k8s Node Bootstrap failed", + // TODO: improve test to remove this event + "Warning ResetK8sNodeFailed k8s Node Reset failed", + })) + }) + + It("should set K8sNodeBootstrapSucceeded to True if the boostrap execution succeeds", func() { + hostReconciler.K8sInstaller = fakeInstaller + result, reconcilerErr := hostReconciler.Reconcile(ctx, controllerruntime.Request{ + NamespacedName: byoHostLookupKey, + }) + Expect(result).To(Equal(controllerruntime.Result{})) + Expect(reconcilerErr).ToNot(HaveOccurred()) + + Expect(fakeCommandRunner.RunCmdCallCount()).To(Equal(1)) + Expect(fakeFileWriter.WriteToFileCallCount()).To(Equal(1)) + + updatedByoHost := &infrastructurev1beta1.ByoHost{} + err := k8sClient.Get(ctx, byoHostLookupKey, updatedByoHost) + Expect(err).ToNot(HaveOccurred()) + + k8sNodeBootstrapSucceeded := conditions.Get(updatedByoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded) + Expect(*k8sNodeBootstrapSucceeded).To(conditions.MatchCondition(clusterv1.Condition{ + Type: infrastructurev1beta1.K8sNodeBootstrapSucceeded, + Status: corev1.ConditionTrue, + })) + + // assert events + events := eventutils.CollectEvents(recorder.Events) + Expect(events).Should(ConsistOf([]string{ + "Normal InstallScriptExecutionSucceeded install script executed", + "Normal BootstrapK8sNodeSucceeded k8s Node Bootstraped", + })) + }) + + AfterEach(func() { + Expect(k8sClient.Delete(ctx, installationSecret)).NotTo(HaveOccurred()) + }) + }) + + AfterEach(func() { + hostReconciler.UseInstallerController = false + }) + }) + AfterEach(func() { Expect(k8sClient.Delete(ctx, bootstrapSecret)).NotTo(HaveOccurred()) hostReconciler.SkipK8sInstallation = false