Skip to content

Add finalizers#72

Draft
shreyabiradar07 wants to merge 1 commit intokruize:mvp_demofrom
shreyabiradar07:add_finalizers
Draft

Add finalizers#72
shreyabiradar07 wants to merge 1 commit intokruize:mvp_demofrom
shreyabiradar07:add_finalizers

Conversation

@shreyabiradar07
Copy link
Contributor

@shreyabiradar07 shreyabiradar07 commented Mar 6, 2026

This PR implements finalizers to cleanup namespace and cluster scoped resources when Kruize Custom Resource (CR) is deleted.

Summary by Sourcery

Add deletion finalization logic to the Kruize controller so that operator-managed resources are cleaned up when a Kruize CR is removed.

Bug Fixes:

  • Ensure namespace-scoped and cluster-scoped resources created for a Kruize instance are deleted when the custom resource is removed.

Enhancements:

  • Introduce a finalizer on Kruize custom resources and associated reconciliation flow to manage lifecycle cleanup of operator-created resources.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 6, 2026

Reviewer's Guide

Implements Kubernetes finalizers for the Kruize custom resource so that when a Kruize CR is deleted, the controller first runs cleanup logic to delete associated namespaced and cluster-scoped resources before allowing the CR to be removed.

Sequence diagram for Kruize CR deletion with finalizer

sequenceDiagram
    actor User
    participant APIServer
    participant ControllerManager
    participant KruizeReconciler
    participant KruizeResourceGenerator
    participant KubernetesAPI

    User->>APIServer: delete KruizeCR
    APIServer->>KruizeCR: set deletionTimestamp
    APIServer-->>User: deletion accepted (pending finalizer)

    APIServer->>ControllerManager: enqueue reconcile request
    ControllerManager->>KruizeReconciler: Reconcile(req)

    KruizeReconciler->>KruizeReconciler: load Kruize
    KruizeReconciler->>KruizeReconciler: GetDeletionTimestamp() != nil
    KruizeReconciler->>KruizeReconciler: controllerutil.ContainsFinalizer(kruizeFinalizer)

    KruizeReconciler->>KruizeReconciler: finalizeKruize(ctx,kruize)
    activate KruizeReconciler
    KruizeReconciler->>KruizeResourceGenerator: NewKruizeResourceGenerator(namespace,autotune_image,autotune_ui_image,clusterType)
    KruizeResourceGenerator-->>KruizeReconciler: generator

    KruizeReconciler->>KruizeResourceGenerator: NamespacedResources()
    KruizeResourceGenerator-->>KruizeReconciler: []client.Object
    loop delete_namespaced_resources
        KruizeReconciler->>KubernetesAPI: deleteResource(ctx,obj)
    end

    KruizeReconciler->>KruizeResourceGenerator: ClusterScopedResources() or KubernetesClusterScopedResources()
    KruizeResourceGenerator-->>KruizeReconciler: []client.Object
    loop delete_cluster_scoped_resources
        KruizeReconciler->>KubernetesAPI: deleteResource(ctx,obj)
    end
    deactivate KruizeReconciler

    KruizeReconciler->>KruizeReconciler: controllerutil.RemoveFinalizer(kruizeFinalizer)
    KruizeReconciler->>KubernetesAPI: Update(kruize)
    KruizeReconciler-->>ControllerManager: ctrl.Result{}

    APIServer->>APIServer: all finalizers removed
    APIServer->>KubernetesAPI: delete KruizeCR resources
    APIServer-->>User: KruizeCR fully deleted
Loading

Sequence diagram for deleteResource helper behavior

sequenceDiagram
    participant KruizeReconciler
    participant KubernetesAPI

    KruizeReconciler->>KruizeReconciler: deleteResource(ctx,obj)
    KruizeReconciler->>KubernetesAPI: Get(ObjectKeyFromObject(obj))
    alt resource_not_found
        KubernetesAPI-->>KruizeReconciler: errors.IsNotFound
        KruizeReconciler->>KruizeReconciler: log skip deletion
        KruizeReconciler-->>KruizeReconciler: return nil
    else other_get_error
        KubernetesAPI-->>KruizeReconciler: error
        KruizeReconciler-->>KruizeReconciler: return wrapped_error
    else resource_found
        KubernetesAPI-->>KruizeReconciler: found_object
        KruizeReconciler->>KubernetesAPI: Delete(found_object)
        alt delete_not_found
            KubernetesAPI-->>KruizeReconciler: errors.IsNotFound
            KruizeReconciler-->>KruizeReconciler: return nil
        else delete_error
            KubernetesAPI-->>KruizeReconciler: error
            KruizeReconciler-->>KruizeReconciler: return wrapped_error
        else delete_success
            KubernetesAPI-->>KruizeReconciler: success
            KruizeReconciler-->>KruizeReconciler: return nil
        end
    end
Loading

Class diagram for KruizeReconciler with finalizer methods

classDiagram
    class KruizeReconciler {
        +Reconcile(ctx,req) ctrl_Result
        +finalizeKruize(ctx,kruize) error
        +deleteResource(ctx,obj) error
        +deployKruize(ctx,kruize) error
        +deployKruizeComponents(ctx,namespace,kruize,clusterType) error
        +checkKruizePodsStatus(ctx,namespace) (bool,error)
        +isTestMode() bool
        +reconcileClusterResource(ctx,obj) error
    }

    class Kruize {
        +Spec KruizeSpec
        +GetDeletionTimestamp() time_Time
    }

    class KruizeSpec {
        +Namespace string
        +Cluster_type string
        +Autotune_image string
        +Autotune_ui_image string
    }

    class KruizeResourceGenerator {
        +KruizeResourceGenerator(namespace,autotune_image,autotune_ui_image,clusterType)
        +NamespacedResources() []client_Object
        +ClusterScopedResources() []client_Object
        +KubernetesClusterScopedResources() []client_Object
        +KruizeServiceAccount() client_Object
        +KruizeConfigMap() client_Object
    }

    class Constants {
        +ClusterTypeOpenShift string
        +IsValidClusterType(clusterType) bool
    }

    class ClientObject {
        +GetName() string
        +GetNamespace() string
        +GetObjectKind() runtime_ObjectKind
        +DeepCopyObject() client_Object
    }

    class ControllerUtil {
        +ContainsFinalizer(kruize,finalizer) bool
        +AddFinalizer(kruize,finalizer) void
        +RemoveFinalizer(kruize,finalizer) void
    }

    class ControllerRuntimeClient {
        +Get(ctx,key,obj) error
        +Update(ctx,obj) error
        +Delete(ctx,obj) error
    }

    KruizeReconciler --> Kruize : manages
    KruizeReconciler --> KruizeResourceGenerator : uses
    KruizeReconciler --> ControllerRuntimeClient : uses
    KruizeReconciler --> ControllerUtil : uses
    Kruize --> KruizeSpec : has
    KruizeReconciler --> Constants : uses
    KruizeReconciler --> ClientObject : deletes/resources
    KruizeResourceGenerator --> ClientObject : produces
Loading

Flow diagram for KruizeReconciler Reconcile with finalizers

flowchart TD
    A_start["Reconcile start"] --> B_load_kruize["Load Kruize CR"]
    B_load_kruize --> C_check_deletion["kruize.GetDeletionTimestamp() != nil?"]

    C_check_deletion -- "yes" --> D_has_finalizer["controllerutil.ContainsFinalizer(kruizeFinalizer)?"]
    D_has_finalizer -- "yes" --> E_finalize["finalizeKruize(ctx,kruize)"]
    E_finalize --> F_remove_finalizer["controllerutil.RemoveFinalizer(kruizeFinalizer)"]
    F_remove_finalizer --> G_update_remove["Update(ctx,kruize)"]
    G_update_remove --> H_return_delete["return ctrl.Result{} (no requeue)"]

    D_has_finalizer -- "no" --> H_return_delete

    C_check_deletion -- "no" --> I_has_finalizer["controllerutil.ContainsFinalizer(kruizeFinalizer)?"]
    I_has_finalizer -- "no" --> J_add_finalizer["controllerutil.AddFinalizer(kruizeFinalizer)"]
    J_add_finalizer --> K_update_add["Update(ctx,kruize)"]
    K_update_add --> L_deploy["deployKruize(ctx,kruize)"]

    I_has_finalizer -- "yes" --> L_deploy

    L_deploy --> M_check_test_mode["isTestMode()? "]
    M_check_test_mode -- "true" --> N_return_no_requeue["return ctrl.Result{}"]
    M_check_test_mode -- "false" --> O_return_requeue["return ctrl.Result{RequeueAfter:5m}"]
Loading

File-Level Changes

Change Details Files
Add finalizer handling to the Kruize reconciler lifecycle so deletion triggers cleanup logic.
  • On each reconcile, check for DeletionTimestamp; if set and the Kruize finalizer is present, call finalizeKruize, then remove the finalizer and update the resource before returning
  • If the resource is not being deleted and the finalizer is missing, add the Kruize finalizer and update the resource before proceeding with deployment
internal/controller/kruize_controller.go
Introduce finalizeKruize helper to delete all operator-managed namespaced and cluster-scoped resources.
  • Determine cluster type from the Kruize spec, falling back to OpenShift as default if invalid
  • Instantiate a KruizeResourceGenerator using spec values (namespace, images, cluster type) to derive resource objects
  • Iterate over generated namespaced resources, attempting deletion via deleteResource and logging failures without aborting
  • Based on cluster type, select appropriate cluster-scoped resources (OpenShift vs generic Kubernetes) and delete them similarly
  • Log progress and completion of cleanup for observability
internal/controller/kruize_controller.go
Add generic deleteResource helper to safely delete arbitrary Kubernetes objects.
  • Fetch the target object using client.Get and treat NotFound as a no-op with an informational log
  • On successful lookup, call client.Delete and treat NotFound during delete as success
  • Log detailed kind/name/namespace information on skip, delete, and errors, and wrap non-NotFound errors with contextual messages
internal/controller/kruize_controller.go
Minor formatting and whitespace cleanups in deployment logic.
  • Normalize whitespace in deployKruize and deployKruizeComponents functions
  • Fix indentation of the OpenShift kruize service account reconciliation block without changing behavior
internal/controller/kruize_controller.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant