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

Reverse-spec · Services

cinder — Scenarios

End-to-end scenarios — 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

Five flows that cover most of what an operator sees. Error statuses refer to 02-errors_stable-2026.2.md, and asynchronous steps to 05-async-processing_stable-2026.2.md.

1. Creating a volume (from an image)

A project member creates a 10 GiB bootable volume from a Glance image. The API only records the request; the scheduler chooses a pool and the volume service does the work, possibly through the image-volume cache.

sequenceDiagram
  autonumber
  actor U as User
  participant API as cinder-api
  participant DB as MariaDB
  participant MQ as RabbitMQ
  participant SCH as cinder-scheduler
  participant VOL as cinder-volume (host@backend)
  participant G as Glance
  participant ARR as Storage array
  U->>API: POST /v3/{project_id}/volumes {"volume": {"size": 10, "imageRef": "…"}}
  API->>G: GET /v2/images/{id} (size, min_disk, status)
  API->>DB: SELECT quota_usages … FOR UPDATE; INSERT reservations
  alt quota exceeded
    API-->>U: 413 overLimit VolumeSizeExceedsAvailableQuota
  end
  API->>DB: INSERT volumes (status=creating); commit reservations
  API->>MQ: cast create_volume (topic cinder-scheduler)
  API-->>U: 202 {"volume": {"status": "creating", …}}
  MQ->>SCH: create_volume
  SCH->>SCH: filters (AZ, capacity, capabilities) + weighers on cached pool stats
  alt no valid backend
    SCH->>DB: UPDATE volumes SET status='error'; INSERT messages (VOLUME_VOLUME_001_003)
  else backend found
    SCH->>DB: UPDATE volumes SET host='node1@lvm#pool'
    SCH->>MQ: cast create_volume (topic cinder-volume.node1@lvm, server node1)
    MQ->>VOL: create_volume
    VOL->>VOL: create flow (notification volume.create.start)
    alt image already in the image-volume cache
      VOL->>ARR: clone the cached volume
    else cache miss
      VOL->>ARR: create volume
      VOL->>G: GET /v2/images/{id}/file
      VOL->>ARR: write the image (qemu-img convert through os-brick)
    end
    alt driver failure and attempts left
      VOL->>MQ: cast create_volume to the scheduler (retry, backend excluded)
    else success
      VOL->>DB: UPDATE volumes SET status='available', bootable=true; INSERT volume_glance_metadata
      VOL->>MQ: notify volume.create.end
    end
  end
  U->>API: GET /v3/{project_id}/volumes/{id} (polling)
  API-->>U: 200 status available | error

Diagnostics: a volume stuck in creating means no scheduler consumed the message (check cinder-scheduler is up and the queue cinder-scheduler), or the chosen volume service died during the flow (its workers row lets init_host or POST /workers/cleanup set it to error). A volume in error right away: read GET /v3/{project_id}/messages?resource_uuid=<id>; VOLUME_VOLUME_001_003 = no pool passed the filters (look at GET /scheduler-stats/get_pools?detail=true: capacity, reserved_percentage, oversubscription). Errors after the scheduler: the cinder-volume log, request ID req-….

2. Attaching a volume to a Nova instance (attachments API)

Nova uses the attachments API (3.27+): reservation, then connection with the compute host's connector, then completion. The attachment and connection info returned by Cinder are what Nova's os-brick uses to connect the host.

sequenceDiagram
  autonumber
  participant N as nova-compute
  participant API as cinder-api
  participant DB as MariaDB
  participant VOL as cinder-volume
  participant ARR as Storage array
  N->>API: POST /v3/{project_id}/attachments {"attachment": {"volume_uuid", "instance_uuid"}} (3.44+)
  API->>DB: UPDATE volumes SET status='reserved' WHERE status IN ('available','downloading') (or in-use if multiattach)
  API->>DB: INSERT volume_attachment (attach_status=reserved)
  API-->>N: 200 {"attachment": {"id", "status": "reserved", "connection_info": {}}}
  N->>API: PUT /v3/{project_id}/attachments/{id} {"attachment": {"connector": {"host", "initiator", "ip", "multipath"…}}}
  API->>API: lock cinder-attachment_update-<volume>-<host>
  API->>VOL: RPC call attachment_update(connector)
  VOL->>ARR: create_export + initialize_connection (map LUN to initiator)
  VOL->>DB: UPDATE volume_attachment SET connection_info, connector, attach_status='attaching'
  VOL-->>API: connection_info {"driver_volume_type": "iscsi", "data": {…}}
  alt driver error or RPC timeout
    API-->>N: 500 "Unable to update the attachment" / computeFault
  end
  API-->>N: 200 {"attachment": {"connection_info": {…}}}
  N->>N: os-brick connect_volume on the compute host
  N->>API: POST /v3/{project_id}/attachments/{id}/action {"os-complete": null}
  API->>DB: attachment attached; volume in-use, attach_status attached
  API-->>N: 204
  Note over N,API: Detach: DELETE /v3/{project_id}/attachments/{id}, sent with a service token, then RPC call attachment_delete (terminate_connection, remove_export)

Diagnostics: 409 ConflictNovaUsingAttachment on DELETE means the call did not carry Nova's service token ([service_user] in nova.conf) while the attachment is connected. 409 on PUT means another host already has a connection to a non-multiattach volume. A 500 on PUT: look in the cinder-volume log for the driver error of initialize_connection; the attachment stays reserved and Nova should delete it.

3. Extending an attached volume

From microversion 3.42, os-extend works on in-use volumes. Cinder extends the LUN, then asks Nova to make the guest see the new size.

sequenceDiagram
  autonumber
  actor U as User
  participant API as cinder-api
  participant DB as MariaDB
  participant SCH as cinder-scheduler
  participant VOL as cinder-volume
  participant NOVA as Nova API
  U->>API: POST /v3/{project_id}/volumes/{id}/action {"os-extend": {"new_size": 20}} (OpenStack-API-Version: volume 3.42)
  API->>DB: UPDATE volumes SET status='extending', previous_status='in-use' WHERE status='in-use'
  API->>DB: reserve quota gigabytes +10
  alt over quota
    API->>DB: status back to in-use
    API-->>U: 413 VolumeSizeExceedsAvailableQuota
  end
  API->>SCH: cast extend_volume
  API-->>U: 202
  SCH->>SCH: backend_passes_filters (capacity of the volume's own pool)
  alt not enough capacity
    SCH->>DB: status back to in-use; rollback quota; user message
  else
    SCH->>VOL: cast extend_volume
    VOL->>VOL: driver.extend_volume
    alt driver failure
      VOL->>DB: status error_extending; rollback quota; message VOLUME_VOLUME_007_010
    else
      VOL->>DB: commit quota; size=20; status in-use; notify volume.resize.end
      VOL->>NOVA: POST /v2.1/os-server-external-events [{"name": "volume-extended", "server_uuid", "tag": volume_id}] (2.51, [nova] service user)
      alt Nova error
        VOL->>DB: user message VOLUME_VOLUME_007_009
      end
    end
  end

Diagnostics: the volume is bigger in Cinder but not in the guest → the Nova event failed (message 007_009, Nova [nova] credentials in cinder.conf, Nova API logs for volume-extended). error_extending → driver failure; an operator can os-reset_status back to in-use after checking the array.

4. Backing up and restoring a volume

sequenceDiagram
  autonumber
  actor U as User
  participant API as cinder-api
  participant DB as MariaDB
  participant SCH as cinder-scheduler
  participant BK as cinder-backup
  participant VOL as cinder-volume
  participant S as Backup store (Swift…)
  U->>API: POST /v3/{project_id}/backups {"backup": {"volume_id", "incremental": false, "force": true}}
  API->>DB: reserve quota backups, backup_gigabytes
  API->>DB: UPDATE volumes SET status='backing-up', previous_status=<status>
  API->>DB: INSERT backups (status creating)
  API->>SCH: cast create_backup
  API-->>U: 202 {"backup": {"id", "name"}}
  SCH->>SCH: pick a live cinder-backup in the AZ
  alt no backup service
    SCH->>DB: backup error, volume previous status, message BACKUP_SCHEDULE_ERROR
  else
    SCH->>BK: cast create_backup (topic cinder-backup.<host>)
    BK->>VOL: RPC call get_backup_device (temporary snapshot/clone if in-use)
    BK->>BK: attach the device locally (os-brick)
    loop each chunk
      BK->>S: PUT object (compressed, sha256 per chunk)
      BK-->>BK: notify backup.createprogress
    end
    BK->>DB: backup available (size, object count); volume back to previous status
  end
  U->>API: POST /v3/{project_id}/backups/{id}/restore {"restore": {"volume_id": …}}
  API->>DB: backup restoring; volume restoring-backup
  API->>BK: cast restore_backup
  BK->>S: GET objects
  BK->>DB: backup available; volume available (or error_restoring)

Diagnostics: POST /backups returning 503 means no cinder-backup service is up (heartbeat), often because its driver never initialised (_setup_backup_driver loops every backup_driver_init_check_interval, and the service sends no heartbeat while it does). Backup in error: read fail_reason on the backup and the user messages.

5. Deleting an encrypted volume

sequenceDiagram
  autonumber
  actor U as User
  participant API as cinder-api
  participant DB as MariaDB
  participant KM as Barbican
  participant VOL as cinder-volume
  participant ARR as Storage array
  U->>API: DELETE /v3/{project_id}/volumes/{id}
  API->>DB: conditional UPDATE status='deleting' (not attached, no snapshots, status in available/error/…)
  alt condition not met
    API-->>U: 400 InvalidVolume "Volume … must not be migrating, attached, …"
  end
  API->>DB: evict image-volume cache entry if any
  API->>KM: DELETE secret encryption_key_id
  alt key deletion fails
    API->>DB: status error_deleting
    API-->>U: 400 "Unable to delete encryption key for volume"
  end
  API->>VOL: cast delete_volume
  API-->>U: 202
  VOL->>VOL: lock cinder-<id>-delete_volume
  VOL->>ARR: remove_export, delete_volume
  alt array says busy
    VOL->>DB: status available
  else failure
    VOL->>DB: status error_deleting
  else success
    VOL->>DB: release quotas; soft-delete volume; notify volume.delete.end
  end

Diagnostics: the key is deleted before the backend deletion: a volume left in error_deleting after this point can no longer be decrypted, so only a force delete makes sense. A volume that was never scheduled (no host) is deleted directly by the API, without RPC (cinder/volume/api.py:423-455).

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