Interactions — 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
Cinder is four cooperating processes around one SQL database and one RabbitMQ bus (see summary): cinder-api (REST), cinder-scheduler, cinder-volume (one per host, one backend per enabled_backends entry) and cinder-backup. The API never touches storage itself: it writes the database and sends RPC messages.
1. RabbitMQ (oslo.messaging)
1.1 Transport and serialisation
- Transport from
[DEFAULT]/transport_url;rpc.initcreates the RPC transport, the notification transport and the notifier (cinder/rpc.py:58-76). The exchange is oslo.messaging's default **openstack**:rpc.set_defaults(control_exchange)exists but no Cinder process calls it (cinder/rpc.py:91-92) [inferred: confirmed by grep, the default comes from oslo.messaging]. - Arguments travel as versioned objects (
cinder_object.name,cinder_object.version,cinder_object.data…) throughCinderObjectSerializer, pinned to the oldest object version of the running services (cinder/rpc.py:216-224,cinder/service.py:234-240). - Rolling upgrades: each client caps its RPC version to the minimum
rpc_current_versionrecorded in theservicestable for that binary (cinder/rpc.py:250-264); methods newer than the cap raiseServiceTooOld(cinder/rpc.py:183-199). The volume client falls back to the pre-3.6 addressing when the cap is lower (cinder/volume/rpcapi.py:150-168). - Remote exceptions allowed to be re-raised on the caller side:
cinder.exception(get_allowed_exmods,cinder/rpc.py:58-62).
1.2 Topology
| Exchange | Type | Routing key / queue | Producer | Consumer |
|---|---|---|---|---|
openstack | topic | cinder-scheduler (any scheduler), cinder-scheduler.<host> | cinder-api, cinder-volume | cinder-scheduler |
cinder-scheduler_fanout | fanout | cinder-scheduler_fanout_<uuid> | cinder-volume, cinder-backup (update_service_capabilities) | every scheduler |
openstack | topic | cinder-volume.<host>@<backend> with server <host> (RPC ≥ 3.6), and cinder-volume.<cluster>@<backend> for active-active clusters | cinder-api, cinder-scheduler, cinder-backup | the cinder-volume serving that backend (cinder/service.py:241-268) |
openstack | topic | cinder-volume with server <host>@<backend> (legacy, pre-3.6) | old clients | cinder-volume |
cinder-volume_fanout | fanout | cinder-api (publish_service_capabilities, failover_completed) | every cinder-volume | |
openstack | topic | cinder-backup, cinder-backup.<host> | cinder-scheduler, cinder-api | cinder-backup |
reply_<uuid> | direct | the callee of a call | the caller | |
openstack (notifications) | topic | notifications.info, notifications.error ([oslo_messaging_notifications]/topics) | all processes, driver messagingv2 | Ceilometer… |
The address of a volume is its host field, host@backend#pool; service_topic_queue is the cluster name when the volume belongs to a cluster, otherwise the host (cinder/volume/rpcapi.py:150-168).
1.3 RPC methods (clients in this repository)
RPC API versions: scheduler 3.12, volume 3.20, backup 2.4 (cinder/scheduler/rpcapi.py:78, cinder/volume/rpcapi.py:145, cinder/backup/rpcapi.py:54). "Version sent" — means the default 3.0 (2.0 for backup), capped as above. The server side is the method of the same name in cinder/scheduler/manager.py, cinder/volume/manager.py and cinder/backup/manager.py (async processing).
| Server | RPC method | Mode | Addressing | Version sent | Python client | Defined at |
|---|---|---|---|---|---|---|
| cinder-scheduler | create_group | cast | any server of the topic | 3.0 (2.0 for backup) | create_group | cinder/scheduler/rpcapi.py:97 |
| cinder-scheduler | create_volume | cast | any server of the topic | 3.0 (2.0 for backup) | create_volume | cinder/scheduler/rpcapi.py:110 |
| cinder-scheduler | validate_host_capacity | call | any server of the topic | 3.0 (2.0 for backup) | validate_host_capacity | cinder/scheduler/rpcapi.py:118 |
| cinder-scheduler | create_snapshot | cast | any server of the topic | 3.0 (2.0 for backup) | create_snapshot | cinder/scheduler/rpcapi.py:129 |
| cinder-scheduler | method | cast | any server of the topic | version | migrate_volume | cinder/scheduler/rpcapi.py:148 |
| cinder-scheduler | retype | cast | any server of the topic | 3.0 (2.0 for backup) | retype | cinder/scheduler/rpcapi.py:155 |
| cinder-scheduler | manage_existing | cast | any server of the topic | 3.0 (2.0 for backup) | manage_existing | cinder/scheduler/rpcapi.py:165 |
| cinder-scheduler | manage_existing_snapshot | cast | any server of the topic | 3.0 (2.0 for backup) | manage_existing_snapshot | cinder/scheduler/rpcapi.py:179 |
| cinder-scheduler | extend_volume | cast | any server of the topic | 3.0 (2.0 for backup) | extend_volume | cinder/scheduler/rpcapi.py:195 |
| cinder-scheduler | get_pools | call | any server of the topic | 3.0 (2.0 for backup) | get_pools | cinder/scheduler/rpcapi.py:199 |
| cinder-scheduler | update_service_capabilities | cast | fanout | version | update_service_capabilities | cinder/scheduler/rpcapi.py:222 |
| cinder-scheduler | notify_service_capabilities | cast | any server of the topic | version | notify_service_capabilities | cinder/scheduler/rpcapi.py:238 |
| cinder-scheduler | work_cleanup | call | any server of the topic | 3.4 | work_cleanup | cinder/scheduler/rpcapi.py:246 |
| cinder-scheduler | do_cleanup | cast | any server of the topic | 3.4 | do_cleanup | cinder/scheduler/rpcapi.py:253 |
| cinder-scheduler | set_log_levels | cast | server service.host | 3.7 | set_log_levels | cinder/scheduler/rpcapi.py:258 |
| cinder-scheduler | get_log_levels | call | server service.host | 3.7 | get_log_levels | cinder/scheduler/rpcapi.py:263 |
| cinder-scheduler | create_backup | cast | any server of the topic | 3.0 (2.0 for backup) | create_backup | cinder/scheduler/rpcapi.py:269 |
| cinder-volume | create_volume | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | create_volume | cinder/volume/rpcapi.py:177 |
| cinder-volume | revert_to_snapshot | cast | server of volume.service_topic_queue | version | revert_to_snapshot | cinder/volume/rpcapi.py:187 |
| cinder-volume | delete_volume | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | delete_volume | cinder/volume/rpcapi.py:202 |
| cinder-volume | create_snapshot | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | create_snapshot | cinder/volume/rpcapi.py:210 |
| cinder-volume | delete_snapshot | cast | server of snapshot.service_topic_queue | 3.0 (2.0 for backup) | delete_snapshot | cinder/volume/rpcapi.py:214 |
| cinder-volume | attach_volume | call | server of volume.service_topic_queue | ('3.3', '3.0') | attach_volume | cinder/volume/rpcapi.py:228 |
| cinder-volume | detach_volume | call | server of volume.service_topic_queue | ('3.4', '3.0') | detach_volume | cinder/volume/rpcapi.py:237 |
| cinder-volume | copy_volume_to_image | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | copy_volume_to_image | cinder/volume/rpcapi.py:241 |
| cinder-volume | initialize_connection | call | server of volume.service_topic_queue | 3.0 (2.0 for backup) | initialize_connection | cinder/volume/rpcapi.py:246 |
| cinder-volume | terminate_connection | call | server of volume.service_topic_queue | 3.0 (2.0 for backup) | terminate_connection | cinder/volume/rpcapi.py:251 |
| cinder-volume | remove_export | call | server of volume.service_topic_queue | 3.0 (2.0 for backup) | remove_export | cinder/volume/rpcapi.py:257 |
| cinder-volume | remove_export | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | remove_export | cinder/volume/rpcapi.py:259 |
| cinder-volume | publish_service_capabilities | cast | fanout | 3.0 (2.0 for backup) | publish_service_capabilities | cinder/volume/rpcapi.py:263 |
| cinder-volume | accept_transfer | call | server of volume.service_topic_queue | ('3.16', '3.0') | accept_transfer | cinder/volume/rpcapi.py:275 |
| cinder-volume | extend_volume | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | extend_volume | cinder/volume/rpcapi.py:279 |
| cinder-volume | extend_volume_completion | cast | server of volume.service_topic_queue | 3.19 | extend_volume_completion | cinder/volume/rpcapi.py:286 |
| cinder-volume | migrate_volume | cast | server of volume.service_topic_queue | version | migrate_volume | cinder/volume/rpcapi.py:300 |
| cinder-volume | migrate_volume_completion | call | server of volume.service_topic_queue | 3.0 (2.0 for backup) | migrate_volume_completion | cinder/volume/rpcapi.py:305 |
| cinder-volume | retype | cast | server of volume.service_topic_queue | version | retype | cinder/volume/rpcapi.py:320 |
| cinder-volume | manage_existing | cast | server of volume.service_topic_queue | 3.0 (2.0 for backup) | manage_existing | cinder/volume/rpcapi.py:327 |
| cinder-volume | update_migrated_volume | call | server of new_volume.service_topic_queue | 3.0 (2.0 for backup) | update_migrated_volume | cinder/volume/rpcapi.py:332 |
| cinder-volume | freeze_host | call | server of service.service_topic_queue | 3.0 (2.0 for backup) | freeze_host | cinder/volume/rpcapi.py:340 |
| cinder-volume | thaw_host | call | server of service.service_topic_queue | 3.0 (2.0 for backup) | thaw_host | cinder/volume/rpcapi.py:345 |
| cinder-volume | method | cast | server of service.service_topic_queue | version | failover | cinder/volume/rpcapi.py:355 |
| cinder-volume | failover_completed | cast | fanout | 3.8 | failover_completed | cinder/volume/rpcapi.py:361 |
| cinder-volume | manage_existing_snapshot | cast | server of backend | 3.0 (2.0 for backup) | manage_existing_snapshot | cinder/volume/rpcapi.py:365 |
| cinder-volume | get_capabilities | call | server of backend_id | 3.0 (2.0 for backup) | get_capabilities | cinder/volume/rpcapi.py:371 |
| cinder-volume | get_backup_device | cast | server of volume.service_topic_queue | ('3.17', '3.2', '3.0') | get_backup_device | cinder/volume/rpcapi.py:377 |
| cinder-volume | get_backup_device | call | server of volume.service_topic_queue | ('3.17', '3.2', '3.0') | get_backup_device | cinder/volume/rpcapi.py:381 |
| cinder-volume | get_backup_device | call | server of volume.service_topic_queue | ('3.17', '3.2', '3.0') | get_backup_device | cinder/volume/rpcapi.py:384 |
| cinder-volume | secure_file_operations_enabled | call | server of volume.service_topic_queue | 3.0 (2.0 for backup) | secure_file_operations_enabled | cinder/volume/rpcapi.py:391 |
| cinder-volume | get_manageable_volumes | call | server of service.service_topic_queue | version | get_manageable_volumes | cinder/volume/rpcapi.py:409 |
| cinder-volume | get_manageable_snapshots | call | server of service.service_topic_queue | version | get_manageable_snapshots | cinder/volume/rpcapi.py:426 |
| cinder-volume | create_group | cast | server of group.service_topic_queue | 3.0 (2.0 for backup) | create_group | cinder/volume/rpcapi.py:432 |
| cinder-volume | delete_group | cast | server of group.service_topic_queue | 3.0 (2.0 for backup) | delete_group | cinder/volume/rpcapi.py:436 |
| cinder-volume | update_group | cast | server of group.service_topic_queue | 3.0 (2.0 for backup) | update_group | cinder/volume/rpcapi.py:440 |
| cinder-volume | create_group_from_src | cast | server of group.service_topic_queue | 3.0 (2.0 for backup) | create_group_from_src | cinder/volume/rpcapi.py:446 |
| cinder-volume | create_group_snapshot | cast | server of group_snapshot.service_topic_queue | 3.0 (2.0 for backup) | create_group_snapshot | cinder/volume/rpcapi.py:451 |
| cinder-volume | delete_group_snapshot | cast | server of group_snapshot.service_topic_queue | 3.0 (2.0 for backup) | delete_group_snapshot | cinder/volume/rpcapi.py:456 |
| cinder-volume | initialize_connection_snapshot | call | server of snapshot.service_topic_queue | 3.13 | initialize_connection_snapshot | cinder/volume/rpcapi.py:462 |
| cinder-volume | terminate_connection_snapshot | call | server of snapshot.service_topic_queue | 3.13 | terminate_connection_snapshot | cinder/volume/rpcapi.py:470 |
| cinder-volume | remove_export_snapshot | call | server of snapshot.service_topic_queue | 3.13 | remove_export_snapshot | cinder/volume/rpcapi.py:478 |
| cinder-volume | remove_export_snapshot | cast | server of snapshot.service_topic_queue | 3.13 | remove_export_snapshot | cinder/volume/rpcapi.py:480 |
| cinder-volume | attachment_update | call | server of vref.service_topic_queue | version | attachment_update | cinder/volume/rpcapi.py:486 |
| cinder-volume | attachment_delete | call | server of vref.service_topic_queue | version | attachment_delete | cinder/volume/rpcapi.py:496 |
| cinder-volume | do_cleanup | cast | server of destination | 3.7 | do_cleanup | cinder/volume/rpcapi.py:509 |
| cinder-volume | set_log_levels | cast | server of service.host | 3.12 | set_log_levels | cinder/volume/rpcapi.py:514 |
| cinder-volume | get_log_levels | call | server of service.host | 3.12 | get_log_levels | cinder/volume/rpcapi.py:519 |
| cinder-volume | enable_replication | cast | server of group.service_topic_queue | 3.14 | enable_replication | cinder/volume/rpcapi.py:524 |
| cinder-volume | disable_replication | cast | server of group.service_topic_queue | 3.14 | disable_replication | cinder/volume/rpcapi.py:530 |
| cinder-volume | failover_replication | cast | server of group.service_topic_queue | 3.14 | failover_replication | cinder/volume/rpcapi.py:537 |
| cinder-volume | list_replication_targets | call | server of group.service_topic_queue | 3.14 | list_replication_targets | cinder/volume/rpcapi.py:544 |
| cinder-volume | reimage | cast | server of volume.service_topic_queue | ('3.20', '3.18') | reimage | cinder/volume/rpcapi.py:552 |
| cinder-volume | reimage | cast | server of volume.service_topic_queue | ('3.20', '3.18') | reimage | cinder/volume/rpcapi.py:555 |
| cinder-backup | create_backup | cast | server backup.host | 3.0 (2.0 for backup) | create_backup | cinder/backup/rpcapi.py:62 |
| cinder-backup | continue_backup | cast | server backup.host | 3.0 (2.0 for backup) | continue_backup | cinder/backup/rpcapi.py:67 |
| cinder-backup | restore_backup | cast | server backup_host | 3.0 (2.0 for backup) | restore_backup | cinder/backup/rpcapi.py:75 |
| cinder-backup | restore_backup | cast | server backup_host | 3.0 (2.0 for backup) | restore_backup | cinder/backup/rpcapi.py:78 |
| cinder-backup | delete_backup | cast | server backup.host | 3.0 (2.0 for backup) | delete_backup | cinder/backup/rpcapi.py:84 |
| cinder-backup | export_record | call | server backup.host | 3.0 (2.0 for backup) | export_record | cinder/backup/rpcapi.py:92 |
| cinder-backup | import_record | cast | server host | 3.0 (2.0 for backup) | import_record | cinder/backup/rpcapi.py:100 |
| cinder-backup | reset_status | cast | server backup.host | 3.0 (2.0 for backup) | reset_status | cinder/backup/rpcapi.py:111 |
| cinder-backup | check_support_to_force_delete | call | server host | 3.0 (2.0 for backup) | check_support_to_force_delete | cinder/backup/rpcapi.py:117 |
| cinder-backup | set_log_levels | cast | server service.host | 2.1 | set_log_levels | cinder/backup/rpcapi.py:122 |
| cinder-backup | get_log_levels | call | server service.host | 2.1 | get_log_levels | cinder/backup/rpcapi.py:127 |
| cinder-backup | publish_service_capabilities | cast | fanout | 2.2 | publish_service_capabilities | cinder/backup/rpcapi.py:132 |
Timeouts: a call waits [DEFAULT]/rpc_response_timeout (oslo.messaging default 60 s) and raises MessagingTimeout; the synchronous calls on the request path of the API are initialize_connection, terminate_connection, attach_volume, detach_volume, attachment_update, attachment_delete, accept_transfer, get_capabilities, get_manageable_*, get_pools, migrate_volume_completion, freeze_host/thaw_host, list_replication_targets, export_record.
1.4 Sample frame — create_volume cast from the scheduler to cinder-volume
{"oslo.version": "2.0",
"oslo.message": "{\"method\": \"create_volume\", \"version\": \"3.0\", \"namespace\": null,
\"args\": {\"volume\": {\"cinder_object.name\": \"Volume\", \"cinder_object.namespace\": \"cinder\",
\"cinder_object.version\": \"1.9\", \"cinder_object.data\": {\"id\": \"…\", \"size\": 10, \"status\": \"creating\", \"host\": \"node1@lvm#lvm\", …}},
\"request_spec\": {\"cinder_object.name\": \"RequestSpec\", …},
\"filter_properties\": {\"retry\": {\"num_attempts\": 1, \"backends\": [\"node1@lvm#lvm\"], \"hosts\": [\"node1@lvm#lvm\"]}, …},
\"allow_reschedule\": true},
\"_unique_id\": \"…\", \"_context_request_id\": \"req-…\", \"_context_project_id\": \"…\", \"_context_user_id\": \"…\",
\"_context_is_admin\": false, \"_context_roles\": [\"member\", \"reader\"], \"_context_auth_token\": \"…\", …}"}
Routing key cinder-volume.node1@lvm, server node1. [inferred] The object versions depend on cinder/objects/*.py (VERSION), and the context fields on RequestContext.to_dict (cinder/context.py); the user token travels in the message (_context_auth_token), because the volume service calls Glance, Nova and Barbican on the user's behalf.
1.5 Notifications
Published with priority INFO unless stated, publisher_id = "<service>.<host>" (cinder/rpc.py:172-179), only when [oslo_messaging_notifications]/driver is set (cinder/rpc.py:69-75).
| event_type | When | Payload | Emitted at |
|---|---|---|---|
volume.create.start/end, volume.delete.start/end, volume.update.start/end, volume.attach.start/end, volume.detach.start/end, volume.resize.start/end, volume.retype, volume.revert.start/end, volume.transfer.{create,accept,delete}.start/end, volume.manage_existing.start/end, volume.exists | volume lifecycle; exists from cinder-volume-usage-audit | tenant, user, AZ, volume id, type id, name, status, size, created/launched at, snapshot id, replication fields, metadata, attachments, Glance metadata (cinder/volume/volume_utils.py:93-134) | cinder/volume/volume_utils.py:162-177 |
snapshot.{create,delete,update,revert}.start/end, snapshot.exists | snapshot lifecycle | cinder/volume/volume_utils.py:197-224 | cinder/volume/volume_utils.py:225-240 |
backup.{create,delete,restore}.start/end, backup.createprogress, backup.reset_status.end, backup.exists | backup lifecycle and progress of chunked drivers | cinder/volume/volume_utils.py:137-158 | cinder/volume/volume_utils.py:180-195 |
group.*, group_snapshot.*, consistencygroup.*, cgsnapshot.* | group operations, including replication enable/disable/failover | cinder/volume/volume_utils.py:293-417 | |
capacity.pool | each stats report of a backend | pool capacities | cinder/volume/volume_utils.py:261-276 |
scheduler.create_volume, scheduler.<method> (ERROR) | scheduling failure | request spec, volume id, state, reason | cinder/scheduler/manager.py:505-541 |
volume_type.*, volume_type_extra_specs.*, volume_type_encryption.*, qos_specs.*, group_type.*, groups.reset_status.* | administrative API changes | cinder/api/contrib/types_manage.py:40-51, cinder/api/contrib/qos_specs_manage.py | |
volume_type_project.access.add/remove [inferred name] | private type access | cinder/volume/volume_types.py:279-300 | |
image_volume_cache.{hit,miss,evict} | image-volume cache use | image id, host | cinder/image/cache.py:257 |
2. Database (oslo.db, SQLAlchemy)
[database]/connection; 35 tables plus alembic_version. The model DDL is in [_rewrite/schema-mysql_stable-2026.2.sql](_rewrite/schema-mysql_stable-2026.2.sql); the schema produced by the migrations, in [_rewrite/schema-sqlite-migrated_stable-2026.2.sql](_rewrite/schema-sqlite-migrated_stable-2026.2.sql). They differ only by two leftover columns (§ 2.3). Every model has created_at, updated_at, deleted_at and deleted (soft delete) through CinderBase (cinder/db/models.py:40-62).
2.1 Tables
| Table | Role | Written by | Read by |
|---|---|---|---|
services | one row per process and backend: host, binary, topic, AZ, report_count heartbeat, disabled, versions (rpc_current_version, object_current_version), replication and frozen state, cluster | every service at start and every report_interval | API (service up/down = updated_at within service_down_time), scheduler, RPC version pins |
clusters | active-active groups of volume services | services, cinder-manage cluster | scheduler, API |
volumes | volumes: status, attach status, size, host, type, AZ, migration, replication, encryption key id, use_quota, group | API, volume manager | everything |
volume_metadata, volume_admin_metadata, volume_glance_metadata | user metadata; admin metadata (readonly, attached mode, extend state); image properties copied from Glance | API, manager | API, manager, notifications |
volume_attachment, attachment_specs | attachments: instance, host, mountpoint, attach status, mode, connection_info, connector | API, volume manager | API, Nova (through the API) |
snapshots, snapshot_metadata | snapshots | API, manager | |
backups, backup_metadata | backups: service, container, parent (incremental), service_metadata, fail_reason, restore_volume_id, data_timestamp | API, backup manager | |
volume_types, volume_type_extra_specs, volume_type_projects, encryption, quality_of_service_specs, default_volume_types | type catalogue, private access, encryption specs, QoS (key/value rows with a parent), per-project default type | admin API | API, scheduler (capabilities filter), drivers |
group_types, group_type_specs, group_type_projects, groups, group_snapshots, group_volume_type_mapping, consistencygroups, cgsnapshots | generic groups and the legacy CG tables | API, manager | |
quotas, quota_classes, quota_usages, reservations | limits per project and class; usage counters (in_use, reserved, until_refresh); two-phase reservations with expiry | quota engine in API and managers | API |
transfers | pending transfers with salt and crypt_hash | API | API |
messages | user messages, expires_at | API, managers | API, scheduler purge |
image_volume_cache_entries | image-volume cache per backend | volume manager | volume manager |
driver_initiator_data | per-initiator key/value data kept by some drivers | drivers | drivers |
workers | resources being worked on, by service, for cleanup after a crash (status, resource_type, resource_id, service_id, race_preventer) | API and managers through @cleanable | cleanup at start, POST /workers/cleanup |
2.2 Notable transactions and patterns
- Compare-and-swap status changes:
conditional_update(values, expected, filters)issues oneUPDATE … WHERE <expected> AND <filters>and returns the number of rows (cinder/db/api.py:551,cinder/objects/base.py:368). Every state transition of the API uses it (delete, extend, attach, revert…), which makes concurrent API workers safe without locks. Example (volume deletion,cinder/volume/api.py:503-520):sql UPDATE volumes SET status='deleting', terminated_at=:now, updated_at=:now WHERE id=:id AND deleted=0 AND (attach_status IS NULL OR attach_status != 'attached') AND (migration_status IS NULL OR migration_status IN ('success','error')) AND consistencygroup_id IS NULL AND group_id IS NULL AND status IN ('available','error','error_restoring','error_extending','error_managing') AND NOT EXISTS (SELECT 1 FROM snapshots WHERE snapshots.volume_id = volumes.id AND snapshots.deleted = 0);[inferred] The exactmigration_statusandNOT EXISTSclauses come fromAVAILABLE_MIGRATION_STATUSandvolume_has_snapshots_filterincinder/db/api.py. - Quotas:
reservelocks the project'squota_usagesrowsFOR UPDATE, refreshes them whenuntil_refresh/max_agesay so, insertsreservations(expiry[DEFAULT]/reservation_expire, 86,400 s), thencommitmovesreservedintoin_useandrollbackcancels (cinder/quota.py:319-440). Retries on deadlock throughoslo_db.api.wrap_db_retry[inferred]. - Soft delete: rows are marked
deleted=1;cinder-manage db purge <age>removes them physically.
2.3 Models versus migrations
The real migrations (Alembic, cinder/db/migrations/versions/) add two columns that the models no longer declare: quotas.allocated and reservations.allocated_id (with an index and a foreign key to quotas.id), leftovers of the removed nested-quota driver. See [_rewrite/schema-diff_stable-2026.2.md](_rewrite/schema-diff_stable-2026.2.md).
3. Outbound REST calls
| Target service | Calls | When | Authentication | Timeout / retry | Errors handled | Defined at |
|---|---|---|---|---|---|---|
| Keystone | token validation GET /v3/auth/tokens | every API request | keystonemiddleware [keystone_authtoken] service user, memcached cache | middleware defaults | 401 to the client | etc/cinder/api-paste.ini (authtoken) |
| Keystone | GET /v3/projects/{id} | /default-types operations (project must exist) | keystoneclient session with the user's token (or service user) | — | 400 when the project is unknown | cinder/api/api_utils.py:170-262 |
| Glance v2 | GET /v2/images/{id}, GET /v2/images, GET /v2/images/{id}/file, POST /v2/images, PUT /v2/images/{id}/file, PATCH /v2/images/{id}, DELETE /v2/images/{id}, GET /v2/info/stores, locations | create from image, upload to image, image metadata, reimage | user token (plus service token when [service_user]/send_service_user_token); endpoint from glance_api_servers or the catalog (glance_catalog_info) | glance_num_retries on ServiceUnavailable/InvalidEndpoint/CommunicationError; glance_request_timeout | 404 → ImageNotFound, 403 → ImageNotAuthorized | cinder/image/glance.py:126-311 |
| Nova (v2.1 + microversion) | POST /os-server-external-events with volume-extended (2.51) or volume-reimaged (2.93) | after extending an attached volume, after a reimage | [nova] service user when auth_type is set (privileged), otherwise the user's token | [nova] session options | failure → user message VOLUME_VOLUME_007_009 / …_016_028, no retry | cinder/compute/nova.py:142-241 |
| Nova | GET /servers/{id}/os-volume_attachments/{volume_id} (2.89) | deleting an attachment that has connection info (bug 2004555) | user token | — | 404 → delete locally | cinder/compute/nova.py:242-247, cinder/volume/api.py:2588-2661 |
| Nova | assisted snapshots POST/DELETE /os-assisted-volume-snapshots | NFS-like drivers snapshotting an attached volume | [nova] privileged | — | cinder/compute/nova.py:190-205 | |
| Barbican (castellan) | create / get / delete secrets (symmetric keys) | create of an encrypted volume, clone, transfer, delete | user token through castellan [key_manager] | castellan defaults | delete failure → volume error_deleting (cinder/volume/api.py:536-553) | cinder/keymgr/__init__.py, cinder/volume/volume_utils.py |
| Swift / S3 / GCS / NFS / Ceph | backup objects | backup and restore | [DEFAULT]/backup_swift_*, backup_s3_*… | per driver | backup error with fail_reason | cinder/backup/drivers/*.py |
Request IDs: global_request_id is propagated to Nova and Glance (cinder/compute/nova.py:119-131).
4. Coordination and locks (tooz)
cinder.coordination.COORDINATOR(prefixcinder-) uses tooz with[coordination]/backend_url, default **file://$state_path** — local file locks, only valid on one host (cinder/coordination.py:38-41,cinder/coordination.py:127). Active-active volume clusters need a distributed backend (etcd, Redis…).- Locks held:
cinder-<volume_id>-delete_volume,cinder-<snapshot_id>-delete_snapshot,cinder-<volume_id>(attach),cinder-<volume_id>-detach_volume,cinder-attachment_update-<volume_id>-<host>,cinder-<image_id>(image download into a cache entry), declared by@coordination.synchronizeddecorators ondelete_volume,delete_snapshot,attach_volume,detach_volume,attachment_updateand_prepare_image_cache_entry(cinder/volume/manager.py:929,cinder/volume/manager.py:1314,cinder/volume/manager.py:1399,cinder/volume/manager.py:1488,cinder/volume/api.py:2527;cinder/volume/flows/manager/create_volume.py:875). - oslo.concurrency file locks (
lock_path) are used by drivers and byutils.api_clean_volume_file_locks.
5. Other interactions
- Storage backends: each
cinder-volumeloadsvolume_driverper backend section (defaultcinder.volume.drivers.lvm.LVMVolumeDriver); drivers talk to arrays over vendor REST/SSH APIs or local tools (LVM,rbd…). Data copy and attach on the volume host go through os-brick connectors (iSCSI, FC, NVMe-oF, RBD) andprivsep/rootwrap(etc/cinder/rootwrap.d/volume.filters). Only the driver interface (cinder/interface/volume_driver.py) is in scope here. - Image conversion:
qemu-imgthrough privsep for image ↔ volume copies, withformat_inspectorchecks of the image header (cinder/image/image_utils.py,cinder/image/format_inspector.py). - Files:
state_path,lock_path, image conversion directoryimage_conversion_dir.
Source: reverse-spec-cinder/03-interactions_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.