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

Reverse-spec · Services

magnum — Interactions

Interactions — magnum — branch stable/2026.2

Branch stable/2026.2 @ 1910928b7d9f — repository https://opendev.org/openstack/magnum — analysed on 2026-11-09

Magnum core talks to six kinds of systems: the client (REST), RabbitMQ (RPC between magnum-api and magnum-conductor, plus notifications), MariaDB, Keystone (token validation and the service catalogue), the OpenStack services used to validate requests and store certificates (Glance, Nova, Neutron, Barbican, Cinder, Octavia), and the Kubernetes API of each cluster (health). Everything a driver does (for the Cluster API driver: the Kubernetes API of the management cluster and the OpenStack APIs through CAPO) is described in 08.

flowchart LR
  client[Client / Skyline / openstack CLI] -->|HTTPS REST :9511| api[magnum-api]
  api -->|GET /v3/auth/tokens| ks[Keystone]
  api -->|AMQP cast / call topic magnum-conductor| mq{{RabbitMQ}}
  mq --> cond[magnum-conductor]
  api -->|SQL - uWSGI mode| db[(MariaDB)]
  cond -->|SQL| db
  api -->|REST validation| glance[Glance] & nova[Nova] & neutron[Neutron]
  cond -->|REST secrets + containers| barbican[Barbican]
  cond -->|AMQP notifications magnum.cluster.*| mq
  cond -->|HTTPS mTLS /healthz /api/v1/nodes| k8s[Cluster Kubernetes API]
  cond -->|Python driver API| drv[Driver e.g. magnum-cluster-api]
  drv -->|HTTPS| mgmt[Management cluster API: CAPI objects]

RabbitMQ

Topology

ExchangeTypeRouting key / queueProducerConsumer
[DEFAULT]/control_exchange (default openstack, magnum in most deployments [inferred])topicmagnum-conductor (shared queue)magnum-api (magnum/conductor/api.py:28)every conductor worker (magnum/common/rpc_service.py:38)
sametopicmagnum-conductor.<server> (per-worker queue; server = random 12-character id, magnum/cmd/conductor.py:57)nobody in core (only ListenerAPI, magnum/conductor/api.py:190)the worker
reply_<uuid>directreply queue of each API workerconductormagnum-api (call replies)
control exchangetopicnotifications.info, notifications.error ([oslo_messaging_notifications]/topics)magnum-conductor (magnum/common/rpc.py:59)Ceilometer, CloudKitty, auditors [external]

The transport is created from [DEFAULT]/transport_url (magnum/common/rpc.py:56). Clients are cached per (topic, server, timeout) for the life of the process (magnum/common/rpc_service.py:78).

RPC methods

MethodDirectionModeTopic / serverVersionArgumentsResponseDefined at
cluster_createapi → conductorcastmagnum-conductornonecluster (Cluster object, not yet saved), master_count, node_count, create_timeout—magnum/conductor/api.py:39
cluster_updateapi → conductorcastidemnonecluster, node_count, health_status, health_status_reason, rollback—magnum/conductor/api.py:58
cluster_deleteapi → conductorcastidemnoneuuid—magnum/conductor/api.py:48
cluster_resizeapi → conductorcastidemnonecluster, node_count, nodes_to_remove, nodegroup (NodeGroup object)—magnum/conductor/api.py:76
cluster_upgradeapi → conductorcallidemnonecluster, cluster_template, max_batch_size, nodegroupCluster objectmagnum/conductor/api.py:84
nodegroup_create / nodegroup_update / nodegroup_deleteapi → conductorcastidemnonecluster, nodegroup—magnum/conductor/api.py:163, magnum/conductor/api.py:177, magnum/conductor/api.py:170
sign_certificateapi → conductorcallidemnonecluster, certificate (Certificate object with csr)Certificate with pemmagnum/conductor/api.py:125
get_ca_certificateapi → conductorcallidemnonecluster, ca_cert_typeCertificate with pemmagnum/conductor/api.py:129
rotate_ca_certificateapi → conductorcallidemnoneclusterClustermagnum/conductor/api.py:133
credential_rotateapi → conductorcallidemnonecluster—magnum/conductor/api.py:182
federation_create / federation_update / federation_deleteapi → conductorcastidemnonefederation, create_timeout / rollback / uuid— (raises)magnum/conductor/api.py:106, magnum/conductor/api.py:119, magnum/conductor/api.py:113
object_class_action_versionsapi → conductorcallidemnoneobjname, objmethod, object_versions, args, kwargsobject primitive or valuemagnum/conductor/api.py:138
object_actionapi → conductorcallidemnoneobjinst, objmethod, args, kwargs(updates, result)magnum/conductor/api.py:146
object_backport_versionsapi → conductorcallidemnoneobjinst, object_versionsobject primitivemagnum/conductor/api.py:151
ping_conductorconductor → conductorcall<topic>.<server>none—truemagnum/conductor/api.py:195

Object versions on the wire (magnum_object.version): Cluster 1.24 (magnum/objects/cluster.py:63), ClusterTemplate 1.21 (magnum/objects/cluster_template.py:47), NodeGroup 1.2 (magnum/objects/nodegroup.py:32), Certificate 1.2, X509KeyPair 1.2, Federation 1.0, Quota 1.0, MagnumService 1.0, Stats 1.0.

Notifications

Only cluster operations are notified; templates, nodegroups, quotas and certificates are not.

event_typePriorityEmitted whenPayloadEmitted at
magnum.cluster.createinfo (pending, success) / error (failure)conductor starts a create; the poller sees CREATE_COMPLETE / CREATE_FAILED; the conductor catches an exceptionCADF event (below)magnum/conductor/handlers/cluster_conductor.py:64, magnum/service/periodic.py:78
magnum.cluster.updateinfo / errorupdate, resize, upgrade, CA rotation start, refusal or failure; poller sees UPDATE_* or ROLLBACK_* final statesCADF eventmagnum/conductor/handlers/cluster_conductor.py:143, magnum/conductor/handlers/cluster_conductor.py:242, magnum/conductor/handlers/ca_conductor.py:104
magnum.cluster.deleteinfo / errordelete start or failure; poller sees DELETE_COMPLETE / DELETE_FAILEDCADF eventmagnum/conductor/handlers/cluster_conductor.py:175, magnum/service/periodic.py:78

publisher_id is container-infra.<[DEFAULT]/host or FQDN> (magnum/common/rpc.py:168). The priority is error when the CADF outcome is failure, info otherwise (magnum/conductor/utils.py:149). The event is built with pycadf (magnum/conductor/utils.py:128): eventType activity, action (create, update, delete), outcome (pending, success, failure), initiator (user, project, domain of the request; empty for the periodic tasks, which run as admin), observer and target of type service/magnum/cluster, and a cluster_data attachment with the cluster fields (magnum/conductor/utils.py:93). One attachment key is misspelt with a trailing colon: docker_volume_size: (magnum/conductor/utils.py:108).

Sample frame (cast cluster_create, AMQP body)

{"oslo.version": "2.0",
 "oslo.message": "{\"method\": \"cluster_create\", \"namespace\": null, \"version\": null,
   \"args\": {\"cluster\": {\"magnum_object.name\": \"Cluster\", \"magnum_object.namespace\": \"magnum\",
       \"magnum_object.version\": \"1.24\",
       \"magnum_object.data\": {\"uuid\": \"5d12f6fd-…\", \"name\": \"k8s-prod\",
         \"cluster_template_id\": \"0b1c…\", \"keypair\": \"ops\", \"labels\": {\"kube_tag\": \"v1.31.4\"},
         \"flavor_id\": \"m1.large\", \"master_flavor_id\": \"m1.medium\", \"project_id\": \"…\", \"user_id\": \"…\",
         \"master_lb_enabled\": true, \"floating_ip_enabled\": true, \"coe_version\": null, \"container_version\": null},
       \"magnum_object.changes\": [\"uuid\", \"name\", \"…\"]},
     \"master_count\": 3, \"node_count\": 4, \"create_timeout\": 60},
   \"_unique_id\": \"…\", \"_context_auth_token\": \"gAAAA…\", \"_context_user_id\": \"…\",
   \"_context_project_id\": \"…\", \"_context_roles\": [\"member\", \"reader\"], \"_context_is_admin\": false,
   \"_context_request_id\": \"req-…\", \"_context_auth_token_info\": {…}}"}

The user's Keystone token and the full token body travel in the context of every message (magnum/common/context.py:66, magnum/common/context.py:79; the context also carries all_tenants, magnum/common/context.py:80): the conductor reuses them to call OpenStack services on the user's behalf. A cast that waits in the queue longer than the token lifetime fails with AuthorizationFailure in the conductor.

Database

oslo.db / SQLAlchemy, [database]/connection. The schema has no foreign keys: integrity is enforced by code (magnum/db/sqlalchemy/models.py). Alembic head: b3e1cf4a2d5e (magnum/db/sqlalchemy/alembic/versions/b3e1cf4a2d5e_add_node_labels_and_node_taints.py).

Tables

TableRoleWritten byRead by
clusterone row per cluster: template, flavors, labels, status, health, API address, certificate references, stack_id (driver's id of the cluster)conductor (create, update, poller, delete); API only through objects in uWSGI modeAPI (all routes), poller, health poller
nodegroupsizes, flavors, images, labels, node labels and taints, status per role (master, worker); unique (cluster_id, name)conductor, driversAPI (cluster sizes and addresses are sums over this table)
cluster_templatetemplates; public / hidden flagsAPI (create, patch, delete)API, conductor (driver selection)
x509keypaircertificates and encrypted private keys with their passphrases, when [certificates]/cert_manager_type = x509keypairconductorconductor
quotas(project_id, resource) → hard_limitAPI (admin)API (cluster create)
magnum_serviceconductor heartbeatsconductorAPI (/v1/mservices)
federationfederations (never written by the API, see 01)nobodyAPI

Notable transactions

  • Template update locks the row (SELECT … FOR UPDATE), then checks whether a cluster uses it before allowing anything other than rename or (un)publish (magnum/db/sqlalchemy/api.py:436): sql SELECT * FROM cluster_template WHERE uuid = :id FOR UPDATE; SELECT 1 FROM cluster WHERE cluster_template_id = :uuid LIMIT 1; UPDATE cluster_template SET … WHERE id = :id;
  • Cluster update (save()) also uses SELECT … FOR UPDATE then UPDATE (magnum/db/sqlalchemy/api.py:267), wrapped in retry_on_deadlock. There is no optimistic version column: two conductors saving the same cluster overwrite each other's fields.
  • Template visibility is a UNION of the project's templates, the public non-hidden ones and, for admins, the public hidden ones (magnum/db/sqlalchemy/api.py:294).
  • Cluster list by size: filtering on node_count sums nodegroup.node_count grouped by cluster_id (magnum/db/sqlalchemy/api.py:139).
  • Stats: SELECT COUNT(*) FROM cluster [WHERE project_id = :p] and SELECT SUM(node_count) FROM nodegroup [WHERE project_id = :p] (magnum/db/sqlalchemy/api.py:221).
  • Status poller: SELECT * FROM cluster WHERE status IN (…4 states…) every 10 s (magnum/service/periodic.py:166), then one nodegroup list per cluster.

Outbound REST calls

All OpenStack clients are openstacksdk connections built from a keystoneauth session (magnum/common/clients.py). In the API and the conductor the session reuses the user's token (AccessInfoPlugin built from keystone.token_info, magnum/common/keystone.py:66). Without a token, i.e. in the periodic tasks and for the Barbican admin client, it uses the service credentials of [keystone_auth] (magnum/common/keystone.py:73). The endpoint comes from the catalogue, with [<service>]/region_name and endpoint_type (publicURL by default) (magnum/common/clients.py:44).

Target serviceMethod + pathWhenAuthenticationTimeout / retryErrors handledDefined at
KeystoneGET /v3/auth/tokensevery authenticated requestservice token (keystonemiddleware [keystone_authtoken])keystonemiddleware defaults401 to the clientetc/magnum/api-paste.ini:7, magnum/api/middleware/auth_token.py:60
KeystoneGET /v3/projects/{id}POST /v1/quotasuser tokensdk defaults404 → ProjectNotFoundmagnum/api/validation.py:148
KeystoneGET /v3/regionsregion name validation (Cinder helpers)user token—→ RegionsListFailedmagnum/common/keystone.py:100
GlanceGET /v2/images/{id} or GET /v2/images?name= (find_image)template create (twice: driver resolution and validation), template patchuser tokensdk defaults404 → ImageNotFound, 403 → ImageNotAuthorized, duplicate → 409magnum/api/validation.py:76, magnum/api/attr_validator.py:36
NovaGET /flavors/detail (all flavors)every flavor check: template create/patch, cluster create/patch, nodegroup create/patch — up to 4 full listings per requestuser token—→ FlavorNotFoundmagnum/api/attr_validator.py:59, magnum/api/attr_validator.py:191
NovaGET /os-keypairs/{name}cluster create with a keypairuser token—404 → KeyPairNotFoundmagnum/api/attr_validator.py:74
NeutronGET /v2.0/networks?router:external=True, GET /v2.0/networks, GET /v2.0/subnets (all, filtered in Python)template and cluster validationuser token—→ *NotFound, 409 on duplicatesmagnum/api/attr_validator.py:83, magnum/api/attr_validator.py:104, magnum/api/attr_validator.py:126
BarbicanPOST /v1/secrets (×2–4), POST /v1/containerseach certificate stored (4 per cluster create, 4 per CA rotation)Magnum service credentials (admin client, magnum/common/cert_manager/barbican_cert_manager.py:73)—rollback of created secrets, then CertificatesToClusterFailedmagnum/common/cert_manager/barbican_cert_manager.py:95
BarbicanGET /v1/containers/{id}, GET /v1/secrets/{id}/payloadCA download, CSR signing, every health poll (unless a cache dir exists)service credentials—exception logged and re-raisedmagnum/common/cert_manager/barbican_cert_manager.py:170
BarbicanDELETE /v1/containers/{id} and secretscluster deleted (Kubernetes CA and client certificate only)service credentials—warning, continuemagnum/common/cert_manager/barbican_cert_manager.py:195
Cluster Kubernetes APIGET {api_address}/healthz, GET {api_address}/api/v1/nodeshealth poller, every 60 s per clustermTLS with the Magnum client certificate (CN=admin, O=system:masters) and the cluster CAno timeout, no retryexception → health unchangedmagnum/conductor/k8s_api.py:44

Because the certificates are created with the service credentials, the Barbican secrets belong to the Magnum service project, not to the user's project. A cluster deleted while Barbican is unreachable leaves its secrets behind, and the etcd and front-proxy CAs are never deleted (magnum/conductor/handlers/common/cert_manager.py:240).

Certificate storage back ends

[certificates]/cert_manager_typeStoragePrivate key protectionDefined at
barbican (default)one Barbican certificate container per certificatekey encrypted with a random passphrase, stored as a separate secret in the same containermagnum/common/cert_manager/barbican_cert_manager.py:95
x509keypairx509keypair tablethe encrypted key and its passphrase are in the same rowmagnum/common/cert_manager/x509keypair_cert_manager.py:47
localfiles under [certificates]/storage_path (/var/lib/magnum/certificates/) on the conductor hostsamemagnum/common/cert_manager/local_cert_manager.py

Certificate formats (magnum/common/x509/operations.py): RSA keys of [x509]/rsa_key_size bits (2048), SHA-256 signatures, CA with BasicConstraints(ca=True, path_length=0) and key usage keyCertSign (magnum/common/x509/operations.py:83), client certificates with clientAuth (magnum/common/x509/operations.py:68), validity [x509]/term_of_validity days (1825).

Other

  • Files: when [cluster]/temp_cache_dir (/var/lib/magnum/certificate-cache) exists, the conductor caches each cluster's CA, client key and certificate in clear text under <dir>/<cluster_uuid>/, mode 0600 (magnum/conductor/handlers/common/cert_manager.py:178). The cache is never refreshed after a CA rotation, so the health poller keeps using the old client certificate [inferred: the cache directory is only written when absent, magnum/conductor/handlers/common/cert_manager.py:184]. Otherwise temporary files are created for each poll.
  • Drivers: loaded with stevedore from the magnum.drivers entry point (magnum/drivers/common/driver.py:36); [drivers]/disabled_drivers hides some.
  • No subprocess, rootwrap, privsep, cache (Memcached/Redis) or coordination back end is used by Magnum core.

Source: reverse-spec-magnum/03-interactions_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.