Appearance
Manage Clouds
A Cloud is a provider account plus its region defaults and the Crossplane provider packages that serve it. This guide drives /v1/clouds with curl; the same operations are available as plexctl cloud subcommands.
Prerequisites
- An authenticated session — see Log in with plexctl.
- Provider data, which differs per provider.
awsneedsendpoint.regionandendpoint.partitionplusregion_defaults.default_region;azureneedsendpoint.cloud_environmentplussubscription_idandtenant_id;gcpneedsendpoint.projectplusregion_defaults.default_region;hetznerneedsendpoint.api_endpointplusregion_defaults.default_location;openstackneedsendpoint.auth_urlplusregion_defaults.default_region. The full table is in the Clouds API reference.
Bind the two placeholders the steps reference. PLEXSPHERE_URL is the control-plane URL; TOKEN reuses the bearer token plexctl login persisted to the default profile (or set PLEXSPHERE_TOKEN directly for a service token):
shell
export PLEXSPHERE_URL="${PLEXSPHERE_URL:-https://localhost:8080}"
TOKEN="$(jq -r '.profiles[.default].token' ~/.config/plexctl/config.json)"Steps
Create a Cloud
shell
curl --silent --show-error --fail-with-body -X POST \
-H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
"${PLEXSPHERE_URL}/v1/clouds" -d '{
"slug": "acme-aws-prod",
"display_name": "Acme AWS Production",
"provider": "aws",
"external_id": "123456789012",
"endpoint": {"region": "eu-central-1", "partition": "aws"},
"region_defaults": {"default_region": "eu-central-1"},
"provider_packages": [
{"source": "xpkg.upbound.io/upbound/provider-aws-ec2", "version": "v2.6.1"},
{"source": "xpkg.upbound.io/upbound/provider-aws-s3", "version": "v2.6.1"}
],
"provider_config_api_version": "aws.m.upbound.io/v1beta1"
}'The slug is immutable. provider_packages names the Crossplane provider packages that serve this Cloud, between one and sixteen entries and each source at most once; the reads render it in source-ascending order whatever order you state it in. provider_config_api_version is a single Cloud-level value: the broker renders one ProviderConfig per Cloud, so every declared package serves that one group.
The body above states the configuration in inline mode, one of the two modes a Cloud has. Inline mode carries the provider_packages / provider_config_api_version pair, and both halves are required together. Bundle mode carries neither and names a provider_bundle_id instead, taking both values from a provider bundle that several Clouds share. A body that names provider_bundle_id alongside either inline field is rejected with 400 invalid_cloud_provider_mode; one that states neither mode, or only one half of the inline pair, with 400 invalid_cloud. Authoring a bundle and pointing Clouds at it is covered in Manage provider bundles.
A PATCH carrying provider_packages replaces the whole set, so restate every package the Cloud should keep; provider_config_api_version patches on its own.
A bundle reference also pins one published version of that bundle. Name it as provider_bundle_version beside the provider_bundle_id, or leave it out and the write pins the bundle's latest_version, the declaration you read when you picked the bundle:
shell
curl --silent --show-error --fail-with-body -X POST \
-H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
"${PLEXSPHERE_URL}/v1/clouds" -d '{
"slug": "acme-aws-staging",
"display_name": "Acme AWS Staging",
"provider": "aws",
"external_id": "123456789013",
"endpoint": {"region": "eu-central-1", "partition": "aws"},
"region_defaults": {"default_region": "eu-central-1"},
"provider_bundle_id": "<bundle-uuid>",
"provider_bundle_version": 2
}'Editing the bundle publishes a new version and moves no Cloud. A PATCH naming provider_bundle_version alone on a Cloud already in bundle mode is what moves this one Cloud onto another declaration, in either direction:
shell
curl -s -X PATCH -H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
"${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>" -d '{"provider_bundle_version": 3}'A version the referenced bundle never published is rejected with 400 provider_bundle_version_not_found; read the versions it did publish at GET /v1/provider-bundles/{id}/versions. Naming the field on a Cloud that declares its packages inline is rejected with 400 invalid_cloud_provider_mode, because there is no bundle for the version to point into.
Override a package on one Cloud
A Cloud in bundle mode may run some of the pinned declaration's packages at other versions without leaving the bundle. provider_package_overrides carries those deviations as {source, version} pairs, each source named at most once and at most sixteen entries:
shell
curl -s -X PATCH -H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
"${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>" -d '{
"provider_package_overrides": [
{"source": "xpkg.upbound.io/upbound/provider-aws-s3", "version": "v2.7.1"}
]
}'The same write with plexctl repeats one flag occurrence per overridden package:
shell
plexctl cloud update <cloud-uuid> \
--package-override xpkg.upbound.io/upbound/provider-aws-s3@v2.7.1The field replaces the whole set, so restate every override the Cloud should keep. Omitting it leaves the current set untouched, which is what carries the deviations across a rename or a version bump. Sending [] clears them and puts the Cloud back on the pinned version as it stands, which is the body the plexctl flag sends:
shell
plexctl cloud update <cloud-uuid> --clear-package-overridesAn override whose source the pinned version carries replaces that entry's version, one naming a source the pinned version does not carry joins the effective set, and nothing is ever removed. Stating the field on a Cloud that declares its packages inline is rejected with 400 invalid_cloud_provider_mode: an override deviates from a referenced declaration, and a Cloud that owns its package set changes a version by editing that set.
Read the Cloud back for both halves, the set it runs and the deviations that shaped it:
shell
plexctl cloud get <cloud-uuid> --output json \
| jq '{provider_package_overrides, provider_packages}'
# {
# "provider_package_overrides": [
# {"source": "xpkg.upbound.io/upbound/provider-aws-s3", "version": "v2.7.1"}
# ],
# "provider_packages": [
# {"source": "xpkg.upbound.io/upbound/provider-aws-ec2", "version": "v2.6.1", "origin": "bundle"},
# {"source": "xpkg.upbound.io/upbound/provider-aws-s3", "version": "v2.7.1", "origin": "override"}
# ]
# }origin reads bundle for an entry taken as the pinned version published it, override where a deviation replaced its version, and addition where the override named a source that version does not carry. The text output states the same pair in two columns: PROVIDER_PACKAGES is the effective set, PACKAGE_OVERRIDES the deviations the operator authored.
List, inspect, update, delete
shell
curl -s -H "Authorization: Bearer ${TOKEN}" "${PLEXSPHERE_URL}/v1/clouds"
curl -s -H "Authorization: Bearer ${TOKEN}" "${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>"
curl -s -X PATCH -H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
"${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>" -d '{"display_name":"Acme AWS (prod)"}'
curl -s -X DELETE -H "Authorization: Bearer ${TOKEN}" "${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>"Verification
shell
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>" | jq '{slug, provider}'
# {
# "slug": "acme-aws-prod",
# "provider": "aws"
# }See also
../../reference/api/clouds.md— the HTTP contract.