diff --git a/content/master/guides/change-provider-registries.md b/content/master/guides/change-provider-registries.md new file mode 100644 index 000000000..a3996d5a2 --- /dev/null +++ b/content/master/guides/change-provider-registries.md @@ -0,0 +1,403 @@ +--- +title: Change Provider Registries +weight: 415 +description: "Change from one provider to a compatible provider in a different registry" +--- + +When you change a provider's OCI reference to a different registry, Crossplane +updates the provider itself with a new revision. Crossplane treats any +**dependencies it automatically installs** (like family providers) as entirely +separate packages. These require careful coordination. + +This problem affects: + +* **Providers with family dependencies**: Most cloud providers depend on a + family provider (like `provider-gcp-compute` depending on `provider-family-gcp`) +* **Providers installed as Configuration dependencies**: When a Configuration + package lists providers as dependencies + +**Single providers without dependencies change automatically** - no manual +intervention needed. + +The most common conflict occurs with **family provider dependencies**. For +example, when changing `provider-gcp-compute` from Upbound to Crossplane +Contrib, both versions depend on different family providers: + +* Old: `xpkg.upbound.io/upbound/provider-gcp-compute` → depends on `upbound/provider-family-gcp` +* New: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute` → depends on `crossplane-contrib/provider-family-gcp` + +This creates two active family providers competing for the same resources, +causing errors like: + +```console +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9 +``` + +## Prerequisites + +Before changing providers, ensure: + +* Crossplane v2.0 or later +* `kubectl` access to your cluster +* Understanding of your current provider setup +* Time for testing and validation +* Backup of critical resources + +{{}} +Test this change in a staging environment first. The process is safe but +requires careful verification at each step. +{{}} + +## Why manual coordination works best + +Crossplane names package dependencies using OCI repository paths. It uses the +pattern `-`. When you change from `upbound/provider-gcp-compute` to +`crossplane-contrib/provider-gcp-compute`, Crossplane sees these as separate +providers and creates both: + +* `upbound-provider-family-gcp` (old, still active) +* `crossplane-contrib-provider-family-gcp` (new, requires ownership coordination) + +Both family providers manage the same CRDs and MRDs, requiring careful +coordination of ownership transfer. + +Crossplane takes this approach because determining package equivalence is +complex. For example, an older Upbound provider version might differ from a +newer Crossplane Contrib version - with more CRDs, different controller +behavior, or updated APIs. Automatically replacing dependencies could break +existing resources or introduce unexpected behavior. + +Manual coordination gives you explicit control to transition ownership +from old to new providers with full visibility into each step. + +## Process overview + +The manual process follows this safe sequence: + +1. **Update provider package** - Change the provider's OCI reference +2. **Identify conflicts** - Find which family provider has conflicts +3. **Set manual activation** - Prevent the old family provider from staying active +4. **Deactivate old revision** - Stop the old family provider from managing resources +5. **Verify transition** - Ensure the new family provider manages all resources +6. **Clean up** - Remove the old family provider + +This deliberate approach gives you full control over the timing and +validation, prevents orphaning resources, and provides clear rollback +points. + +## Step-by-step process + +This example changes from Upbound's GCP Compute provider to the Crossplane +community version, which demonstrates the family provider dependency issue: + +* **From**: `xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1` +* **To**: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0` + +This change requires coordinating multiple package dependencies because each +version depends on a different family provider. + +### Step 1: Inventory current providers + +Check your current provider setup: + +```shell +kubectl get providers +``` + +```console +NAME INSTALLED HEALTHY PACKAGE AGE +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d +provider-gcp-compute True True xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1 30d +``` + +List managed resources to understand what the provider manages: + +```shell +kubectl get managed +``` + +```console +NAME READY SYNCED EXTERNAL-NAME AGE +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d +``` + +### Step 2: Update the provider package + +Edit the existing provider to change its package reference: + +```shell +kubectl patch provider provider-gcp-compute --type=merge \ + -p='{"spec":{"package":"xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0"}}' +``` + +This creates a new family provider dependency. Check what providers exist: + +```shell +kubectl get providers +``` + +```console +NAME INSTALLED HEALTHY PACKAGE AGE +crossplane-contrib-provider-family-gcp True False xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 2m +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 2m +``` + +Notice the new family provider is `HEALTHY=False` due to the ownership conflict. + +### Step 3: Set old family provider to manual activation + +Prevent the old family provider from automatically activating its revisions: + +```shell +kubectl patch provider upbound-provider-family-gcp --type=merge \ + -p='{"spec":{"revisionActivationPolicy":"Manual"}}' +``` + +Verify the change: + +```shell +kubectl get provider upbound-provider-family-gcp -o yaml | grep revisionActivationPolicy +``` + +```console + revisionActivationPolicy: Manual +``` + +### Step 4: Deactivate old family provider revision + +Find the current revision of the old family provider: + +```shell +kubectl get providerrevisions | grep upbound-provider-family-gcp +``` + +```console +NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE +upbound-provider-family-gcp-f0aa3640a6a9 True 1 xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 Active 0 0 30d +``` + +Set the old family provider revision to inactive: + +```shell +kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \ + -p='{"spec":{"desiredState":"Inactive"}}' +``` + +### Step 5: Verify the new family provider becomes healthy + +Check that the new family provider can now establish control: + +```shell +kubectl get providers +``` + +```console +NAME INSTALLED HEALTHY PACKAGE AGE +crossplane-contrib-provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 5m +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 5m +``` + +Verify the old family provider revision is inactive: + +```shell +kubectl get providerrevisions | grep upbound-provider-family-gcp +``` + +```console +NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE +upbound-provider-family-gcp-f0aa3640a6a9 True 1 xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 Inactive 0 0 30d +``` + +Check that managed resources are still healthy: + +```shell +kubectl get managed +``` + +```console +NAME READY SYNCED EXTERNAL-NAME AGE +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d +``` + +### Step 6: Delete the old family provider + +After verifying everything works, remove the old family provider: + +```shell +kubectl delete provider upbound-provider-family-gcp +``` + +### Step 7: Final verification + +Confirm only the new providers remain: + +```shell +kubectl get providers +``` + +```console +NAME INSTALLED HEALTHY PACKAGE AGE +crossplane-contrib-provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 10m +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 10m +``` + +Verify managed resources are still healthy: + +```shell +kubectl get managed +``` + +```console +NAME READY SYNCED EXTERNAL-NAME AGE +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d +``` + +## Other common scenarios + +### Providers without dependencies + +For providers that don't depend on other packages (like `provider-helm`, +`provider-kubernetes`, or standalone providers), the change happens automatically: + +1. Update the provider's `spec.package` +2. Crossplane creates a new revision with the new package +3. The old revision automatically becomes inactive +4. No conflicts occur because there are no dependencies + +Examples of providers that typically change automatically: + +* `provider-helm` +* `provider-kubernetes` +* `provider-sql` + +{{}} + +You can check which providers have dependencies by inspecting the package lock: + + +```shell +kubectl get lock lock -o yaml +``` + +Look for providers with non-empty `dependencies` arrays. For example: +```yaml +- name: provider-gcp-compute-a41e4ba551fc + dependencies: + - constraints: '>= 0.0.0' + package: xpkg.crossplane.io/crossplane-contrib/provider-family-gcp + type: Provider +``` + +Providers with empty `dependencies: []` change automatically. +{{}} + +### Configuration package dependencies + +When changing providers that are dependencies of Configuration packages, the +same conflicts can occur. The Configuration creates provider dependencies based +on OCI references, so changing registries creates duplicate providers. + +To change providers in this scenario: +1. Update the Configuration's package OCI reference +2. Follow the same manual coordination steps for any conflicted providers +3. Verify all providers the Configuration depends on are healthy + +### Rollback procedure + +If you need to rollback during the process: + +1. **Before deleting the old provider (step 6)**: Reactivate the old family + provider revision: + ```shell + kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \ + -p='{"spec":{"desiredState":"Active"}}' + ``` + + Then deactivate the new family provider revision and delete the new provider. + +2. **After deleting the old provider**: You must recreate the old provider + because Crossplane automatically deletes all revisions when you delete a + provider. Create this manifest: + + ```yaml + apiVersion: pkg.crossplane.io/v1 + kind: Provider + metadata: + name: upbound-provider-family-gcp + spec: + package: xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 + ``` + + Save as `rollback-provider.yaml` and apply: + ```shell + kubectl apply -f rollback-provider.yaml + ``` + + Then follow the process in reverse to switch back. + +## Troubleshooting + +### New family provider stays unhealthy + +If the new family provider remains `HEALTHY=False` after deactivating the old one: + +1. Check the provider revision status: + ```shell + kubectl get providerrevisions | grep crossplane-contrib-provider-family + ``` + +2. Look for ownership conflict errors in the provider logs: + ```shell + kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=crossplane-contrib-provider-family-gcp + ``` + +3. Verify the old revision is truly inactive: + ```shell + kubectl describe providerrevision upbound-provider-family-gcp-f0aa3640a6a9 + ``` + +### Ownership conflicts persist + +If you see persistent ownership conflicts: + +```console +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9 +``` + + +This means the old revision is still active. Double-check: + + +1. The old provider has `revisionActivationPolicy: Manual` +2. The old revision has `desiredState: Inactive` +3. Wait a moment for the change to propagate + +### Provider doesn't deactivate + +If the old provider revision doesn't become inactive: + + +1. Check for active managed resources preventing deactivation + +2. Verify the patch command succeeded +3. Check provider logs for errors: + + ```shell + kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=upbound-provider-family-gcp + ``` + +## Next steps + +After successfully changing providers: + +* Update any documentation referencing the old provider +* Consider changing to v2 namespaced resources if using Crossplane v2 +* Review other providers for potential registry changes +* Share your experience with the Crossplane community + +For more information: +* [Provider documentation]({{}}) +* [Troubleshooting guide]({{}}) +* [Crossplane community](https://crossplane.io/community/) diff --git a/content/master/guides/upgrade-to-crossplane-v2.md b/content/master/guides/upgrade-to-crossplane-v2.md index 1610a2e99..ced6dc179 100644 --- a/content/master/guides/upgrade-to-crossplane-v2.md +++ b/content/master/guides/upgrade-to-crossplane-v2.md @@ -217,6 +217,14 @@ Provider v2 releases support both legacy cluster-scoped and new namespaced managed resources. Your existing cluster-scoped MRs continue working unchanged. {{}} +{{}} +If you're switching from Upbound family providers (like +`xpkg.upbound.io/upbound/provider-gcp-compute`) to Crossplane Contrib family +providers (like `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute`), +see the [changing provider registries guide]({{}}) for +step-by-step instructions to handle family provider dependencies. +{{}} + ### 5. Start using v2 features After upgrading, you can begin using Crossplane v2 features: