Interactions — nova — branch stable/2026.2
Branch
stable/2026.2@8df1922926dd(34.0.0+ 7 commits) — repository https://opendev.org/openstack/nova — analysed on 2026-10-28
Related files: REST API · errors · scenarios · async processing. Client-side expectations of Glance and Placement are already specified in reverse-spec-glance/07-rewrite-pack_stable-2026.2.md and reverse-spec-placement/07-rewrite-pack_stable-2026.2.md (§ "What the clients expect").
0. Overview
| System | Protocol | Library | Configuration | Used by | Usage |
|---|---|---|---|---|---|
| RabbitMQ (per cell) | AMQP 0-9-1 | oslo.messaging (rabbit driver) | [DEFAULT]/transport_url, cell_mappings.transport_url | all services | RPC between api, conductor, scheduler, compute; notifications |
| MariaDB/MySQL — API DB | SQL | oslo.db + SQLAlchemy 2 | [api_database]/connection | api, conductor, scheduler | flavors, mappings, build requests, request specs, quotas, aggregates, key pairs, server groups |
| MariaDB/MySQL — cell DBs (cell0 + N cells) | SQL | oslo.db + SQLAlchemy 2 | [database]/connection, cell_mappings.database_connection | api (read/write through mappings), conductor, scheduler (read) | instances, BDMs, migrations, compute nodes, services, actions, faults |
| Placement | HTTPS REST (microversioned) | keystoneauth1 adapter | [placement] | api, conductor, scheduler, compute | resource providers, inventories, traits, aggregates, allocation candidates, allocations |
| Neutron | HTTPS REST | python-neutronclient | [neutron] | api, compute | ports, networks, port bindings, security groups, floating IPs, QoS resource requests |
| Cinder | HTTPS REST (v3 microversioned) | python-cinderclient | [cinder] | api, conductor, compute | volumes, attachments (3.44), snapshots, reimage (3.68) |
| Glance | HTTPS REST (v2) | python-glanceclient | [glance] | api, conductor, compute | image metadata, download, snapshot upload |
| Keystone | HTTPS REST (v3) | keystonemiddleware, keystoneauth1, oslo.limit | [keystone_authtoken], [keystone], [oslo_limit], [service_user] | api (and all for service tokens) | token validation, project existence, unified limits, service tokens |
| Cyborg | HTTPS REST (v2) | openstacksdk / keystoneauth | [cyborg] | api, conductor, compute | device profiles, accelerator requests (ARQs) |
| Manila | HTTPS REST | openstacksdk | [manila] | api, compute | share access rules for virtiofs shares (2.97+) |
| Memcached / Redis (oslo.cache) | memcached / RESP | oslo.cache (dogpile) | [cache] | api (metadata, AZ), compute | metadata responses, availability-zone names per host |
| Hypervisor | local (libvirt socket, vCenter API, Ironic REST, z/VM) | virt drivers | [DEFAULT]/compute_driver | compute | guest lifecycle — out of scope for OpenKeel (KubeVirt) |
1. RabbitMQ (oslo.messaging RPC)
1.1 Topology
Nova uses one RPC transport per cell plus an optional API-level transport:
[DEFAULT]/transport_urlof each service points at its own cell's broker; nova-api and nova-conductor (super-conductor) reach a cell's broker throughcell_mappings.transport_urlin the API database.nova.rpc.ClientRouterpicks the transport from the request context (context.mq_connection, set byset_target_cell) and falls back to the default client (nova/rpc.py:423-444).- Exchange:
[DEFAULT]/control_exchange(defaultnova). Topics and servers:
| Topic | Server (queue topic.server) | Consumers | Fanout | Defined at |
|---|---|---|---|---|
conductor | conductor host | ConductorManager (v3.0) + ComputeTaskManager (namespace compute_task, v1.26) | no | nova/conductor/rpcapi.py:30, nova/conductor/manager.py:120, nova/conductor/manager.py:269 |
scheduler | scheduler host | SchedulerManager (v4.5) | yes (scheduler_fanout) for instance/aggregate tracking | nova/scheduler/rpcapi.py:28, nova/scheduler/manager.py:65 |
compute | compute host name (CONF.host) | ComputeManager (v6.5) and _ComputeV5Proxy (v5.13, previous major) | no | nova/compute/rpcapi.py:34, nova/compute/manager.py:646, nova/compute/manager.py:12006 |
compute-alt | compute host name | same endpoints, second RPC server used during graceful shutdown | no | nova/compute/rpcapi.py:42, nova/service.py:267-285 |
- Graceful shutdown (new in 2026.2, compute RPC 6.5): every compute creates a second RPC server on
compute-alt(nova/service.py:267-285). On shutdown it stops consumingcomputebut keepscompute-altalive until its ongoing operations end. Calls that belong to an operation already in progress on that host —finish_resize,finish_revert_resize,finish_snapshot_based_resize_at_dest,finish_revert_snapshot_based_resize_at_source,check_instance_shared_storage,validate_console_port,live_migration,pre_live_migration,post_live_migration_at_destination— are sent tocompute-alt(nova/compute/rpcapi.py:578-603), with a fallback tocomputewhen the target is pinned below 6.5.
1.2 Versioning and rolling upgrades
- Each client pins a
version_cap. For compute it is[upgrade_levels]/compute(autoby default): the minimumnova-computeservice version across all cells is read from theservicestables and mapped to an RPC version throughSERVICE_VERSION_HISTORY(nova/compute/rpcapi.py:496-560); release aliases go frombobcat= 6.2 tohibiscus= 6.5 (nova/compute/rpcapi.py:440-446). Conductor and scheduler use static aliases (nova/conductor/rpcapi.py:203-218). - Clients downgrade messages with
can_send_version()checks, dropping or converting arguments for older servers (nova/conductor/rpcapi.py:331-386for examples). - Objects travel as
nova_object.*primitives (NovaObjectSerializer); a receiver that is too old asks the conductor to backport them (object_backport_versions). calltimeouts:[DEFAULT]/rpc_response_timeout(60 s). Long calls (select_destinations,migrate_server,attach_volume,cache_images,check_can_live_migrate_*,prep_snapshot_based_resize_at_*…) use[DEFAULT]/long_rpc_timeout(1800 s) withcall_monitor_timeout = rpc_response_timeout, which makes the server send heartbeats so that a dead server is detected early (nova/compute/rpcapi.py:562-575).
1.3 RPC methods
90 client methods (nova/compute/rpcapi.py, nova/conductor/rpcapi.py, nova/scheduler/rpcapi.py), each matched to its server handler. "Mode" is call (request/response) or cast (fire-and-forget); call/cast means the client chooses at run time (e.g. do_cast arguments). Versions are the ones the client may send depending on the pin. Compute messages are always sent to server=<instance.host> or an explicit host (nova/compute/rpcapi.py:61-77 _compute_host). Machine-readable: _rewrite/rpc-contract_stable-2026.2.json.
| Client method | Mode | RPC method | Topic | Version(s) sent | prepare() | Server handler |
|---|---|---|---|---|---|---|
nova/compute/rpcapi.py:605 add_fixed_ip_to_instance | cast | add_fixed_ip_to_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:6923 |
nova/compute/rpcapi.py:612 attach_interface | call | attach_interface | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:8566 |
nova/compute/rpcapi.py:623 attach_volume | cast | attach_volume | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7845 |
nova/compute/rpcapi.py:629 check_can_live_migrate_destination | call | check_can_live_migrate_destination | compute | 5.0 | call_monitor_timeout=CONF.rpc_response_timeoutserver=destinationtimeout=CONF.long_rpc_timeout | nova/compute/manager.py:8810 |
nova/compute/rpcapi.py:656 check_can_live_migrate_source | call | check_can_live_migrate_source | compute | — | server=source | nova/compute/manager.py:9036 |
nova/compute/rpcapi.py:669 check_instance_shared_storage | call | check_instance_shared_storage | compute | — | — | nova/compute/manager.py:8785 |
nova/compute/rpcapi.py:698 confirm_snapshot_based_resize_at_source | call | confirm_snapshot_based_resize_at_source | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=migration.source_computetimeout=CONF.long_rpc_timeout | nova/compute/manager.py:5152 |
nova/compute/rpcapi.py:733 detach_interface | cast | detach_interface | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:8707 |
nova/compute/rpcapi.py:740 detach_volume | cast | detach_volume | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:8001 |
nova/compute/rpcapi.py:749 finish_resize | cast | finish_resize | compute | 5.0 | — | nova/compute/manager.py:6646 |
nova/compute/rpcapi.py:774 finish_revert_resize | cast | finish_revert_resize | compute | 5.0 | — | nova/compute/manager.py:5661 |
nova/compute/rpcapi.py:799 finish_snapshot_based_resize_at_dest | call | finish_snapshot_based_resize_at_dest | compute | — | — | nova/compute/manager.py:6730 |
nova/compute/rpcapi.py:847 finish_revert_snapshot_based_resize_at_source | call | finish_revert_snapshot_based_resize_at_source | compute | — | — | nova/compute/manager.py:5452 |
nova/compute/rpcapi.py:889 get_console_output | call | get_console_output | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7550 |
nova/compute/rpcapi.py:896 get_diagnostics | call | get_diagnostics | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7098 |
nova/compute/rpcapi.py:902 get_instance_diagnostics | call | get_instance_diagnostics | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7114 |
nova/compute/rpcapi.py:909 get_vnc_console | call | get_vnc_console | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7582 |
nova/compute/rpcapi.py:916 get_spice_console | call | get_spice_console | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7628 |
nova/compute/rpcapi.py:923 get_mks_console | call | get_mks_console | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7695 |
nova/compute/rpcapi.py:930 get_serial_console | call | get_serial_console | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7741 |
nova/compute/rpcapi.py:937 validate_console_port | call | validate_console_port | compute | — | — | nova/compute/manager.py:7780 |
nova/compute/rpcapi.py:951 host_maintenance_mode | call | host_maintenance_mode | compute | — | server=host | nova/compute/manager.py:7015 |
nova/compute/rpcapi.py:966 host_power_action | call | host_power_action | compute | — | server=host | nova/compute/manager.py:7010 |
nova/compute/rpcapi.py:972 inject_network_info | cast | inject_network_info | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7540 |
nova/compute/rpcapi.py:978 live_migration | cast | live_migration | compute | — | — | nova/compute/manager.py:9469 |
nova/compute/rpcapi.py:993 live_migration_force_complete | cast | live_migration_force_complete | compute | — | server=_compute_host(migration.source_compute, instance) | nova/compute/manager.py:9507 |
nova/compute/rpcapi.py:1001 live_migration_abort | cast | live_migration_abort | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:9539 |
nova/compute/rpcapi.py:1008 pause_instance | cast | pause_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:6969 |
nova/compute/rpcapi.py:1014 post_live_migration_at_destination | call | post_live_migration_at_destination | compute | — | — | nova/compute/manager.py:9950 |
nova/compute/rpcapi.py:1031 pre_live_migration | call | pre_live_migration | compute | 6.0, 5.0 | — | nova/compute/manager.py:9066 |
nova/compute/rpcapi.py:1054 prep_resize | cast | prep_resize | compute | 6.0, 5.1, 5.0 | server=host | nova/compute/manager.py:5955 |
nova/compute/rpcapi.py:1090 prep_snapshot_based_resize_at_dest | call | prep_snapshot_based_resize_at_dest | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=destinationtimeout=CONF.long_rpc_timeout | nova/compute/manager.py:6124 |
nova/compute/rpcapi.py:1145 prep_snapshot_based_resize_at_source | call | prep_snapshot_based_resize_at_source | compute | — | — | nova/compute/manager.py:6197 |
nova/compute/rpcapi.py:1190 reboot_instance | cast | reboot_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4407 |
nova/compute/rpcapi.py:1200 rebuild_instance | cast | rebuild_instance | compute | 6.2, 6.1, 5.0 | server=_compute_host(host, instance) | nova/compute/manager.py:3894 |
nova/compute/rpcapi.py:1252 remove_fixed_ip_from_instance | cast | remove_fixed_ip_from_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:6945 |
nova/compute/rpcapi.py:1259 remove_volume_connection | call | remove_volume_connection | compute | 6.3 | — | nova/compute/manager.py:8301 |
nova/compute/rpcapi.py:1281 rescue_instance | cast | rescue_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4864 |
nova/compute/rpcapi.py:1293 resize_instance | cast | resize_instance | compute | 6.0, 5.0 | — | nova/compute/manager.py:6331 |
nova/compute/rpcapi.py:1323 resume_instance | cast | resume_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7157 |
nova/compute/rpcapi.py:1329 revert_resize | cast | revert_resize | compute | 5.0 | server=_compute_host(host, instance) | nova/compute/manager.py:5610 |
nova/compute/rpcapi.py:1353 revert_snapshot_based_resize_at_dest | call | revert_snapshot_based_resize_at_dest | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=migration.dest_computetimeout=CONF.long_rpc_timeout | nova/compute/manager.py:5339 |
nova/compute/rpcapi.py:1389 rollback_live_migration_at_destination | cast | rollback_live_migration_at_destination | compute | — | — | nova/compute/manager.py:10290 |
nova/compute/rpcapi.py:1412 drop_move_claim_at_destination | call | drop_move_claim_at_destination | compute | — | — | nova/compute/manager.py:10276 |
nova/compute/rpcapi.py:1431 set_admin_password | call | set_admin_password | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4771 |
nova/compute/rpcapi.py:1438 set_host_enabled | call | set_host_enabled | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=hosttimeout=CONF.long_rpc_timeout | nova/compute/manager.py:7067 |
nova/compute/rpcapi.py:1446 swap_volume | cast | swap_volume | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:8192 |
nova/compute/rpcapi.py:1458 get_host_uptime | call | get_host_uptime | compute | — | server=host | nova/compute/manager.py:7091 |
nova/compute/rpcapi.py:1464 reserve_block_device_name | call | reserve_block_device_name | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=_compute_host(None, instance)timeout=CONF.long_rpc_timeout | nova/compute/manager.py:7798 |
nova/compute/rpcapi.py:1479 backup_instance | cast | backup_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4553 |
nova/compute/rpcapi.py:1490 snapshot_instance | cast | snapshot_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4569 |
nova/compute/rpcapi.py:1498 start_instance | cast | start_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:3581 |
nova/compute/rpcapi.py:1513 suspend_instance | cast | suspend_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:7131 |
nova/compute/rpcapi.py:1519 terminate_instance | cast | terminate_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:3446 |
nova/compute/rpcapi.py:1526 unpause_instance | cast | unpause_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:6991 |
nova/compute/rpcapi.py:1532 unrescue_instance | cast | unrescue_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4929 |
nova/compute/rpcapi.py:1538 soft_delete_instance | cast | soft_delete_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:3636 |
nova/compute/rpcapi.py:1545 restore_instance | cast | restore_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:3658 |
nova/compute/rpcapi.py:1551 shelve_instance | cast | shelve_instance | compute | 5.0 | server=_compute_host(None, instance) | nova/compute/manager.py:7204 |
nova/compute/rpcapi.py:1573 shelve_offload_instance | cast | shelve_offload_instance | compute | 5.0 | server=_compute_host(None, instance) | nova/compute/manager.py:7289 |
nova/compute/rpcapi.py:1589 unshelve_instance | cast | unshelve_instance | compute | 5.2, 5.0 | server=host | nova/compute/manager.py:7384 |
nova/compute/rpcapi.py:1613 volume_snapshot_create | cast | volume_snapshot_create | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4682 |
nova/compute/rpcapi.py:1621 volume_snapshot_delete | cast | volume_snapshot_delete | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:4694 |
nova/compute/rpcapi.py:1630 allow_share | cast | allow_share | compute | 6.4 | server=_compute_host(None, instance) | nova/compute/manager.py:4708 |
nova/compute/rpcapi.py:1646 deny_share | cast | deny_share | compute | 6.4 | server=_compute_host(None, instance) | nova/compute/manager.py:4715 |
nova/compute/rpcapi.py:1662 external_instance_event | cast | external_instance_event | compute | — | — | nova/compute/manager.py:11657 |
nova/compute/rpcapi.py:1676 build_and_run_instance | cast | build_and_run_instance | compute | 5.0 | server=host | nova/compute/manager.py:2396 |
nova/compute/rpcapi.py:1706 quiesce_instance | call | quiesce_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:11861 |
nova/compute/rpcapi.py:1712 unquiesce_instance | cast | unquiesce_instance | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:11885 |
nova/compute/rpcapi.py:1719 trigger_crash_dump | cast | trigger_crash_dump | compute | — | server=_compute_host(None, instance) | nova/compute/manager.py:3613 |
nova/compute/rpcapi.py:1726 cache_images | call | cache_images | compute | — | call_monitor_timeout=CONF.rpc_response_timeoutserver=hosttimeout=CONF.long_rpc_timeout | nova/compute/manager.py:11722 |
nova/conductor/rpcapi.py:302 live_migrate_instance | cast | live_migrate_instance | conductor (namespace compute_task) | 1.15 | — | nova/conductor/manager.py:494 |
nova/conductor/rpcapi.py:317 migrate_server | call/cast | migrate_server | conductor (namespace compute_task) | 1.20, 1.13, 1.11, 1.10, 1.6, 1.4 | call_monitor_timeout=CONF.rpc_response_timeouttimeout=CONF.long_rpc_timeout | nova/conductor/manager.py:339 |
nova/conductor/rpcapi.py:355 build_instances | cast | build_instances | conductor (namespace compute_task) | 1.19, 1.18, 1.10, 1.9, 1.8, 1.5 | — | nova/conductor/manager.py:671 |
nova/conductor/rpcapi.py:395 schedule_and_build_instances | cast | schedule_and_build_instances | conductor (namespace compute_task) | 1.17, 1.16 | — | nova/conductor/manager.py:1675 |
nova/conductor/rpcapi.py:418 unshelve_instance | cast | unshelve_instance | conductor (namespace compute_task) | 1.14, 1.3 | — | nova/conductor/manager.py:1033 |
nova/conductor/rpcapi.py:429 rebuild_instance | cast | rebuild_instance | conductor (namespace compute_task) | 1.25, 1.24, 1.12, 1.8 | — | nova/conductor/manager.py:1233 |
nova/conductor/rpcapi.py:471 cache_images | cast | cache_images | conductor (namespace compute_task) | 1.21 | — | nova/conductor/manager.py:2086 |
nova/conductor/rpcapi.py:480 confirm_snapshot_based_resize | call/cast | confirm_snapshot_based_resize | conductor (namespace compute_task) | 1.22 | — | nova/conductor/manager.py:2217 |
nova/conductor/rpcapi.py:491 revert_snapshot_based_resize | cast | revert_snapshot_based_resize | conductor (namespace compute_task) | 1.23 | — | nova/conductor/manager.py:2236 |
nova/conductor/rpcapi.py:499 attach_volume | call/cast | attach_volume | conductor (namespace compute_task) | 1.26 | call_monitor_timeout=CONF.rpc_response_timeouttimeout=CONF.long_rpc_timeout | nova/conductor/manager.py:2267 |
nova/conductor/rpcapi.py:237 object_class_action_versions | call | object_class_action_versions | conductor | — | — | nova/conductor/manager.py:147 |
nova/conductor/rpcapi.py:245 object_action | call | object_action | conductor | — | — | nova/conductor/manager.py:172 |
nova/conductor/rpcapi.py:250 object_backport_versions | call | object_backport_versions | conductor | — | — | nova/conductor/manager.py:192 |
nova/scheduler/rpcapi.py:132 select_destinations | call | select_destinations | scheduler | 4.5, 4.4, 4.3, 4.0 | call_monitor_timeout=CONF.rpc_response_timeouttimeout=CONF.long_rpc_timeout | nova/scheduler/manager.py:188 |
nova/scheduler/rpcapi.py:162 update_aggregates | cast | update_aggregates | scheduler | — | fanout=True | nova/scheduler/manager.py:800 |
nova/scheduler/rpcapi.py:167 delete_aggregate | cast | delete_aggregate | scheduler | — | fanout=True | nova/scheduler/manager.py:810 |
nova/scheduler/rpcapi.py:172 update_instance_info | cast | update_instance_info | scheduler | — | fanout=True | nova/scheduler/manager.py:819 |
nova/scheduler/rpcapi.py:177 delete_instance_info | cast | delete_instance_info | scheduler | — | fanout=True | nova/scheduler/manager.py:826 |
nova/scheduler/rpcapi.py:182 sync_instance_info | cast | sync_instance_info | scheduler | — | fanout=True | nova/scheduler/manager.py:833 |
1.4 Notifications
- Driver and topics come from
[oslo_messaging_notifications]; the format is chosen by[notifications]/notification_format, whose default on this branch is **unversioned** (nova/conf/notifications.py:59-60): only legacycompute.instance.*notifications are sent unless it is set toversionedorboth. Versioned notifications go to the topics in[notifications]/versioned_notifications_topics(defaultversioned_notifications,nova/conf/notifications.py:86-87). [notifications]/notify_on_state_change(Noneby default;vm_stateorvm_and_task_state,nova/conf/notifications.py:30-40) addscompute.instance.update/instance.updatenotifications on state transitions.- Versioned payloads are
nova.notifications.objects.*objects; 141 samples indoc/notification_samples/(101instance-*, 15aggregate-*, 6keypair-*, 3flavor-*, 3server_group-*, 3service-*, 3compute_task-*, 2scheduler-*…). Event types follow<object>.<action>[.<phase>]with phasestart/end/error, publishernova-compute:<host>,nova-api:<host>, etc. - Sample envelope (versioned, AMQP body after oslo.messaging unwrapping):
{"priority": "INFO", "event_type": "instance.pause.end",
"publisher_id": "nova-compute:compute-1", "timestamp": "2026-10-28 10:00:00.000000",
"message_id": "…",
"payload": {"nova_object.name": "InstanceActionPayload", "nova_object.namespace": "nova",
"nova_object.version": "1.9",
"nova_object.data": {"uuid": "…", "state": "paused", "power_state": "paused",
"task_state": null, "host": "compute-1", "flavor": {"…": "…"},
"fault": null, "action_initiator_user": "…"}}}
1.5 Sample RPC frame
nova-api → conductor, cast schedule_and_build_instances (AMQP body on exchange nova, routing key conductor):
{"oslo.version": "2.0",
"oslo.message": "{\"method\": \"schedule_and_build_instances\", \"namespace\": \"compute_task\", \"version\": \"1.17\", \"args\": {\"build_requests\": [{\"nova_object.name\": \"BuildRequest\", \"nova_object.version\": \"1.3\", \"nova_object.data\": {…}}], \"request_specs\": [{\"nova_object.name\": \"RequestSpec\", …}], \"image\": {…}, \"admin_password\": \"…\", \"injected_files\": [], \"requested_networks\": {…}, \"block_device_mapping\": [{…}], \"tags\": []}, \"_unique_id\": \"…\", \"_context_request_id\": \"req-…\", \"_context_global_request_id\": null, \"_context_project_id\": \"…\", \"_context_user_id\": \"…\", \"_context_roles\": [\"member\", \"reader\"], \"_context_service_catalog\": [ … ], \"_context_auth_token\": \"gAAAA…\", \"_context_is_admin\": false, \"_context_read_deleted\": \"no\", \"_context_timestamp\": \"…\"}"}
The serialised context carries the service catalog (nova/context.py:195-211) and, through the oslo.context base class, the user token [inferred: auth_token is part of oslo_context.RequestContext.to_dict], so computes can call Neutron/Cinder/Glance on behalf of the user; admin_password travels in clear in the message body.
2. Databases
2.1 Layout (cells v2)
flowchart LR api[nova-api] -->|SQL| apidb[(nova_api)] api -->|SQL via instance_mappings| cell0[(nova_cell0)] api -->|SQL via instance_mappings| cell1[(nova cell1)] sc[super-conductor] --> apidb sc --> cell0 sc --> cell1 sched[nova-scheduler] -->|read| apidb sched -->|read compute_nodes| cell1 cc[cell conductor] --> cell1 cpu[nova-compute] -.->|RPC object_action| cc
- API database (
nova/db/api/models.py, 20 tables):cell_mappings(name, UUID,transport_url,database_connection,disabled,nova/db/api/models.py:135-147),host_mappings,instance_mappings(instance → cell,queued_for_delete, project/user),build_requests(serialised instance before scheduling),request_specs(serialisedRequestSpecreused on every move),flavors,flavor_extra_specs,flavor_projects,aggregates,aggregate_hosts,aggregate_metadata,instance_groups,instance_group_policy,instance_group_member,key_pairs,quotas,project_user_quotas,quota_classes, and the legacyquota_usages/reservations(no longer written: usage is counted). DDL:_rewrite/schema-api-mysql_stable-2026.2.sql. - Cell databases (
nova/db/main/models.py, 30 tables +shadow_*copies created by the migrations):instances,instance_extra(NUMA, PCI requests, flavor copy, vCPU model, keypairs, trusted certs, resources),instance_system_metadata,instance_metadata,instance_info_caches(network info JSON),instance_faults,instance_actions,instance_actions_events,block_device_mapping,migrations,compute_nodes,services,pci_devices,tags,virtual_interfaces,console_auth_tokens,share_mapping,task_log,volume_usage_cache,instance_id_mappings,s3_images, plus legacysecurity_groups/security_group_rules/security_group_instance_association,certificates,quotas… DDL:_rewrite/schema-mysql_stable-2026.2.sql. - cell0 has the same schema as a cell; it only holds instances that failed scheduling.
- Migrations: Alembic,
nova/db/api/migrations/versions/(3 revisions) andnova/db/main/migrations/versions/(10 revisions, the latest addinginstances.compute_id,console_auth_tokens.tls_port, share mappings and BDM encryption fields). - Soft delete: most cell tables have
deleted(=idwhen deleted) anddeleted_at; rows are moved toshadow_*tables bynova-manage db archive_deleted_rows(nova/cmd/manage.py:301) and removed bynova-manage db purge(nova/cmd/manage.py:526).
2.2 Notable transactions and locking
| Where | What | Source |
|---|---|---|
| Boot, API | request_specs + build_requests + instance_mappings inserted in one API-DB transaction | nova/compute/api.py:1256 |
| Boot, conductor | instance created in the cell, then instance_mappings.cell_id set, then build request deleted (three separate steps; the build request deletion is the commit point that detects a concurrent delete) | nova/conductor/manager.py:1758, nova/conductor/manager.py:1944, nova/conductor/manager.py:2027 |
| Any state change | Instance.save(expected_task_state=…, expected_vm_state=…): UPDATE instances … WHERE uuid = ? AND task_state IN (…); a mismatch raises UnexpectedTaskStateError / UnexpectedDeletingTaskStateError (compare-and-swap) | nova/db/main/api.py:2242 instance_update_and_get_original |
| Quotas | no reservations: usage counted from cell DBs (and Placement when [quota]/count_usage_from_placement) at check time, optional re-check after creation ([quota]/recheck_quota) | nova/quota.py |
| Retries | @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) on hot writes (instance update, BDM update, migrations) | nova/db/main/api.py:563, nova/db/main/api.py:869, nova/db/main/api.py:1243 |
2.3 Cross-cell reads
List and lookup operations scatter-gather over all cells in parallel with a per-cell timeout (nova/context.py:456 scatter_gather_cells, CELL_TIMEOUT = 60 at nova/context.py:51); a cell that does not answer is either skipped or returned as a partial record (01 § 1.6).
3. Outbound REST calls
All clients authenticate with keystoneauth sessions built from the service's config group; when [service_user]/send_service_user_token = true the user token is sent with an extra X-Service-Token so that expired user tokens are still accepted during long operations (nova/service_auth.py:73-91). X-OpenStack-Request-ID carries the global request id.
3.1 Placement (nova/scheduler/client/report.py)
| Call | Microversion | When | Defined at |
|---|---|---|---|
GET /allocation_candidates?… | from the request (up to 1.36 for same_subtree) | scheduling (select_destinations) | nova/scheduler/client/report.py:1719 |
PUT /allocations/{consumer} | 1.28 (consumer generation) or the candidates' version | scheduler claim; move/replace allocations | nova/scheduler/client/report.py:2033, nova/scheduler/client/report.py:2255 |
POST /allocations | 1.28 | atomic move of allocations between instance and migration consumers | nova/scheduler/client/report.py:2104 |
GET /allocations/{consumer} | 1.28 | compute build, move operations | nova/scheduler/client/report.py:1612 |
DELETE /allocations/{consumer} | — | delete, failed build/reschedule | nova/scheduler/client/report.py:2201 |
GET/POST /resource_providers, GET /resource_providers?in_tree= | 1.14 / 1.20 | compute node registration and provider-tree refresh | nova/scheduler/client/report.py:549, nova/scheduler/client/report.py:594 |
PUT /resource_providers/{uuid}/inventories | 1.26 | resource tracker | nova/scheduler/client/report.py:989 |
PUT /resource_providers/{uuid}/traits, GET /traits, PUT /traits/{name} | 1.6 | capabilities and custom traits | nova/scheduler/client/report.py:1145, nova/scheduler/client/report.py:1074-1081 |
PUT /resource_providers/{uuid}/aggregates | 1.19 | host aggregate membership mirroring | nova/scheduler/client/report.py:1223 |
PUT /resource_classes/{name} | 1.7 | custom resource classes | nova/scheduler/client/report.py:1290 |
POST /reshaper | 1.30 | driver reshapes its provider tree (e.g. VGPU, PCPU) | nova/scheduler/client/report.py:1332 |
DELETE /resource_providers/{uuid} | — | service delete, orphan node | nova/scheduler/client/report.py:736 |
GET /usages?project_id=… | 1.9 | quota counting from Placement | nova/scheduler/client/report.py:2610 |
Generation conflicts (409 placement.concurrent_update) are retried by the retries decorator (nova/scheduler/client/report.py:149); with safe_connect (nova/scheduler/client/report.py:115-140) an unreachable or misconfigured Placement is logged ("Placement API service is not responding.") and the call returns None, so the resource tracker keeps running; a failed claim makes the scheduler try the next host.
3.2 Neutron (nova/network/neutron.py, python-neutronclient v2.0)
| Operation | Calls | When |
|---|---|---|
| Validate requested networks/ports | list_networks, show_network, show_port, list_ports, list_extensions, show_quota | API, POST /servers and interface attach |
| Allocate/bind ports | create_port (when a network is requested), update_port with binding:host_id, device_id, device_owner=compute:<az>, binding:profile (PCI, allocation) | compute, build/attach (nova/network/neutron.py:211-253 client setup) |
| Multiple port bindings (live migration) | create_port_binding, show_port_binding, delete_port_binding, activate | compute, live migration |
| Deallocate | update_port (unbind) or delete_port for Nova-created ports | compute, delete/detach |
| Network info cache | list_ports(device_id=…), list_subnets, list_floatingips | compute (on events), API (ips) |
| Legacy proxies | security groups (create_security_group, rules…), floating IPs | API ≤ 2.35 |
Neutron calls back with POST /os-server-external-events (01 § 3.7). Admin calls use [neutron] credentials; user calls use the user token (nova/network/neutron.py:230 get_client).
3.3 Cinder (nova/volume/cinder.py, python-cinderclient v3)
Minimum version 3.0 (nova/volume/cinder.py:237); the new attachment flow uses 3.44 (attachment_create/update/complete/delete, nova/volume/cinder.py:781-940), multiattach needs 3.48 [inferred], reimage of boot volumes 3.68 (nova/volume/cinder.py:953). Legacy calls (reserve_volume, initialize_connection, attach, detach, begin_detaching, roll_detaching) remain for old BDMs. Cinder calls back with volume-extended/volume-reimaged external events and with /os-assisted-volume-snapshots.
3.4 Glance (nova/image/glance.py, python-glanceclient v2)
show/detail (image metadata, compute and API), download (compute, streamed to the image cache; direct RBD download optional), create/update/upload (snapshot, shelve, backup), delete (backup rotation, failed snapshot), image_import_copy / copy_image_to_store (multi-store), signature verification with Barbican (cursive) when img_signature_verify [inferred].
3.5 Keystone
keystonemiddleware.auth_tokenvalidates each incoming token (GET /v3/auth/tokens, cached in memcached).PUT /os-quota-sets/{project}checks that the project exists:GET /v3/projects/{id}(nova/api/openstack/identity.py:26-39).- Unified limits (
[quota]/driver = nova.quota.UnifiedLimitsDriver): registered limits and project limits read through oslo.limit (nova/limit/local.py:18-19,nova/limit/placement.py).
3.6 Cyborg and Manila
- Cyborg (
nova/accelerator/cyborg.py:113-114):GET /v2/device_profiles?name=at boot (API),POST /v2/accelerator_requestsandPATCHto bind ARQs (conductor),GET/DELETEARQs (compute). Cyborg notifiesaccelerator-request-bound. - Manila (
nova/share/manila.py):GET /shares/{id}, access rules list,allow/denyaccess for the compute host (virtiofs shares, 2.97+).
4. Cache (oslo.cache)
| Key | Value | TTL | Writer / reader | Defined at |
|---|---|---|---|---|
metadata-<fixed_ip> / metadata-<instance_uuid> | InstanceMetadata object | [api]/metadata_cache_expiration (15 s, nova/conf/api.py:158) | metadata API | nova/api/metadata/handler.py:63-93 |
azcache-<host> | availability-zone name of a host | 3600 s (AZ_CACHE_SECONDS, nova/availability_zones.py:26) | API, AZ lookups; reset on aggregate changes | nova/availability_zones.py:36, nova/availability_zones.py:51-52 |
| EC2 id mappings | memoised id translations | _CACHE_TIME | metadata API (EC2 ids) | nova/objects/ec2.py:43-56 |
When [cache]/enabled is false, an in-process dictionary is used (nova/cache_utils.py:47-58), so each API worker has its own cache.
5. Other
- Privileged operations:
oslo.privsepdaemons (nova/privsep/) for file, network and libvirt helpers on the compute host; rootwrap is no longer used for new code. - Console proxies:
nova-novncproxy,nova-spicehtml5proxy,nova-serialproxyvalidate tokens against the cell DBconsole_auth_tokens(nova/console/websocketproxy.py) and proxy WebSocket ↔ VNC/SPICE/serial on the compute. - Hypervisor: libvirt over its UNIX socket (
qemu:///system), VMware vCenter SOAP, Ironic REST, z/VM REST — replaced by the KubeVirt API in OpenKeel.
Source: reverse-spec-nova/03-interactions_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.