OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Services

cinder — REST API

REST API — cinder — branch stable/2026.2

Branch stable/2026.2 @ c117f9cf08b4 (29.0.0-1-gc117f9cf0) — repository https://opendev.org/openstack/cinder — analysed on 2026-10-28

This file describes the Block Storage API v3 as the code serves it. The operation table (§ 3) was extracted from the live router (cinder.api.v3.router.APIRouter with the contrib extensions loaded) rather than from the api-ref, so it lists what a client can really call. The machine-readable version is [_rewrite/routes_stable-2026.2.json](_rewrite/routes_stable-2026.2.json) and [_rewrite/openapi_stable-2026.2.json](_rewrite/openapi_stable-2026.2.json). Errors are detailed in 02-errors_stable-2026.2.md, and the asynchronous follow-up of each operation in 05-async-processing_stable-2026.2.md.

1. Conventions shared by every endpoint

1.1 Entry point and pipeline

  • Root: osapi_volume composite (etc/cinder/api-paste.ini:5-8): / → version list, /healthcheck → oslo.middleware health check (disabled by the file /etc/cinder/healthcheck_disable, etc/cinder/api-paste.ini:55), /v3 → the API. /v1 and /v2 are removed and only produce a log warning (cinder/api/__init__.py:30-44).
  • v3 pipeline with auth_strategy = keystone (etc/cinder/api-paste.ini:15): request_id → cors → http_proxy_to_wsgi → faultwrap → sizelimit → osprofiler → authtoken (keystonemiddleware) → keystonecontext → apiv3. The pipeline is chosen by pipeline_factory from [DEFAULT]/auth_strategy (cinder/api/middleware/auth.py:47-58); noauth replaces the last two filters by a fake authentication that trusts X-Auth-Token: user:project and sets is_admin=True (cinder/api/middleware/auth.py:132-176).
  • Request context: CinderKeystoneContext builds cinder.context from the headers set by keystonemiddleware and answers 401 without body when no user is identified (cinder/api/middleware/auth.py:105-126). X-Forwarded-For is trusted only with [DEFAULT]/use_forwarded_for (cinder/api/middleware/auth.py:33-37).

1.2 URLs

  • Every resource exists twice: /v3/{project_id}/<resource> and /v3/<resource> (cinder/api/v3/router.py:60-95, cinder/api/openstack/wsgi.py:1289-1307). The project-less form is accepted at every microversion: microversion 3.67 only announces it, nothing checks it.
  • {project_id} must match [DEFAULT]/project_id_regex (default [0-9a-f\-]+, cinder/api/openstack/__init__.py:25-29). When present, it must equal the project of the token, otherwise 400 "Malformed request url" (cinder/api/openstack/wsgi.py:897-901).
  • A trailing .json is accepted and forces JSON (cinder/api/openstack/wsgi.py:232-254, cinder/api/openstack/wsgi.py:1281-1287).

1.3 Microversions

  • Header OpenStack-API-Version: volume 3.x (cinder/api/openstack/wsgi.py:62-64). Without it the request is served at 3.0, the minimum, not the maximum (cinder/api/openstack/wsgi.py:326-327). latest means 3.71.
  • Range 3.0 – 3.71 (cinder/api/openstack/api_version_request.py:165-166); history in [_rewrite/microversions_stable-2026.2.md](_rewrite/microversions_stable-2026.2.md).
  • Out of range → 406; malformed → 400; header present without a volume entry → VersionNotFoundForAPIMethod (cinder/api/openstack/wsgi.py:292-327, cinder/api/openstack/wsgi.py:820-829).
  • A versioned method called outside its range → 404 without explanation, as if the route did not exist (cinder/api/openstack/wsgi.py:1001-1010).
  • Every response carries OpenStack-API-Version: volume <served version> and Vary: OpenStack-API-Version (cinder/api/openstack/wsgi.py:957-964).

1.4 Body-dispatched actions

POST …/{id}/action dispatches on the single key of the JSON body ({"os-extend": {...}}): action_peek_json rejects a body with more than one key ("too many body keys", 400) and an unknown key gives 400 "There is no such action: …" (cinder/api/openstack/wsgi.py:565-580, cinder/api/openstack/wsgi.py:858-866, cinder/api/openstack/wsgi.py:968-999). The same fallback also maps POST /types, PUT /types/{id}, DELETE /types/{id} and DELETE /groups/{id} to @wsgi.action methods named create, update, delete (cinder/api/openstack/wsgi.py:977-985).

1.5 Request validation

  • JSON-schema validation through @validation.schema(schema, min, max), which applies a schema only inside its microversion range (cinder/api/validation/__init__.py:27-63). The 112 schemas are in [_rewrite/request-schemas_stable-2026.2.json](_rewrite/request-schemas_stable-2026.2.json); which one applies per operation and microversion is in routes_stable-2026.2.json (variants[].schemas).
  • Accepted content types: application/json and application/vnd.openstack.volume+json; anything else → 415 (cinder/api/openstack/wsgi.py:46-55, cinder/api/openstack/wsgi.py:836-843).
  • Body size limited by oslo.middleware sizelimit ([oslo_middleware]/max_request_body_size).

1.6 Responses

  • Error body: {"<faultName>": {"code": <status>, "message": "<text>"}} with faultName among badRequest, unauthorized, forbidden, itemNotFound, badMethod, conflictingRequest, overLimit, badMediaType, notImplemented, serviceUnavailable, otherwise computeFault (cinder/api/openstack/wsgi.py:1310-1363).
  • Request ID: x-openstack-request-id (oslo RequestId, cinder/api/middleware/request_id.py:25-71) and the legacy x-compute-request-id (cinder/api/openstack/wsgi.py:1369-1372).
  • Lists: limit (bounded by [DEFAULT]/osapi_max_limit, default 1000), marker, offset, sort/sort_key/sort_dir, with_count (3.45); filters allowed per resource by resource_filters.json (cinder/api/common.py:38-45, cinder/api/common.py:63-141). Next-page links are volumes_links, snapshots_links…

1.7 Authorisation

Policies (167 default rules in [_rewrite/policies_stable-2026.2.json](_rewrite/policies_stable-2026.2.json)) are checked in the business layer (context.authorize(...) in cinder/volume/api.py, cinder/backup/api.py…), not in the router. Defaults on this branch:

  • rule:xena_system_admin_or_project_member = (role:admin) or (role:member and project_id:%(project_id)s) for writes (56 rules);
  • rule:xena_system_admin_or_project_reader for reads (27 rules);
  • rule:admin_api = is_admin:True or (role:admin and is_admin_project:True) for operator actions (78 rules).

So role:admin in any project is a cloud administrator by default (cinder/policies/base.py:69-184). A denial gives 403 Policy doesn't allow <rule> to be performed..

2. Functional description by area

2.1 Volumes (/volumes)

POST /volumes — create a volume

  • Purpose: allocate a block device of size GiB, empty or populated from a snapshot, another volume, an image or a backup.
  • Actor: project member (volume:create, or volume:create_from_image when imageRef is set, cinder/volume/api.py:240-243).
  • Preconditions: the source (snapshot, volume, backup) is visible to the caller; a volume type is resolved: the requested one, otherwise the project default type (default_volume_types table, API 3.62), otherwise [DEFAULT]/default_volume_type. A misconfigured default gives 500 VolumeTypeDefaultMisconfiguredError (cinder/volume/volume_types.py:214-240, cinder/api/v3/volumes.py:468-473).
  • Business rules:
    • size must be a positive integer, or is taken from the source when omitted (cinder/api/v3/volumes.py:444-450, cinder/volume/api.py:261-267); it must be ≥ the source size (cinder/volume/flows/api/create_volume.py:174-205), and within the volume type's provisioning:min_vol_size / max_vol_size (cinder/volume/api.py:269-270).
    • The multiattach parameter is refused: multi-attach comes from the volume type (cinder/api/v3/volumes.py:454-461).
    • A different type from the source's is allowed only if a retype between both types would be possible (cinder/volume/api.py:295-314).
    • Availability zone: requested, otherwise the source's, otherwise default_availability_zone / storage_availability_zone; it must be one of the zones of live cinder-volume services (and of the type's RESKEY:availability_zones), unless allow_availability_zone_fallback (cinder/volume/flows/api/create_volume.py:260-350).
    • Metadata keys and values are limited to 255 characters (cinder/volume/api.py:325).
    • Quotas volumes, gigabytes, volumes_<type>, gigabytes_<type> are reserved, and per_volume_gigabytes is checked (cinder/volume/flows/api/create_volume.py:676-731).
  • Flow:
    1. (synchronous) Validation, quota reservation, INSERT volumes with status creating, quota commit, then RPC cast create_volume to cinder-scheduler (cinder/volume/flows/api/create_volume.py:889-922).
    2. (asynchronous) The scheduler filters and weighs the backends and casts create_volume to the chosen cinder-volume (05 § 2.1).
    3. (asynchronous) The volume manager runs its create flow (raw, from snapshot, clone, image with image-volume cache, backup), and sets available or error (05 § 3.1).
  • Outcome: 202 with the volume in creating; the client polls GET /volumes/{id} until available or error. On error, the reason is in GET /messages (API ≥ 3.3).
  • Effects visible elsewhere: notifications volume.create.start/end; Glance download when created from an image; Barbican key creation for an encrypted type.
  • Limitations: when the scheduler finds no backend, the volume goes to error with user message VOLUME_001_003 (no HTTP error).

GET /volumes, /volumes/detail, /volumes/{id}, /volumes/summary

  • Purpose: list or show volumes; summary (3.12) returns the total count and size, and metadata keys (3.36).
  • Rules: non-admins only see their project; all_tenants, host and migration attributes are admin-only (policies volume_extension:volume_host_attribute, …mig_status_attribute, …tenant_attribute). Filters are checked against resource_filters.json; time comparisons on created_at/updated_at use gt/gte/eq/neq/lt/lte (3.60) (cinder/api/v3/volumes.py:114-213).
  • Response by microversion: group_id (3.13), provider_id (3.21), service_uuid and shared_targets (3.48), cluster_name (3.61), volume_type_id (3.63), encryption_key_id (3.64), consumes_quota (3.65); shared_targets may be null from 3.69 (cinder/api/v3/views/volumes.py:201).

PUT /volumes/{id}

Updates name, description, metadata (cinder/volume/api.py:571-593); notification volume.update.start/end.

DELETE /volumes/{id}[?cascade=true&force=true]

  • Preconditions (one conditional UPDATE): not attached, not migrating, not in a group, no snapshot (unless cascade), status in available, error, error_restoring, error_extending, error_managing (unless force, 3.23 and policy volume:force_delete) (cinder/volume/api.py:414-566, cinder/api/v3/volumes.py:68-95).
  • Flow: status → deleting; cascaded snapshots → deleting; image-volume cache entry evicted; the encryption key is deleted from the key manager before the RPC, which makes the deletion irreversible; cast delete_volume to the volume's backend (cinder/volume/api.py:532-566). A volume never scheduled (no host) is deleted directly in the API, quota released (cinder/volume/api.py:423-455).
  • Outcome: 202; the volume disappears from lists when the manager finishes, or ends in error_deleting.

POST /volumes/{id}/action — the volume actions

ActionPurposePreconditions / rulesAsynchronous part
os-extendgrow the volumenew_size > size; status available, or in-use from 3.42 (policy volume:extend_attached_volume); quota on the size increase; status → extending (cinder/api/contrib/volume_actions.py:274-289, cinder/volume/api.py:1551-1660)scheduler checks the capacity (extend_volume), then the manager extends and, for an attached volume, sends Nova the volume-extended external event (05 § 3.4)
os-extend_volume_completionNova reports the end of a driver-assisted extendadmin/service only; status must be extending; reads extend_new_size and extend_reservations from the admin metadata (cinder/api/contrib/admin_actions.py:205-214, cinder/volume/api.py:1681-1720)cast extend_volume_completion. Not gated by microversion 3.71 although the history says it was added there
os-attach, os-detach, os-reserve, os-unreserve, os-begin_detaching, os-roll_detaching, os-initialize_connection, os-terminate_connectionlegacy attach flow (before the attachments API)status checks done by conditional updates; os-initialize_connection and os-terminate_connection are synchronous RPC calls to the volume service, which returns the connection info (cinder/volume/api.py:751-931)none beyond the call
os-force_detachadmin cleanup of an attachmentadmincall terminate_connection + detach_volume
os-reset_statusadmin overrides status, attach_status, migration_statusadmin; no backend action (cinder/api/contrib/admin_actions.py:59-125)none
os-force_deletedelete whatever the statusadminas DELETE
os-migrate_volume, os-migrate_volume_completionmove a volume to another backend; Nova completes a migration of an attached volumeadmin; target host or cluster (3.16)scheduler migrate_volume, manager migrate_volume (05)
os-retypechange the volume type, migrating if needed (migration_policy never/on-demand)policy volume:retype; quota moved between types (cinder/volume/api.py:1880-2041)scheduler retype → manager retype
os-volume_upload_imagecopy the volume into a new Glance imagestatus available (or in-use with force, [DEFAULT]/enable_force_upload); policy upload_public for public images; status → uploading (cinder/volume/api.py:1480-1660)cast copy_volume_to_image; the manager uploads to Glance and restores the status
os-set_bootable, os-update_readonly_flag, os-set_image_metadata, os-unset_image_metadata, os-show_image_metadataflags and image metadata—none
os-unmanageforget the volume without deleting it on the backendnot encrypted (cinder/volume/api.py:466-475)cast delete_volume(unmanage_only=True)
revert (3.40)revert to the latest snapshotvolume and snapshot available → reverting / restoring (cinder/volume/api.py:387-412)cast revert_to_snapshot
os-reimage (3.68)rewrite the volume from an image (rebuild of a boot volume)status available/error, or reserved with reimage_reserved (Nova) (cinder/volume/api.py:2696-2749)cast reimage; Nova is notified with volume-reimaged

2.2 Attachments (/attachments, 3.27+) — what Nova uses

  • POST /attachments: reserve the volume for an instance (volume:attachment_create). The volume must not be in an error status; status → reserved with an attachment row reserved (cinder/volume/api.py:2476-2523). With a connector, the volume service is called synchronously (attachment_update) to export the volume and returns connection_info. A driver exception becomes 500 "Unable to create attachment for volume" (cinder/api/v3/attachments.py:200-211). mode (rw/ro) from 3.54.
  • PUT /attachments/{id}: give the connector of the compute host (attachment_update, serialised by a lock attachment_update-<volume_id>-<host>); 409 when the volume is in error or when a non-multiattach volume already has a connection on another host (cinder/volume/api.py:2525-2586).
  • **POST /attachments/{id}/action os-complete** (3.44): attachment → attached, volume → in-use, notification volume.attach.end (cinder/api/v3/attachments.py:289-306).
  • DELETE /attachments/{id}: allowed for a connected attachment only if the request carries a service token (Nova) or if Nova no longer knows the attachment; otherwise **409 ConflictNovaUsingAttachment** (bug 2004555, cinder/volume/api.py:2588-2661). Calls attachment_delete on the volume service, which unexports and returns the remaining attachments.

2.3 Snapshots (/snapshots, /snapshots/{id}/metadata)

  • POST /snapshots: volume available, or in-use with force; quotas snapshots, gigabytes; status creating; cast create_snapshot to the volume's backend (cinder/volume/api.py:980-1223). Snapshots of a volume in-use are refused when force is false.
  • DELETE /snapshots/{id}: status available or error, not part of a group snapshot; cast delete_snapshot (cinder/volume/api.py:1225-1257).
  • Actions: os-reset_status, os-force_delete (admin), os-update_snapshot_status (used by Nova for assisted snapshots), os-unmanage.

2.4 Backups (/backups)

  • POST /backups: volume available (or in-use with force) or a snapshot available; incremental requires a previous available backup; quotas backups, backup_gigabytes; volume → backing-up; backup creating; cast create_backup to the scheduler, which picks a cinder-backup host in the same AZ (cinder/backup/api.py:218-374). Metadata (3.43), availability zone (3.51).
  • POST /backups/{id}/restore: into a new or existing volume (restoring-backup); GET /backups/{id}/export_record, POST /backups/import_record (admin): move backup records between deployments (cinder/backup/api.py:376-648).
  • DELETE /backups/{id}: available or error, no dependent incremental backup.

2.5 Volume types, extra specs, encryption, access, QoS, default types

  • /types (admin writes through types_manage, cinder/api/contrib/types_manage.py:54-160); /types/{id}/extra_specs; /types/{id}/encryption (provider, cipher, key size, control location); /types/{id}/os-volume-type-access and the addProjectAccess/removeProjectAccess actions for private types; /qos-specs with associate/disassociate as GET requests with a query string (cinder/api/contrib/qos_specs_manage.py:229-370).
  • /default-types (3.62): per-project default type; the project is checked in Keystone (cinder/api/api_utils.py:238-262, cinder/api/v3/default_types.py:42-116).
  • Group types and group specs (3.11).

2.6 Groups and group snapshots (3.13 / 3.14), consistency groups (deprecated)

Generic volume groups bound to a backend; actions delete (with delete-volumes), create-from-src, reset_status, enable_replication, disable_replication, failover_replication, list_replication_targets (3.38). Consistency groups (/consistencygroups, /cgsnapshots) are kept for compatibility and map to the same group code (cinder/group/api.py:109-1151).

2.7 Transfers (/volume-transfers 3.55, /os-volume-transfer)

  • Create: volume available → awaiting-transfer; returns once an auth_key (16 hex characters by default) stored as HMAC-SHA1(salt, auth_key) with an 8-character salt (cinder/transfer/api.py:106-176). no_snapshots (3.55); encrypted volumes allowed from 3.70 (cinder/api/v3/volume_transfer.py:100).
  • Accept POST …/{id}/accept: compares the HMAC (else **400 InvalidAuthKey), reserves quota in the recipient project and releases it in the donor project, then **calls accept_transfer on the volume service (cinder/transfer/api.py:235-330).

2.8 Quotas and limits

/os-quota-sets/{project_id} (show with ?usage=true, update, delete = reset to defaults, defaults), /os-quota-class-sets/{class}; /limits returns absolute limits and usage (cinder/api/contrib/quotas.py:69-160, cinder/api/v3/limits.py:27). Resources: volumes, snapshots, gigabytes, backups, backup_gigabytes, groups, per_volume_gigabytes, plus per-type volumes_<type>, snapshots_<type>, gigabytes_<type>.

2.9 Operator APIs

/os-services (list, enable, disable, freeze/thaw, failover_host, get-log/set-log 3.32), /clusters (3.7), /workers/cleanup (3.24, re-run cleanup of resources left by a dead service), /scheduler-stats/get_pools, /capabilities/{host}, /os-hosts (deprecated), /manageable_volumes and /manageable_snapshots (list unmanaged backend objects), /os-volume-manage and /os-snapshot-manage (adopt them), /messages (3.3, user-facing asynchronous errors), /resource_filters (3.33), /os-availability-zone, /extensions.

3. Operation table

218 operations (the 52 body actions counted separately), extracted from the router. "Microversion" gives the range of each implementation (3.27+, or 3.0–3.15 / 3.16+ when the handler changes). An empty cell means available from 3.0. "Policy rule(s)" comes from the operations declared by the policy rules; the code may check more rules than these.

MethodPath (after /v3/{project_id})HandlerPolicy rule(s) from operationsMicroversionBody schema(s) (cinder/api/schemas/)Success
GET/volumes/detailcinder/api/v3/volumes.py:219volume:get_all
volume_extension:volume_host_attribute
volume_extension:volume_image_metadata:show
volume_extension:volume_mig_status_attribute
volume_extension:volume_tenant_attribute
—200
GET/volumes/summarycinder/api/v3/volumes.py:224volume:get_all3.12+—200
POST/volumescinder/api/v3/volumes.py:360volume:create
volume:create_from_image
volume:multiattach
volumes.create@3.0, volumes.create_volume_v313@3.13, volumes.create_volume_v347@3.47, volumes.create_volume_v353@3.53202
GET/volumescinder/api/v3/volumes.py:215volume:get_all—200
POST/volumes/{id}/action {"os-attach"}cinder/api/contrib/volume_actions.py:55volume:update_volume_admin_metadata
volume_extension:volume_actions:attach
volume_actions.attach202
POST/volumes/{id}/action {"os-begin_detaching"}cinder/api/contrib/volume_actions.py:139volume_extension:volume_actions:begin_detachingvolume_actions.begin_detaching202
POST/volumes/{id}/action {"os-detach"}cinder/api/contrib/volume_actions.py:91volume_extension:volume_actions:detachvolume_actions.detach202
POST/volumes/{id}/action {"os-extend"}cinder/api/contrib/volume_actions.py:274volume:extend
volume:extend_attached_volume
volume_actions.extend202
POST/volumes/{id}/action {"os-extend_volume_completion"}cinder/api/contrib/admin_actions.py:205volume_extension:volume_admin_actions:extend_volume_completionadmin_actions.extend_volume_completion202
POST/volumes/{id}/action {"os-force_delete"}cinder/api/contrib/admin_actions.py:218volume_extension:volume_admin_actions:force_deleteadmin_actions.force_delete_volume202
POST/volumes/{id}/action {"os-force_detach"}cinder/api/contrib/admin_actions.py:130volume_extension:volume_admin_actions:force_detachadmin_actions.force_detach202
POST/volumes/{id}/action {"os-initialize_connection"}cinder/api/contrib/volume_actions.py:160volume_extension:volume_actions:initialize_connectionvolume_actions.initialize_connection200
POST/volumes/{id}/action {"os-migrate_volume"}cinder/api/contrib/admin_actions.py:168volume_extension:volume_admin_actions:migrate_volumeadmin_actions.migrate_volume@3.0, admin_actions.migrate_volume_v316@3.16202
POST/volumes/{id}/action {"os-migrate_volume_completion"}cinder/api/contrib/admin_actions.py:187volume_extension:volume_admin_actions:migrate_volume_completionadmin_actions.migrate_volume_completion200
POST/volumes/{id}/action {"os-reimage"}cinder/api/contrib/volume_actions.py:375volume:reimage
volume:reimage_reserved
3.68+volume_actions.reimage@3.68202
POST/volumes/{id}/action {"os-reserve"}cinder/api/contrib/volume_actions.py:117volume_extension:volume_actions:reservevolume_actions.reserve202
POST/volumes/{id}/action {"os-reset_status"}cinder/api/contrib/admin_actions.py:59volume_extension:volume_admin_actions:reset_statusadmin_actions.reset_status_volume202
POST/volumes/{id}/action {"os-retype"}cinder/api/contrib/volume_actions.py:310volume:retypevolume_actions.retype202
POST/volumes/{id}/action {"os-roll_detaching"}cinder/api/contrib/volume_actions.py:150volume_extension:volume_actions:roll_detachingvolume_actions.roll_detaching202
POST/volumes/{id}/action {"os-set_bootable"}cinder/api/contrib/volume_actions.py:322volume:updatevolume_actions.set_bootable200
POST/volumes/{id}/action {"os-set_image_metadata"}cinder/api/contrib/volume_image_metadata.py:89volume_extension:volume_image_metadata:setvolume_image_metadata.set_image_metadata200
POST/volumes/{id}/action {"os-show_image_metadata"}cinder/api/contrib/volume_image_metadata.py:125volume:get_volume_metadatavolume_image_metadata.index200
POST/volumes/{id}/action {"os-terminate_connection"}cinder/api/contrib/volume_actions.py:187volume_extension:volume_actions:terminate_connectionvolume_actions.terminate_connection202
POST/volumes/{id}/action {"os-unmanage"}cinder/api/contrib/volume_unmanage.py:37volume_extension:volume_unmanagevolume_unmanage.unmanage202
POST/volumes/{id}/action {"os-unreserve"}cinder/api/contrib/volume_actions.py:128volume_extension:volume_actions:unreservevolume_actions.unreserve202
POST/volumes/{id}/action {"os-unset_image_metadata"}cinder/api/contrib/volume_image_metadata.py:131volume_extension:volume_image_metadata:removevolume_image_metadata.unset_image_metadata200
POST/volumes/{id}/action {"os-update_readonly_flag"}cinder/api/contrib/volume_actions.py:294volume:update_readonly_flag
volume:update_volume_admin_metadata
volume_actions.volume_readonly_update202
POST/volumes/{id}/action {"os-volume_upload_image"}cinder/api/contrib/volume_actions.py:205volume_extension:volume_actions:upload_image
volume_extension:volume_actions:upload_public
volume_actions.volume_upload_image@3.0, volume_actions.volume_upload_image_v31@3.1202
POST/volumes/{id}/action {"revert"}cinder/api/v3/volumes.py:251volume:revert_to_snapshot3.40+volumes.revert202
PUT/volumes/{id}cinder/api/v3/volumes.py:482—volumes.update@3.0, volumes.update_v353@3.53200
DELETE/volumes/{id}cinder/api/v3/volumes.py:68volume:delete
volume:force_delete
—202
GET/volumes/{id}cinder/api/v3/volumes.py:97volume:get
volume_extension:volume_host_attribute
volume_extension:volume_image_metadata:show
volume_extension:volume_mig_status_attribute
volume_extension:volume_tenant_attribute
—200
GET/messagescinder/api/v3/messages.py:78message:get_all3.3+—200
DELETE/messages/{id}cinder/api/v3/messages.py:66message:delete3.3+—204
GET/messages/{id}cinder/api/v3/messages.py:53message:get3.3+—200
GET/clusterscinder/api/v3/clusters.py:49clusters:get_all3.7+—200
GET/clusters/detailcinder/api/v3/clusters.py:57clusters:get_all3.7+—200
GET/clusters/{id}cinder/api/v3/clusters.py:36clusters:get3.7+—200
PUT/clusters/enablecinder/api/v3/clusters.py:142—3.7+clusters.enable_cluster200
PUT/clusters/disablecinder/api/v3/clusters.py:118—3.7+clusters.disable_cluster200
POST/typescinder/api/contrib/types_manage.py:54volume_extension:type_create
volume_extension:volume_type_access
volume_types.create200
GET/typescinder/api/v3/types.py:41volume_extension:access_types_extra_specs
volume_extension:access_types_qos_specs_id
volume_extension:type_get_all
volume_extension:types_extra_specs:read_sensitive
volume_extension:volume_type_access
—200
POST/types/{id}/action {"addProjectAccess"}cinder/api/contrib/volume_type_access.py:100volume_extension:volume_type_access:addProjectAccessvolume_type_access.add_project_access202
POST/types/{id}/action {"create"}cinder/api/contrib/types_manage.py:54—volume_types.create200
POST/types/{id}/action {"delete"}cinder/api/contrib/types_manage.py:150——202
POST/types/{id}/action {"removeProjectAccess"}cinder/api/contrib/volume_type_access.py:114volume_extension:volume_type_access:removeProjectAccessvolume_type_access.remove_project_access202
POST/types/{id}/action {"update"}cinder/api/contrib/types_manage.py:89—volume_types.update200
PUT/types/{id}cinder/api/contrib/types_manage.py:89—volume_types.update200
DELETE/types/{id}cinder/api/contrib/types_manage.py:150——202
GET/types/{id}cinder/api/v3/types.py:50volume_extension:access_types_extra_specs
volume_extension:access_types_qos_specs_id
volume_extension:type_get
volume_extension:types_extra_specs:read_sensitive
volume_extension:volume_type_access
—200
POST/group_typescinder/api/v3/group_types.py:57group:group_types:create3.11+group_types.create202
GET/group_typescinder/api/v3/group_types.py:165—3.11+—200
PUT/group_types/{id}cinder/api/v3/group_types.py:93group:group_types:update3.11+group_types.update200
DELETE/group_types/{id}cinder/api/v3/group_types.py:142group:group_types:delete3.11+—202
GET/group_types/{id}cinder/api/v3/group_types.py:172group:access_group_types_specs3.11+—200
POST/group_types/{group_type_id}/group_specscinder/api/v3/group_specs.py:59group:group_types_specs:create3.11+group_specs.create202
GET/group_types/{group_type_id}/group_specscinder/api/v3/group_specs.py:49group:group_types_specs:get_all3.11+—200
PUT/group_types/{group_type_id}/group_specs/{id}cinder/api/v3/group_specs.py:76group:group_types_specs:update3.11+group_specs.update200
DELETE/group_types/{group_type_id}/group_specs/{id}cinder/api/v3/group_specs.py:111group:group_types_specs:delete3.11+—202
GET/group_types/{group_type_id}/group_specs/{id}cinder/api/v3/group_specs.py:96group:group_types_specs:get3.11+—200
GET/groups/detailcinder/api/v3/groups.py:144group:get_all
group:group_project_attribute
3.13+—200
POST/groupscinder/api/v3/groups.py:188group:create3.13+groups.create202
GET/groupscinder/api/v3/groups.py:139group:get_all3.13+—200
POST/groups/{id}/action {"create-from-src"}cinder/api/v3/groups.py:229—3.14+groups.create_from_source202
POST/groups/{id}/action {"delete"}cinder/api/v3/groups.py:112group:delete3.13+groups.delete200
POST/groups/{id}/action {"disable_replication"}cinder/api/v3/groups.py:362group:disable_replication3.38+groups.disable_replication202
POST/groups/{id}/action {"enable_replication"}cinder/api/v3/groups.py:342group:enable_replication3.38+groups.enable_replication202
POST/groups/{id}/action {"failover_replication"}cinder/api/v3/groups.py:382group:failover_replication3.38+groups.failover_replication202
POST/groups/{id}/action {"list_replication_targets"}cinder/api/v3/groups.py:409group:list_replication_targets3.38+groups.list_replication200
POST/groups/{id}/action {"reset_status"}cinder/api/v3/groups.py:73group:reset_status3.20+groups.reset_status200
PUT/groups/{id}cinder/api/v3/groups.py:284group:update3.13+groups.update202
DELETE/groups/{id}cinder/api/v3/groups.py:112—3.13+groups.delete200
GET/groups/{id}cinder/api/v3/groups.py:56group:get
group:group_project_attribute
3.13+—200
POST/groups/action {"create-from-src"}cinder/api/v3/groups.py:229—3.14+groups.create_from_source202
POST/groups/action {"delete"}cinder/api/v3/groups.py:112—3.13+groups.delete200
POST/groups/action {"disable_replication"}cinder/api/v3/groups.py:362—3.38+groups.disable_replication202
POST/groups/action {"enable_replication"}cinder/api/v3/groups.py:342—3.38+groups.enable_replication202
POST/groups/action {"failover_replication"}cinder/api/v3/groups.py:382—3.38+groups.failover_replication202
POST/groups/action {"list_replication_targets"}cinder/api/v3/groups.py:409—3.38+groups.list_replication200
POST/groups/action {"reset_status"}cinder/api/v3/groups.py:73—3.20+groups.reset_status200
GET/group_snapshots/detailcinder/api/v3/group_snapshots.py:103group:get_all_group_snapshots
group:group_snapshot_project_attribute
3.14+—200
POST/group_snapshotscinder/api/v3/group_snapshots.py:152group:create_group_snapshot3.14+group_snapshots.create202
GET/group_snapshotscinder/api/v3/group_snapshots.py:98group:get_all_group_snapshots3.14+—200
POST/group_snapshots/{id}/action {"reset_status"}cinder/api/v3/group_snapshots.py:185group:reset_group_snapshot_status3.19+group_snapshots.reset_status200
DELETE/group_snapshots/{id}cinder/api/v3/group_snapshots.py:70group:delete_group_snapshot3.14+—202
GET/group_snapshots/{id}cinder/api/v3/group_snapshots.py:56group:get_group_snapshot
group:group_snapshot_project_attribute
3.14+—200
GET/snapshots/detailcinder/api/v3/snapshots.py:179volume:get_all_snapshots
volume_extension:extended_snapshot_attributes
—200
POST/snapshotscinder/api/v3/snapshots.py:185volume:create_snapshotsnapshots.create202
GET/snapshotscinder/api/v3/snapshots.py:175volume:get_all_snapshots—200
POST/snapshots/{id}/action {"os-force_delete"}cinder/api/contrib/admin_actions.py:289volume_extension:snapshot_admin_actions:force_deleteadmin_actions.force_delete_snapshot202
POST/snapshots/{id}/action {"os-reset_status"}cinder/api/contrib/admin_actions.py:248volume_extension:snapshot_admin_actions:reset_statusadmin_actions.reset_status_snapshot202
POST/snapshots/{id}/action {"os-unmanage"}cinder/api/contrib/snapshot_unmanage.py:39snapshot_extension:snapshot_unmanagesnapshot_unmanage.unmanage202
POST/snapshots/{id}/action {"os-update_snapshot_status"}cinder/api/contrib/snapshot_actions.py:37snapshot_extension:snapshot_actions:update_snapshot_statussnapshot_actions.update_snapshot_status202
PUT/snapshots/{id}cinder/api/v3/snapshots.py:236volume:update_snapshotsnapshots.update200
DELETE/snapshots/{id}cinder/api/v3/snapshots.py:67volume:delete_snapshot—202
GET/snapshots/{id}cinder/api/v3/snapshots.py:57volume:get_snapshot
volume_extension:extended_snapshot_attributes
—200
GET/limitscinder/api/v3/limits.py:27limits_extension:used_limits—200
POST/snapshots/{snapshot_id}/metadatacinder/api/v3/snapshot_metadata.py:50volume:update_snapshot_metadatasnapshot_metadata.create200
GET/snapshots/{snapshot_id}/metadatacinder/api/v3/snapshot_metadata.py:44volume:get_snapshot_metadata—200
PUT/snapshots/{snapshot_id}/metadata/{id}cinder/api/v3/snapshot_metadata.py:62volume:update_snapshot_metadatasnapshot_metadata.update200
DELETE/snapshots/{snapshot_id}/metadata/{id}cinder/api/v3/snapshot_metadata.py:124volume:delete_snapshot_metadata—200
GET/snapshots/{snapshot_id}/metadata/{id}cinder/api/v3/snapshot_metadata.py:113volume:get_snapshot_metadata—200
PUT/snapshots/{snapshot_id}/metadatacinder/api/v3/snapshot_metadata.py:82—snapshot_metadata.create200
POST/volumes/{volume_id}/metadatacinder/api/v3/volume_metadata.py:76volume:create_volume_metadatavolume_metadata.create200
GET/volumes/{volume_id}/metadatacinder/api/v3/volume_metadata.py:62volume:get_volume_metadata—200
PUT/volumes/{volume_id}/metadata/{id}cinder/api/v3/volume_metadata.py:108volume:update_volume_metadatavolume_metadata.updateHTTPStatus.PRECONDITION_FAILED
DELETE/volumes/{volume_id}/metadata/{id}cinder/api/v3/volume_metadata.py:157volume:delete_volume_metadata—200
GET/volumes/{volume_id}/metadata/{id}cinder/api/v3/volume_metadata.py:146volume:get_volume_metadata—200
PUT/volumes/{volume_id}/metadatacinder/api/v3/volume_metadata.py:132volume:update_volume_metadatavolume_metadata.createHTTPStatus.PRECONDITION_FAILED
GET/consistencygroups/detailcinder/api/contrib/consistencygroups.py:98——200
POST/consistencygroupscinder/api/contrib/consistencygroups.py:141—consistencygroups.create202
GET/consistencygroupscinder/api/contrib/consistencygroups.py:93——200
PUT/consistencygroups/{id}cinder/api/v3/consistencygroups.py:56—consistencygroups.update202
DELETE/consistencygroups/{id}cinder/api/contrib/consistencygroups.py:64—consistencygroups.delete202
GET/consistencygroups/{id}cinder/api/contrib/consistencygroups.py:52——200
GET/manageable_volumes/detailcinder/api/v3/resource_common_manage.py:83volume_extension:list_manageable—200
POST/manageable_volumescinder/api/v3/volume_manage.py:37volume_extension:volume_managevolume_manage.volume_manage_create@3.0, volume_manage.volume_manage_create_v316@3.16202
GET/manageable_volumescinder/api/v3/resource_common_manage.py:78volume_extension:list_manageable—200
GET/manageable_snapshots/detailcinder/api/v3/resource_common_manage.py:83snapshot_extension:list_manageable—200
POST/manageable_snapshotscinder/api/v3/snapshot_manage.py:34snapshot_extension:snapshot_managesnapshot_manage.create202
GET/manageable_snapshotscinder/api/v3/resource_common_manage.py:78snapshot_extension:list_manageable—200
GET/backups/detailcinder/api/v3/backups.py:93backup:backup_project_attribute
backup:get_all
—200
POST/backupscinder/api/contrib/backups.py:153backup:createbackups.create@3.0, backups.create_backup_v343@3.43, backups.create_backup_v351@3.51202
GET/backupscinder/api/contrib/backups.py:76backup:get_all—200
PUT/backups/{id}cinder/api/v3/backups.py:41backup:update3.9+backups.update@3.9, backups.update_backup_v343@3.43200
DELETE/backups/{id}cinder/api/contrib/backups.py:63backup:delete—202
GET/backups/{id}cinder/api/v3/backups.py:73backup:backup_project_attribute
backup:get
—200
GET/attachments/detailcinder/api/v3/attachments.py:71—3.27+—200
POST/attachmentscinder/api/v3/attachments.py:113volume:attachment_create
volume:multiattach_bootable_volume
3.27+attachments.create@3.27, attachments.create_v354@3.54200
GET/attachmentscinder/api/v3/attachments.py:65—3.27+—200
POST/attachments/{id}/action {"os-complete"}cinder/api/v3/attachments.py:289volume:attachment_complete3.44+attachments.complete204
PUT/attachments/{id}cinder/api/v3/attachments.py:215volume:attachment_update3.27+attachments.update200
DELETE/attachments/{id}cinder/api/v3/attachments.py:271volume:attachment_delete3.27+—200
GET/attachments/{id}cinder/api/v3/attachments.py:53—3.27+—200
POST/workers/cleanupcinder/api/v3/workers.py:43workers:cleanup3.24+workers.cleanup202
GET/resource_filterscinder/api/v3/resource_filters.py:32—3.33+—200
GET/volume-transfers/detailcinder/api/v3/volume_transfer.py:75volume:get_all_transfers—200
POST/volume-transferscinder/api/v3/volume_transfer.py:83—volume_transfer.create@3.0, volume_transfer.create_v355@3.55202
GET/volume-transferscinder/api/v3/volume_transfer.py:71——200
POST/volume-transfers/{id}/acceptcinder/api/contrib/volume_transfer.py:112volume:accept_transfervolume_transfer.accept202
DELETE/volume-transfers/{id}cinder/api/contrib/volume_transfer.py:137volume:delete_transfer—202
GET/volume-transfers/{id}cinder/api/contrib/volume_transfer.py:42volume:get_transfer—200
PUT/default-types/{id}cinder/api/v3/default_types.py:45—3.62+default_types.create_or_update200
GET/default-typescinder/api/v3/default_types.py:84volume_extension:default_get_all3.62+—200
GET/default-types/{id}cinder/api/v3/default_types.py:68volume_extension:default_get3.62+—200
DELETE/default-types/{id}cinder/api/v3/default_types.py:100volume_extension:default_unset3.62+—204
GET/os-servicescinder/api/v3/services.py:54volume_extension:services:index—200
PUT/os-services/enablecinder/api/v3/services.py:277—services.enable_and_disable200
PUT/os-services/disablecinder/api/v3/services.py:302—services.enable_and_disable200
PUT/os-services/disable-log-reasoncinder/api/v3/services.py:243—services.disable_log_reason200
PUT/os-services/get-logcinder/api/v3/services.py:212—3.32+services.get_log200
PUT/os-services/set-logcinder/api/v3/services.py:190—3.32+services.set_log202
PUT/os-services/freezecinder/api/v3/services.py:130volume:freeze_hostservices.freeze_and_thaw200
PUT/os-services/thawcinder/api/v3/services.py:142volume:thaw_hostservices.freeze_and_thaw200
PUT/os-services/failover_hostcinder/api/v3/services.py:152volume:failover_hostservices.failover_host202
GET/extensionscinder/api/extensions.py:95——200
GET/extensions/{id}cinder/api/extensions.py:101——200
GET/cgsnapshots/detailcinder/api/contrib/cgsnapshots.py:87——200
POST/cgsnapshotscinder/api/contrib/cgsnapshots.py:123—cgsnapshots.create202
GET/cgsnapshotscinder/api/contrib/cgsnapshots.py:82——200
DELETE/cgsnapshots/{id}cinder/api/contrib/cgsnapshots.py:60——202
GET/cgsnapshots/{id}cinder/api/contrib/cgsnapshots.py:49——200
GET/volumes/{volume_id}/encryptioncinder/api/contrib/volume_encryption_metadata.py:28volume_extension:volume_encryption_metadata—200
GET/volumes/{volume_id}/encryption/{id}cinder/api/contrib/volume_encryption_metadata.py:36volume_extension:volume_encryption_metadata—200
POST/backups/import_recordcinder/api/contrib/backups.py:257—backups.import_record201
POST/backups/{id}/restorecinder/api/contrib/backups.py:206backup:restorebackups.restore202
POST/backups/{id}/action {"os-force_delete"}cinder/api/contrib/admin_actions.py:338volume_extension:backup_admin_actions:force_deleteadmin_actions.force_delete_backup202
POST/backups/{id}/action {"os-reset_status"}cinder/api/contrib/admin_actions.py:319volume_extension:backup_admin_actions:reset_statusadmin_actions.reset_status_backup202
GET/backups/{id}/export_recordcinder/api/contrib/backups.py:239——200
GET/os-volume-transfer/detailcinder/api/contrib/volume_transfer.py:55volume:get_all_transfers—200
POST/os-volume-transfercinder/api/contrib/volume_transfer.py:83volume:create_transfervolume_transfer.create202
GET/os-volume-transfercinder/api/contrib/volume_transfer.py:51volume:get_all_transfers—200
POST/os-volume-transfer/{id}/acceptcinder/api/contrib/volume_transfer.py:112volume:accept_transfervolume_transfer.accept202
DELETE/os-volume-transfer/{id}cinder/api/contrib/volume_transfer.py:137volume:delete_transfer—202
GET/os-volume-transfer/{id}cinder/api/contrib/volume_transfer.py:42volume:get_transfer—200
GET/types/{type_id}/os-volume-type-accesscinder/api/contrib/volume_type_access.py:41volume_extension:volume_type_access:get_all_for_type—200
GET/scheduler-stats/get_poolscinder/api/contrib/scheduler_stats.py:42scheduler_extension:scheduler_stats:get_pools—200
POST/qos-specscinder/api/contrib/qos_specs_manage.py:80volume_extension:qos_specs_manage:createqos_specs.create200
GET/qos-specscinder/api/contrib/qos_specs_manage.py:59volume_extension:qos_specs_manage:get_all—200
GET/qos-specs/{id}/associationscinder/api/contrib/qos_specs_manage.py:229volume_extension:qos_specs_manage:get_all—200
GET/qos-specs/{id}/associatecinder/api/contrib/qos_specs_manage.py:262volume_extension:qos_specs_manage:update—202
GET/qos-specs/{id}/disassociatecinder/api/contrib/qos_specs_manage.py:314volume_extension:qos_specs_manage:update—202
GET/qos-specs/{id}/disassociate_allcinder/api/contrib/qos_specs_manage.py:357volume_extension:qos_specs_manage:update—202
PUT/qos-specs/{id}/delete_keyscinder/api/contrib/qos_specs_manage.py:202volume_extension:qos_specs_manage:deleteqos_specs.unset202
PUT/qos-specs/{id}cinder/api/contrib/qos_specs_manage.py:119volume_extension:qos_specs_manage:updateqos_specs.set200
DELETE/qos-specs/{id}cinder/api/contrib/qos_specs_manage.py:162volume_extension:qos_specs_manage:delete—202
GET/qos-specs/{id}cinder/api/contrib/qos_specs_manage.py:152volume_extension:qos_specs_manage:get—200
PUT/os-hostscinder/api/contrib/hosts.py:110—hosts.update200
GET/os-hostscinder/api/contrib/hosts.py:103volume_extension:hosts—200
PUT/os-hosts/{id}cinder/api/contrib/hosts.py:110volume_extension:hostshosts.update200
GET/os-hosts/{id}cinder/api/contrib/hosts.py:146volume_extension:hosts—200
POST/types/{type_id}/extra_specscinder/api/contrib/types_extra_specs.py:86volume_extension:types_extra_specs:createtypes_extra_specs.create200
GET/types/{type_id}/extra_specscinder/api/contrib/types_extra_specs.py:55volume_extension:types_extra_specs:index
volume_extension:types_extra_specs:read_sensitive
—200
PUT/types/{type_id}/extra_specs/{id}cinder/api/contrib/types_extra_specs.py:115volume_extension:types_extra_specs:updatetypes_extra_specs.update200
DELETE/types/{type_id}/extra_specs/{id}cinder/api/contrib/types_extra_specs.py:161volume_extension:types_extra_specs:delete—202
GET/types/{type_id}/extra_specs/{id}cinder/api/contrib/types_extra_specs.py:148volume_extension:types_extra_specs:read_sensitive
volume_extension:types_extra_specs:show
—200
GET/os-volume-manage/detailcinder/api/contrib/volume_manage.py:170——200
POST/os-volume-managecinder/api/contrib/volume_manage.py:54—volume_manage.volume_manage_create@3.0, volume_manage.volume_manage_create_v316@3.16202
GET/os-volume-managecinder/api/contrib/volume_manage.py:161——200
PUT/os-quota-class-sets/{id}cinder/api/contrib/quota_classes.py:56volume_extension:quota_classes:updatequota_classes.update_quota_class200
GET/os-quota-class-sets/{id}cinder/api/contrib/quota_classes.py:42volume_extension:quota_classes:get—200
GET/os-snapshot-manage/detailcinder/api/contrib/snapshot_manage.py:122——200
POST/os-snapshot-managecinder/api/contrib/snapshot_manage.py:43—snapshot_manage.create202
GET/os-snapshot-managecinder/api/contrib/snapshot_manage.py:113——200
GET/capabilities/{id}cinder/api/contrib/capabilities.py:41volume_extension:capabilities—200
GET/os-availability-zonecinder/api/contrib/availability_zones.py:31——200
POST/consistencygroups/create_from_srccinder/api/contrib/consistencygroups.py:188—consistencygroups.create_from_src202
POST/consistencygroups/{id}/deletecinder/api/contrib/consistencygroups.py:64—consistencygroups.delete202
PUT/consistencygroups/{id}/updatecinder/api/contrib/consistencygroups.py:267—consistencygroups.update202
GET/os-quota-sets/{id}/defaultscinder/api/contrib/quotas.py:145——200
PUT/os-quota-sets/{id}cinder/api/contrib/quotas.py:90volume_extension:quotas:updatequotas.update200
DELETE/os-quota-sets/{id}cinder/api/contrib/quotas.py:153volume_extension:quotas:delete—200
GET/os-quota-sets/{id}cinder/api/contrib/quotas.py:69volume_extension:quotas:show—200
POST/types/{type_id}/encryptioncinder/api/contrib/volume_type_encryption.py:69volume_extension:volume_type_encryption:createvolume_type_encryption.create200
GET/types/{type_id}/encryptioncinder/api/contrib/volume_type_encryption.py:60volume_extension:volume_type_encryption:get—200
PUT/types/{type_id}/encryption/{id}cinder/api/contrib/volume_type_encryption.py:97volume_extension:volume_type_encryption:updatevolume_type_encryption.update200
DELETE/types/{type_id}/encryption/{id}cinder/api/contrib/volume_type_encryption.py:135volume_extension:volume_type_encryption:delete—202
GET/types/{type_id}/encryption/{id}cinder/api/contrib/volume_type_encryption.py:121volume_extension:volume_type_encryption:get—200

Plus GET / (version list, 300, cinder/api/versions.py:87-92) and GET /v3/ (version document, cinder/api/versions.py:76-79). The router also declares routes whose controller has no method (for example GET /volumes/new, PUT /limits/{id}): they answer 404, or 400 "There is no such action" when the controller has body actions. They are listed in [_rewrite/routes-unimplemented_stable-2026.2.json](_rewrite/routes-unimplemented_stable-2026.2.json) and must not be implemented by a rewrite.

Spec/code mismatches

  • os-extend_volume_completion is documented as added in 3.71, but mv.EXTEND_VOLUME_COMPLETION is never used: the action exists at every microversion for whoever passes the policy (cinder/api/microversions.py:182, cinder/api/contrib/admin_actions.py:205-214).
  • The policy operations contain 13 entries that match no route (PUT /clusters/{id}, POST /backups/{id}/export_record instead of GET, GET /os-quota-sets/{id}/default instead of defaults, /volume_transfers instead of /volume-transfers…), listed in [_rewrite/policy-operations-unmatched_stable-2026.2.json](_rewrite/policy-operations-unmatched_stable-2026.2.json). 58 operations have no policy rule in any operations list; their checks are in the code.
  • associate, disassociate and disassociate_all on QoS specs change data with GET (cinder/api/contrib/qos_specs_manage.py:262-370).
  • os-hosts and consistencygroups/cgsnapshots are deprecated but routed.

4. Lifecycles

Volume

stateDiagram-v2
  [*] --> creating: POST /volumes (API)
  creating --> available: create flow done (cinder-volume)
  creating --> error: no valid backend (scheduler) / driver failure (cinder-volume)
  creating --> downloading: create from image (cinder-volume)
  downloading --> available: image copied
  available --> reserved: POST /attachments or os-reserve (API)
  reserved --> attaching: os-attach (API)
  reserved --> in_use: attachments os-complete (API)
  attaching --> in_use: attach_volume (RPC call)
  in_use --> detaching: os-begin_detaching (API)
  detaching --> available: detach_volume / attachment_delete (RPC call)
  available --> extending: os-extend (API)
  in_use --> extending: os-extend >= 3.42 (API)
  extending --> available: extend_volume (cinder-volume)
  extending --> in_use: extend_volume (attached)
  extending --> error_extending: driver failure
  available --> retyping: os-retype (API)
  retyping --> available: retype done
  available --> uploading: os-volume_upload_image (API)
  uploading --> available: copy_volume_to_image done
  available --> backing_up: POST /backups (API)
  backing_up --> available: backup done (cinder-backup)
  available --> restoring_backup: POST /backups/{id}/restore (API)
  restoring_backup --> available: restore done
  restoring_backup --> error_restoring: restore failure
  available --> awaiting_transfer: POST /volume-transfers (API)
  awaiting_transfer --> available: accept or DELETE transfer
  available --> reverting: revert (API)
  reverting --> available: revert_to_snapshot (cinder-volume)
  available --> deleting: DELETE (API)
  error --> deleting: DELETE (API)
  deleting --> [*]: delete_volume (cinder-volume)
  deleting --> error_deleting: driver failure
  available --> maintenance: migration (cinder-volume)

in_use, backing_up, restoring_backup, awaiting_transfer stand for in-use, backing-up, restoring-backup, awaiting-transfer (Mermaid identifiers cannot contain -). The statuses are listed in cinder/objects/fields.py:162-191; os-reset_status can set any of them.

Attachment (volume_attachment.attach_status)

stateDiagram-v2
  [*] --> reserved: POST /attachments without connector
  reserved --> attaching: PUT /attachments/{id} with connector (connection_info returned)
  [*] --> attaching: POST /attachments with connector
  attaching --> attached: os-complete
  attached --> detached: DELETE /attachments/{id}
  reserved --> detached: DELETE /attachments/{id}
  attaching --> error_attaching: driver failure
  detached --> [*]

Statuses from cinder/objects/fields.py:145-152. [inferred] The intermediate attaching value is written by the volume manager's attachment_update.

Snapshot and backup

stateDiagram-v2
  [*] --> creating: POST /snapshots
  creating --> available: create_snapshot (cinder-volume)
  creating --> error: driver failure
  available --> deleting: DELETE
  error --> deleting: DELETE
  deleting --> [*]
  deleting --> error_deleting: driver failure
  available --> backing_up: backup of the snapshot
  backing_up --> available
  available --> restoring: revert (volume)
  restoring --> available
stateDiagram-v2
  [*] --> creating: POST /backups
  creating --> available: create_backup (cinder-backup)
  creating --> error: driver failure / backup service down
  available --> restoring: POST /backups/{id}/restore
  restoring --> available: restore done
  available --> deleting: DELETE
  error --> deleting: DELETE
  deleting --> deleted: delete_backup (cinder-backup)
  deleting --> error_deleting: driver failure

Statuses from cinder/objects/fields.py:25-36 and cinder/objects/fields.py:113-127.

Source: reverse-spec-cinder/01-rest-api_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.