Skip to content

fix: add do-not-delete finalizer to signal the finalizer shouldn't be removed manually#2574

Open
assafgi wants to merge 1 commit into
mainfrom
05-31-fix_add_do-not-delete_finalizer_to_signal_the_finalizer_shouldn_t_be_removed_manually
Open

fix: add do-not-delete finalizer to signal the finalizer shouldn't be removed manually#2574
assafgi wants to merge 1 commit into
mainfrom
05-31-fix_add_do-not-delete_finalizer_to_signal_the_finalizer_shouldn_t_be_removed_manually

Conversation

@assafgi
Copy link
Copy Markdown
Member

@assafgi assafgi commented May 31, 2026

No description provided.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@assafgi assafgi marked this pull request as ready for review May 31, 2026 12:44
@assafgi assafgi requested a review from a team as a code owner May 31, 2026 12:44
Copilot AI review requested due to automatic review settings May 31, 2026 12:44
Copy link
Copy Markdown
Member Author

assafgi commented May 31, 2026


How to use the Graphite Merge Queue

Add the label main-merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented May 31, 2026

Claude finished @assafgi's task in 2m 8s —— View job


Claude PR Review

  • Read all changed files
  • Understand the do-not-delete finalizer pattern
  • Identify code quality / correctness issues
  • Post review feedback

Summary

The intent — adding a second, human-readable guard finalizer alongside WekaFinalizer so the name itself signals "do not strip manually" — is reasonable and the diff is small and consistent across the three controllers. However, the rollout has a real correctness issue that I think should be fixed before merge.

Findings (see inline comments for details and suggested fixes):

  1. 🐞 Bug — guard finalizer is never persisted on existing resources (wekaclient/client_reconciler_loop.go:265, wekacontainer/funcs_active_state_init.go:83, wekacluster/steps_cluster_creation.go:140-152).
    AddFinalizer returns false when the finalizer is already present. In all three "ensure"/"init" sites, the code reaches Update() only when WekaFinalizer was missing — so any resource that already has WekaFinalizer (i.e. every resource that exists today) gets the new guard finalizer added in-memory but never written back. The protection effectively only applies to freshly created resources, which probably isn't the intent.

  2. 🎨 Naming — protection.io is not a domain this project owns (internal/consts/consts.go:11). All sibling constants use weka.io. Suggest do-not-delete.weka.io/guard to keep the semantic signal while staying inside an owned domain.

  3. 🧹 Consistency — finalizer-remove ordering differs across controllers (wekacluster/steps_deletion.go:216). Not a bug, but wekacluster removes the guard before WekaFinalizer; the other two do the opposite. Pick one order across the codebase.

  4. 🧪 No tests. A small unit test asserting that (a) both finalizers are added together on init and (b) both are removed on deletion would lock in the contract this PR is establishing, and would have caught issue Operator sdk #1.

Non-issues I looked at: the HandleDeletion sites correctly skip Update() on early-return so no partial state is persisted; the new constant is used consistently; the protection.io/guard string is syntactically a valid finalizer name.

Overall: nice idea, low-risk diff, but please address #1 before merge — otherwise the guard won't be doing its job on the fleet that actually needs protecting.


· Branch: 05-31-fix_add_do-not-delete_finalizer_to_signal_the_finalizer_shouldn_t_be_removed_manually

@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented May 31, 2026

Graphite Automations

"Add anton/matt/sergey/kristina as reviwers on operator PRs" took an action on this PR • (05/31/26)

2 reviewers were added to this PR based on Anton Bykov's automation.

Comment on lines 263 to 267
logger.Info("Adding Finalizer for weka client")
controllerutil.AddFinalizer(c.wekaClient, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(c.wekaClient, consts.WekaFinalizer); !ok {
return nil
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: guard finalizer is not persisted on existing resources.

AddFinalizer returns false when the finalizer is already present. So for a WekaClient created before this PR (which has WekaFinalizer but no DeletionProtectionFinalizer), the flow is:

  1. AddFinalizer(DeletionProtectionFinalizer) — mutates the in-memory object.
  2. AddFinalizer(WekaFinalizer) returns false → early return nil.
  3. Update() is never called → the guard addition is lost.

This means rollout to existing clusters won't backfill the protection finalizer; only freshly created WekaClient resources will get it.

Suggest tracking whether either call mutated the object and only short-circuiting when neither did:

Suggested change
logger.Info("Adding Finalizer for weka client")
controllerutil.AddFinalizer(c.wekaClient, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(c.wekaClient, consts.WekaFinalizer); !ok {
return nil
}
logger.Info("Adding Finalizer for weka client")
addedGuard := controllerutil.AddFinalizer(c.wekaClient, consts.DeletionProtectionFinalizer)
addedWeka := controllerutil.AddFinalizer(c.wekaClient, consts.WekaFinalizer)
if !addedGuard && !addedWeka {
return nil
}

Fix this →

Comment on lines 82 to 85
controllerutil.AddFinalizer(container, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(container, consts.WekaFinalizer); !ok {
return nil
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same bug as in wekaclient: if WekaFinalizer is already present, AddFinalizer returns false, the function returns early, and the DeletionProtectionFinalizer addition is never Update()'d. Existing WekaContainer resources will not be backfilled with the guard finalizer.

Suggested change
controllerutil.AddFinalizer(container, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(container, consts.WekaFinalizer); !ok {
return nil
}
addedGuard := controllerutil.AddFinalizer(container, consts.DeletionProtectionFinalizer)
addedWeka := controllerutil.AddFinalizer(container, consts.WekaFinalizer)
if !addedGuard && !addedWeka {
return nil
}

Comment thread internal/consts/consts.go Outdated
// DeletionProtectionFinalizer is a guard finalizer with a clear name to prevent
// accidental deletion by automation or AI agents. It is added alongside WekaFinalizer
// and removed only during intentional operator-driven deletion flows.
DeletionProtectionFinalizer = "do-not-delete.protection.io/guard"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit (naming): every other finalizer/annotation/resource constant in this file uses the weka.io domain that the project owns (e.g. weka.weka.io/finalizer, weka.io/weka-drives). protection.io is a generic, unowned domain and breaks that convention.

Suggest something like do-not-delete.weka.io/guard so the "do-not-delete" semantic signal is preserved while staying within a domain you control.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a second Kubernetes finalizer intended to act as a deletion-protection guard alongside the existing Weka finalizer, and updates WekaContainer, WekaCluster, and WekaClient deletion paths to remove it during operator-managed cleanup.

Changes:

  • Adds DeletionProtectionFinalizer in internal/consts.
  • Adds the new finalizer during active/init reconciliation for Weka resources.
  • Removes the new finalizer during deletion handling.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/consts/consts.go Defines the new deletion-protection finalizer constant.
internal/controllers/wekacontainer/funcs_active_state_init.go Adds the protection finalizer during container finalizer reconciliation.
internal/controllers/wekacontainer/funcs_common_deletion.go Removes the protection finalizer during container deletion.
internal/controllers/wekacluster/steps_cluster_creation.go Adds the protection finalizer during cluster initialization.
internal/controllers/wekacluster/steps_deletion.go Removes the protection finalizer during cluster deletion.
internal/controllers/wekaclient/client_reconciler_loop.go Adds/removes the protection finalizer for WekaClient resources.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 82 to 84
controllerutil.AddFinalizer(container, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(container, consts.WekaFinalizer); !ok {
return nil
Comment on lines 151 to 152
controllerutil.AddFinalizer(wekaCluster, consts.DeletionProtectionFinalizer)
if updated := controllerutil.AddFinalizer(wekaCluster, consts.WekaFinalizer); updated {
Comment on lines 264 to 266
controllerutil.AddFinalizer(c.wekaClient, consts.DeletionProtectionFinalizer)
if ok := controllerutil.AddFinalizer(c.wekaClient, consts.WekaFinalizer); !ok {
return nil
Comment thread internal/consts/consts.go Outdated
// DeletionProtectionFinalizer is a guard finalizer with a clear name to prevent
// accidental deletion by automation or AI agents. It is added alongside WekaFinalizer
// and removed only during intentional operator-driven deletion flows.
DeletionProtectionFinalizer = "do-not-delete.protection.io/guard"
@assafgi assafgi force-pushed the 05-31-fix_add_do-not-delete_finalizer_to_signal_the_finalizer_shouldn_t_be_removed_manually branch from f21ffdb to 5293e20 Compare May 31, 2026 13:24
@claude
Copy link
Copy Markdown

claude Bot commented May 31, 2026

Claude finished @assafgi's task in 37s —— View job


Claude PR Review

  • Compare current PR state against prior review
  • Exit early — no code changes since last review

Status: no new changes since prior review

The current PR head is still commit 5293e20b with the same six files and same +27/−13 diff that I reviewed at 12:44 UTC. The prior review feedback still stands — re-posting it below for convenience.


Summary (unchanged)

The intent — adding a second, human-readable guard finalizer alongside WekaFinalizer so the name itself signals "do not strip manually" — is reasonable and the diff is small and consistent across the three controllers. However, the rollout has a real correctness issue that I think should be fixed before merge.

Findings (see inline comments on the prior review for details and suggested fixes):

  1. 🐞 Bug — guard finalizer is never persisted on existing resources (wekaclient/client_reconciler_loop.go:265, wekacontainer/funcs_active_state_init.go:83, wekacluster/steps_cluster_creation.go:140-152).
    AddFinalizer returns false when the finalizer is already present. In all three "ensure"/"init" sites, the code reaches Update() only when WekaFinalizer was missing — so any resource that already has WekaFinalizer (i.e. every resource that exists today) gets the new guard finalizer added in-memory but never written back. The protection effectively only applies to freshly created resources, which probably isn't the intent. Copilot flagged the same issue independently.

  2. 🎨 Naming — protection.io is not a domain this project owns (internal/consts/consts.go:11). All sibling constants use weka.io. Suggest do-not-delete.weka.io/guard to keep the semantic signal while staying inside an owned domain.

  3. 🧹 Consistency — finalizer-remove ordering differs across controllers (wekacluster/steps_deletion.go:216). Not a bug, but wekacluster removes the guard before WekaFinalizer; the other two do the opposite. Pick one order across the codebase.

  4. 🧪 No tests. A small unit test asserting that (a) both finalizers are added together on init and (b) both are removed on deletion would lock in the contract this PR is establishing, and would have caught issue Operator sdk #1.

Issue #1 is the main blocker — please address before merge.

--- · Branch: 05-31-fix_add_do-not-delete_finalizer_to_signal_the_finalizer_shouldn_t_be_removed_manually

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.

2 participants