Skip to content

fix(controller): retry when the SealedSecret status update fails - #2099

Open
lbarrosby wants to merge 1 commit into
bitnami:mainfrom
lbarrosby:fix/retry-status-update
Open

lbarrosby wants to merge 1 commit into
bitnami:mainfrom
lbarrosby:fix/retry-status-update

Conversation

@lbarrosby

Copy link
Copy Markdown

Description of the change

When the status write at the end of unseal fails, the error is only logged. unseal still returns nil, so the key is forgotten, and status-only changes never trigger the SealedSecret update handler (it only requeues on spec changes). The SealedSecret keeps its old condition, typically Synced=False with the previous error, even though the Secret was unsealed fine. It stays like that until the next spec change or a restart. A conflict is enough to hit this, and so is the UID precondition error from #898 when a SealedSecret is replaced.

There is a second problem behind it: the condition was written into the object owned by the informer cache. After a failed write, the cache already holds the new condition, so a retry compares against it, decides nothing changed and skips the write anyway.

The fix works on a deep copy of the cached object and, when the unseal itself succeeded but the status write failed, returns that error so the item is retried with the normal rate limiting and --max-unseal-retries.

Benefits

The Synced condition reflects reality after transient API errors, which removes stale Synced=False reports and false positives from alerts based on the status. The informer cache is no longer mutated outside the informer.

Possible drawbacks

A failed status write now causes one more unseal attempt (idempotent: the Secret is unchanged, and an Unsealed event is recorded again).

Applicable issues

Additional information

TestStatusUpdateFailureIsRetried makes the first UpdateStatus call return a conflict and expects Synced=True to be stored eventually. It fails on main (only one status update is attempted). I also checked that it still fails with only the retry or only the deep copy, so both parts are needed. go test ./pkg/... ./cmd/... and golangci-lint run ./pkg/controller/ are clean.

A failed status write was only logged: unseal still returned nil, the key
was forgotten and nothing requeued it, since status-only changes do not
trigger the SealedSecret update handler. The SealedSecret then kept its
previous condition (e.g. Synced=False) although the Secret had been
unsealed, until the next spec change or controller restart. This is what
happens on a conflict or on the UID precondition error from bitnami#898.

The status was also written into the object owned by the informer cache,
so a retry would compare against the condition that never made it to the
API server and skip the write. Work on a copy and return the status error
so the item is retried with the usual rate limiting.

Signed-off-by: Lucas Barros <lucasbarros.kam@gmail.com>

This branch has not been deployed

No deployments
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.

Unseal updated secret: Precondition failed

1 participant