diff --git a/controllers/operator_controller.go b/controllers/operator_controller.go index 8492bb8df..22a614358 100644 --- a/controllers/operator_controller.go +++ b/controllers/operator_controller.go @@ -175,6 +175,17 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha return ctrl.Result{}, err } + if isBundleDepStale(existingTypedBundleDeployment) { + apimeta.SetStatusCondition(&op.Status.Conditions, metav1.Condition{ + Type: operatorsv1alpha1.TypeReady, + Status: metav1.ConditionUnknown, + Reason: operatorsv1alpha1.ReasonInstallationStatusUnknown, + Message: fmt.Sprintf("waiting for bundleDeployment %q status to be updated. BundleDeployment conditions out of date.", existingTypedBundleDeployment.Name), + ObservedGeneration: op.GetGeneration(), + }) + return ctrl.Result{}, nil + } + // set the status of the operator based on the respective bundle deployment status conditions. apimeta.SetStatusCondition(&op.Status.Conditions, mapBDStatusToReadyCondition(existingTypedBundleDeployment, op.GetGeneration())) return ctrl.Result{}, nil @@ -338,3 +349,8 @@ func mapBDStatusToReadyCondition(existingBD *rukpakv1alpha1.BundleDeployment, ob ObservedGeneration: observedGeneration, } } + +// isBundleDepStale returns true if conditions are out of date. +func isBundleDepStale(existingTypedBundleDeployment *rukpakv1alpha1.BundleDeployment) bool { + return existingTypedBundleDeployment != nil && existingTypedBundleDeployment.Status.ObservedGeneration != existingTypedBundleDeployment.GetGeneration() +} diff --git a/controllers/operator_controller_test.go b/controllers/operator_controller_test.go index f1764ca19..bae2cc63e 100644 --- a/controllers/operator_controller_test.go +++ b/controllers/operator_controller_test.go @@ -348,8 +348,31 @@ var _ = Describe("Reconcile Test", func() { Expect(err).NotTo(HaveOccurred()) }) + It("verify operator status when bundle deployment status is stale while being created", func() { + res, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: opKey}) + Expect(res).To(Equal(ctrl.Result{})) + Expect(err).NotTo(HaveOccurred()) + + By("fetching the updated operator after reconcile") + op := &operatorsv1alpha1.Operator{} + err = cl.Get(ctx, opKey, op) + Expect(err).NotTo(HaveOccurred()) + + By("checking the expected conditions") + cond := apimeta.FindStatusCondition(op.Status.Conditions, operatorsv1alpha1.TypeReady) + Expect(cond).NotTo(BeNil()) + Expect(cond.Status).To(Equal(metav1.ConditionUnknown)) + Expect(cond.Reason).To(Equal(operatorsv1alpha1.ReasonInstallationStatusUnknown)) + Expect(cond.Message).To(Equal(fmt.Sprintf("waiting for bundleDeployment %q status to be updated. BundleDeployment conditions out of date.", bd.Name))) + }) + It("verify operator status when bundle deployment is waiting to be created", func() { By("running reconcile") + bd.Status.ObservedGeneration = bd.GetGeneration() + By("updating the status of bundleDeployment") + err := cl.Status().Update(ctx, bd) + Expect(err).NotTo(HaveOccurred()) + res, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: opKey}) Expect(res).To(Equal(ctrl.Result{})) Expect(err).NotTo(HaveOccurred()) @@ -364,16 +387,18 @@ var _ = Describe("Reconcile Test", func() { Expect(cond).NotTo(BeNil()) Expect(cond.Status).To(Equal(metav1.ConditionUnknown)) Expect(cond.Reason).To(Equal(operatorsv1alpha1.ReasonInstallationStatusUnknown)) - Expect(cond.Message).To(ContainSubstring(`waiting for bundleDeployment`)) + Expect(cond.Message).To(Equal(fmt.Sprintf("waiting for bundleDeployment %q status to be updated", bd.Name))) }) It("verify operator status when `HasValidBundle` condition of rukpak is false", func() { apimeta.SetStatusCondition(&bd.Status.Conditions, metav1.Condition{ - Type: rukpakv1alpha1.TypeHasValidBundle, - Status: metav1.ConditionFalse, - Message: "failed to unpack", - Reason: rukpakv1alpha1.ReasonUnpackFailed, + Type: rukpakv1alpha1.TypeHasValidBundle, + Status: metav1.ConditionFalse, + Message: "failed to unpack", + Reason: rukpakv1alpha1.ReasonUnpackFailed, + ObservedGeneration: 1, }) + bd.Status.ObservedGeneration = bd.GetGeneration() By("updating the status of bundleDeployment") err := cl.Status().Update(ctx, bd) @@ -404,6 +429,7 @@ var _ = Describe("Reconcile Test", func() { Message: "failed to install", Reason: rukpakv1alpha1.ReasonInstallFailed, }) + bd.Status.ObservedGeneration = bd.GetGeneration() By("updating the status of bundleDeployment") err := cl.Status().Update(ctx, bd) @@ -434,6 +460,7 @@ var _ = Describe("Reconcile Test", func() { Message: "operator installed successfully", Reason: rukpakv1alpha1.ReasonInstallationSucceeded, }) + bd.Status.ObservedGeneration = bd.GetGeneration() By("updating the status of bundleDeployment") err := cl.Status().Update(ctx, bd) @@ -471,6 +498,7 @@ var _ = Describe("Reconcile Test", func() { Message: "installing", Reason: rukpakv1alpha1.ReasonInstallationSucceeded, }) + bd.Status.ObservedGeneration = bd.GetGeneration() By("updating the status of bundleDeployment") err := cl.Status().Update(ctx, bd) @@ -501,6 +529,7 @@ var _ = Describe("Reconcile Test", func() { Message: "installing", Reason: rukpakv1alpha1.ReasonInstallationSucceeded, }) + bd.Status.ObservedGeneration = bd.GetGeneration() By("updating the status of bundleDeployment") err := cl.Status().Update(ctx, bd)