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

Reverse-spec · Services

nova — Rewrite pack

Rewrite pack — 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 Client repositories cited: neutron: = neutron stable/2026.2 @ eef1a0f7ee36, cinder: = cinder stable/2026.2 @ c117f9cf08b4, masakari: = masakari stable/2026.2 @ ae41528e1ebc.

Target: OpenKeel, a Go, Kubernetes-native re-implementation in which nova-compute's hypervisor is KubeVirt. This file adds what files 01–05 and the extracted contracts do not say by themselves. The flavor → KubeVirt instancetype mapping is in 07-flavors-kubevirt-mapping_stable-2026.2.md.

1. Contents of _rewrite/

FileUse in a rewrite
[api-operations_stable-2026.2.json](_rewrite/api-operations_stable-2026.2.json)authoritative operation list (265): method, path, action key, handler def line, microversion range, success codes per range, expected_errors, request/query/response schema names per range, policy rules, internal calls. Generated from the live route table and decorator closures
[api-schemas_stable-2026.2.json](_rewrite/api-schemas_stable-2026.2.json)all 763 JSON schemas of nova/api/openstack/compute/schemas/ (request, query and response), keyed module.name; every name referenced by the operations exists
[openapi_stable-2026.2.json](_rewrite/openapi_stable-2026.2.json)OpenAPI 3.0.3 built from the two files above: 133 paths, 209 path operations, body actions grouped under one POST …/action with x-actions; schema variants per microversion in oneOf + x-microversion-selection. Not validated against a strict OpenAPI validator: Nova schemas use draft-4 keywords and custom formats
[schema-selection_stable-2026.2.json](_rewrite/schema-selection_stable-2026.2.json), [routes_stable-2026.2.json](_rewrite/routes_stable-2026.2.json)raw output of the generic extractor (rewrite_pack.py); superseded by api-operations for actions and versions, kept for traceability
[api-ref_stable-2026.2.json](_rewrite/api-ref_stable-2026.2.json), [microversions_stable-2026.2.md](_rewrite/microversions_stable-2026.2.md)251 documented operations with parameters; the 104 microversions with their first-sentence summary and source line
[exceptions_stable-2026.2.json](_rewrite/exceptions_stable-2026.2.json)539 exception classes with code, message template, raise sites, API conversions
[rpc-contract_stable-2026.2.json](_rewrite/rpc-contract_stable-2026.2.json)93 RPC sends (90 client methods): mode, method, topic, versions, prepare() options, server handler — needed only if OpenKeel keeps Nova's internal RPC (see § 5)
[schema-api-mysql_stable-2026.2.sql](_rewrite/schema-api-mysql_stable-2026.2.sql), [schema-api-postgresql_stable-2026.2.sql](_rewrite/schema-api-postgresql_stable-2026.2.sql)API database DDL from the models (20 tables)
[schema-mysql_stable-2026.2.sql](_rewrite/schema-mysql_stable-2026.2.sql), [schema-postgresql_stable-2026.2.sql](_rewrite/schema-postgresql_stable-2026.2.sql)cell database DDL from the models (30 tables)
[schema-api-sqlite-migrated_stable-2026.2.sql](_rewrite/schema-api-sqlite-migrated_stable-2026.2.sql), [schema-sqlite-migrated_stable-2026.2.sql](_rewrite/schema-sqlite-migrated_stable-2026.2.sql), [schema-diff_stable-2026.2.md](_rewrite/schema-diff_stable-2026.2.md)schemas after nova-manage api_db sync / db sync, and their comparison with the models (§ 5)
[policies_stable-2026.2.json](_rewrite/policies_stable-2026.2.json), [policies_stable-2026.2.yaml](_rewrite/policies_stable-2026.2.yaml)214 default rules with check_str, scope types and documented operations
[config_stable-2026.2.conf](_rewrite/config_stable-2026.2.conf)oslo-config-generator sample of every option
[exchanges_stable-2026.2.json](_rewrite/exchanges_stable-2026.2.json), [response-schemas_stable-2026.2.json](_rewrite/response-schemas_stable-2026.2.json) / [.md](_rewrite/response-schemas_stable-2026.2.md), [observed-errors_stable-2026.2.md](_rewrite/observed-errors_stable-2026.2.md)HTTP exchanges recorded from Nova's functional API-sample tests, with inferred response schemas and observed errors (§ 7)
extra-spec-validators_*, flavor-kubevirt-*, flavor-to-kubevirt_*flavors-scoped spec (unchanged)

Library versions used for the extraction (Nova venv, Python 3.13): oslo.policy 6.0.1, oslo.config 10.7.0, oslo.db 18.1.1, oslo.messaging 18.3.1, oslo.versionedobjects 3.12.0, keystonemiddleware 13.0.1, jsonschema 4.26.0, SQLAlchemy 2.0.52, Alembic 1.19.1, os-traits 3.9.0, os-resource-classes 1.1.0.

2. HTTP behaviour that the contracts do not show

2.1 Middleware pipeline

Order and effects are in 01 § 1.1 (etc/nova/api-paste.ini:31-33). What a rewrite must reproduce: 413 (sizelimit) wins over 401; 401 (authtoken) wins over 404/405 and over version errors; the version document at / and /v2.1 is served without authentication (oscomputeversions pipelines, etc/nova/api-paste.ini:63-70).

2.2 Error body

{"<faultName>": {"code": N, "message": "…"}}, fault name by status (nova/api/openstack/wsgi.py:876-920); see 02 § 1.1. Clients parse message only for display; the status code is the contract (§ 4).

2.3 Microversions

  • Accept OpenStack-API-Version: compute X.Y and X-OpenStack-Nova-API-Version: X.Y; latest; default 2.1; out of range → 406; echo both headers and Vary on every response including errors (nova/api/openstack/wsgi.py:609-615, nova/api/openstack/wsgi.py:922-925).
  • Method not available at the requested version → 404 with no message (nova/api/openstack/wsgi.py:658-667).
  • Request schema, query schema, response schema and success code are chosen independently by version (api-operations lists each with its range).
  • Query-string validation: most list APIs reject unknown parameters only from a given microversion (e.g. servers from 2.75: index_query_v275), earlier versions ignore them. The exact behaviour is in each query schema's additionalProperties.

2.4 Other cross-cutting rules

  • POST …/action: the body must have exactly one key; dispatch on that key (nova/api/openstack/wsgi.py:347-366).
  • Optional {project_id} segment after /v2.1; when present it must match the token (nova/api/openstack/wsgi.py:566-572).
  • POST /servers returns a Location header and links with both self and bookmark (nova/api/openstack/compute/servers.py:103 _add_location).
  • Responses are JSON only; there is no XML since v2.1.
  • Response bodies are validated against the response schemas at run time according to [api]/response_validation: error, warn (default: log a warning, still return the body) or ignore (nova/conf/api.py:363-380, nova/api/validation/__init__.py:278). A rewrite can treat the response schemas as hard contracts: the original only warns.

3. Algorithms a rewrite must reproduce

3.1 Server status mapping

status = _STATE_MAP[vm_state][task_state or 'default'] (nova/api/openstack/common.py:44-111, nova/api/openstack/common.py:114). Clients (Horizon, Skyline, Heat, Tempest, Masakari) poll on status; a rewrite on KubeVirt must keep Nova's vm_state/task_state model (or an exact equivalent) and this table. task_and_vm_state_from_status (nova/api/openstack/common.py:126) is the inverse used by the status list filter.

3.2 Action preconditions

The matrix of 01 § 4 is the contract: allowed vm_state, required task_state (default None), lock check (admin bypass), host checks, and the 409 message format. The compare-and-swap on task_state (Instance.save(expected_task_state=…)) is what makes concurrent actions fail with 409 instead of corrupting state.

3.3 Scheduling

For KubeVirt the Kubernetes scheduler places VMIs, but Placement remains the source of truth for quotas, traits and Neutron/Cyborg resources. The Nova algorithm to keep or deliberately replace (05 § 3.1):

  1. request filters translate the request into Placement query parameters (nova/scheduler/request_filter.py:608-633);
  2. GET /allocation_candidates with resources from the flavor (resources_from_request_spec, nova/scheduler/utils.py:721), extra specs (resources:*, trait:*, hw:cpu_policy → PCPU, granular groups), image traits and port resource requests; PCPU fallback query;
  3. filters (ComputeFilter, ComputeCapabilitiesFilter, ImagePropertiesFilter, server-group filters) and weighers on the candidate hosts;
  4. random pick among the top host_subset_size, claim with PUT /allocations/{instance}, next host on conflict;
  5. alternates (not claimed) for reschedules; max_attempts total.

A rewrite that lets Kubernetes choose the node must still write the same Placement allocations (consumer = instance UUID, project_id, user_id, consumer generation) before the VMI is created, or quota counting from Placement and Neutron QoS bandwidth will diverge.

3.4 Move operations and allocations

Cold and live migrations move the instance's allocation to the migration UUID as consumer before choosing a destination, so that the source usage stays reserved while the instance holds the destination (nova/conductor/tasks/migrate.py:29-110). Confirm deletes the migration's allocation; revert moves it back. Neutron and Cyborg observe the same split via binding:profile.allocation.

3.5 Quota counting

DbQuotaDriver counts instances, cores and RAM from the cell databases (or from Placement usages with [quota]/count_usage_from_placement), key pairs, server groups and members from the API database; limits from quotas/project_user_quotas/quota_classes with defaults from configuration; check before create and optional re-check after (nova/quota.py, nova/compute/api.py:1441, nova/compute/api.py:1570-1583). Unified limits replace the limit source with Keystone (nova/limit/).

3.6 Test cases

No dedicated algorithm vectors were recorded: Nova's scheduling tests depend on in-process fake computes and Placement fixtures, not on a pure function. The functional exchanges (§ 7) cover the API-visible results.

4. What the clients expect

ExpectationWhere the client relies on it
POST /os-server-external-events at microversion 2.1 accepts network-vif-plugged, network-changed, network-vif-deleted, network-vif-unplugged with status completed/failed and an optional tag (port id)neutron:neutron/notifiers/nova.py:46-49, neutron:neutron/notifiers/nova.py:245
The response is a **list of events each with code**; 200 = delivered, anything else logged as failure; a missing code is an errorneutron:neutron/notifiers/nova.py:296-319
A 404 for the whole request (no event matched any server) is tolerated and only loggedneutron:neutron/notifiers/nova.py:286-287, cinder:cinder/compute/nova.py:157-158
The extension server_external_events (and assisted_volume_snapshots for Cinder) is discoverable through novaclient's extension listneutron:neutron/notifiers/nova.py:77-78, cinder:cinder/compute/nova.py:67-69
volume-extended requires microversion 2.51, volume-reimaged 2.93cinder:cinder/compute/nova.py:217, cinder:cinder/compute/nova.py:230
PUT /servers/{id}/os-volume_attachments/{volume} swaps a volume (Cinder volume migration/retype)cinder:cinder/compute/nova.py:183-188
GET /servers/{id}/os-volume_attachments/{volume} at 2.89 (attachment id, bdm_uuid)cinder:cinder/compute/nova.py:243-246
POST/DELETE /os-assisted-volume-snapshotscinder:cinder/compute/nova.py:190-202
Masakari uses microversion 2.53 (service ids are UUIDs): list servers by host (all_tenants, host), disable/enable a compute with reason, read service state/forced_down, evacuate with optional target, os-resetState, os-stop/os-start, lock/unlock, aggregates list and add_hostmasakari:masakari/compute/nova.py:41, masakari:masakari/compute/nova.py:147-264
Nova as a client of Placement and Glance: expectations already specifiedreverse-spec-placement/07-rewrite-pack_stable-2026.2.md § 4, reverse-spec-glance/07-rewrite-pack_stable-2026.2.md

Statuses that must not change: 207 (not 200) when some external events fail; 404 (not 400) for a bad microversion method; 202 for asynchronous actions; 409 for state conflicts.

5. Database strategy

  • Two schemas + cells. The API database (20 modelled tables) and one cell database per cell (30 modelled tables) plus cell0. A Kubernetes-native rewrite with a single cell can merge them, but the instance mapping, build request and request spec concepts are visible in behaviour (servers listed before scheduling, cell0 for failures) and should be kept or emulated.
  • Migrated schema ≠ models (_rewrite/schema-diff_stable-2026.2.md): the migrations still create 11 legacy Placement tables in the API database (resource_providers, allocations, inventories, traits…) and 28 legacy tables in the cell database (nova-network, cells v1, instance_types, snapshots…), plus 52 shadow_* archive tables; on common tables the only differences are two columns present only after migration (instances.internal_id, instance_extra.vpmems). A rewrite that must open an existing Nova database uses the migrated schema; a fresh OpenKeel deployment can use the models' DDL.
  • Soft delete (deleted = id, deleted_at) on cell tables, with archive to shadow_* and purge (nova-manage db archive_deleted_rows, purge); unique constraints include deleted.
  • Concurrency: compare-and-swap on task_state/vm_state; wrap_db_retry on deadlocks; no SELECT … FOR UPDATE on instances; quotas counted without reservations.
  • Serialised objects in columns: build_requests.instance and request_specs.spec hold nova_object JSON; instance_extra.* columns hold JSON of NUMA topology, PCI requests, flavor (old/new), vCPU model, keypairs, trusted certs. A rewrite that shares the database must read and write these formats exactly.
  • Startup data: none besides migrations; cells are created by nova-manage cell_v2 map_cell0 / create_cell and hosts by discover_hosts.

6. Authentication, policies, configuration and CLI

  • Auth: keystonemiddleware auth_token + NovaKeystoneContext (nova/api/auth.py); the service also needs a service user to call Neutron/Cinder/Glance/Placement and to send X-Service-Token.
  • Policies: 214 rules with enforce_scope/enforce_new_defaults personas (admin, project manager/member/reader, service); rule names are part of the deployment contract (policy.yaml overrides). A Go rewrite must evaluate the oslo.policy rule language (role:, project_id:%(project_id)s, rule:, or/and/not, @/!) with the same targets the handlers pass (project_id, user_id of the server…).
  • Configuration: config_stable-2026.2.conf lists every option; the ones that change API-visible behaviour are listed in 05 § 4.3 (timeouts), 03 (clients, notifications), 01 § 1.3 (none for microversions), [api]/max_limit, [api]/enable_instance_password, [DEFAULT]/reclaim_instance_interval, [quota]/*, [scheduler]/*, [filter_scheduler]/*, [workarounds]/*.
  • CLI: deployment tools call nova-manage api_db sync, db sync, cell_v2 map_cell0|create_cell|discover_hosts|list_cells, db online_data_migrations, placement heal_allocations, and nova-status upgrade check. A drop-in rewrite needs equivalents or must change the Helm/operator tooling.

7. Conformance strategy

  • Tempest tempest/api/compute (and scenario tests) is the language-independent black-box suite; run it against both the original and the rewrite.
  • Recorded exchanges: conformance_capture.py http --wrap nova.api.openstack.urlmap:urlmap_factory over the 71 modules of nova/tests/functional/api_sample_tests/ (keystone stubbed, fake virt driver, in-process conductor/scheduler/compute on the fake RPC transport) — 1262 tests run, 0 failures, 0 errors; 2590 exchanges recorded over 329 route/method/microversion operations. Paths are recorded with the version and project prefix (/{version}/{project_id}/servers). These exchanges are evidence, not replayable cases: the tests build their state through the API and fixtures, so there is no seed to load.
  • Response schemas: unlike most services, Nova declares a response schema per handler and microversion (api-schemas); the inferred response-schemas file is a cross-check of what the tests actually returned.
  • API samples: doc/api_samples/** (739 JSON files) are request/response templates per microversion that the API-sample tests compare against; a rewrite can reuse them with the same %(uuid)s-style substitutions (nova/tests/functional/api_samples_test_base.py).
  • Original fixtures: OSAPIFixture (nova/tests/fixtures/nova.py:1018) and PlacementFixture, NeutronFixture, CinderFixture, GlanceFixture in nova/tests/fixtures/ show the minimal behaviour of the external services the tests assume.

8. Gaps found while building the pack

  • The generic extractor found only 3 request schemas and no body actions; Nova-specific tools (api-operations, api-schemas, openapi) replace it.
  • The api-ref documents 251 operations while the code has 265 (counting each body action): actions are documented per key and removed APIs only partially (01 § 8); no operation-by-operation reconciliation was done.
  • os_compute_api:os-hypervisors:list-detail documents a wrong path (01 § 8).
  • The migrated schemas keep many legacy tables that the models no longer describe (§ 5).
  • No algorithm vectors (§ 3.6) and no replay of the exchanges.

9. Non-functional requirements

  • Asynchrony: API latency stays low because work is cast; a rewrite must not make POST /servers wait for scheduling.
  • Scale: list operations scatter-gather over cells with a 60 s cell timeout; [api]/max_limit 1000; periodic tasks on every compute every 60 s tick (resource tracker) — on KubeVirt, prefer watches over polling.
  • Rolling upgrades: RPC version pinning and object backports (03 § 1.2) allow mixed versions; irrelevant if all OpenKeel components ship together, essential if Python and Go computes coexist.
  • Security: RabbitMQ carries tokens and admin passwords (00 § Points of attention 6); metadata API trust relies on a shared secret.

10. Rewrite checklist

  • [ ] Version document and microversion negotiation (2.1–2.104, default 2.1, 404 for out-of-range methods, 406 global)
  • [ ] All 211 live operations with request/query/response schemas per microversion; 54 removed operations answering 410
  • [ ] Error bodies with fault names; per-handler status mapping (not class codes)
  • [ ] oslo.policy-compatible evaluation of the 214 rules and their targets
  • [ ] vm_state/task_state model, _STATE_MAP status mapping, action precondition matrix, compare-and-swap
  • [ ] Instance actions and events, instance faults (details hidden from non-admins for 500)
  • [ ] Placement allocations for every instance and migration (consumer generations, move to migration consumer)
  • [ ] Neutron port binding flow and network-vif-plugged wait; external events endpoint with per-event codes and 207
  • [ ] Cinder attachments 3.44 flow, swap volume, volume-extended/volume-reimaged, assisted snapshots
  • [ ] Glance image download/snapshot; quotas (DB or unified limits); server groups (late affinity check)
  • [ ] Metadata API (Neutron proxy HMAC headers, vendordata, password)
  • [ ] Notifications (unversioned by default; versioned payloads per doc/notification_samples)
  • [ ] Masakari, Cinder and Neutron client expectations of § 4
  • [ ] Tempest compute API suite and the recorded exchanges as regression baseline

Source: reverse-spec-nova/07-rewrite-pack_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.