Preview — pending review
This reference is generated from the platform API contract and is still under review. Operations, fields, and descriptions can change before publication.
Detach a volume from its instance
Detaches the block volume volumeId from the instance it is currently attached to,
releasing the device path. Triggered from the volume detail header, the attachment panel
and the per-row "Detach" action. On success attachedTo becomes null and the status moves
from IN_USE back to AVAILABLE; the resulting state is visible to subsequent reads.
Validation: volumeId must reference an existing volume in the scope (unknown → 404
NOT_FOUND); the volume must currently be attached — detaching a detached volume → 409
CONFLICT; for multi-attach volumes the optional instanceId selects which attachment to
remove and must match an existing attachment (mismatch → 404/409); root/boot volumes of a
running instance cannot be detached while the instance is running (→ 409 CONFLICT); caller
needs owner|admin|contributor (→ 403).
Async & state: Conditional — a fast detach completes synchronously with 200 returning
the updated Volume (IN_USE → AVAILABLE, attachedTo: null); a slow detach (in-flight I/O
draining) returns 202 with an Operation and the same terminal transition. Progress is
emitted as resource.updated SSE frames (kind storage.volume, patch
{status, attachedTo, updatedAt}).
Errors: 401 unauthenticated; 403 caller lacks permission on the scope; 404 unknown
scopeId/volumeId or no matching attachment; 409 CONFLICT volume not attached, boot
volume of a running instance, or state does not permit detach; 412 If-Match mismatch;
422 malformed body; 500 unexpected backend failure.
Idempotency/Concurrency: Idempotency-Key is optional (recommended); replaying the same
key returns
the original outcome. If-Match with the volume ETag guards against racing a concurrent
attach/detach.
bearerTokenAuthorizationBearer <token>An API token (pc_live_…) or a service-account key (sak_live_…), created in Identity & Access Management and sent as Authorization: Bearer <token>. Requests are rate limited per credential and per tenant: every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a refused request gets 429 RATE_LIMITED with Retry-After.
scopeId*stringOpaque ownership+authorization scope resolving to tenant + subscription + project.
volumeId*stringIdentifier of the block volume.
Idempotency-Key?stringOptional; recommended for safe retries. When sent, the same key+body within 24h replays the original result and the same key with a different body is 409 CONFLICT; keys are unique per tenant. When an API token or service-account (bearer) caller omits it, the request is applied once with no replay protection (a retry may apply it again). A console session gets one from the edge.
uuidIf-Match?stringETag for optimistic concurrency on mutations/deletes; mismatch results in 412.
application/json- body
Optional payload for detaching a volume; only needed to disambiguate multi-attach volumes.
instanceId?|For multi-attach volumes, the specific instance attachment to remove; omitted detaches the sole attachment.
Detach completed synchronously; returns the updated volume (status AVAILABLE, attachedTo null).
application/json- response
Block volume read model as rendered by the Volumes page and the volume detail page.
origin?stringWhere the resource was made -- portal for a create on the console, api for an object made straight against the OpenStack API (CLI, Terraform, the Kubernetes cloud provider) that discovery adopted. Informational; nothing behaves differently. Absent from a backend that predates it, which means portal.
"portal""api""system""imported"id*stringVolume identifier (e.g. vol-0a1b2c3d).
name*stringVolume display name.
status*stringLifecycle status of the volume.
"CREATING""AVAILABLE""IN_USE""AWAITING_TRANSFER""ERROR"statusReason*|Human-readable, customer-facing reason for the current status when it is a failure (e.g. "This request exceeds the quota available to this project. Free up existing resources or request a quota increase." on an ERROR volume); never raw provider text. Null while the volume is healthy or the failure carried no detail.
statusReasonCode*|Machine-readable companion to statusReason: a small, OPEN vocabulary of codes the console can branch on without parsing the human text, deliberately a plain string rather than a closed enum so a code the client does not recognize yet degrades to the generic failure message. Today the only value is cancelled: the resource is in its failure state because its create operation was CANCELLED; a provider object the create had already built may be left in place, and the resource's DELETE removes it. Reported only while the resource is in that failure state; null otherwise.
sizeGb*integerProvisioned size in GB (1–16,384).
type*|Volume performance tier. Null when the volume sits on a provider volume type no platform tier maps to (e.g. a volume adopted from an imported project): the tier is then UNKNOWN and unpriced, never reported as a tier it is not. providerVolumeType carries the provider's own type name in that case.
providerVolumeType*|The provider's (Cinder's) own volume type name, present only when type is null because no platform tier maps to it (an adopted volume on a legacy type). Null for a volume on a platform tier. Display-only: it has no price and cannot be requested.
attachedTo*|nullInstance attachment (instance id, name, device), or null when detached.
bootable*booleanWhether the volume carries a bootable OS image.
encrypted*booleanWhether the volume is encrypted at rest, DERIVED from the provider's own view of the volume (the volume type's encryption spec) — never from the create request. False until the provider confirms encryption, so this field never asserts a security property the platform did not actually deliver.
multiAttach*booleanAllow attaching to more than one instance (RWX).
availabilityZone*stringAvailability zone the volume lives in (e.g. ist-1a).
description*stringOperator-supplied description.
source*Provenance of a block volume — empty, created from an image, restored from a snapshot, or cloned from another volume.
kmsKeyId*|Customer-managed KMS key for envelope encryption; null when platform-managed or encryption is off.
keyRotationDays*integerAutomatic key-rotation period in days (0 = manual).
pricePerGbMonthlyCents*|Price per GB per month in hundredths of the currency unit (an integer, not a Money object): the rate billing meters this volume's tier at for the volume's subscription, rounded down to the hundredth. Null when no price applies to the tier: there is no per-type default figure.
deletionProtection*booleanPlatform-owned deletion guard. While true, storage.volume.delete is refused with 409 DELETION_PROTECTED before any work starts; turn it off with the metadata PATCH, then delete. It guards the console and this API ONLY: Cinder has no lock, so an OpenStack API credential with Full access can still delete the volume directly. False for every volume unless a caller turned it on; the collector never writes it.
tags*array<>Key-value pairs shown on the Tags tab; double as Cost Explorer dimensions.
createdAt*stringCreation timestamp (ISO 8601).
date-timeupdatedAt*stringLast modification timestamp (ISO 8601).
date-timecurl -X POST "https://example.com/scopes/string/storage/volumes/string/actions/detach" \ -H "Content-Type: application/json" \ -d '{}'{ "origin": "portal", "id": "string", "name": "string", "status": "CREATING", "statusReason": "string", "statusReasonCode": "string", "sizeGb": 0, "type": "Standard SSD", "providerVolumeType": "string", "attachedTo": { "instanceId": "string", "instanceName": "string", "device": "string" }, "bootable": true, "encrypted": true, "multiAttach": true, "availabilityZone": "string", "description": "string", "source": { "kind": "empty", "ref": "string" }, "kmsKeyId": "string", "keyRotationDays": 0, "pricePerGbMonthlyCents": 0, "deletionProtection": true, "tags": [ { "key": "string", "value": "string" } ], "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z"}