End-to-end scenarios — glance — branch stable/2026.2
Branch
stable/2026.2@a3e5f490b7a2— repository https://opendev.org/openstack/glance — analysed on 2026-10-28
Participants: the client (user, Nova, Cinder), glance-api workers (several per deployment, possibly on different hosts), MariaDB, the image store (any glance_store backend), the staging directory of a worker, RabbitMQ (notifications only), Keystone.
1. Create an image and upload its data (classic upload)
The simplest path, used by openstack image create --file and by Nova snapshots on non-RBD backends. Everything happens in one HTTP request; there is no task.
sequenceDiagram
autonumber
actor U as Client
participant A as glance-api
participant K as Keystone
participant DB as MariaDB
participant S as Store
participant MQ as RabbitMQ
U->>A: POST /v2/images {name, disk_format, container_format}
A->>K: validate token (keystonemiddleware, cached)
A->>DB: INSERT images (status=queued), image_properties, image_tags
A->>MQ: notify image.create
A-->>U: 201 + Location + OpenStack-image-import-methods
U->>A: PUT /v2/images/{id}/file (octet-stream)
A->>DB: UPDATE images SET status=saving WHERE status=queued
A->>MQ: notify image.prepare
A->>S: add(data) streamed, md5 + sha512 + format inspection on the fly
alt data stored
A->>DB: INSERT image_locations; UPDATE images SET status=active, size, checksum, os_hash_value, virtual_size WHERE status=saving
A->>MQ: notify image.upload, image.activate
A-->>U: 204
else store full / write denied / quota / format mismatch
A->>DB: UPDATE images SET status=queued
A->>MQ: notify image.upload (ERROR)
A-->>U: 413 / 503 / 413 / 415
else image deleted during upload
A->>S: delete written data
A-->>U: 410
endDiagnostics: a queued image after a failed upload is normal and can be re-uploaded; saving that never ends means the worker died during the upload. Format mismatches show "Image disk_format %s does not match stream data %s" in the API log. References: 01 § upload, glance/api/v2/image_data.py:108-328, glance/location.py:574-700.
2. Interoperable import with glance-direct on a multi-worker deployment
The staged data lives on the local disk of the worker that received PUT /stage. Any later request that reaches another worker is proxied to it, using worker_self_reference_url.
sequenceDiagram
autonumber
actor U as Client
participant W1 as glance-api (worker 1)
participant W2 as glance-api (worker 2)
participant DB as MariaDB
participant ST as Staging dir of worker 1
participant S as Store(s)
U->>W1: POST /v2/images
W1->>DB: INSERT images (queued)
W1-->>U: 201
U->>W1: PUT /v2/images/{id}/stage
W1->>DB: UPDATE status=uploading
W1->>ST: write <id>
W1->>DB: SET os_glance_stage_host = http://worker1
W1-->>U: 204
U->>W2: POST /v2/images/{id}/import {method: glance-direct, stores: [a, b]}
W2->>DB: read image (os_glance_stage_host != self)
W2->>W1: POST /v2/images/{id}/import (same body, user's token, 60 s)
W1->>DB: INSERT tasks (pending); INSERT image_properties os_glance_import_task (unique)
W1-->>W2: 202
W2-->>U: 202
Note over W1: tasks_pool thread, taskflow
W1->>DB: task processing; image importing; os_glance_importing_to_stores=a,b
loop each store
W1->>ST: read <id>
W1->>S: add(data)
W1->>DB: INSERT image_locations; remove store from os_glance_importing_to_stores
end
W1->>ST: delete <id>
W1->>DB: image active; task success; DELETE os_glance_import_task
U->>W2: GET /v2/images/{id} (poll)
W2-->>U: status=activeDiagnostics: 504 "Stage host is unavailable" on import means worker 1 cannot be reached at its worker_self_reference_url; the data must then be staged again. A 409 "Image has active task" means another import holds the lock: it expires after 60 minutes (120 for a pending task, glance/api/v2/images.py:171-220). Stores that failed are listed in os_glance_failed_import. References: 05 § api_image_import, glance/api/v2/images.py:246-291.
3. web-download import into several stores, one of them failing
sequenceDiagram
autonumber
actor U as Client
participant A as glance-api
participant DB as MariaDB
participant H as Remote HTTP server
participant ST as Staging
participant SA as Store a
participant SB as Store b
U->>A: POST …/import {method: {name: web-download, uri}, stores: [a, b], all_stores_must_succeed: false}
A->>A: validate uri against import_filtering_opts
alt uri refused
A-->>U: 400 "URI for web-download does not pass filtering"
else accepted
A->>DB: task pending + import lock
A-->>U: 202
A->>DB: image importing; quotas image_stage_total, image_count_uploading
A->>H: GET uri (IP pinned, redirects re-validated)
H-->>A: image bytes
A->>ST: write <id>
A->>SA: add(data)
A->>DB: location a added
A->>SB: add(data)
SB--xA: StorageFull
A->>DB: os_glance_failed_import=b (flow continues because all_stores_must_succeed=false)
A->>ST: delete <id>
A->>DB: image active (a only); task success
endDiagnostics: with the default all_stores_must_succeed = true, the failure of store b would revert the whole import: location a removed, image back to queued, task failure with the store error in message. References: glance/async_/flows/api_image_import.py:596-720.
4. Delete with delayed delete and the scrubber
sequenceDiagram
autonumber
actor U as Client
participant A as glance-api
participant DB as MariaDB
participant SC as glance-scrubber
participant S as Store
U->>A: DELETE /v2/images/{id}
alt protected
A-->>U: 403
else delayed_delete = true
A->>DB: images.status=pending_delete, deleted=1; image_locations.status=pending_delete
A-->>U: 204
loop every wakeup_time (300 s)
SC->>DB: SELECT images WHERE status=pending_delete
SC->>SC: keep those with deleted_at + scrub_time past
SC->>S: delete(location)
SC->>DB: image_locations.status=deleted; images.status=deleted
end
else delayed_delete = false (default)
A->>S: delete each location
A->>DB: images.status=deleted, soft-delete rows
A-->>U: 204
endDiagnostics: images stuck in pending_delete mean the scrubber is not running or cannot reach the store; glance-scrubber --restore <id> brings one back to active. A 409 on delete with RBD comes from clones of the image (HasSnapshot/InUseByStore). References: glance/domain/__init__.py:249-255, glance/scrubber.py:309-414.
5. Nova snapshot published through the locations API (service role)
Deployments where Nova and Glance share a store (e.g. Ceph RBD) avoid copying data: Nova creates the snapshot in the store itself and registers its location.
sequenceDiagram
autonumber
participant N as nova-compute
participant A as glance-api
participant DB as MariaDB
participant S as Store (shared with Nova)
N->>A: POST /v2/images (snapshot metadata)
A-->>N: 201 (queued)
N->>S: create snapshot/clone directly
N->>A: POST /v2/images/{id}/locations {url, validation_data?} (service token)
A->>DB: task location_import + import lock
A-->>N: 202
A->>S: get_size / read data to compute os_hash_value (do_secure_hash)
A->>DB: INSERT image_locations; image active; hash values; task success
N->>A: GET /v2/images/{id} (poll until active)Diagnostics: 403 "http store must be enabled to use location API by normal user." means the caller lacks the service role; a mismatch between validation_data and the computed hash puts the image back to queued. References: 05 § location_import, glance/api/v2/images.py:1161-1257.
Source: reverse-spec-glance/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.