Skip to content

feat: migrate to Crossplane v2 with namespaced composite resources#10

Merged
kaessert merged 1 commit intomainfrom
migrate-to-v2
Apr 14, 2026
Merged

feat: migrate to Crossplane v2 with namespaced composite resources#10
kaessert merged 1 commit intomainfrom
migrate-to-v2

Conversation

@kaessert
Copy link
Copy Markdown
Contributor

Summary

Migrates configuration-getting-started to the Crossplane v2 programming model with namespaced composite resources. Claims are gone in v2, so the tutorial now shows how to apply XRs directly to a namespace (default default).

Context: found while debugging a UXP v2 incompatibility with Mark Anderson-Trocme. The immediate UXP bug (suffix-stripping regression in v2.2.0-up.1..up.4) is already fixed in v2.2.0-up.5 via upbound/crossplane#213, but the repo itself still targeted the v1 model and was overdue for a v2 port.

Changes

XRDs (8 files)

  • apiextensions.crossplane.io/v1v2
  • Added spec.scope: Namespaced
  • Removed claimNames (claims aren't supported in v2)
  • Dropped the X prefix from metadata.name, spec.names.kind, spec.names.plural
v1 v2
xclusters.platform.acme.co / XCluster clusters.platform.acme.co / Cluster
xdatabases / XDatabase databases / Database
xnetworks / XNetwork networks / Network
xnodepools / XNodePool nodepools / NodePool
xserviceaccounts / XServiceAccount serviceaccounts / ServiceAccount
xsubnetworks / XSubnetwork subnetworks / Subnetwork
xaccountscaffolds / XAccountScaffold accountscaffolds / AccountScaffold
xcompositeclusters / XCompositeCluster compositeclusters / CompositeCluster

Compositions (8 files)

  • metadata.name + compositeTypeRef.kind updated to drop X-prefix
  • KCL source: every composed resource (nested XRs in AccountScaffold/CompositeCluster, and every NopResource) now sets metadata.namespace = oxr.metadata.namespace. Without this, Crossplane rejects the composition with cannot apply cluster scoped composed resource ... for a namespaced composite resource.
  • Composition kind stays at apiextensions.crossplane.io/v1 — Crossplane v2 introduced a v2 XRD API but compositions remain v1.

Examples (8 folders)

  • Directories renamed to drop the X prefix
  • claim.yaml and claim.k deleted (claims don't exist in v2)
  • Each xr.yaml updated: new kind, metadata.namespace: default, updated render.crossplane.io/composition-path annotation
  • test-harness.sh removed (it was entirely claim-based; kubectl apply -f examples/<resource>/xr.yaml is the v2 equivalent)

crossplane.yaml

  • crossplane.version: ">=v1.15.2"">=v2.0.0-0". The -0 is defensive: it makes the constraint semver-match pre-release tags like UXP's v2.2.0-up.N, which otherwise fail a plain >= range.
  • provider-nop: v0.2.1v0.5.0 — v0.5.0 introduced the namespaced NopResource alongside a cluster-scoped ClusterNopResource. Required for namespaced XRs.
  • function-kcl: v0.8.0v0.12.1 — built against crossplane-runtime/v2, correctly emits namespaced composed resources.
  • function-auto-ready: v0.2.1v0.6.3

Plan file

  • .agents/plans/CROSSPLANE_V2_MIGRATION.md documents the phase-by-phase migration (generated off the plan-v2-migration skill template, adapted for the classic crossplane.yaml package format).

Verification

End-to-end on upstream Crossplane v2.2.0 on kind:

  1. Built package with crossplane xpkg build, pushed to ttl.sh, installed via Configuration.
  2. All 8 XRDs: ESTABLISHED=True, OFFERED empty (correct — no claims).
  3. Applied Network + Subnetwork + Cluster XRs in default → all SYNCED=True, READY=True, each composed a namespaced NopResource in default.
  4. Applied CompositeCluster XR → composed 5 nested namespaced XRs (Network, Subnetwork, Cluster, NodePool, ServiceAccount), each composed a namespaced NopResource. Final state:
    NAME                       READY   SYNCED
    custom-cluster1-cluster    True    True
    custom-cluster1-net        True    True
    custom-cluster1-nodepool   True    True
    custom-cluster1-sa         True    True
    custom-cluster1-subnet     True    True
    

Breaking changes

This is a breaking change for any user on v0.3.0:

  • Existing claims no longer work — claims don't exist in v2
  • XR kinds changed (XClusterCluster, etc.)
  • Minimum Crossplane version is now 2.0

Suggest cutting this as v1.0.0 to signal the break.

Draft because

  • README.md is unchanged — it still describes the v1/claim-based flow. Happy to update in this PR or follow up.
  • No release has been cut from main since v0.2.0 (v0.3.0 on the registry predates the switch to function-kcl). Worth deciding whether to cut a fresh v0.4.0 of the v1 artifact from main first, or jump straight to v1.0.0 from this branch.
  • e2e workflow in .github/workflows/e2e.yaml may reference removed files/scripts — haven't audited it.

Test plan

  • Review the plan in .agents/plans/CROSSPLANE_V2_MIGRATION.md
  • CI builds
  • Update README.md for v2 usage
  • Verify .github/workflows/e2e.yaml still works (or update it)
  • Decide on release version (v1.0.0 vs v0.4.0)

Migrates the tutorial to the Crossplane v2 programming model with
namespaced XRs. Claims no longer exist in v2, so claim examples/harness
are dropped; XRs are now applied directly to a namespace (default).

Changes:
- All 8 XRDs: apiextensions.crossplane.io/v1 -> v2, scope: Namespaced,
  claimNames removed, X-prefix dropped from kind/plural/name
- Compositions: update metadata.name + compositeTypeRef.kind; set
  metadata.namespace = oxr.metadata.namespace on every composed resource
  (required: namespaced XRs can only compose namespaced resources)
- Examples: rename X-prefixed directories, drop claim.yaml/claim.k,
  each xr.yaml sets kind to the new name and metadata.namespace: default
- Dependencies bumped for v2 compatibility:
  - provider-nop v0.2.1 -> v0.5.0 (adds namespaced NopResource kind)
  - function-kcl v0.8.0 -> v0.12.1 (built against crossplane-runtime/v2)
  - function-auto-ready v0.2.1 -> v0.6.3
- crossplane version constraint: >=v1.15.2 -> >=v2.0.0-0 (the -0
  suffix matches pre-release tags like UXP v2.2.0-up.N)
- Makefile: fix uptest paths for renamed dirs, update CROSSPLANE_NAMESPACE
  to crossplane-system, promote crossplane beta render -> crossplane render
- README.md: rewrite for v2 (namespaced XRs, up CLI preferred, no claims)
- Remove test-harness.sh (claim-based) and migration plan file

Verified end-to-end on fresh kind cluster with upstream Crossplane v2.2.0:
all 8 XRDs established, all 8 example XRs SYNCED + READY, 14 namespaced
NopResources in default, CompositeCluster composes 5 nested XRs, clean
deletion confirmed.
@kaessert kaessert marked this pull request as ready for review April 14, 2026 08:26
Copy link
Copy Markdown
Member

@haarchri haarchri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for unblock v2, can we get this converted to a Project in a followup ? And use our normal CI Workflow and RepoSetup too ?

@kaessert kaessert merged commit 8b5e876 into main Apr 14, 2026
1 check passed
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.

2 participants