End-to-end scenarios — placement — branch stable/2026.2
Branch
stable/2026.2@f4a89d3803cb— repository https://opendev.org/openstack/placement — analysed on 2026-10-28
Placement is synchronous: each scenario ends with the HTTP response. Periodic processing is done by the clients, Nova first, and is marked [inferred] when it lies outside this repository. Statuses and codes refer to errors.
1. Registering a compute host (nova-compute resource tracker)
sequenceDiagram
autonumber
participant NC as nova-compute (resource tracker)
participant P as placement-api
participant DB as MariaDB (placement)
NC->>P: GET /resource_providers?in_tree=<host uuid> (1.14+)
P->>DB: SELECT resource_providers …
alt unknown host
NC->>P: POST /resource_providers {name, uuid}
P->>DB: INSERT resource_providers (generation = 0, root = itself)
alt name or uuid already taken
P-->>NC: 409 placement.duplicate_name
else
P-->>NC: 200 {generation: 0, …}
end
end
NC->>P: PUT /resource_providers/{uuid}/inventories {resource_provider_generation: g, inventories: {VCPU, MEMORY_MB, DISK_GB}}
P->>DB: SELECT inventories; DELETE/INSERT/UPDATE inventories; UPDATE resource_providers SET generation = g+1 WHERE generation = g
alt stale generation
P-->>NC: 409 placement.concurrent_update
Note over NC: Nova re-reads the provider and starts again [inferred]
else a removed class is still allocated
P-->>NC: 409 placement.inventory.inuse
else total reduced below current usage
P-->>NC: 200, and the Placement log shows WARNING … is now over-capacity
else
P-->>NC: 200 {resource_provider_generation: g+1, inventories}
end
NC->>P: PUT /resource_providers/{uuid}/traits {resource_provider_generation, traits: [HW_CPU_X86_AVX2, COMPUTE_…]}
P->>DB: DELETE/INSERT resource_provider_traits; UPDATE generation
P-->>NC: 200
NC->>P: PUT /resource_providers/{uuid}/aggregates {aggregates, resource_provider_generation}
P-->>NC: 200
loop every ~60 s (Nova's update_available_resource) [inferred]
NC->>P: PUT …/inventories (only when the inventory changed on the Nova side) [inferred]
endDiagnostics:
- Repeated 409s on inventories: another actor modifies the same provider (Neutron on a child? an administrator?). Look for the
X-Openstack-Request-Ids in Placement's access log. - The host never appears as a candidate:
GET /resource_providers/{uuid}/inventoriesand/usagesgive the remaining capacity. Also check theCOMPUTE_STATUS_DISABLEDtrait. - 403 with a valid token after upgrading to this branch: the token's scope does not match the policy's
scope_types, and scope checks can no longer be disabled (see change history, change 6).
2. Scheduling and reserving an instance (nova-scheduler and nova-conductor)
sequenceDiagram
autonumber
participant S as nova-scheduler
participant P as placement-api
participant DB as MariaDB
S->>P: GET /allocation_candidates?resources=VCPU:2,MEMORY_MB:4096,DISK_GB:20&required=!COMPUTE_STATUS_DISABLED&member_of=…&limit=1000
P->>DB: providers with free capacity (one query per class) + trait/aggregate filters + usages per tree
P->>P: per-tree overall capacity pre-check (bug 2160721 fix), then Cartesian product
alt unknown class or trait, invalid syntax
P-->>S: 400 (placement.query.bad_value…)
else no possible host
P-->>S: 200 {allocation_requests: [], provider_summaries: {}}
Note over S: NoValidHost on the Nova side [inferred]
else
P-->>S: 200 {allocation_requests: [...], provider_summaries: {...}}
end
Note over S: Nova filters and weighers, choice of one candidate [inferred]
S->>P: PUT /allocations/{instance_uuid} {allocations of the candidate, project_id, user_id, consumer_generation: null, consumer_type: INSTANCE}
P->>DB: INSERT projects/users/consumers if needed
P->>DB: transaction: DELETE consumer allocations; capacity check; INSERT allocations; UPDATE generation (providers, consumer)
alt another scheduler took the space meanwhile (provider generation changed)
P->>P: re-read and retry (up to allocation_conflict_retry_count = 10)
alt capacity still enough
P-->>S: 204
else capacity exhausted
P-->>S: 409 "… would exceed the capacity"
Note over S: Nova tries the next candidate [inferred]
end
else consumer_generation ≠ null for a new consumer
P-->>S: 409 placement.concurrent_update (no server-side retry)
else
P-->>S: 204
endDiagnostics:
- **Slow
GET /allocation_candidates** comes from wide trees or many providers. Tune[placement]/max_allocation_candidatesandallocation_candidates_generation_strategy=breadth-first. The bug 2160721 fix on this branch removes the slowest case, where a tree almost fits the request. - Frequent capacity 409s reveal a race between schedulers. This is normal under load, and Nova retries.
- **
Exceeded retry limit of 10 on allocations write** in the logs signals extreme contention on a single provider.
3. Migrating an instance: atomic allocation swap
sequenceDiagram
autonumber
participant C as nova-conductor
participant P as placement-api
participant DB as MariaDB
C->>P: GET /allocations/{instance}
P-->>C: 200 {allocations: {source: …}, consumer_generation: 5}
C->>P: POST /allocations {instance: {allocations: {}, consumer_generation: 5}, migration: {allocations: {source: …}, consumer_generation: null, consumer_type: MIGRATION}}
Note over P: the source allocations move from the instance to the migration
P->>DB: one transaction: replacement of both consumers' allocations, generations +1
alt instance modified meanwhile
P-->>C: 409 placement.concurrent_update
else
P-->>C: 204
end
Note over C: scheduling of the target (scenario 2) with PUT /allocations/{instance} on the target [inferred]
Note over C: on confirm: DELETE /allocations/{migration}; on revert: allocations given back to the instance [inferred]Diagnostics: "doubled" or orphan allocations held by a migration (consumer_type = MIGRATION, from 1.38) reveal a migration interrupted on the Nova side. GET /resource_providers/{uuid}/allocations shows the consumers present on a host.
4. Reorganising a tree (reshaper), for example vGPUs moved to child providers
sequenceDiagram
autonumber
participant NC as nova-compute (driver upgrade)
participant P as placement-api
participant DB as MariaDB
NC->>P: POST /resource_providers {name: host_pGPU1, parent_provider_uuid: host} (×N)
P-->>NC: 200
NC->>P: POST /reshaper (service role) {inventories: {host: {gen, inventories without VGPU}, pGPU1: {gen, VGPU}}, allocations: {instances: {…on pGPU1…}}}
alt admin role only
P-->>NC: 403
else stale provider generation
P-->>NC: 409 placement.concurrent_update
else unknown provider
P-->>NC: 400 placement.resource_provider.not_found
else
P->>DB: one transaction: new inventories, new allocations, generations
P-->>NC: 204
end5. Deleting a host
sequenceDiagram
autonumber
participant A as nova-compute / administrator
participant P as placement-api
participant DB as MariaDB
A->>P: DELETE /resource_providers/{host}
P->>DB: SELECT children; SELECT COUNT allocations
alt child providers present
P-->>A: 409 placement.resource_provider.cannot_delete_parent
Note over A: delete the children first
else allocations present
P-->>A: 409 placement.resource_provider.inuse
Note over A: delete or move the allocations (instances, migrations)
else
P->>DB: DELETE inventories, resource_provider_aggregates, resource_provider_traits, resource_providers
P-->>A: 204
endDiagnostics: GET /resource_providers/{uuid}/allocations lists the consumers that block the deletion. For deleted instances whose allocations were left behind, Nova's audit tool finds them [inferred].
Source: reverse-spec-placement/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.