Skip to content

Update reconciliation with status conditions and event-driven updates#90

Open
shreyabiradar07 wants to merge 2 commits into
kruize:mvp_demofrom
shreyabiradar07:update_reconciliation
Open

Update reconciliation with status conditions and event-driven updates#90
shreyabiradar07 wants to merge 2 commits into
kruize:mvp_demofrom
shreyabiradar07:update_reconciliation

Conversation

@shreyabiradar07
Copy link
Copy Markdown
Contributor

@shreyabiradar07 shreyabiradar07 commented Apr 27, 2026

Summary by Sourcery

Update Kruize controller reconciliation to use condition-based status reporting and event-driven updates for managed resources.

New Features:

  • Add validation of the Kruize custom resource cluster type before finalizer handling to reject unsupported configurations early.
  • Introduce status condition updates on the Kruize custom resource to reflect deployment progress, readiness, and failure states.
  • Add readiness checks for all required Kruize deployments to drive non-blocking reconciliation based on deployment status.

Enhancements:

  • Refactor finalizer handling to use a common utility for consistent lifecycle management of Kruize resources.
  • Extend the controller to watch and own related Deployments, Services, ConfigMaps, and PersistentVolumeClaims for event-driven reconciliation instead of periodic requeues.

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

sourcery-ai Bot commented Apr 27, 2026

Reviewer's Guide

Refactors the Kruize controller reconciliation loop to validate cluster type early, centralize finalizer handling, add non-blocking deployment readiness checks, standardize status conditions/phases, and register owned resources for event-driven reconciliation.

Sequence diagram for updated Kruize reconciliation loop

sequenceDiagram
    participant Manager
    participant KruizeReconciler
    participant API_Server

    Manager->>KruizeReconciler: Reconcile(req)
    KruizeReconciler->>API_Server: Get(Kruize)
    KruizeReconciler->>KruizeReconciler: IsBeingDeleted(kruize)
    alt not being deleted
        KruizeReconciler->>KruizeReconciler: IsValidClusterType(kruize.Spec.Cluster_type)
        alt invalid cluster type
            KruizeReconciler-->>Manager: error (unsupported cluster type)
        else valid cluster type
            KruizeReconciler->>KruizeReconciler: HandleFinalizer(kruize, finalizeKruize)
            alt finalizer error
                KruizeReconciler-->>Manager: error
            else needsRequeue
                KruizeReconciler-->>Manager: ctrl.Result{Requeue: true}
            else ready to reconcile
                KruizeReconciler->>KruizeReconciler: deployKruize(ctx, kruize)
                alt deploy error
                    KruizeReconciler->>KruizeReconciler: updateStatus(Progressing, Failed)
                    KruizeReconciler-->>Manager: ctrl.Result{RequeueAfter: 30s}
                else deploy ok
                    KruizeReconciler->>KruizeReconciler: checkAllDeploymentsReady(namespace)
                    alt check error
                        KruizeReconciler->>KruizeReconciler: updateStatus(Progressing, Unknown)
                        KruizeReconciler-->>Manager: ctrl.Result{RequeueAfter: 10s}
                    else not all ready
                        KruizeReconciler->>KruizeReconciler: updateStatus(Progressing, Progressing)
                        KruizeReconciler-->>Manager: ctrl.Result{RequeueAfter: 15s}
                    else all ready
                        KruizeReconciler->>KruizeReconciler: updateStatus(Ready, Ready)
                        KruizeReconciler-->>Manager: ctrl.Result{}
                    end
                end
            end
        end
    else being deleted
        KruizeReconciler->>KruizeReconciler: HandleFinalizer(kruize, finalizeKruize)
        KruizeReconciler-->>Manager: ctrl.Result{}
    end
Loading

File-Level Changes

Change Details Files
Early cluster type validation before finalizer handling and reconciliation.
  • Add pre-finalizer validation of kruize.Spec.Cluster_type against supported types
  • Return an error and skip reconciliation when an unsupported cluster type is specified
internal/controller/kruize_controller.go
Centralized finalizer lifecycle management using a shared utility with dedicated cleanup logic.
  • Replace inline finalizer logic with common.HandleFinalizer utility
  • Invoke a finalizeKruize callback during deletion and requeue once when the finalizer is first added
  • Exit reconciliation early when the resource is being deleted after finalizer handling
internal/controller/kruize_controller.go
Introduce non-blocking deployment readiness checks for Kruize components instead of waiting on Pods.
  • Remove blocking waitForKruizePods call and logging around pod readiness
  • Add checkDeploymentReady helper that inspects Deployment status fields for readiness
  • Add checkAllDeploymentsReady to verify a fixed set of Kruize deployments and collect non-ready ones
  • Skip readiness checks entirely when the controller is in test mode
internal/controller/kruize_controller.go
Standardize Kruize status updates using phases and conditions that reflect controller progress and deployment health.
  • Add updateStatus helper to set kruize.Status.Phase and a Kubernetes-style Available condition with reason and message
  • Use updateStatus on deployment errors, readiness progress, and when all components are ready
  • Propagate deployment health via condition status (True/False/Unknown) and appropriate reasons (AllComponentsReady, ComponentsNotReady, DeploymentFailed, Unknown)
internal/controller/kruize_controller.go
Enable event-driven reconciliation by declaring ownership of Kruize component resources in the controller setup.
  • Register ownership of Deployments, Services, ConfigMaps, and PersistentVolumeClaims in SetupWithManager
  • Rely on controller-runtime to enqueue Kruize reconciliations when owned resources change instead of periodic requeues
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

@shreyabiradar07 shreyabiradar07 marked this pull request as ready for review May 19, 2026 04:59
@shreyabiradar07 shreyabiradar07 moved this to In Progress in Monitoring May 19, 2026
@shreyabiradar07 shreyabiradar07 added this to the Kruize Operator 0.0.7 milestone May 19, 2026
@shreyabiradar07 shreyabiradar07 self-assigned this May 19, 2026
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In updateStatus, the conditionType parameter is never used and the condition type is hard-coded to "Available"; either wire conditionType through to meta.SetStatusCondition or remove the parameter to avoid confusion.
  • The updateStatus helper calls r.Status().Update once without handling Conflict errors, which could lead to dropped status updates under concurrent reconciles; consider wrapping the status update in a retry loop (e.g., using client.RetryOnConflict) to make this more robust.
  • In the if !allReady branch, the closing brace alignment/indentation looks off in the diff (the block ends with a tab-indented }); double-check the block structure/formatting there to avoid accidental logic or formatting issues.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `updateStatus`, the `conditionType` parameter is never used and the condition type is hard-coded to `"Available"`; either wire `conditionType` through to `meta.SetStatusCondition` or remove the parameter to avoid confusion.
- The `updateStatus` helper calls `r.Status().Update` once without handling `Conflict` errors, which could lead to dropped status updates under concurrent reconciles; consider wrapping the status update in a retry loop (e.g., using `client.RetryOnConflict`) to make this more robust.
- In the `if !allReady` branch, the closing brace alignment/indentation looks off in the diff (the block ends with a tab-indented `}`); double-check the block structure/formatting there to avoid accidental logic or formatting issues.

## Individual Comments

### Comment 1
<location path="internal/controller/kruize_controller.go" line_range="168" />
<code_context>
 	if err != nil {
 		logger.Error(err, "Failed to deploy Kruize")
-		return ctrl.Result{RequeueAfter: time.Minute}, err
+		r.updateStatus(ctx, kruize, "Progressing", "Failed", fmt.Sprintf("Deployment failed: %v", err))
+		return ctrl.Result{RequeueAfter: 30 * time.Second}, err
 	}
</code_context>
<issue_to_address>
**issue (bug_risk):** Status phase on deployment failure should likely be set to a failure phase instead of "Progressing".

In this failure branch, `phase` is set to "Progressing" even though the message and `conditionType` indicate a failure. This makes it difficult for consumers of the CR to distinguish an in-progress state from a terminal error. Please set `phase` to something like "Failed" here, or otherwise ensure it accurately reflects the lifecycle state when deployment fails.
</issue_to_address>

### Comment 2
<location path="internal/controller/kruize_controller.go" line_range="252-253" />
<code_context>
+		return allReady, notReadyDeployments, nil
+	}
+	
+	// updateStatus updates the Kruize CR status with conditions
+	func (r *KruizeReconciler) updateStatus(ctx context.Context, kruize *kruizev1alpha1.Kruize,
+		phase, conditionType, message string) {
+		logger := log.FromContext(ctx)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The `conditionType` parameter is unused and the condition type is hard-coded to "Available".

`updateStatus` takes `conditionType` but always sets the condition `Type` to "Available", so callers can’t actually control it. Either remove `conditionType` from the signature or use it to set the `Type` field (e.g., "Available", "Progressing", "Degraded"), and update call sites accordingly to keep the status semantics consistent.

Suggested implementation:

```golang
	// updateStatus updates the Kruize CR status with conditions
	func (r *KruizeReconciler) updateStatus(ctx context.Context, kruize *kruizev1alpha1.Kruize,
		phase, conditionType, message string) {
		logger := log.FromContext(ctx)

```

```golang
			Type:               conditionType,

```

1. Ensure all call sites of `updateStatus` pass an appropriate `conditionType` value (e.g. `"Available"`, `"Progressing"`, `"Degraded"`) instead of assuming it is always `"Available"`.
2. If there are existing callers that relied on the hard‑coded `"Available"` behavior and do not yet pass a meaningful type, update them to pass `"Available"` explicitly to preserve current semantics.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

if err != nil {
logger.Error(err, "Failed to deploy Kruize")
return ctrl.Result{RequeueAfter: time.Minute}, err
r.updateStatus(ctx, kruize, "Progressing", "Failed", fmt.Sprintf("Deployment failed: %v", err))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Status phase on deployment failure should likely be set to a failure phase instead of "Progressing".

In this failure branch, phase is set to "Progressing" even though the message and conditionType indicate a failure. This makes it difficult for consumers of the CR to distinguish an in-progress state from a terminal error. Please set phase to something like "Failed" here, or otherwise ensure it accurately reflects the lifecycle state when deployment fails.

Comment on lines +252 to +253
// updateStatus updates the Kruize CR status with conditions
func (r *KruizeReconciler) updateStatus(ctx context.Context, kruize *kruizev1alpha1.Kruize,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): The conditionType parameter is unused and the condition type is hard-coded to "Available".

updateStatus takes conditionType but always sets the condition Type to "Available", so callers can’t actually control it. Either remove conditionType from the signature or use it to set the Type field (e.g., "Available", "Progressing", "Degraded"), and update call sites accordingly to keep the status semantics consistent.

Suggested implementation:

	// updateStatus updates the Kruize CR status with conditions
	func (r *KruizeReconciler) updateStatus(ctx context.Context, kruize *kruizev1alpha1.Kruize,
		phase, conditionType, message string) {
		logger := log.FromContext(ctx)
			Type:               conditionType,
  1. Ensure all call sites of updateStatus pass an appropriate conditionType value (e.g. "Available", "Progressing", "Degraded") instead of assuming it is always "Available".
  2. If there are existing callers that relied on the hard‑coded "Available" behavior and do not yet pass a meaningful type, update them to pass "Available" explicitly to preserve current semantics.

@shreyabiradar07 shreyabiradar07 added enhancement New feature or request Operator labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant