Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.

fix(dynamic): invalidate discovery cache on CustomResourceDefinition events - #2

Merged
braghettos merged 2 commits into
mainfrom
fix/crd-watch-discovery-invalidation
Jun 18, 2026
Merged

fix(dynamic): invalidate discovery cache on CustomResourceDefinition events#2
braghettos merged 2 commits into
mainfrom
fix/crd-watch-discovery-invalidation

Conversation

@braghettos

Copy link
Copy Markdown
Collaborator

The composition-dynamic-controller renders compositions using a DeferredDiscoveryRESTMapper backed by a MemCache discovery client (internal/tools/dynamic/dynamic.go). It is built once at startup and never refreshed, and there is no CRD watch to invalidate it.

So any CRD — or a new version of an existing CRD — registered after the cache warms is invisible to RESTMapping/IsNamespaced, and (for the Krateo installer umbrella) to the inst.crdExists Pass-B gate: those Compositions silently never emit, even though the CompositionDefinitions are Ready and a server-side dry-run of the same chart renders them fine. The only workaround today is a manual controller restart on every umbrella version bump / component-CRD roll.

Change

Add WatchCRDsAndInvalidate (crdwatch.go): a dynamic informer on CustomResourceDefinition that calls mapper.Reset() on add/update/delete.

  • Reset() (client-go v0.35.3) invalidates the MemCache and drops the delegate, so the next lookup re-discovers from the live cluster.
  • Debounced/coalesced (2s quiet window) so the informer’s initial list and bursty Pass-A renders (many CRDs at once) collapse into a single invalidation.
  • Skips resync no-ops (same resourceVersion).
  • Wired into main right after the mapper is built; non-fatal — if the watch can’t start, the controller still runs and IsNamespaced keeps its reactive reset.

Complements krateoplatformops#183 (reactive Reset() on an IsNamespaced miss) with a proactive refresh that also covers the render-time crdExists lookup, removing the manual-restart nudge.

Tests

go build ./..., go vet, and go test ./internal/tools/dynamic/ pass; added TestWatchCRDsAndInvalidate_NoResetIsNoop for the static-mapper no-op branch.

RBAC

The cdc ServiceAccount needs get;list;watch on customresourcedefinitions.apiextensions.k8s.io (already required for the crdExists lookup).

🤖 Generated with Claude Code

braghettos and others added 2 commits June 18, 2026 01:07
…events

The RESTMapper is a DeferredDiscoveryRESTMapper backed by a MemCache
discovery client, built once at startup and never refreshed. CRDs (or new
CRD versions) registered after the cache warms are therefore invisible to
RESTMapping/IsNamespaced — and, for the installer umbrella, to the
`inst.crdExists` Pass-B gate — until the controller is restarted. This is
the stale-CRD-discovery-cache class that forces a manual cdc restart on
every umbrella version bump / component CRD roll.

Add WatchCRDsAndInvalidate: a dynamic informer on CustomResourceDefinition
that calls mapper.Reset() on add/update/delete (debounced/coalesced, and
skipping resync no-ops). Reset() invalidates the MemCache and drops the
delegate, so the next lookup re-discovers from the live cluster — no
restart needed. Wired into main after the mapper is built; non-fatal so
the controller still runs (IsNamespaced keeps its reactive reset).

Complements krateoplatformops#183 (reactive Reset on IsNamespaced miss) with a proactive
refresh that also covers the render-time crdExists lookup.

Note: the cdc ServiceAccount needs get;list;watch on
customresourcedefinitions.apiextensions.k8s.io (already required for the
crdExists lookup).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndow

Self-review follow-ups:
- WaitForCacheSync + log so a missing/denied CRD watch (RBAC) is visible
  instead of silently degrading to the reactive-only reset.
- Add a startup Info log confirming the watch is active.
- Rename crdInvalidateDebounce -> crdInvalidateWindow and correct the
  comment: it is a fixed coalescing window from the first event (a
  throttle that bounds staleness), not an extending debounce.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant