declarative-conversion-operator¶
Alpha, under active development
APIs (the CRDs, the Helm chart's values, and CLI flags) may still change without notice, and this hasn't yet been run in production. Expect rough edges; issues and feedback are welcome on GitHub.
Declarative conversion webhooks for Crossplane XRDs and plain native Kubernetes CRDs — configure hub/spoke version conversions without hand-writing a webhook.
The problem¶
Both Crossplane CompositeResourceDefinitions (XRDs) and native Kubernetes CustomResourceDefinitions support multiple served API versions. That's great for evolving an API over time — but Kubernetes only lets one of those versions be the storage (hub) version, and every other version needs a conversion webhook to translate objects to and from it on every read and write.
Today, writing that webhook means:
- Standing up a Go binary that implements the
ConversionReviewprotocol correctly. - Deploying it with its own TLS certificate,
Service, and wiring it intospec.conversionon the target resource by hand. - Re-implementing basically the same field-mapping logic (rename this, wrap that in an object, join these three fields into one) for every API you version — and getting it wrong is a silent, production-facing data-loss bug, not a compile error.
Most version migrations are not exotic: they're field renames, reshaping a scalar into an object, splitting one field into several, or moving a value into an annotation. declarative-conversion-operator lets you describe exactly that, declaratively, and handles the webhook plumbing for you — for a Crossplane XRD via XRDConversionConfig, or for a plain native CRD via CRDConversionConfig, sharing the exact same rule vocabulary and engine.
What this operator does¶
You create one XRDConversionConfig per Crossplane XRD you want to version-convert, or one CRDConversionConfig per plain native CRD — both share the identical spec shape and rule vocabulary. Each names:
- the resource's hub version (the one Kubernetes/Crossplane already stores objects as),
- for each other served (spoke) version, a list of conversion rules — one of the built-in strategies like
fieldRename,scalarToObject,enumRemap, orjsonPatchas an escape hatch (see the Strategy Reference for the full set).
The operator then:
- Validates the whole mapping against the target resource's real schemas — every hub and spoke field must be explicitly claimed by a rule or be structurally identical on both sides. Nothing is silently dropped.
- Analyzes losslessness per rule, per direction. Anything the engine can't prove round-trips cleanly must be explicitly acknowledged with
acknowledgeLossy: true, or the config is rejected. - Compiles the rules into a resolved-path execution plan — no schema walking or YAML parsing on the request hot path.
- Only once the config is valid and a healthy
ConversionWebhookServeris available, patchesspec.conversionon the target resource via server-side apply, scoped to just that field.
From then on, a shared, horizontally-scalable ConversionWebhookServer actually serves the ConversionReview requests the apiserver sends, converting objects in-memory using the exact same engine the controller validated with.
flowchart LR
A["XRDConversionConfig or\nCRDConversionConfig\n(kubectl apply)"] -->|validated by| B["operator\ncmd/manager"]
B -->|"SSA patch\nspec.conversion"| C["target XRD or CRD"]
B -->|resolves assignment| D["ConversionWebhookServer"]
D -->|owns| E["webhook-server pods\nin-memory plan registry"]
C -->|ConversionReview| E
See Architecture for the full picture.
Why declarative-conversion-operator¶
- Declarative, not hand-written. No Go code, no bespoke webhook deployment per resource — describe the mapping, the operator does the rest.
- Works for Crossplane XRDs and plain native CRDs alike, independently toggleable — disable XRD support entirely on clusters without Crossplane installed.
- Conservative by default. Any conversion the engine can't prove is lossless is rejected unless you explicitly acknowledge it. Unknown fields are treated as lossy, never silently passed through.
- Safe by construction. The target resource is never patched until the config is validated, it's healthy, and the assigned webhook server is confirmed ready. Deleting a config that would leave clients stranded on a non-storage version is blocked, not silently reverted.
- Fast where it matters. Every rule is precompiled into a resolved-path plan once; the webhook server's hot path is pure in-memory execution against a lock-free, copy-on-write registry — no network calls, no re-parsing, on the API admission critical path.
- Testable before it touches a cluster. The
convctlCLI runs the exact same conversion engine against local YAML fixtures — or against every real object already in your cluster via--live— so you can validate a config before you ever apply it.
Main use cases¶
-
Evolving an XRD's API without breaking clients
Rename fields, reshape a scalar into a richer object, or introduce a new required field with a sane default — all while existing clients on an older served version keep working unmodified.
-
Pre-upgrade safety checks
Before rolling out a changed
XRDConversionConfig, runconvctl test --liveagainst every composite resource that already exists in the cluster — not just hand-written fixtures — and catch a conversion that would break a real object before it ships. -
Consolidating legacy fields during a v1 → v2 migration
Use
fieldsToMap/mapToFields,arrayToMapByKey/mapToArrayByKey, orscalarToFields/fieldsToScalarto clean up an API's shape at the hub version while keeping the messier legacy shape alive on an older spoke version for backward compatibility. -
Scaling the conversion path independently of the operator
Create additional
ConversionWebhookServerinstances for tenant isolation or extra throughput — every replica is symmetric, runs its own informers, and serves from an in-memory registry with no shared state.
Where to go next¶
- New to the operator? Start with Getting Started.
- Ready to install? See Installation.
- Want a complete, runnable config to copy? See Examples.
- Configuring a real XRD? See XRDConversionConfig.
- Looking for a specific strategy? See the Strategy Reference.
- Already running and something's off? See Troubleshooting.
- Wondering what this doesn't do (yet)? See Limitations and the Roadmap.