Skip to content

[shell-operator] fix: patch CRD conversion without overwriting fields - #930

Merged
ldmonster merged 2 commits into
mainfrom
fix/patch-conversion-webhook
Sep 7, 2026
Merged

ldmonster merged 2 commits into
mainfrom
fix/patch-conversion-webhook

Conversation

@fuldaxxx

@fuldaxxx fuldaxxx commented Sep 4, 2026

Copy link
Copy Markdown
Member

Description

Replace the read-modify-write update of the CRD in the conversion webhook manager with a JSON Patch that touches only spec.conversion.

CrdClientConfig.Update() used to Get() the whole CustomResourceDefinition, mutate spec.conversion in memory and Update() the entire object back. It is now CrdClientConfig.PatchConversion(), which marshals the desired CustomResourceConversion (webhook strategy, service reference, CA bundle, supported review versions) and sends a single [{"op":"add","path":"/spec/conversion","value":{…}}] patch.

Other changes that come with it:

  • The retry budget (60 attempts × 15s = 15 min) now wraps the write call instead of only the Get, so a CRD that does not exist yet when a hook registers its conversion binding is still picked up once it appears.
  • The retry sleep is select-based on ctx.Done() instead of a blocking time.Sleep(), so the loop stops on context cancellation instead of holding startup for up to 15 minutes.
  • The method and the error messages are renamed to reflect what actually happens (update CRDpatch CRD conversion).

Why do we need it, and what problem does it solve?

Sending the full CRD back on Update() makes shell-operator a last-write-wins writer for the entire object. Anything written to that CRD between our Get() and our Update() — by Helm, by another controller, by an operator that owns the same CRD, or by a parallel shell-operator instance — is silently reverted to the snapshot we read, and the change is not limited to spec.conversion: schema edits, versions, labels and annotations all travel in that request. On a busy cluster this shows up as CRD fields mysteriously rolling back right after the operator starts, and as the object has been modified conflicts on startup.

A JSON Patch scoped to /spec/conversion states the actual intent — "point this CRD's conversion at my webhook, leave everything else alone" — so the operator can no longer clobber fields it does not own, and concurrent writers to other parts of the CRD stop conflicting with it.

The second problem was retry placement: only the Get was retried, so a CRD that appeared during startup was fetched successfully but the very first failing write aborted WebhookManager.Start(). Retrying the write instead covers the real race (the CRD being created around the same time as the operator), and making the wait
context-aware means a shutdown during that window no longer blocks for minutes.

Signed-off-by: Ruslan Gorbunov <ruslan.gorbunov@flant.com>
@fuldaxxx
fuldaxxx requested review from ipaqsa and ldmonster September 4, 2026 08:49
@fuldaxxx fuldaxxx self-assigned this Sep 4, 2026
@fuldaxxx fuldaxxx changed the title fix: patch CRD conversion without overwriting fields [shell-operator] fix: patch CRD conversion without overwriting fields Sep 4, 2026
@fuldaxxx fuldaxxx added bug Something isn't working go Pull requests that update Go code labels Sep 4, 2026
Signed-off-by: Ruslan Gorbunov <ruslan.gorbunov@flant.com>
@ldmonster
ldmonster merged commit 9ff8894 into main Sep 7, 2026
9 checks passed
@ldmonster
ldmonster deleted the fix/patch-conversion-webhook branch September 7, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants