Skip to content

fix(crossplane-providers): install provider-helm as the dependsOn-derived CR (one CR, not two) - #154

Merged
patrick-hermann-sva merged 1 commit into
mainfrom
fix/provider-helm-single-cr
Jul 23, 2026
Merged

fix(crossplane-providers): install provider-helm as the dependsOn-derived CR (one CR, not two)#154
patrick-hermann-sva merged 1 commit into
mainfrom
fix/provider-helm-single-cr

Conversation

@patrick-hermann-sva

Copy link
Copy Markdown
Contributor

Fixes stuttgart-things/crossplane-configurations#147.

Problem

provider-helm was installed here as CR provider-helm from xpkg.upbound.io. Four Configurations (bootstrap/{platform,flux-init,cni,vault-config}) dependsOn provider-helm from xpkg.crossplane.io, from which the package manager derives a second Provider CR crossplane-contrib-provider-helm. Two Provider CRs for the same package (same digest) fight over the releases.helm.m.crossplane.io CRD:

crossplane-contrib-provider-helm  HEALTHY=False
  UnhealthyPackageRevision: cannot establish control of object:
  releases.helm.m.crossplane.io is already controlled by provider-helm-<digest>

That fails the machinery bootstrap's kubectl wait provider --all --for=condition=Healthy gate. Verified on a fresh LabUL machinery cluster. provider-kubernetes does not hit this — it is (deliberately) not installed here and comes solely via dependsOn, so there is only one CR.

Unlike the function-kcl cross-mirror pair (functions own no CRDs → benign, per crossplane-configurations CLAUDE.md), providers own CRDs, so there must be exactly one provider-helm CR.

Fix

Name this install crossplane-contrib-provider-helm and source it from xpkg.crossplane.io — exactly what the dependsOn derives. The provider helmfile runs before the Configurations, so this CR exists first; the dependsOn then finds it (carrying the runtimeConfigRef + cluster-admin DeploymentRuntimeConfig needed for InjectedIdentity) instead of adding its own. One CR, healthy.

Blast radius

  • ClusterProviderConfigs are named in-cluster, independent of the provider CR name — nothing referencing the provider by config name changes.
  • The DeploymentRuntimeConfig, ServiceAccount and ClusterRoleBinding all derive from $p.name, so they rename with it, consistently.
  • kind1 is not affected until an explicit re-apply: no ArgoCD auto-sync, and its crossplane-providers release is a one-shot from bootstrap (revision 1, 2026-07-10). A future re-apply moves it to the fixed single-CR state.

…ived CR

provider-helm was installed here as `provider-helm` from xpkg.upbound.io.
Four Configurations (crossplane-configurations bootstrap/{platform,
flux-init,cni,vault-config}) dependsOn provider-helm from
xpkg.crossplane.io, from which the package manager derives a second
Provider CR `crossplane-contrib-provider-helm`. Two Provider CRs for the
same package fight over the releases.helm.m.crossplane.io CRD — the loser
is stuck UnhealthyPackageRevision, which fails the machinery bootstrap's
`kubectl wait provider --all --for=condition=Healthy` gate.

Verified on a fresh LabUL machinery cluster. Unlike the function-kcl
cross-mirror pair (functions own no CRDs, benign), providers own CRDs, so
there must be exactly ONE provider-helm CR.

Fix: name this install `crossplane-contrib-provider-helm` and source it
from xpkg.crossplane.io — exactly what the dependsOn derives. The provider
helmfile runs before the Configurations, so this CR exists first; the
dependsOn then finds it (carrying the runtimeConfigRef + cluster-admin
DeploymentRuntimeConfig for InjectedIdentity) instead of adding its own.
One CR, healthy.

ClusterProviderConfigs are named `in-cluster`, independent of the provider
CR name, so nothing referencing the provider by config name changes.
kind1 is unaffected until an explicit re-apply (no ArgoCD auto-sync; the
release is a one-shot from bootstrap).

Refs stuttgart-things/crossplane-configurations#147
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants