🐛 fix(api): snapshot.enabled: false is unsettable and never cleans up - #7
Merged
Conversation
Enabled was a non-pointer bool with omitempty and +kubebuilder:default=true.
false is Go's zero value, so it was dropped on marshal and the API server
re-applied the default, meaning an explicit false could not survive the
operator's own full-object write when adding the finalizer.
Verified before the fix:
enabled=false marshals to: {"schedule":"0 * * * *","retentionCount":5}
enabled=true marshals to: {"enabled":true,"schedule":"0 * * * *","retentionCount":5}
A CR that declares snapshot.enabled: false therefore ends up running a
snapshot CronJob anyway.
Behaviour-neutral on its own: the call site still gates on Enabled, so no
CronJob is deleted until that gate is removed. The CRD schema is unchanged —
*bool and bool both render as type: boolean with default: true.
S3BackupSpec.Enabled is deliberately left a plain bool: it has no kubebuilder
default, so absent and explicit-false are already equivalent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ble removes it The call site gated on Spec.Snapshot.Enabled, but the delete branch lives inside the function being gated. The function could therefore only ever run when snapshots were enabled, and its first act was to check whether they were disabled — dead code. Disabling snapshots never removed an existing CronJob. Combined with the enabled:false fix, "disable snapshots" now works end to end and cleans up CronJobs left behind on clusters that no longer want them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Minor, not patch: disabling snapshots now actually disables them, which changes behaviour on every existing cluster. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-raises #6 against
main.#6 was stacked on
fix/snapshot-cronjob-scheduling(the branch behind #5). #5 was squash-merged, somaingained a single new commit rather than that branch's history, and #6 — merged into its original base — never reachedmain. GitHub auto-retargets a stacked PR when its base branch is deleted on merge, butdelete_branch_on_mergeis off for this repo, so it kept pointing at the stale branch.No code changes: the three commits from #6 are cherry-picked onto
main, and the resulting tree is byte-identical to the reviewed branch (git diff origin/fix/snapshot-enabled-false --statis empty). Cherry-picked cleanly with no conflicts.The original review discussion lives on #6.
What this contains
1.
snapshot.enabled: falseis unsettable.SnapshotSpec.Enabledwas a non-pointerboolwithomitemptyand+kubebuilder:default=true.falseis Go's zero value, so it is dropped on marshal and the API server re-applies the default:It therefore cannot survive the operator's own full-object write when adding the finalizer.
Enabledbecomes*boolwith anIsEnabled()accessor treating nil as true, matching the CRD default. The CRD schema is unchanged —*boolandboolboth render astype: booleanwithdefault: true; only the field description differs.S3BackupSpec.Enabledis deliberately left a plainbool: it has no kubebuilder default, so absent and explicit-false are already equivalent there.2. The cleanup path was unreachable. The call site gated on
Spec.Snapshot.Enabled, but the delete branch lives inside the function being gated — so it could only run when snapshots were enabled, and its first act was to check whether they were disabled.reconcileSnapshotCronJobis now called unconditionally.Deployment note
snapshot.enabled: falsewill have its snapshot CronJob deleted on the first reconcile after upgrade. That is the intended fix, but it is a behaviour change on upgrade rather than a pure bugfix, hence the minor version bump to0.3.0.This should ship together with or ahead of #5, not after it. #5 alone repairs the CronJobs without removing them, which starts snapshot jobs on clusters that have disabled them.
Testing
make cipasses — lint 0 issues, all packages green, build succeeds.api/v1alpha1coverage at 90.2%.🤖 Generated with Claude Code