| 
 | 1 | +---  | 
 | 2 | +title: Change Provider Registries  | 
 | 3 | +weight: 415  | 
 | 4 | +description: "Safely change from one provider to a compatible provider in a different registry"  | 
 | 5 | +---  | 
 | 6 | + | 
 | 7 | +When changing a provider's OCI reference to a different registry, the provider   | 
 | 8 | +itself updates normally with a new revision. However, any **dependencies that   | 
 | 9 | +Crossplane automatically installs** (like family providers) are treated as   | 
 | 10 | +entirely separate packages, requiring careful coordination.  | 
 | 11 | + | 
 | 12 | +This problem affects:  | 
 | 13 | + | 
 | 14 | +* **Providers with family dependencies**: Most cloud providers depend on a   | 
 | 15 | +  family provider (like `provider-gcp-compute` depending on `provider-family-gcp`)  | 
 | 16 | +* **Providers installed as Configuration dependencies**: When a Configuration   | 
 | 17 | +  package lists providers as dependencies  | 
 | 18 | + | 
 | 19 | +**Single providers without dependencies change automatically** - no manual   | 
 | 20 | +intervention needed.  | 
 | 21 | + | 
 | 22 | +The most common conflict occurs with **family provider dependencies**. For   | 
 | 23 | +example, when changing `provider-gcp-compute` from Upbound to Crossplane   | 
 | 24 | +Contrib, both versions depend on different family providers:  | 
 | 25 | + | 
 | 26 | +* Old: `xpkg.upbound.io/upbound/provider-gcp-compute` → depends on `upbound/provider-family-gcp`  | 
 | 27 | +* New: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute` → depends on `crossplane-contrib/provider-family-gcp`  | 
 | 28 | + | 
 | 29 | +This creates two active family providers competing for the same resources,   | 
 | 30 | +causing errors like:  | 
 | 31 | + | 
 | 32 | +```console  | 
 | 33 | +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9  | 
 | 34 | +```  | 
 | 35 | + | 
 | 36 | +## Prerequisites  | 
 | 37 | + | 
 | 38 | +Before changing providers, ensure:  | 
 | 39 | + | 
 | 40 | +* Crossplane v2.0 or later  | 
 | 41 | +* `kubectl` access to your cluster  | 
 | 42 | +* Understanding of your current provider setup  | 
 | 43 | +* Time for testing and validation  | 
 | 44 | +* Backup of critical resources  | 
 | 45 | + | 
 | 46 | +{{<hint "tip">}}  | 
 | 47 | +Test this change in a staging environment first. The process is safe but   | 
 | 48 | +requires careful verification at each step.  | 
 | 49 | +{{</hint>}}  | 
 | 50 | + | 
 | 51 | +## Why manual coordination is recommended  | 
 | 52 | + | 
 | 53 | +Crossplane names package dependencies using OCI repository paths. It uses the  | 
 | 54 | +pattern `<org>-<repo>`. When you change from `upbound/provider-gcp-compute` to  | 
 | 55 | +`crossplane-contrib/provider-gcp-compute`, Crossplane sees these as completely  | 
 | 56 | +different providers and creates both:  | 
 | 57 | + | 
 | 58 | +* `upbound-provider-family-gcp` (old, still active)  | 
 | 59 | +* `crossplane-contrib-provider-family-gcp` (new, requires ownership coordination)  | 
 | 60 | + | 
 | 61 | +Both family providers manage the same CRDs and MRDs, requiring careful   | 
 | 62 | +coordination of ownership transfer.   | 
 | 63 | + | 
 | 64 | +Crossplane takes this conservative approach because determining package   | 
 | 65 | +equivalence is complex. For example, an older Upbound provider version might   | 
 | 66 | +differ significantly from a newer Crossplane Contrib version - with additional   | 
 | 67 | +CRDs, different controller behavior, or updated APIs. Automatically replacing   | 
 | 68 | +dependencies could break existing resources or introduce unexpected behavior.  | 
 | 69 | + | 
 | 70 | +Manual coordination gives you explicit control to safely transition ownership   | 
 | 71 | +from old to new providers with full visibility into each step.  | 
 | 72 | + | 
 | 73 | +## Process overview  | 
 | 74 | + | 
 | 75 | +The manual process follows this safe sequence:  | 
 | 76 | + | 
 | 77 | +1. **Update provider package** - Change the provider's OCI reference  | 
 | 78 | +2. **Identify conflicts** - Find which family provider is conflicted  | 
 | 79 | +3. **Set manual activation** - Prevent the old family provider from staying active  | 
 | 80 | +4. **Deactivate old revision** - Stop the old family provider from managing resources  | 
 | 81 | +5. **Verify transition** - Ensure the new family provider manages all resources  | 
 | 82 | +6. **Clean up** - Remove the old family provider  | 
 | 83 | + | 
 | 84 | +This deliberate approach gives you full control over the timing and   | 
 | 85 | +validation, ensures no resources are orphaned, and provides clear rollback   | 
 | 86 | +points.  | 
 | 87 | + | 
 | 88 | +## Step-by-step process  | 
 | 89 | + | 
 | 90 | +This example changes from Upbound's GCP Compute provider to the Crossplane   | 
 | 91 | +community version, which demonstrates the family provider dependency issue:  | 
 | 92 | + | 
 | 93 | +* **From**: `xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1`  | 
 | 94 | +* **To**: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0`  | 
 | 95 | + | 
 | 96 | +This change requires coordinating multiple package dependencies because each   | 
 | 97 | +version depends on a different family provider.  | 
 | 98 | + | 
 | 99 | +### Step 1: Inventory current providers  | 
 | 100 | + | 
 | 101 | +Check your current provider setup:  | 
 | 102 | + | 
 | 103 | +```shell  | 
 | 104 | +kubectl get providers  | 
 | 105 | +```  | 
 | 106 | + | 
 | 107 | +```console  | 
 | 108 | +NAME                        INSTALLED   HEALTHY   PACKAGE                                                   AGE  | 
 | 109 | +upbound-provider-family-gcp True        True      xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1     30d  | 
 | 110 | +provider-gcp-compute        True        True      xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1    30d  | 
 | 111 | +```  | 
 | 112 | + | 
 | 113 | +List managed resources to understand what the provider manages:  | 
 | 114 | + | 
 | 115 | +```shell  | 
 | 116 | +kubectl get managed  | 
 | 117 | +```  | 
 | 118 | + | 
 | 119 | +```console  | 
 | 120 | +NAME                                           READY   SYNCED   EXTERNAL-NAME           AGE  | 
 | 121 | +address.compute.gcp.upbound.io/my-address     True    True     my-address-abc123       5d  | 
 | 122 | +```  | 
 | 123 | + | 
 | 124 | +### Step 2: Update the provider package  | 
 | 125 | + | 
 | 126 | +Edit the existing provider to change its package reference:  | 
 | 127 | + | 
 | 128 | +```shell  | 
 | 129 | +kubectl patch provider provider-gcp-compute --type=merge \  | 
 | 130 | +  -p='{"spec":{"package":"xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0"}}'  | 
 | 131 | +```  | 
 | 132 | + | 
 | 133 | +This creates a new family provider dependency. Check what providers exist:  | 
 | 134 | + | 
 | 135 | +```shell  | 
 | 136 | +kubectl get providers  | 
 | 137 | +```  | 
 | 138 | + | 
 | 139 | +```console  | 
 | 140 | +NAME                                     INSTALLED   HEALTHY   PACKAGE                                                             AGE  | 
 | 141 | +crossplane-contrib-provider-family-gcp   True        False     xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0    2m  | 
 | 142 | +upbound-provider-family-gcp              True        True      xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1                30d  | 
 | 143 | +provider-gcp-compute                     True        True      xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0   2m  | 
 | 144 | +```  | 
 | 145 | + | 
 | 146 | +Notice the new family provider is `HEALTHY=False` due to the ownership conflict.  | 
 | 147 | + | 
 | 148 | +### Step 3: Set old family provider to manual activation  | 
 | 149 | + | 
 | 150 | +Prevent the old family provider from automatically activating its revisions:  | 
 | 151 | + | 
 | 152 | +```shell  | 
 | 153 | +kubectl patch provider upbound-provider-family-gcp --type=merge \  | 
 | 154 | +  -p='{"spec":{"revisionActivationPolicy":"Manual"}}'  | 
 | 155 | +```  | 
 | 156 | + | 
 | 157 | +Verify the change:  | 
 | 158 | + | 
 | 159 | +```shell  | 
 | 160 | +kubectl get provider upbound-provider-family-gcp -o yaml | grep revisionActivationPolicy  | 
 | 161 | +```  | 
 | 162 | + | 
 | 163 | +```console  | 
 | 164 | +  revisionActivationPolicy: Manual  | 
 | 165 | +```  | 
 | 166 | + | 
 | 167 | +### Step 4: Deactivate old family provider revision  | 
 | 168 | + | 
 | 169 | +Find the current revision of the old family provider:  | 
 | 170 | + | 
 | 171 | +```shell  | 
 | 172 | +kubectl get providerrevisions | grep upbound-provider-family-gcp  | 
 | 173 | +```  | 
 | 174 | + | 
 | 175 | +```console  | 
 | 176 | +NAME                                    HEALTHY   REVISION   IMAGE                                                     STATE    DEP-FOUND   DEP-INSTALLED   AGE  | 
 | 177 | +upbound-provider-family-gcp-f0aa3640a6a9 True      1          xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1     Active   0           0               30d  | 
 | 178 | +```  | 
 | 179 | + | 
 | 180 | +Set the old family provider revision to inactive:  | 
 | 181 | + | 
 | 182 | +```shell  | 
 | 183 | +kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \  | 
 | 184 | +  -p='{"spec":{"desiredState":"Inactive"}}'  | 
 | 185 | +```  | 
 | 186 | + | 
 | 187 | +### Step 5: Verify the new family provider becomes healthy  | 
 | 188 | + | 
 | 189 | +Check that the new family provider can now establish control:  | 
 | 190 | + | 
 | 191 | +```shell  | 
 | 192 | +kubectl get providers  | 
 | 193 | +```  | 
 | 194 | + | 
 | 195 | +```console  | 
 | 196 | +NAME                                     INSTALLED   HEALTHY   PACKAGE                                                             AGE  | 
 | 197 | +crossplane-contrib-provider-family-gcp   True        True      xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0    5m  | 
 | 198 | +upbound-provider-family-gcp              True        True      xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1                30d  | 
 | 199 | +provider-gcp-compute                     True        True      xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0   5m  | 
 | 200 | +```  | 
 | 201 | + | 
 | 202 | +Verify the old family provider revision is inactive:  | 
 | 203 | + | 
 | 204 | +```shell  | 
 | 205 | +kubectl get providerrevisions | grep upbound-provider-family-gcp  | 
 | 206 | +```  | 
 | 207 | + | 
 | 208 | +```console  | 
 | 209 | +NAME                                    HEALTHY   REVISION   IMAGE                                                     STATE      DEP-FOUND   DEP-INSTALLED   AGE  | 
 | 210 | +upbound-provider-family-gcp-f0aa3640a6a9 True      1          xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1     Inactive   0           0               30d  | 
 | 211 | +```  | 
 | 212 | + | 
 | 213 | +Check that managed resources are still healthy:  | 
 | 214 | + | 
 | 215 | +```shell  | 
 | 216 | +kubectl get managed  | 
 | 217 | +```  | 
 | 218 | + | 
 | 219 | +```console  | 
 | 220 | +NAME                                           READY   SYNCED   EXTERNAL-NAME           AGE  | 
 | 221 | +address.compute.gcp.upbound.io/my-address     True    True     my-address-abc123       5d  | 
 | 222 | +```  | 
 | 223 | + | 
 | 224 | +### Step 6: Delete the old family provider  | 
 | 225 | + | 
 | 226 | +After verifying everything works correctly, remove the old family provider:  | 
 | 227 | + | 
 | 228 | +```shell  | 
 | 229 | +kubectl delete provider upbound-provider-family-gcp  | 
 | 230 | +```  | 
 | 231 | + | 
 | 232 | +### Step 7: Final verification  | 
 | 233 | + | 
 | 234 | +Confirm only the new providers remain:  | 
 | 235 | + | 
 | 236 | +```shell  | 
 | 237 | +kubectl get providers  | 
 | 238 | +```  | 
 | 239 | + | 
 | 240 | +```console  | 
 | 241 | +NAME                                     INSTALLED   HEALTHY   PACKAGE                                                             AGE  | 
 | 242 | +crossplane-contrib-provider-family-gcp   True        True      xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0    10m  | 
 | 243 | +provider-gcp-compute                     True        True      xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0   10m  | 
 | 244 | +```  | 
 | 245 | + | 
 | 246 | +Verify managed resources are still healthy:  | 
 | 247 | + | 
 | 248 | +```shell  | 
 | 249 | +kubectl get managed  | 
 | 250 | +```  | 
 | 251 | + | 
 | 252 | +```console  | 
 | 253 | +NAME                                           READY   SYNCED   EXTERNAL-NAME           AGE  | 
 | 254 | +address.compute.gcp.upbound.io/my-address     True    True     my-address-abc123       5d  | 
 | 255 | +```  | 
 | 256 | + | 
 | 257 | +## Other common scenarios  | 
 | 258 | + | 
 | 259 | +### Providers without dependencies  | 
 | 260 | + | 
 | 261 | +For providers that don't depend on other packages (like `provider-helm`,   | 
 | 262 | +`provider-kubernetes`, or standalone providers), the change happens automatically:  | 
 | 263 | + | 
 | 264 | +1. Update the provider's `spec.package`  | 
 | 265 | +2. Crossplane creates a new revision with the new package  | 
 | 266 | +3. The old revision automatically becomes inactive  | 
 | 267 | +4. No conflicts occur because there are no dependencies  | 
 | 268 | + | 
 | 269 | +Examples of providers that typically change automatically:  | 
 | 270 | +* `provider-helm`  | 
 | 271 | +* `provider-kubernetes`   | 
 | 272 | +* `provider-sql`  | 
 | 273 | +* Single-resource providers without family dependencies  | 
 | 274 | + | 
 | 275 | +{{<hint "tip">}}  | 
 | 276 | +You can check which providers have dependencies by inspecting the package lock:  | 
 | 277 | + | 
 | 278 | +```shell  | 
 | 279 | +kubectl get lock lock -o yaml  | 
 | 280 | +```  | 
 | 281 | + | 
 | 282 | +Look for providers with non-empty `dependencies` arrays. For example:  | 
 | 283 | +```yaml  | 
 | 284 | +- name: provider-gcp-compute-a41e4ba551fc  | 
 | 285 | +  dependencies:  | 
 | 286 | +  - constraints: '>= 0.0.0'  | 
 | 287 | +    package: xpkg.crossplane.io/crossplane-contrib/provider-family-gcp  | 
 | 288 | +    type: Provider  | 
 | 289 | +```  | 
 | 290 | +
  | 
 | 291 | +Providers with empty `dependencies: []` change automatically.  | 
 | 292 | +{{</hint>}}  | 
 | 293 | + | 
 | 294 | +### Configuration package dependencies  | 
 | 295 | + | 
 | 296 | +When changing providers that are dependencies of Configuration packages, the   | 
 | 297 | +same conflicts can occur. The Configuration creates provider dependencies based   | 
 | 298 | +on OCI references, so changing registries creates duplicate providers.  | 
 | 299 | + | 
 | 300 | +To change providers in this scenario:  | 
 | 301 | +1. Update the Configuration's package OCI reference  | 
 | 302 | +2. Follow the same manual coordination steps for any conflicted providers  | 
 | 303 | +3. Verify all providers the Configuration depends on are healthy  | 
 | 304 | + | 
 | 305 | +### Rollback procedure  | 
 | 306 | + | 
 | 307 | +If you need to rollback during the process:  | 
 | 308 | + | 
 | 309 | +1. **Before deleting the old provider (step 6)**: Reactivate the old family   | 
 | 310 | +   provider revision:  | 
 | 311 | +   ```shell  | 
 | 312 | +   kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \  | 
 | 313 | +     -p='{"spec":{"desiredState":"Active"}}'  | 
 | 314 | +   ```  | 
 | 315 | +     | 
 | 316 | +   Then deactivate the new family provider revision and delete the new provider.  | 
 | 317 | + | 
 | 318 | +2. **After deleting the old provider**: You must recreate the old provider   | 
 | 319 | +   because Crossplane automatically deletes all revisions when you delete a   | 
 | 320 | +   provider. Create this manifest:  | 
 | 321 | +     | 
 | 322 | +   ```yaml  | 
 | 323 | +   apiVersion: pkg.crossplane.io/v1  | 
 | 324 | +   kind: Provider  | 
 | 325 | +   metadata:  | 
 | 326 | +     name: upbound-provider-family-gcp  | 
 | 327 | +   spec:  | 
 | 328 | +     package: xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1  | 
 | 329 | +   ```  | 
 | 330 | +     | 
 | 331 | +   Save as `rollback-provider.yaml` and apply:  | 
 | 332 | +   ```shell  | 
 | 333 | +   kubectl apply -f rollback-provider.yaml  | 
 | 334 | +   ```  | 
 | 335 | +     | 
 | 336 | +   Then follow the process in reverse to switch back.  | 
 | 337 | + | 
 | 338 | +## Troubleshooting  | 
 | 339 | + | 
 | 340 | +### New family provider stays unhealthy  | 
 | 341 | + | 
 | 342 | +If the new family provider remains `HEALTHY=False` after deactivating the old one:  | 
 | 343 | + | 
 | 344 | +1. Check the provider revision status:  | 
 | 345 | +   ```shell  | 
 | 346 | +   kubectl get providerrevisions | grep crossplane-contrib-provider-family  | 
 | 347 | +   ```  | 
 | 348 | + | 
 | 349 | +2. Look for ownership conflict errors in the provider logs:  | 
 | 350 | +   ```shell  | 
 | 351 | +   kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=crossplane-contrib-provider-family-gcp  | 
 | 352 | +   ```  | 
 | 353 | + | 
 | 354 | +3. Verify the old revision is truly inactive:  | 
 | 355 | +   ```shell  | 
 | 356 | +   kubectl describe providerrevision upbound-provider-family-gcp-f0aa3640a6a9  | 
 | 357 | +   ```  | 
 | 358 | + | 
 | 359 | +### CRD ownership conflicts persist  | 
 | 360 | + | 
 | 361 | +If you see persistent ownership conflicts:  | 
 | 362 | + | 
 | 363 | +```console  | 
 | 364 | +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9  | 
 | 365 | +```  | 
 | 366 | + | 
 | 367 | +This usually means the old revision is still active. Double-check:  | 
 | 368 | + | 
 | 369 | +1. The old provider has `revisionActivationPolicy: Manual`  | 
 | 370 | +2. The old revision has `desiredState: Inactive`  | 
 | 371 | +3. Wait a few minutes for the change to propagate  | 
 | 372 | + | 
 | 373 | +### Provider won't deactivate  | 
 | 374 | + | 
 | 375 | +If the old provider revision won't become inactive:  | 
 | 376 | + | 
 | 377 | +1. Check for active managed resources preventing deactivation  | 
 | 378 | +2. Verify the patch command succeeded  | 
 | 379 | +3. Check provider logs for errors:  | 
 | 380 | +   ```shell  | 
 | 381 | +   kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=upbound-provider-family-gcp  | 
 | 382 | +   ```  | 
 | 383 | + | 
 | 384 | +## Next steps  | 
 | 385 | + | 
 | 386 | +After successfully changing providers:  | 
 | 387 | + | 
 | 388 | +* Update any documentation referencing the old provider  | 
 | 389 | +* Consider changing to v2 namespaced resources if using Crossplane v2  | 
 | 390 | +* Review other providers for potential registry changes  | 
 | 391 | +* Share your experience with the Crossplane community  | 
 | 392 | + | 
 | 393 | +For more information:  | 
 | 394 | +* [Provider documentation]({{<ref "../packages/providers">}})  | 
 | 395 | +* [Troubleshooting guide]({{<ref "troubleshoot-crossplane">}})  | 
 | 396 | +* [Crossplane community](https://crossplane.io/community/)  | 
0 commit comments