diff --git a/pkg/controller/state/reconciler.go b/pkg/controller/state/reconciler.go index 73a3d11a70..c9b6d2b8e0 100644 --- a/pkg/controller/state/reconciler.go +++ b/pkg/controller/state/reconciler.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/finalizer" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/state" @@ -103,13 +104,6 @@ func NewStateReconciler[T any](target StateHandler[T], options ...ReconcilerOpti return r } -func NewUnstructuredStateReconciler(target UnstructuredStateReconciler, gvk schema.GroupVersionKind) *Reconciler[unstructured.Unstructured] { - return &Reconciler[unstructured.Unstructured]{ - reconciler: target, - unstructuredGVK: gvk, - } -} - func (r *Reconciler[T]) SetupWithManager(mgr ctrl.Manager, defaultOptions controller.Options) error { r.cluster = mgr return r.reconciler.SetupWithManager(mgr, r, defaultOptions) @@ -142,6 +136,17 @@ func (r *Reconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (reconc currentStatus := newStatusObject(obj) currentState := state.GetState(currentStatus.Status.Conditions) + if customresource.ReconciliationShouldBeSkipped(clientObj) { + logger.Info(fmt.Sprintf("Skipping reconciliation by annotation %s=%s", customresource.ReconciliationPolicyAnnotation, customresource.ReconciliationPolicySkip)) + if currentState == state.StateDeleted { + if err := finalizer.UnsetFinalizers(ctx, r.cluster.GetClient(), clientObj, "mongodb.com/finalizer"); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to unset finalizer: %w", err) + } + } + + return ctrl.Result{}, nil + } + logger.Info("reconcile started", "currentState", currentState) if err := finalizer.EnsureFinalizers(ctx, r.cluster.GetClient(), clientObj, "mongodb.com/finalizer"); err != nil { return ctrl.Result{}, fmt.Errorf("failed to manage finalizers: %w", err) diff --git a/pkg/controller/state/reconciler_test.go b/pkg/controller/state/reconciler_test.go index f51c543b3e..5391b5cbfd 100644 --- a/pkg/controller/state/reconciler_test.go +++ b/pkg/controller/state/reconciler_test.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/state" ) @@ -304,6 +305,20 @@ func TestReconcile(t *testing.T) { return Result{NextState: "Initial"}, nil }, }, + { + name: "should skip reconcile request", + existingObj: baseObj.WithSkipReconciliationAnnotation(), + handleState: func(ctx context.Context, do *dummyObject) (Result, error) { + return Result{Result: reconcile.Result{}}, nil + }, + }, + { + name: "should skip reconcile request on deleted object", + existingObj: baseObj.WithSkipReconciliationAnnotation().WithDeletedStaze(), + handleState: func(ctx context.Context, do *dummyObject) (Result, error) { + return Result{Result: reconcile.Result{}}, nil + }, + }, } for _, tc := range tests { @@ -534,6 +549,33 @@ func (do *dummyObject) DeepCopy() *dummyObject { } } +func (do *dummyObject) WithSkipReconciliationAnnotation() *dummyObject { + copyOfDo := do.DeepCopy() + + if copyOfDo.Annotations == nil { + copyOfDo.Annotations = make(map[string]string) + } + copyOfDo.Annotations[customresource.ReconciliationPolicyAnnotation] = customresource.ReconciliationPolicySkip + + return copyOfDo +} + +func (do *dummyObject) WithDeletedStaze() *dummyObject { + copyOfDo := do.DeepCopy() + + if len(copyOfDo.Status.Conditions) == 0 { + copyOfDo.Status.Conditions = []metav1.Condition{} + } + + copyOfDo.Status.Conditions = append(copyOfDo.Status.Conditions, metav1.Condition{ + Type: "State", + Status: metav1.ConditionTrue, + Reason: "Deleted", + }) + + return copyOfDo +} + func prevStatusObject(state state.ResourceState, observedGen int64) StatusObject { return newDummyObject(metav1.ObjectMeta{}, []metav1.Condition{ newStateCondition(state, metav1.ConditionTrue, observedGen),