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

Reverse-spec · Services

magnum — Driver magnum cluster api

Cluster API driver (magnum-cluster-api) — magnum — branch stable/2026.2

Driver repository https://github.com/vexxhost/magnum-cluster-api @ v0.39.0 (066fdc2) — analysed on 2026-11-09 — paired with Magnum stable/2026.2 @ 1910928

Reference convention: magnum-cluster-api:<path>:<line> points into the driver clone at tag v0.39.0 (full SHA 066fdc23d45f2d0f9a0633bc7c9b61e2f64e4268); magnum:<path>:<line> points into the Magnum clone at 1910928. Statements marked [inferred] were not traced to the end.

Tag choice: v0.39.0 is the latest tag and the first release whose changelog says it runs under Magnum 2026.2 ("run under Magnum 2026.2, which dropped eventlet and novaclient", magnum-cluster-api:CHANGELOG.md:17). The driver supports both eventlet (≤ 2026.1) and native threads (2026.2) by detecting the eventlet patcher (magnum-cluster-api:magnum_cluster_api/utils.py:63-91).


1. Overview

magnum-cluster-api is an out-of-tree Magnum driver that turns a Magnum cluster into a **Cluster API (CAPI) topology-managed Cluster** reconciled by the CAPI core, kubeadm bootstrap / control-plane providers and CAPO (Cluster API Provider OpenStack). The driver itself never creates Nova servers: it writes Kubernetes objects into a management cluster (namespace magnum-system) and reads their status back.

Code layout:

PartLanguageRole
magnum_cluster_api/driver.pyPythonMagnum Driver subclass: entry points called by the Magnum conductor (magnum-cluster-api:magnum_cluster_api/driver.py:46-737).
magnum_cluster_api/resources.pyPythonBuilds the CAPI Cluster (topology + ~40 variables), secrets, autoscaler release (magnum-cluster-api:magnum_cluster_api/resources.py:871-1294).
magnum_cluster_api/utils.pyPythonLabel parsing, validation, server groups, Octavia cleanup, cloud.conf generation (magnum-cluster-api:magnum_cluster_api/utils.py:144-772).
src/ (crate magnum-cluster-api 0.39.0, pyo3 0.29, kube-rs 4)Rust (pyo3 extension module magnum_cluster_api.magnum_cluster_api)Driver (ClusterClass + addon ClusterResourceSets), KubeClient (generic create/replace/delete), Monitor (health) (magnum-cluster-api:src/lib.rs:26-35, magnum-cluster-api:Cargo.toml:3, magnum-cluster-api:Cargo.toml:48-49).
magnum_cluster_api/charts/*Helm chartscilium, openstack-cloud-controller-manager, openstack-cinder-csi, openstack-manila-csi, k8s-keystone-auth, cluster-autoscaler, rendered with helm template (Python, external helm binary) or an in-process Rust templater.
magnum_cluster_api/manifests/calico/*.yaml, manifests/nfs-csiYAMLStatic Calico and NFS CSI manifests (magnum-cluster-api:magnum_cluster_api/resources.py:436-462).
magnum_cluster_api/proxy/*PythonOptional magnum-cluster-api-proxy daemon: HAProxy in Neutron network namespaces for clusters without API floating IP (magnum-cluster-api:magnum_cluster_api/proxy/manager.py:333-353).

Key design facts:

  • One shared ClusterClass per driver release, named magnum-<git describe> (e.g. magnum-v0.39.0) (magnum-cluster-api:src/lib.rs:17-18), re-applied on every create/upgrade (magnum-cluster-api:src/driver.rs:302-319). All per-cluster differences are topology variables consumed by ClusterClass JSON patches (magnum-cluster-api:src/resources.rs:144-153).
  • CAPI name ≠ Magnum UUID: the CAPI Cluster is named kube-<5 random [a-z0-9]> and stored in Magnum's cluster.stack_id (magnum-cluster-api:magnum_cluster_api/utils.py:113-123, magnum-cluster-api:magnum_cluster_api/driver.py:81-82).
  • Status is polled, not watched: Magnum's periodic sync_cluster_status calls update_cluster_status (magnum:magnum/service/periodic.py:66-71, magnum:magnum/service/periodic.py:161-169).
  • No Heat, needs_trust = False (magnum-cluster-api:magnum_cluster_api/driver.py:47); CAPO/CCM/CSI authenticate with a per-cluster Keystone application credential (magnum-cluster-api:magnum_cluster_api/driver.py:98-102).
  • A distributed lock (sherlock KubernetesLock, name cluster-<uuid>, namespace magnum-system, expiry 60 s) serialises every mutating call and the status sync across conductors (magnum-cluster-api:magnum_cluster_api/sync.py:18-36, magnum-cluster-api:magnum_cluster_api/driver.py:37-43).

2. Driver interface implemented

Registration: five magnum.drivers entry points (magnum-cluster-api:pyproject.toml:68-73), one per OS; all share BaseDriver and differ only in provides (server_type is always vm, coe always kubernetes). Config options are exported with oslo.config.opts (magnum-cluster-api:pyproject.toml:75).

Entry pointClassprovides (server_type / os / coe)Source
k8s_cluster_api_ubuntuUbuntuDrivervm / ubuntu / kubernetesmagnum-cluster-api:magnum_cluster_api/driver.py:740-745
k8s_cluster_api_ubuntu_focalUbuntuFocalDrivervm / ubuntu-focal / kubernetesmagnum-cluster-api:magnum_cluster_api/driver.py:748-753
k8s_cluster_api_debianDebianDrivervm / debian / kubernetesmagnum-cluster-api:magnum_cluster_api/driver.py:756-761
k8s_cluster_api_flatcarFlatcarDrivervm / flatcar / kubernetesmagnum-cluster-api:magnum_cluster_api/driver.py:764-769
k8s_cluster_api_rockylinuxRockyLinuxDrivervm / rockylinux / kubernetesmagnum-cluster-api:magnum_cluster_api/driver.py:772-777

The Magnum cluster template's cluster_distro (image os_distro) selects the driver; get_operating_system then maps it by prefix to ubuntu|debian|flatcar|rockylinux for the operatingSystem variable (magnum-cluster-api:magnum_cluster_api/utils.py:46, magnum-cluster-api:magnum_cluster_api/utils.py:545-550).

Methods (base contract in magnum:magnum/drivers/common/driver.py:199-308):

MethodLockedSync/async for Magnum APIWhat it doesSource
__init__——Builds a pykube client from KUBECONFIG/in-cluster and the Rust Driver("magnum-system")magnum-cluster-api:magnum_cluster_api/driver.py:49-51
create_cluster(ctx, cluster, timeout)inner _create_cluster lockedasync (conductor)Generates stack_id, saves it; Rust create_cluster (ClusterClass + legacy CRS + cloud-provider CRS); validates; then app credential, cloud-config secret, 4 CA secrets, server groups, addon secrets, CAPI Cluster. cluster_create_timeout is ignored.magnum-cluster-api:magnum_cluster_api/driver.py:70-138
update_cluster_status(ctx, cluster)yesperiodicDerives KCP / nodegroup / cluster status, fills api_address, coe_version, installs autoscaler, finishes deletion. See §5.magnum-cluster-api:magnum_cluster_api/driver.py:200-313
update_cluster(...)yes—raise NotImplementedError() (cluster template updates are not supported).magnum-cluster-api:magnum_cluster_api/driver.py:316-329
resize_cluster(ctx, cluster, mgr, node_count, nodes_to_remove, nodegroup)yesasyncValidates; annotates the Machines whose OpenStack instance UUID is in nodes_to_remove with cluster.x-k8s.io/delete-machine: "yes"; then _update_nodegroup.magnum-cluster-api:magnum_cluster_api/driver.py:332-372
upgrade_cluster(ctx, cluster, template, max_batch_size, nodegroup, ...)yessyncCopies kube_tag and image_id of the new template into cluster and all nodegroups (ignores nodegroup, max_batch_size), re-applies ClusterClass/addons, replaces the CAPI Cluster topology.magnum-cluster-api:magnum_cluster_api/driver.py:375-436
delete_cluster(ctx, cluster)yesasyncNo-op if stack_id is None; deletes Octavia LBs created by the in-cluster CCM; Rust deletes addon CRS/secrets; deletes CAPI Cluster; helm delete of the autoscaler.magnum-cluster-api:magnum_cluster_api/driver.py:442-465
validate_master_resize(node_count)nosync (API)Allows control-plane resize; rejects even or < 1 counts with MasterNGSizeInvalid (base driver raises MasterNGResizeNotSupported).magnum-cluster-api:magnum_cluster_api/driver.py:468-470, magnum:magnum/drivers/common/driver.py:258-260
validate_master_size——Inherited (odd and ≥ 1).magnum:magnum/drivers/common/driver.py:253-256
create_nodegroup(ctx, cluster, ng)yesasyncValidates name (RFC 1123), ensures worker server group, appends a machineDeployments[] entry to the topology (server-side apply).magnum-cluster-api:magnum_cluster_api/driver.py:473-499
update_nodegroup(ctx, cluster, ng)yesasync_update_nodegroup (control-plane replicas, or MD replicas/autoscaler annotations).magnum-cluster-api:magnum_cluster_api/driver.py:613-679
delete_nodegroup(ctx, cluster, ng)yesasyncSets ng DELETE_IN_PROGRESS, removes the MD from the topology; raises heatclient HTTPNotFound if absent.magnum-cluster-api:magnum_cluster_api/driver.py:682-720
get_monitor(ctx, cluster)yesperiodicReturns monitor.Monitor (Rust health + autoscaler replica sync).magnum-cluster-api:magnum_cluster_api/driver.py:722-724
rotate_ca_certificate——Not overridden (commented out) → base raises NotSupported.magnum-cluster-api:magnum_cluster_api/driver.py:726-728, magnum:magnum/drivers/common/driver.py:306-308
rotate_credential, pre_delete_cluster, get_scale_manager——Not overridden (base behaviour).magnum:magnum/drivers/common/driver.py:228-233, magnum:magnum/drivers/common/driver.py:292-304
create/update/delete_federation——NotImplementedError.magnum-cluster-api:magnum_cluster_api/driver.py:730-737

3. Objects created on the management cluster

3.1 Management cluster access

  • Python side: pykube.HTTPClient(pykube.KubeConfig.from_env()) — KUBECONFIG env or in-cluster service account (magnum-cluster-api:magnum_cluster_api/clients.py:173-174).
  • Rust side: one process-wide kube::Client::try_default() (same resolution rules), cached in a OnceCell to avoid FD leaks (magnum-cluster-api:src/clients/kubernetes.rs:37-60).
  • Workload cluster access: kubeconfig read from the CAPI-generated secret <stack_id>-kubeconfig, key value, in magnum-system (magnum-cluster-api:src/magnum.rs:247-287). Used only during upgrade to delete legacy addon workloads (magnum-cluster-api:src/driver.rs:82-105) and by the autoscaler (clusterAPIKubeconfigSecret) (magnum-cluster-api:magnum_cluster_api/resources.py:82).
  • There is no driver option for the management kubeconfig: everything is in the hard-coded namespace magnum-system (magnum-cluster-api:magnum_cluster_api/driver.py:51).
  • Write semantics: Rust create_or_update = GET → replace with resourceVersion, retried with exponential backoff on HTTP 409; 404 → create (magnum-cluster-api:src/clients/kubernetes.rs:153-176). Topology edits from Python use server-side apply with fieldManager=atmosphere-operator, force=true (magnum-cluster-api:magnum_cluster_api/utils.py:589-607). Upgrade uses a GET/replace of metadata.labels, spec.clusterNetwork, spec.topology with 409 retry (magnum-cluster-api:src/client.rs:73-107).

3.2 Object catalogue

Object (apiVersion / kind)NameCreated by / whenContentLabels / annotationsSource
v1 Namespacemagnum-systemRust apply_cluster_class (create, upgrade)——magnum-cluster-api:src/driver.rs:210-212, magnum-cluster-api:src/driver.rs:381-391
infrastructure.cluster.x-k8s.io/v1beta1 OpenStackClusterTemplatemagnum-<version>idemidentityRef {name: PLACEHOLDER, cloudName: default}, managedSecurityGroups.allowAllInClusterTraffic: true + NodePort 30000-32767 TCP/UDP from 0.0.0.0/0—magnum-cluster-api:src/features/mod.rs:378-421
infrastructure.cluster.x-k8s.io/v1beta1 OpenStackMachineTemplatemagnum-<version>idemplaceholder flavor / image id / identityRef—magnum-cluster-api:src/features/mod.rs:354-374
controlplane.cluster.x-k8s.io/v1beta1 KubeadmControlPlaneTemplatemagnum-<version>idemrolloutBefore.certificatesExpiryDays: 21; apiserver profiling=false, webhooks hostPath volume; etcd metrics 0.0.0.0:2381; controller-manager/scheduler bind-address 0.0.0.0, cloud-provider external; files: audit policy, keystone webhook kubeconfig, kube-proxy script; format cloud-config; kubelet cloud-provider=external; node name {{ local_hostname }}—magnum-cluster-api:src/features/mod.rs:187-313
bootstrap.cluster.x-k8s.io/v1beta1 KubeadmConfigTemplatemagnum-<version>idemjoin config, kubelet cloud-provider=external—magnum-cluster-api:src/features/mod.rs:317-350
cluster.x-k8s.io/v1beta1 ClusterClassmagnum-<version>idemcontrol plane + one worker class default-worker; MHC (maxUnhealthy 80 %, Ready False/Unknown 5m); nodeVolumeDetachTimeout 5m0s; variables + patches from every registered feature—magnum-cluster-api:src/resources.rs:41-153
v1 Secret type cluster.x-k8s.io/secret<stack_id>-ca, -etcd, -proxy, -saPython _create_clustertls.crt/tls.key of the Magnum-generated CAs (decrypted key)cluster.x-k8s.io/cluster-name=<stack_id>magnum-cluster-api:magnum_cluster_api/resources.py:513-632, magnum-cluster-api:magnum_cluster_api/driver.py:112-123
v1 Secret<stack_id>-cloud-configPython _create_clusterclouds.yaml (cloud default, app credential), cacertcluster-uuid=<uuid>magnum-cluster-api:magnum_cluster_api/resources.py:635-699
v1 Secret type addons.cluster.x-k8s.io/resource-set<uuid> ("legacy")Python (data) + Rust (cilium.yaml)cilium.yaml (if cilium) or calico.yml, cloud-config-secret.yaml, NFS CSI manifests (if Manila), keystone-auth.yaml (if enabled)—magnum-cluster-api:magnum_cluster_api/resources.py:379-500, magnum-cluster-api:src/magnum.rs:350-374
addons.cluster.x-k8s.io/v1beta1 ClusterResourceSet<uuid>Rust create_cluster onlyselects clusters with label cluster-uuid=<uuid>, resource Secret <uuid>, default strategy—magnum-cluster-api:src/magnum.rs:328-348, magnum-cluster-api:src/driver.rs:44-63
v1 Secret type addons.cluster.x-k8s.io/resource-set<stack_id>-cloud-providerPython (data)cloud-controller-manager.yaml (Rust-rendered OCCM chart), cloud-config-secret.yaml, cinder-csi.yaml + one StorageClass block-<type> per Cinder volume type (default type annotated default), manila-csi.yaml + csi-manila-secrets + StorageClass share-<type> (only if manila_csi_share_network_id)—magnum-cluster-api:magnum_cluster_api/resources.py:210-366
addons.cluster.x-k8s.io/v1beta1 ClusterResourceSet<stack_id>-cloud-providerRust (create + upgrade)selector cluster-uuid=<uuid>, strategy Reconcile—magnum-cluster-api:src/magnum.rs:289-313, magnum-cluster-api:src/driver.rs:65-119
cluster.x-k8s.io/v1beta1 Cluster<stack_id>Python resources.Cluster.applyclusterNetwork, topology (class, version, controlPlane, workers.machineDeployments, variables) — see §4cluster-uuid=<uuid>, cni=calico-<tag> (Calico only)magnum-cluster-api:magnum_cluster_api/resources.py:871-1289
Helm release (in magnum-system)<stack_id> (fullnameOverride <stack_id>-autoscaler)update_cluster_status once API is up (create) or apply_cluster_from_magnum_cluster (upgrade)cluster-autoscaler, cloudProvider: clusterapi, clusterAPIMode: kubeconfig-incluster, nodeSelector openstack-control-plane=enabled, enforce-node-group-min-size—magnum-cluster-api:magnum_cluster_api/resources.py:60-108, magnum-cluster-api:magnum_cluster_api/driver.py:254-258
Lock objectcluster-<uuid> in magnum-systemsherlock KubernetesLockexpiry 60 s, retry 1 s—magnum-cluster-api:magnum_cluster_api/sync.py:24-36 (object kind [inferred]: sherlock's Kubernetes backend)
Annotation on Machine—resize_clustercluster.x-k8s.io/delete-machine: "yes"—magnum-cluster-api:magnum_cluster_api/driver.py:363-370
v1 Service / discovery.k8s.io/v1 EndpointSlice<stack_id>magnum-cluster-api-proxy (optional daemon)port 6443 → HAProxy in the Neutron netns; rewrites the kubeconfig secret to https://<stack_id>.magnum-system:6443—magnum-cluster-api:magnum_cluster_api/proxy/manager.py:279-313, magnum-cluster-api:magnum_cluster_api/proxy/structs.py:44-78

Objects created by CAPI/CAPO from the topology (not by the driver) but read by the driver: KubeadmControlPlane, MachineDeployment (label topology.cluster.x-k8s.io/deployment-name=<ng.name>), Machine, OpenStackMachine, OpenStackCluster, <stack_id>-kubeconfig secret (magnum-cluster-api:magnum_cluster_api/objects.py:72-98, magnum-cluster-api:magnum_cluster_api/driver.py:562-569).

Addons delivered to the workload cluster (via CRS, namespace kube-system):

AddonConditionVersion sourceSource
Cilium (Helm chart 1.15.3, kube-proxy replacement serviceProxyName: cilium, pool cilium_ipv4pool)network_driver == ciliumlabel cilium_tag (default v1.15.3)magnum-cluster-api:src/addons/cilium.rs:130-140, magnum-cluster-api:src/addons/cilium.rs:319-339, magnum-cluster-api:src/magnum.rs:30-37
Calico (static manifest)network_driver == calicolabel calico_tag (default v3.32.1)magnum-cluster-api:magnum_cluster_api/resources.py:50, magnum-cluster-api:magnum_cluster_api/resources.py:436-447
OpenStack CCM (chart 2.35.0)alwayslabel cloud_provider_tag, else per Kubernetes minor (1.22→v1.22.2 … 1.35→v1.35.0, default v1.35.0)magnum-cluster-api:src/addons/cloud_controller_manager.rs:74-133, magnum-cluster-api:src/magnum.rs:113-150
Cinder CSI (chart 2.32.0)label cinder_csi_enabled (default true) and Keystone catalog has volumev3 or block-storagecinder_csi_plugin_tag v1.32.0, sidecar tags csi_*_tagmagnum-cluster-api:magnum_cluster_api/integrations/cinder.py:25-28, magnum-cluster-api:src/magnum.rs:46-106
Manila CSI + NFS CSIlabel manila_csi_enabled (default true) and service sharev2/sharemanila_csi_plugin_tag v1.32.0magnum-cluster-api:magnum_cluster_api/integrations/manila.py:20-23, magnum-cluster-api:magnum_cluster_api/resources.py:449-462
k8s-keystone-auth (DaemonSet, hostNetwork, 127.0.0.1:8443)label keystone_auth_enabled (default true)chart appVersion v1.29.0magnum-cluster-api:magnum_cluster_api/resources.py:465-495, magnum-cluster-api:magnum_cluster_api/charts/k8s-keystone-auth/templates/daemonset.yaml:54, magnum-cluster-api:magnum_cluster_api/charts/k8s-keystone-auth/templates/daemonset.yaml:75

Image mirroring: when container_infra_prefix is set, every image is rewritten to the private registry with fixed rules (calico, cilium, k8scloudprovider, sig-storage, provider-os, coredns, autoscaling, etcd/kube-*/pause) (magnum-cluster-api:magnum_cluster_api/image_utils.py:42-77).

flowchart LR
  subgraph Magnum
    MC[Magnum cluster uuid + stack_id]
  end
  subgraph mgmt["Management cluster, ns magnum-system"]
    CC[ClusterClass magnum-vX.Y.Z]
    OCT[OpenStackClusterTemplate]
    OMT[OpenStackMachineTemplate]
    KCPT[KubeadmControlPlaneTemplate]
    KCT[KubeadmConfigTemplate]
    CL[Cluster stack_id\nlabel cluster-uuid]
    CCS[Secret stack_id-cloud-config\nclouds.yaml app cred]
    CAS[Secrets stack_id-ca/-etcd/-proxy/-sa]
    LS[Secret uuid legacy addons]
    CPS[Secret stack_id-cloud-provider]
    CRS1[CRS uuid]
    CRS2[CRS stack_id-cloud-provider Reconcile]
    AS[Helm release stack_id autoscaler]
    KCP[KubeadmControlPlane]
    MD[MachineDeployment per nodegroup]
    M[Machine / OpenStackMachine]
    OSC[OpenStackCluster]
    KC[Secret stack_id-kubeconfig]
  end
  subgraph OpenStack
    NOVA[Nova servers + server groups]
    NEU[Neutron net/subnet/router/SG/FIP]
    OCTA[Octavia API LB]
    CIN[Cinder boot/etcd/docker volumes]
  end
  subgraph Workload["Workload cluster kube-system"]
    CNI[Cilium or Calico]
    CCM[OpenStack CCM]
    CSI[Cinder / Manila CSI]
    KA[k8s-keystone-auth]
  end
  MC --> CL
  CC --> OCT & OMT & KCPT & KCT
  CL -- topology.class --> CC
  CL --> KCP & MD & OSC
  KCP --> M
  MD --> M
  CCS -. identityRef .-> OSC & M
  CAS -. kubeadm CA .-> KCP
  OSC --> NEU & OCTA
  M --> NOVA & CIN
  CL --> KC
  LS --> CRS1 --> CNI & KA
  CPS --> CRS2 --> CCM & CSI
  KC -.-> AS

4. Field / label mapping (Magnum → CAPI / CAPO)

Unless stated, the target is a **CAPI Cluster.spec.topology.variables[] entry**, then a ClusterClass JSON patch writes it into the concrete template. Label values are strings; booleans are parsed with strutils.bool_from_string(strict=True) and integers with validate_integer (magnum-cluster-api:magnum_cluster_api/utils.py:327-356). Cluster labels are Magnum's merged template+cluster labels; nodegroup labels are used for per-MD overrides.

4.1 Cluster / template fields

Magnum fieldDefaultVariable / CAPI fieldFinal target (patch)Source
cluster.stack_id (generated kube-xxxxx)—Cluster.metadata.name; all CAPI child names—magnum-cluster-api:magnum_cluster_api/resources.py:897-898
cluster.uuid—label cluster-uuid on Cluster; CRS selector; legacy secret/CRS name; CCM cluster.name—magnum-cluster-api:magnum_cluster_api/resources.py:204-207, magnum-cluster-api:src/addons/cloud_controller_manager.rs:125-129
labels.kube_tagv1.25.3 (Python)topology.versionKCP/MD Kubernetes version; also selects autoscaler + CCM imagemagnum-cluster-api:magnum_cluster_api/utils.py:228-229, magnum-cluster-api:magnum_cluster_api/resources.py:977
cluster.master_count—topology.controlPlane.replicasKCP replicas (must be odd)magnum-cluster-api:magnum_cluster_api/resources.py:984, magnum-cluster-api:magnum_cluster_api/utils.py:504-505
cluster.master_flavor_id (name or id, resolved via Nova)—controlPlaneFlavor = flavor namecontrol-plane OpenStackMachineTemplate.spec.flavormagnum-cluster-api:magnum_cluster_api/resources.py:944, magnum-cluster-api:magnum_cluster_api/resources.py:1098-1100, magnum-cluster-api:src/features/flavors.rs:52-54
cluster.flavor_id—flavor (cluster level)worker OSMT spec.flavormagnum-cluster-api:magnum_cluster_api/resources.py:1159-1162, magnum-cluster-api:src/features/flavors.rs:75-77
default_ng_master.image_id (validated via Glance)—imageUUID; hardwareDiskBus from image property hw_disk_busOSMT spec.image.id (CP + workers); device names /dev/sdX vs /dev/vdXmagnum-cluster-api:magnum_cluster_api/resources.py:946, magnum-cluster-api:magnum_cluster_api/resources.py:1169-1172, magnum-cluster-api:magnum_cluster_api/resources.py:1199-1202, magnum-cluster-api:src/features/images.rs:52-54
cluster.master_lb_enabled—apiServerLoadBalancer.enabledOpenStackClusterTemplate.spec.apiServerLoadBalancermagnum-cluster-api:magnum_cluster_api/resources.py:948-950, magnum-cluster-api:src/features/api_server_load_balancer.rs:66
cluster.keypair""sshKeyNameOSMT spec.sshKeyNamemagnum-cluster-api:magnum_cluster_api/resources.py:1191-1194, magnum-cluster-api:src/features/ssh_key.rs:52-54
template.external_network_id (name/id resolved)—externalNetworkIdOpenStackCluster.spec.externalNetwork.idmagnum-cluster-api:magnum_cluster_api/resources.py:1138-1144, magnum-cluster-api:src/features/external_network.rs:48-53
cluster.fixed_network (name/id)""fixedNetworkIdif set: spec.network.id; if empty: CAPO creates managedSubnetsmagnum-cluster-api:magnum_cluster_api/resources.py:1145-1151, magnum-cluster-api:src/features/networks.rs:48-49, magnum-cluster-api:src/features/networks.rs:84-96
cluster.fixed_subnet""fixedSubnetIdspec.subnets[0].idmagnum-cluster-api:magnum_cluster_api/resources.py:1152-1158, magnum-cluster-api:src/features/networks.rs:116-128
template.dns_nameserver (comma list)—dnsNameserversmanagedSubnets[0].dnsNameserversmagnum-cluster-api:magnum_cluster_api/resources.py:1133-1137, magnum-cluster-api:src/features/networks.rs:61-70
template.network_drivermust be cilium or calicopod CIDR choice, CNI addon, Cluster label cni—magnum-cluster-api:magnum_cluster_api/utils.py:500-501, magnum-cluster-api:magnum_cluster_api/resources.py:903-908
template.cluster_distro—operatingSystemFlatcar: Ignition format patches; Ubuntu/Debian: apt proxymagnum-cluster-api:magnum_cluster_api/resources.py:1195-1198, magnum-cluster-api:src/features/operating_system.rs:65, magnum-cluster-api:src/features/operating_system.rs:137-138
template.http_proxy / https_proxy / no_proxynonesystemdProxyConfig, aptProxyConfig (base64)/etc/systemd/system/containerd.service.d/proxy.conf, apt proxy filemagnum-cluster-api:magnum_cluster_api/utils.py:273-312, magnum-cluster-api:magnum_cluster_api/resources.py:1079-1090, magnum-cluster-api:src/features/containerd_config.rs:131-150
cluster.docker_volume_sizeNoneenableDockerVolume, dockerVolumeSizeextra Cinder block device mounted at /var/lib/containerd (CP + workers)magnum-cluster-api:magnum_cluster_api/resources.py:1203-1210, magnum-cluster-api:src/features/volumes.rs:249-305
cluster.keypair, cluster.project_id—keystone-auth default policy (role member + project)—magnum-cluster-api:magnum_cluster_api/utils.py:566-586
cluster.labels → admission_control_listNodeRestriction (always prepended)admissionControlListapiserver --enable-admission-pluginsmagnum-cluster-api:magnum_cluster_api/resources.py:916-926, magnum-cluster-api:src/features/admission_plugins.rs:47
cluster.floating_ip_enabled—not used (only master_lb_floating_ip_enabled label)—[inferred] from absence in magnum-cluster-api:magnum_cluster_api/resources.py:955-1289
cluster_create_timeout—ignored—magnum-cluster-api:magnum_cluster_api/driver.py:70-88

4.2 Cluster labels

LabelDefaultVariableTargetSource
calico_ipv4pool / cilium_ipv4pool10.100.0.0/16—Cluster.spec.clusterNetwork.pods.cidrBlocks[0] (+ Cilium IPAM pool)magnum-cluster-api:magnum_cluster_api/resources.py:57, magnum-cluster-api:magnum_cluster_api/resources.py:931-941
service_cluster_ip_range10.254.0.0/16—clusterNetwork.services.cidrBlocks[0]magnum-cluster-api:magnum_cluster_api/resources.py:967-972
dns_cluster_domaincluster.local—clusterNetwork.serviceDomainmagnum-cluster-api:magnum_cluster_api/resources.py:962-964
fixed_subnet_cidr10.0.0.0/24nodeCidrOpenStackCluster.spec.managedSubnets[0].cidrmagnum-cluster-api:magnum_cluster_api/resources.py:1185-1190
master_lb_floating_ip_enabledtruedisableAPIServerFloatingIP (+ ...Managed gate)OpenStackCluster.spec.disableAPIServerFloatingIPmagnum-cluster-api:magnum_cluster_api/utils.py:244-245, magnum-cluster-api:magnum_cluster_api/resources.py:1101-1131, magnum-cluster-api:src/features/disable_api_server_floating_ip.rs:61
api_server_floating_ip""apiServerFloatingIPOpenStackCluster.spec.apiServerFloatingIPmagnum-cluster-api:magnum_cluster_api/resources.py:1006-1011, magnum-cluster-api:src/features/api_server_floating_ip.rs:47
octavia_providerCCM: amphorav2; API LB: unset (CAPO default)apiServerLoadBalancer.provider; CCM lb-providerOpenStackCluster.spec.apiServerLoadBalancer.provider; cloud.confmagnum-cluster-api:src/immutable_fields.rs:162-167, magnum-cluster-api:magnum_cluster_api/utils.py:161
api_server_lb_flavorunsetapiServerLoadBalancer.flavor...apiServerLoadBalancer.flavormagnum-cluster-api:src/immutable_fields.rs:168-173
api_server_lb_availability_zoneunsetapiServerLoadBalancer.availabilityZone...apiServerLoadBalancer.availabilityZonemagnum-cluster-api:src/immutable_fields.rs:174-179
octavia_lb_algorithmROUND_ROBIN (amphora*), SOURCE_IP_PORT (ovn; anything else rejected)—CCM cloud.conf lb-methodmagnum-cluster-api:magnum_cluster_api/utils.py:162-172
octavia_lb_healthcheckTrue—CCM create-monitormagnum-cluster-api:magnum_cluster_api/utils.py:163, magnum-cluster-api:magnum_cluster_api/utils.py:186
api_server_tls_cipher_suites6 ECDHE suitesapiServerTLSCipherSuitesapiserver --tls-cipher-suitesmagnum-cluster-api:magnum_cluster_api/resources.py:999-1005, magnum-cluster-api:src/features/tls.rs:57-59
kubelet_tls_cipher_suites3 ECDSA suiteskubeletTLSCipherSuiteskubelet tls-cipher-suites (init/join, CP + workers)magnum-cluster-api:magnum_cluster_api/resources.py:1173-1179, magnum-cluster-api:src/features/tls.rs:66-77
api_server_cert_sans (comma list)""apiServerSANs (YAML list text)clusterConfiguration.apiServer.certSANsmagnum-cluster-api:magnum_cluster_api/utils.py:610-615, magnum-cluster-api:src/features/tls.rs:86-93
oidc_issuer_url, oidc_client_id, oidc_username_claim (sub), oidc_username_prefix (-), oidc_groups_claim, oidc_groups_prefixas shownopenidConnect.* (patch only if issuer set)apiserver --oidc-*magnum-cluster-api:magnum_cluster_api/resources.py:1012-1034, magnum-cluster-api:src/features/openid_connect.rs:59-120
audit_log_enabled (false), audit_log_max_age (30), audit_log_max_backup (10), audit_log_max_size (100)as shownauditLog.*apiserver --audit-log-*, policy file, hostPath volumesmagnum-cluster-api:magnum_cluster_api/resources.py:1035-1051, magnum-cluster-api:src/features/audit_log.rs:55-103
boot_volume_size[cinder] default_boot_volume_size (0 = no boot volume)bootVolume.sizeOSMT spec.rootVolume.sizeGiB (patch only if > 0)magnum-cluster-api:magnum_cluster_api/resources.py:1052-1065, magnum-cluster-api:src/features/boot_volume.rs:48-76
boot_volume_type[cinder] default_boot_volume_type, else Cinder default typebootVolume.typerootVolume.typemagnum-cluster-api:magnum_cluster_api/integrations/cinder.py:31-50
boot_volume_availability_zoneavailability_zone labelbootVolumeAvailabilityZonerootVolume.availabilityZone.namemagnum-cluster-api:magnum_cluster_api/resources.py:1066-1072
etcd_volume_size (0), etcd_volume_type (Cinder default)as shownenableEtcdVolume, etcdVolumeSize, etcdVolumeTypeCP additionalBlockDevices + partition/fs label etcd_disk mounted /var/lib/etcdmagnum-cluster-api:magnum_cluster_api/resources.py:1218-1241, magnum-cluster-api:src/features/volumes.rs:152-240
docker_volume_typeCinder default typedockerVolumeTypeblock device typemagnum-cluster-api:magnum_cluster_api/resources.py:1211-1217
availability_zone""availabilityZoneAZ of the extra etcd/docker volumesmagnum-cluster-api:magnum_cluster_api/resources.py:1242-1245, magnum-cluster-api:src/features/volumes.rs:166-179
control_plane_availability_zones (comma list)""controlPlaneAvailabilityZonesOpenStackCluster.spec.controlPlaneAvailabilityZones (only if first item non-empty)magnum-cluster-api:magnum_cluster_api/resources.py:1260-1265, magnum-cluster-api:src/features/control_plane_availability_zones.rs:34-49
server_group_policiessoft-anti-affinitycreates Nova server group <stack_id> → serverGroupIdOSMT spec.serverGroup.idmagnum-cluster-api:magnum_cluster_api/utils.py:47-53, magnum-cluster-api:magnum_cluster_api/utils.py:656-692, magnum-cluster-api:src/features/server_groups.rs:58-63
different_failure_domainfalseisServerGroupDiffFailureDomainOSMT schedulerHintAdditionalProperties[different_failure_domain]magnum-cluster-api:magnum_cluster_api/utils.py:677-680, magnum-cluster-api:src/features/server_groups.rs:75-81
container_infra_prefix""imageRepository; addon image rewriteKCP clusterConfiguration.imageRepositorymagnum-cluster-api:magnum_cluster_api/resources.py:1163-1168, magnum-cluster-api:src/features/image_repository.rs:39-53
(computed)pause registry.k8s.io/pause:3.9containerdConfig (base64 TOML, SystemdCgroup=true)/etc/containerd/config.tomlmagnum-cluster-api:magnum_cluster_api/utils.py:248-270, magnum-cluster-api:magnum_cluster_api/images.py:21, magnum-cluster-api:src/features/containerd_config.rs:65-71
(computed)<stack_id>-cloud-configclusterIdentityRefNameidentityRef.name in OSCT and OSMTmagnum-cluster-api:magnum_cluster_api/resources.py:1073-1078, magnum-cluster-api:src/features/cluster_identity.rs:53, magnum-cluster-api:src/features/cluster_identity.rs:74
keystone_auth_enabledtrueenableKeystoneAuthkube-apiserver static pod kustomized with --authentication-token-webhook-config-file, --authorization-webhook-config-file, --authorization-mode=Webhookmagnum-cluster-api:magnum_cluster_api/resources.py:1246-1251, magnum-cluster-api:src/features/keystone_auth.rs:58-123
kubelet_serving_cert_verification_enabledfalseenableKubeletServingCertificateVerificationkubelet serverTLSBootstrap: true, apiserver --kubelet-certificate-authoritymagnum-cluster-api:magnum_cluster_api/resources.py:1252-1259, magnum-cluster-api:src/features/kubelet_serving_certificate_verification.rs:49-77
auto_healing_enabledtrue—topology.controlPlane.machineHealthCheck.enable and per-MD machineHealthCheck.enablemagnum-cluster-api:magnum_cluster_api/utils.py:236-237, magnum-cluster-api:magnum_cluster_api/resources.py:985-987, magnum-cluster-api:magnum_cluster_api/resources.py:798
auto_scaling_enabledfalse—MD annotations + autoscaler Helm releasemagnum-cluster-api:magnum_cluster_api/utils.py:232-233
calico_tagv3.32.1—Calico manifest file, Cluster label cnimagnum-cluster-api:magnum_cluster_api/resources.py:437
cilium_tag (v1.15.3), cilium_hubble_ui_enabled (false)as shown—Cilium chart valuesmagnum-cluster-api:src/magnum.rs:30-43
cloud_provider_tagper K8s minor—OCCM image tagmagnum-cluster-api:src/magnum.rs:68-70, magnum-cluster-api:src/magnum.rs:122-150
cinder_csi_enabled, cinder_csi_plugin_tag, manila_csi_enabled, manila_csi_plugin_tag, manila_csi_share_network_id, csi_attacher_tag (v4.7.0), csi_liveness_probe_tag (v2.14.0), csi_node_driver_registrar_tag (v2.12.0), csi_provisioner_tag (v5.1.0), csi_resizer_tag (v1.12.0), csi_snapshotter_tag (v8.1.0)as shown—CSI chart values / StorageClassesmagnum-cluster-api:src/magnum.rs:46-106, magnum-cluster-api:magnum_cluster_api/resources.py:304

Variables are first passed through resolve_immutable_fields: for each mapped path, the value **already present on the live OpenStackCluster wins over the label**, so LB provider/flavor/AZ and disableAPIServerFloatingIP never change after creation (CAPO's webhook rejects changes) (magnum-cluster-api:src/immutable_fields.rs:66-100, magnum-cluster-api:src/immutable_fields.rs:159-196, magnum-cluster-api:magnum_cluster_api/resources.py:951-953).

4.3 Nodegroup → topology.workers.machineDeployments[]

Magnum nodegroup field / labelDefaultTargetSource
name (must match RFC 1123)—machineDeployments[].name; MD label topology.cluster.x-k8s.io/deployment-namemagnum-cluster-api:magnum_cluster_api/utils.py:534-538, magnum-cluster-api:magnum_cluster_api/resources.py:797
—default-workerclassmagnum-cluster-api:magnum_cluster_api/resources.py:796
role—MD metadata.labels: node-role.kubernetes.io/<role>: "", node.cluster.x-k8s.io/nodegroup: <name>magnum-cluster-api:magnum_cluster_api/resources.py:730-733
node_count (autoscaling off)—replicasmagnum-cluster-api:magnum_cluster_api/resources.py:768-770
min_node_count / max_node_count (or label max_node_count, else min+1) (autoscaling on)—replicas removed; annotations cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size / -max-size, capacity.cluster-autoscaler.kubernetes.io/{memory,cpu,ephemeral-disk,labels} from the flavormagnum-cluster-api:magnum_cluster_api/resources.py:741-767, magnum-cluster-api:magnum_cluster_api/utils.py:315-324
flavor_id—variable override flavor (name)magnum-cluster-api:magnum_cluster_api/resources.py:815-818
image_id—override imageUUID, hardwareDiskBusmagnum-cluster-api:magnum_cluster_api/resources.py:826-833
labels boot_volume_size, boot_volume_typeconf / Cinder defaultoverride bootVolumemagnum-cluster-api:magnum_cluster_api/resources.py:802-814
label container_infra_prefix""override imageRepositorymagnum-cluster-api:magnum_cluster_api/resources.py:819-825
labels server_group_policies, different_failure_domaincluster valuesNova server group <stack_id>-<ng.name> → overrides serverGroupId, isServerGroupDiffFailureDomainmagnum-cluster-api:magnum_cluster_api/resources.py:834-846, magnum-cluster-api:magnum_cluster_api/utils.py:644-705
label availability_zonenonefailureDomainmagnum-cluster-api:magnum_cluster_api/resources.py:851-853
auto_healing_enabled (cluster label)truemachineHealthCheck.enablemagnum-cluster-api:magnum_cluster_api/resources.py:798
—300snodeVolumeDetachTimeoutmagnum-cluster-api:magnum_cluster_api/resources.py:52, magnum-cluster-api:magnum_cluster_api/resources.py:773-775

On existing MDs only replicas/annotations/labels/nodeVolumeDetachTimeout (and an empty→set failureDomain) are changed; variables are frozen to avoid rolling updates (magnum-cluster-api:magnum_cluster_api/resources.py:776-789). Nodegroups with role master or status DELETE* are excluded (magnum-cluster-api:magnum_cluster_api/resources.py:857-868). The master nodegroup is represented only by topology.controlPlane; its image_id is the cluster imageUUID (magnum-cluster-api:magnum_cluster_api/resources.py:946).


5. Status reconciliation

Triggers (Magnum core): sync_cluster_status periodic task selects clusters in CREATE/UPDATE/DELETE/ROLLBACK_IN_PROGRESS and calls driver.update_cluster_status; on DELETE_COMPLETE Magnum destroys certificates, nodegroups and the cluster row (magnum:magnum/service/periodic.py:66-91, magnum:magnum/service/periodic.py:161-169). sync_cluster_health_status calls get_monitor().poll_health_status() and stores health_status/health_status_reason (magnum:magnum/service/periodic.py:104-125, magnum:magnum/conductor/monitors.py:58-66).

5.1 Control-plane nodegroup (KubeadmControlPlane)

update_cluster_control_plane_status (magnum-cluster-api:magnum_cluster_api/driver.py:166-198):

  1. action = prefix of the current master nodegroup status (CREATE, UPDATE, …); if KCP status.observedGeneration > 1 the action becomes UPDATE (lines 172-180).
  2. updatedReplicas != replicas → <action>_IN_PROGRESS (lines 188-189).
  3. updatedReplicas == replicas == ng.node_count and status.ready → <action>_COMPLETE (lines 190-193).
  4. status_reason = KCP status.failureMessage (line 194). No _FAILED is ever derived.

5.2 Worker nodegroups (MachineDeployment)

update_nodegroups_status (magnum-cluster-api:magnum_cluster_api/driver.py:501-610):

Current ng statusCondition on management clusterNew ng statusLines
DELETE_COMPLETE (non-default, or cluster deleting)—row destroyed517-524
DELETE_IN_PROGRESSMD not foundNova server group deleted, DELETE_COMPLETE535-544
CREATE_IN_PROGRESSMD status.phase == RunningCREATE_COMPLETE546-559
UPDATE_IN_PROGRESSMD Running and equals_spec (annotations equal when autoscaling, else spec.replicas equal) and every OpenStackMachine.spec.image.id == imageUUID override and every spec.flavor == flavor overrideUPDATE_COMPLETE562-608, magnum-cluster-api:magnum_cluster_api/objects.py:112-126
anything else—unchanged—

5.3 Cluster

update_cluster_status (magnum-cluster-api:magnum_cluster_api/driver.py:200-313), under the cluster lock, after cluster.refresh():

  • CREATE_IN_PROGRESS / UPDATE_IN_PROGRESS: if no CAPI Cluster yet → return. Builds a map of CAPI Cluster.status.conditions; if any of ControlPlaneReady, InfrastructureReady, Ready is not "True" (missing counts as not true) → status_reason = "CAPI Cluster status: <reason>: <message>. CAPI OpenstackCluster status reason: <reason>: <message>" from the latest Kubernetes Event of the Cluster and of the OpenStackCluster, save, return (lines 222-244, 140-164). Otherwise:
    • api_address = "https://<controlPlaneEndpoint.host>:<port>", coe_version = spec.topology.version (lines 246-250);
    • on create with autoscaling, helm upgrade --install the autoscaler (lines 254-258);
    • if any nodegroup (incl. master) is not *_COMPLETE → return (lines 260-270);
    • CREATE_IN_PROGRESS → CREATE_COMPLETE, UPDATE_IN_PROGRESS → UPDATE_COMPLETE, status_reason = None (lines 272-279).
  • DELETE_IN_PROGRESS: while the CAPI Cluster exists → refresh status_reason from events, return. When gone → delete application credential <uuid> (Forbidden/NotFound ignored), cloud-config secret, 4 CA secrets, all Nova server groups → DELETE_COMPLETE (lines 281-313, magnum-cluster-api:magnum_cluster_api/clients.py:52-73).
  • **No *_FAILED state is produced by the driver.** _FAILED comes only from Magnum core when a driver call raises (magnum:magnum/conductor/handlers/cluster_conductor.py:77-79, magnum:magnum/conductor/handlers/cluster_conductor.py:181-185, magnum:magnum/conductor/handlers/nodegroup_conductor.py:85-89). A CAPI cluster that never becomes Ready stays *_IN_PROGRESS forever (cluster_create_timeout is ignored).
  • Not filled: node_addresses, master_addresses, discovery_url (no reference in the driver; [inferred] by grep absence).

5.4 Health monitor

Rust Monitor.poll_health_status (magnum-cluster-api:src/monitor.rs:131-185): lists Machines and KubeadmControlPlane labelled cluster.x-k8s.io/cluster-name=<stack_id>; HEALTHY iff KCP condition Available=True and every Machine NodeHealthy=True; health_status_reason = {"<infraRef name>.Ready": "True|False", "api": "ok|nok"}; UNKNOWN if no stack_id (magnum-cluster-api:src/monitor.rs:18-49, magnum-cluster-api:src/monitor.rs:75-89). With autoscaling, the Python monitor also copies each MD's spec.replicas into nodegroup.node_count (magnum-cluster-api:magnum_cluster_api/monitor.py:31-51).

stateDiagram-v2
  [*] --> CREATE_IN_PROGRESS: conductor create_cluster OK
  [*] --> CREATE_FAILED: driver raised (Magnum core)
  CREATE_IN_PROGRESS --> CREATE_IN_PROGRESS: CAPI Cluster absent or ControlPlaneReady/InfrastructureReady/Ready != True (status_reason = last events)
  CREATE_IN_PROGRESS --> CREATE_IN_PROGRESS: conditions True but a nodegroup not *_COMPLETE
  CREATE_IN_PROGRESS --> CREATE_COMPLETE: conditions True and all nodegroups *_COMPLETE (api_address, coe_version set)
  CREATE_COMPLETE --> UPDATE_IN_PROGRESS: resize / nodegroup create-update-delete / upgrade
  UPDATE_COMPLETE --> UPDATE_IN_PROGRESS: idem
  UPDATE_IN_PROGRESS --> UPDATE_COMPLETE: conditions True and all nodegroups *_COMPLETE
  UPDATE_IN_PROGRESS --> UPDATE_FAILED: driver raised (Magnum core)
  CREATE_COMPLETE --> DELETE_IN_PROGRESS: delete_cluster OK
  UPDATE_COMPLETE --> DELETE_IN_PROGRESS: delete_cluster OK
  DELETE_IN_PROGRESS --> DELETE_IN_PROGRESS: CAPI Cluster still exists
  DELETE_IN_PROGRESS --> DELETE_COMPLETE: CAPI Cluster gone, app cred + secrets + server groups removed
  [*] --> DELETE_FAILED: delete_cluster raised (Magnum core)
  DELETE_COMPLETE --> [*]: Magnum destroys rows
Magnum statusSet byDerived fromSource
CREATE_IN_PROGRESSMagnum API/conductor—magnum:magnum/conductor/handlers/cluster_conductor.py:60-79
CREATE_COMPLETEdriverCAPI Cluster conditions ControlPlaneReady, InfrastructureReady, Ready all True + all ngs _COMPLETEmagnum-cluster-api:magnum_cluster_api/driver.py:238-274
UPDATE_IN_PROGRESSdriver (_update_nodegroup) or Magnum—magnum-cluster-api:magnum_cluster_api/driver.py:675-679
UPDATE_COMPLETEdriversame as CREATE_COMPLETEmagnum-cluster-api:magnum_cluster_api/driver.py:275-277
DELETE_IN_PROGRESSMagnum after delete_cluster returns—magnum:magnum/conductor/handlers/cluster_conductor.py:178-180
DELETE_COMPLETEdriverCAPI Cluster no longer existsmagnum-cluster-api:magnum_cluster_api/driver.py:281-313
*_FAILEDMagnum core onlyexception from a driver callmagnum:magnum/conductor/handlers/cluster_conductor.py:77-79
ng <action>_IN_PROGRESS/_COMPLETE (master)driverKCP updatedReplicas, replicas, ready, observedGenerationmagnum-cluster-api:magnum_cluster_api/driver.py:166-198
ng CREATE/UPDATE/DELETE_COMPLETE (workers)driverMD status.phase, spec equality, OpenStackMachine image/flavormagnum-cluster-api:magnum_cluster_api/driver.py:501-610
health_status HEALTHY/UNHEALTHY/UNKNOWNdriver monitorKCP Available, Machine NodeHealthymagnum-cluster-api:src/monitor.rs:131-185

6. Credentials and certificates

  • Application credential per cluster, created in the context of the requesting user: name = cluster UUID, description Magnum cluster (<uuid>), user = cluster.user_id, unrestricted roles [inferred: no roles/access_rules passed] (magnum-cluster-api:magnum_cluster_api/driver.py:98-102, magnum-cluster-api:magnum_cluster_api/clients.py:37-50). Deleted only once the CAPI Cluster is gone, so CAPO keeps access during teardown (magnum-cluster-api:magnum_cluster_api/driver.py:287-294).
  • CAPO identity: secret <stack_id>-cloud-config with clouds.yaml (cloud default, region_name = Cinder region, endpoint_type from [capi_client] endpoint_type minus URL, verify = not [capi_client] insecure, auth_url from the catalog) and cacert = [capi_client] ca_file content or the certifi bundle (magnum-cluster-api:magnum_cluster_api/resources.py:635-699). Referenced by identityRef.name of OpenStackCluster and OpenStackMachines (magnum-cluster-api:src/features/cluster_identity.rs:53-74).
  • CCM / Cinder CSI: workload secret kube-system/cloud-config with cloud.conf built by re-reading the app credential from <stack_id>-cloud-config: [Global] auth-url (public identity endpoint), region, application-credential-id/secret, tls-insecure from Magnum [drivers] verify_ca, ca-file=/etc/config/ca.crt when Magnum has an OpenStack CA; [LoadBalancer] lb-provider, lb-method, create-monitor (magnum-cluster-api:magnum_cluster_api/utils.py:144-188, magnum-cluster-api:magnum_cluster_api/resources.py:243-260). The CSI chart mounts that secret (secret.name: cloud-config) (magnum-cluster-api:src/addons/cinder_csi.rs:182-187).
  • Manila CSI: workload secret kube-system/csi-manila-secrets with os-authURL, os-region, os-applicationCredentialID/Secret, os-TLSInsecure, optional os-certAuthorityPath (magnum-cluster-api:magnum_cluster_api/utils.py:191-225).
  • Keystone webhook: k8s-keystone-auth gets auth_url (public, /v3 appended), Magnum's OpenStack CA and a policy from [kubernetes] keystone_auth_default_policy (file, $PROJECT_ID substituted) or a built-in policy (role member in the cluster's project may list pods/services/deployments/pvc in default) (magnum-cluster-api:magnum_cluster_api/resources.py:465-495, magnum-cluster-api:magnum_cluster_api/utils.py:566-586). The apiserver calls it at https://127.0.0.1:8443/webhook with insecure-skip-tls-verify: true (magnum-cluster-api:data/keystone-auth/webhook.yaml:7-8).
  • Certificates — Magnum CA is the kubeadm CA: Magnum core generates the cluster CAs before calling the driver (magnum:magnum/conductor/handlers/cluster_conductor.py:62-63); the driver uploads them as CAPI-format secrets <stack_id>-ca (Kubernetes CA, ca_cert_ref), -etcd (etcd_ca_cert_ref), -proxy (front_proxy_ca_cert_ref), -sa (service-account key pair from magnum_cert_ref) with decrypted private keys (magnum-cluster-api:magnum_cluster_api/resources.py:558-632). kubeadm then signs component certs from these CAs, so magnum ca-show / ca-sign stay consistent. KCP renews leaf certs 21 days before expiry (magnum-cluster-api:src/features/mod.rs:194-196). CA rotation is not supported (magnum-cluster-api:magnum_cluster_api/driver.py:726-728).
  • Kubelet serving certificates (optional): serverTLSBootstrap + external cluster-api-csr-approver in the management cluster (magnum-cluster-api:docs/admin/kubelet-serving-certificates.md:14-15).

7. Operations

7.1 Create

sequenceDiagram
  participant MC as Magnum conductor
  participant D as Driver (Py + Rust)
  participant K as Mgmt K8s API (magnum-system)
  participant C as CAPI / KCP / CAPO controllers
  participant OS as Nova / Neutron / Octavia / Cinder / Keystone
  MC->>MC: generate cluster CAs (cert_manager)
  MC->>D: create_cluster(ctx, cluster, timeout)
  D->>K: GET Cluster kube-xxxxx (name uniqueness, retry on conflict)
  D->>MC: cluster.stack_id = kube-xxxxx; save
  D->>K: apply Namespace, 4 templates, ClusterClass magnum-vX
  D->>K: apply CRS <uuid>, CRS <stack_id>-cloud-provider
  D->>OS: validate network driver / master_count / fixed net+subnet (Neutron)
  D->>K: acquire lock cluster-<uuid>
  D->>OS: Keystone create application credential <uuid>
  D->>K: Secret <stack_id>-cloud-config, Secrets -ca -etcd -proxy -sa
  D->>OS: Nova ensure server groups <stack_id>, <stack_id>-<ng>
  D->>OS: Cinder volume types, Glance image, Nova flavors, Keystone catalog
  D->>K: Secret <uuid> (CNI, keystone-auth), Secret <stack_id>-cloud-provider (CCM, CSI, StorageClasses)
  D->>K: create Cluster <stack_id> (topology + variables)
  D-->>MC: return (status CREATE_IN_PROGRESS)
  C->>K: watch Cluster, render OpenStackCluster/KCP/MD from ClusterClass patches
  C->>OS: Neutron network/subnet/router/SGs, Octavia API LB (+FIP)
  C->>OS: Nova servers (+Cinder boot/etcd/docker volumes, server group hints)
  C->>K: Secret <stack_id>-kubeconfig, conditions Ready
  C->>K: CRS applies CNI/CCM/CSI/keystone-auth into the workload cluster
  loop periodic sync_cluster_status
    MC->>D: update_cluster_status
    D->>K: read KCP, MDs, OpenStackMachines, Cluster conditions, Events
    D->>K: helm upgrade --install autoscaler (if enabled, once API up)
    D-->>MC: CREATE_COMPLETE, api_address, coe_version
  end

Sources: magnum-cluster-api:magnum_cluster_api/driver.py:70-138, magnum-cluster-api:src/driver.rs:302-310, magnum-cluster-api:magnum_cluster_api/resources.py:1297-1313.

Note the order: the Rust create_cluster (ClusterClass and CRSs) runs before validate_cluster, so a rejected cluster still leaves two CRS objects (deleted later by delete_cluster) (magnum-cluster-api:magnum_cluster_api/driver.py:84-86).

7.2 Resize / nodegroup operations

sequenceDiagram
  participant MC as Magnum conductor
  participant D as Driver
  participant K as Mgmt K8s API
  participant C as CAPI / CAPO
  participant OS as Nova / Cinder
  MC->>D: resize_cluster(node_count, nodes_to_remove, ng)
  D->>K: lock cluster-<uuid>; strip empty failureDomain (JSON patch)
  opt nodes_to_remove
    D->>K: list Machines (cluster-name, deployment-name)
    D->>K: annotate matching Machine cluster.x-k8s.io/delete-machine=yes
  end
  alt ng.role == master
    D->>K: SSA Cluster topology.controlPlane.replicas = node_count
  else worker
    D->>OS: ensure Nova server group <stack_id>-<ng>
    D->>K: SSA Cluster machineDeployments[ng].replicas (or autoscaler annotations)
  end
  D->>MC: ng + cluster UPDATE_IN_PROGRESS
  C->>K: MachineSet scale (annotated machines deleted first)
  C->>OS: create / delete Nova servers and volumes
  MC->>D: update_cluster_status (periodic) -> UPDATE_COMPLETE

Create nodegroup appends a new MD entry (magnum-cluster-api:magnum_cluster_api/driver.py:473-499); delete nodegroup removes it, and the periodic sync later deletes the server group and marks DELETE_COMPLETE (magnum-cluster-api:magnum_cluster_api/driver.py:682-720, magnum-cluster-api:magnum_cluster_api/driver.py:535-544). No-op detection: identical replicas / MD spec → return without status change (magnum-cluster-api:magnum_cluster_api/driver.py:646-668).

Autoscaler: cluster-autoscaler runs in the management cluster (one Helm release per cluster, image [auto_scaling] image_repository/cluster-autoscaler:v<per-minor>) and scales MDs through the CAPI provider; replicas are left unset in the topology (magnum-cluster-api:magnum_cluster_api/images.py:23-49, magnum-cluster-api:magnum_cluster_api/resources.py:750-753).

Auto-healing: CAPI MachineHealthCheck generated by the ClusterClass (Ready False/Unknown for 5 min, maxUnhealthy 80 %), enabled per topology flag auto_healing_enabled (magnum-cluster-api:src/resources.rs:46-61, magnum-cluster-api:src/resources.rs:96-111).

7.3 Upgrade

sequenceDiagram
  participant MC as Magnum conductor
  participant D as Driver
  participant K as Mgmt K8s API
  participant W as Workload K8s API
  participant C as CAPI / KCP / CAPO
  participant OS as Nova / Glance
  MC->>D: upgrade_cluster(cluster, new_template, ...)
  D->>D: cluster.template_id, labels.kube_tag; every ng: image_id, kube_tag, UPDATE_IN_PROGRESS
  D->>K: strip empty failureDomain
  D->>K: apply ClusterClass magnum-<new driver version>
  D->>W: delete legacy CCM/CSI workloads (via <stack_id>-kubeconfig)
  D->>K: replace CRS <stack_id>-cloud-provider
  D->>K: re-apply server groups, Secret <uuid>, Secret <stack_id>-cloud-provider, autoscaler release
  D->>K: GET+replace Cluster (labels, clusterNetwork, topology incl. new class/version/imageUUID)
  C->>K: KCP rolling replace, then MD rolling replace
  C->>OS: new Nova servers from new image, old ones deleted
  MC->>D: update_cluster_status -> UPDATE_COMPLETE when KCP + MDs + OpenStackMachine image ids match

Sources: magnum-cluster-api:magnum_cluster_api/driver.py:375-436, magnum-cluster-api:src/driver.rs:65-119, magnum-cluster-api:src/driver.rs:312-319, magnum-cluster-api:src/client.rs:73-107. Only kube_tag and image_id are taken from the new template; other label changes are not propagated (magnum-cluster-api:magnum_cluster_api/driver.py:388-396). Because existing MD variables are frozen (§4.3) the per-MD imageUUID override is kept [inferred: worker image change depends on mutate_machine_deployment returning the existing spec unchanged; whether workers get the new image needs verification against CAPI topology semantics].

7.4 Delete

sequenceDiagram
  participant MC as Magnum conductor
  participant D as Driver
  participant K as Mgmt K8s API
  participant C as CAPI / CAPO
  participant OS as Octavia / Neutron / Nova / Keystone
  MC->>D: delete_cluster(cluster)
  D->>OS: Octavia list LBs "Kubernetes .+ from cluster <uuid>", cascade delete, delete VIP FIPs, wait (pre_delete_lb_timeout)
  D->>K: delete CRS+Secret <stack_id>-cloud-provider, CRS+Secret <uuid>
  D->>K: delete Cluster <stack_id>
  D->>K: helm delete <stack_id> (autoscaler)
  D-->>MC: return -> DELETE_IN_PROGRESS
  C->>OS: delete servers, volumes, API LB, network, router, SGs
  loop periodic
    MC->>D: update_cluster_status
    D->>K: Cluster still exists? -> status_reason from events
  end
  D->>OS: Keystone delete app cred <uuid>; Nova delete server groups
  D->>K: delete Secrets cloud-config, ca, etcd, proxy, sa
  D-->>MC: DELETE_COMPLETE (Magnum destroys DB rows)

Sources: magnum-cluster-api:magnum_cluster_api/driver.py:442-465, magnum-cluster-api:magnum_cluster_api/utils.py:359-465, magnum-cluster-api:magnum_cluster_api/driver.py:281-313. Octavia LBs created by the in-cluster CCM (Services of type LoadBalancer) are removed by the driver because CAPO does not know them (magnum-cluster-api:magnum_cluster_api/driver.py:451-455).


8. Errors and logs

ErrorRaised whenEffectSource
UnsupportedCNI (plain Exception)network_driver ∉ {cilium, calico}create → CREATE_FAILEDmagnum-cluster-api:magnum_cluster_api/utils.py:500-501, magnum-cluster-api:magnum_cluster_api/exceptions.py:60-61
ClusterMasterCountEvenmaster_count evenCREATE_FAILEDmagnum-cluster-api:magnum_cluster_api/utils.py:504-505
MasterNGSizeInvalid (Magnum)control-plane resize to even or < 1API 400 [inferred]magnum-cluster-api:magnum_cluster_api/driver.py:468-470
MachineInvalidName (InvalidName)nodegroup name not RFC 1123"Expected a lowercase RFC 1123 subdomain name, got %(name)s."magnum-cluster-api:magnum_cluster_api/utils.py:534-538, magnum-cluster-api:magnum_cluster_api/exceptions.py:64-65
MachineDeploymentNotFound (ObjectNotFound)MD lookup fails"MachineDeployment %(name)s not found."magnum-cluster-api:magnum_cluster_api/exceptions.py:68-69, magnum-cluster-api:magnum_cluster_api/objects.py:96-97
heatclient HTTPNotFounddelete_nodegroup and MD absentintended to let Magnum destroy the ng; in Magnum 2026.2 the handler catches any Exception → DELETE_FAILED (confirmed by the history: Magnum commit 31b84327db88 removed the HTTPNotFound special case, see 06 § 21)magnum-cluster-api:magnum_cluster_api/driver.py:708-714, magnum:magnum/conductor/handlers/nodegroup_conductor.py:121-131
InvalidOctaviaLoadBalancerAlgorithm (Invalid)octavia_provider=ovn with algorithm ≠ SOURCE_IP_PORT"Invalid value for octavia_lb_algorithm: …"magnum-cluster-api:magnum_cluster_api/utils.py:169-172, magnum-cluster-api:magnum_cluster_api/exceptions.py:72-73
FlavorNotFoundflavor name/id not in Nova list—magnum-cluster-api:magnum_cluster_api/utils.py:475-486
VolumeTypeNotFoundno default Cinder type and no conf—magnum-cluster-api:magnum_cluster_api/integrations/cinder.py:47-48
ServicesListFailedKeystone service list fails (log Failed to list services)—magnum-cluster-api:magnum_cluster_api/integrations/common.py:40-44
Conflictgenerated name exists (retried by tenacity) / >1 server group with same name—magnum-cluster-api:magnum_cluster_api/utils.py:113-123, magnum-cluster-api:magnum_cluster_api/utils.py:638-639
PreDeletionFailedany Octavia cleanup error, incl. "Timeout waiting for the load balancers %s to be deleted."DELETE_FAILEDmagnum-cluster-api:magnum_cluster_api/utils.py:395-396, magnum-cluster-api:magnum_cluster_api/utils.py:460-463
Exception("Certificate for %s doesn't exist.")Magnum cert ref missingCREATE_FAILEDmagnum-cluster-api:magnum_cluster_api/resources.py:559-563
OpenStackClusterNotCreatedopenstack_cluster property with no OpenStackCluster (also reachable from _get_cluster_status_reason)status sync raises [inferred]magnum-cluster-api:magnum_cluster_api/objects.py:247-258
HelmReleaseNotFoundhelm delete without skip_missing—magnum-cluster-api:magnum_cluster_api/helm.py:92-109
NotImplementedErrorupdate_cluster, federationUPDATE_FAILEDmagnum-cluster-api:magnum_cluster_api/driver.py:329
Rust ImmutableFieldErrorambiguous / unpatchable OpenStackCluster fields ("expected at most 1 {kind} for cluster …")—magnum-cluster-api:src/driver.rs:22-28, magnum-cluster-api:src/immutable_fields.rs:16-38
Rust KubeError / RuntimeErrorany Kubernetes API failure ("API request failed: …", "missing stack id for cluster", "kubeconfig secret not found for cluster")—magnum-cluster-api:src/client.rs:16-42, magnum-cluster-api:src/magnum.rs:153-181
Rust PyMonitorError"Failed to get machines", "Failed to get find KubeadmControlPlane"Magnum logs a warning and skips healthmagnum-cluster-api:src/monitor.rs:92-113, magnum:magnum/service/periodic.py:109-118

Logs: very few. Python: Helm release %s is already in progress / already exists (INFO, swallowed), Helm template %s failed, There is no %s service enabled in the cloud. (magnum-cluster-api:magnum_cluster_api/helm.py:84-87, magnum-cluster-api:magnum_cluster_api/helm.py:152, magnum-cluster-api:magnum_cluster_api/integrations/common.py:49). Rust logs go to stderr via env_logger, default level warn, controlled by RUST_LOG (not oslo.log) (magnum-cluster-api:src/logging.rs:37-45); one debug message on upgrade (magnum-cluster-api:src/driver.rs:83). The user-visible diagnostic channel is status_reason built from Kubernetes Events.

Rust / pyo3 summary: the extension provides (a) Driver: ClusterClass + templates generation from a feature registry (inventory), addon CRS/secret rendering with an embedded Helm templater (crates/helm), immutable-field resolution, failure-domain cleanup; (b) KubeClient: generic dict→DynamicObject create/replace/delete; (c) Monitor: health. Blocking calls release the GIL (Python::detach) and run on a Tokio runtime (magnum-cluster-api:src/driver.rs:187-241, magnum-cluster-api:src/client.rs:52-70).


9. Configuration options

Driver-specific (registered via oslo.config.opts) (magnum-cluster-api:magnum_cluster_api/conf.py:99-126):

GroupOptionDefaultUseSource
[auto_scaling]image_repositoryregistry.k8s.io/autoscalingautoscaler image prefixmagnum-cluster-api:magnum_cluster_api/conf.py:31-37
[capi_client]endpoint_typepublicURLinterface written in clouds.yaml / auth_url lookupmagnum-cluster-api:magnum_cluster_api/conf.py:40-49
[capi_client]ca_file, cert_file, key_file, insecure (False)—cacert and verify of clouds.yaml (cert/key unused [inferred])magnum-cluster-api:magnum_cluster_api/conf.py:85-97
[manila_client]region_name, endpoint_type (publicURL), api_version (3), ca_file, cert_file, key_file, insecure—manilaclient for share typesmagnum-cluster-api:magnum_cluster_api/conf.py:52-73, magnum-cluster-api:magnum_cluster_api/clients.py:151-170
[proxy]haproxy_pid_path/var/run/haproxy.pidproxy daemonmagnum-cluster-api:magnum_cluster_api/conf.py:76-82

Magnum core options consumed: [cinder] default_boot_volume_size (0) and default_boot_volume_type (''), [drivers] verify_ca (True), [kubernetes] keystone_auth_default_policy (/etc/magnum/keystone_auth_default_policy.json), [cluster] pre_delete_lb_timeout (60), [nova_client] endpoint/region (magnum:magnum/conf/cinder.py:40-50, magnum:magnum/conf/drivers.py:19, magnum:magnum/conf/kubernetes.py:19-20, magnum:magnum/conf/cluster.py:35-38, magnum-cluster-api:magnum_cluster_api/clients.py:121-125).

Environment: KUBECONFIG (management cluster), RUST_LOG; proxy: PROXY_PORT, PROXY_BIND, PROXY_ALWAYS (magnum-cluster-api:magnum_cluster_api/proxy/manager.py:44-47, magnum-cluster-api:magnum_cluster_api/proxy/structs.py:51-55). Hard-coded: namespace magnum-system, SSA field manager atmosphere-operator, lock expiry 60 s, server-group cache TTL 300 s on local disk (diskcache) (magnum-cluster-api:magnum_cluster_api/cache.py:12-20).

External requirements:

RequirementValueSource
CAPI core / kubeadm bootstrap / kubeadm control planev1.13.2 in CI (API v1beta1 used everywhere)magnum-cluster-api:devstack/plugin.sh:1, magnum-cluster-api:src/cluster_api/clusters.rs:19-24
CAPOv0.14.4 in CI (infrastructure.cluster.x-k8s.io/v1beta1)magnum-cluster-api:devstack/plugin.sh:2, magnum-cluster-api:src/cluster_api/openstackclusters.rs:17
CAPI feature gatesEXP_CLUSTER_RESOURCE_SET=true, EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true (Flatcar), CLUSTER_TOPOLOGY=truemagnum-cluster-api:devstack/plugin.sh:65-67
helm binary on every conductorfor autoscaler release and keystone-auth templatingmagnum-cluster-api:magnum_cluster_api/helm.py:26-28
Management nodes labelled openstack-control-plane=enabledautoscaler podsmagnum-cluster-api:magnum_cluster_api/resources.py:90-92
Optional cluster-api-csr-approverkubelet serving cert verificationmagnum-cluster-api:docs/admin/kubelet-serving-certificates.md:14-15
Node imagesvexxhost/capo-image-elements qcow2 with os_distro and kubeadm binaries baked inmagnum-cluster-api:docs/user/images.md:13-18, magnum-cluster-api:devstack/local.conf.sample:32
Nova API ≥ 2.15soft-(anti-)affinity server groupsmagnum-cluster-api:magnum_cluster_api/utils.py:747-748
Management cluster ≥ 1.30 recommendedCRD validation ratcheting for legacy failureDomain: ""magnum-cluster-api:magnum_cluster_api/driver.py:59-68
Network reachabilityCAPI controllers must reach each workload API (FIP / LB VIP), or run the proxy daemon on Neutron network nodes for clusters without FIPmagnum-cluster-api:magnum_cluster_api/proxy/structs.py:49-78

10. What an OpenKeel Go rewrite must reproduce vs can simplify

Context: OpenKeel already runs on Kubernetes; Nova is backed by KubeVirt, Neutron by OVN/Kube-OVN, Octavia API in neutron-api, Cinder on CSI block storage.

Must reproduce (user-visible contract)

  1. Magnum API semantics of the driver: provides tuples for the OS values users already put in templates (ubuntu, ubuntu-focal, debian, flatcar, rockylinux); update_cluster unsupported; control-plane resize allowed only for odd counts; upgrade changes only kube_tag + image of the target template (§2).
  2. The status machine of §5 exactly: CAPI Cluster conditions ControlPlaneReady+InfrastructureReady+Ready → *_COMPLETE; nodegroup rules on KCP replicas and MD phase/spec; status_reason built from the latest Events; api_address = https://host:port of controlPlaneEndpoint; coe_version = topology.version; health HEALTHY/UNHEALTHY/UNKNOWN with <machine>.Ready and api keys (tools and Skyline read these).
  3. The label catalogue of §4 with the same defaults (pod CIDR 10.100.0.0/16, service CIDR 10.254.0.0/16, auto_healing_enabled=true, keystone_auth_enabled=true, master_lb_floating_ip_enabled=true, boot_volume_*, octavia_*, OIDC, audit, TLS suites, CSI/CCM tags). Unknown labels are silently ignored.
  4. Magnum-generated CAs used as kubeadm CAs (secrets <name>-ca/-etcd/-proxy/-sa) so ca-show/ca-sign keep working.
  5. Per-cluster application credential lifecycle (create at cluster create, delete after infrastructure is gone) and the cloud.conf for CCM/Cinder CSI/Manila CSI.
  6. Pre-delete cleanup of CCM-created Octavia LBs matching Kubernetes .+ from cluster <uuid>.
  7. Immutable OpenStackCluster fields (API LB provider/flavor/AZ, disableAPIServerFloatingIP) must not change on later updates.
  8. Autoscaler min/max annotations and MHC behaviour (auto_healing_enabled).

Can simplify

  • Drop pykube + Python/Rust split: one Go controller using controller-runtime and the upstream CAPI/CAPO Go types; no GIL/eventlet workarounds (magnum-cluster-api:magnum_cluster_api/utils.py:63-91, magnum-cluster-api:src/logging.rs:1-45), no tpool.
  • Watch instead of poll: an informer on Cluster, KubeadmControlPlane, MachineDeployment, Machine can update Magnum status immediately, replacing sync_cluster_status polling and the sherlock lock (use the Magnum DB row lock or a Lease per cluster).
  • Management cluster = OpenKeel's own cluster: no separate kubeconfig, no magnum-cluster-api-proxy/HAProxy-in-netns (OpenKeel pods can reach tenant networks through OVN/Kube-OVN or a Service) [inferred: depends on OpenKeel tenant-network reachability design].
  • Infrastructure provider choice: CAPO against OpenKeel's Nova/Neutron/Octavia/Cinder APIs (zero-change compatibility, CAPO only needs the OpenStack API) vs. CAPK (Cluster API Provider KubeVirt) directly on KubeVirt (fewer hops, but loses Nova server groups, Octavia API LB, Cinder root volumes and the OpenStackMachine image/flavor checks in §5.2 — status logic would need re-mapping). Recommendation: keep CAPO first for behavioural parity [inferred].
  • No Helm binary: render addon manifests in-process (Go helm.sh/helm/v3 engine or pre-rendered embedded YAML) and deploy the autoscaler as a plain Deployment.
  • Drop legacy paths: the legacy CRS <uuid> vs <stack_id>-cloud-provider split, Calico manifest zoo (18 versions), legacy CCM/CSI cleanup on upgrade, failureDomain: "" cleanup, disableAPIServerFloatingIPManaged, ubuntu-focal — all exist only for upgrades from older driver releases.
  • Single ClusterClass per OpenKeel release is a good pattern to keep; versioned name makes upgrades a topology.class switch.
  • No Memcached/Redis: the driver's only cache is a local diskcache for server-group ids (magnum-cluster-api:magnum_cluster_api/cache.py:4-20) — replace with an in-process map or none.

11. Blind spots / [inferred]

  • Magnum 2026.2 + heatclient: the driver still imports heatclient.exc (magnum-cluster-api:magnum_cluster_api/driver.py:18) and relies on its own python-heatclient dependency (magnum-cluster-api:pyproject.toml:44); Magnum 2026.2's nodegroup_delete no longer special-cases HTTPNotFound (magnum:magnum/conductor/handlers/nodegroup_conductor.py:121-131), so deleting a nodegroup whose MD is already gone ends in DELETE_FAILED instead of row deletion: Magnum commit 31b84327db88 removed the HTTPNotFound special case (06 § 21). Not run.
  • needs_trust = False (magnum-cluster-api:magnum_cluster_api/driver.py:47) is not read anywhere in Magnum 2026.2 core (grep found no consumer); whether 2026.2 still creates trusts for this driver was not traced.
  • kube_tag default mismatch: Python defaults to v1.25.3 (magnum-cluster-api:magnum_cluster_api/utils.py:228-229) while the Rust ClusterLabels.kube_tag has no pyo3 default (magnum-cluster-api:src/magnum.rs:108-110); a cluster without the label likely fails Rust extraction — not executed.
  • _get_cluster_status_reason may raise OpenStackClusterNotCreated before CAPO creates the OpenStackCluster (magnum-cluster-api:magnum_cluster_api/driver.py:153, magnum-cluster-api:magnum_cluster_api/objects.py:255-256); impact on the periodic sync not verified.
  • Sherlock's Kubernetes lock object kind (Lease vs. custom) not checked (library not installed locally).
  • Upgrade of worker images: depends on CAPI topology propagation of the top-level imageUUID vs. per-MD overrides frozen by mutate_machine_deployment (§7.3); not traced in CAPI.
  • Exact rendered contents of Cilium/OCCM/CSI charts (values beyond those cited) were not reviewed line by line; Flatcar Ignition patches and volume partition layouts summarised from patch paths only.
  • docs/user/configs.md documents [auto_scaling] v1_22_image…v1_27_image options that no longer exist in conf.py (magnum-cluster-api:docs/user/configs.md:15-49 vs magnum-cluster-api:magnum_cluster_api/conf.py:31-37): doc drift.
  • CI versions (CAPI v1.13.2, CAPO v0.14.4) are what the project tests with; no hard version constraint is enforced at runtime.
  • The magnum-cluster-api-image-builder CLI (magnum-cluster-api:pyproject.toml:65) was not analysed.

Source: reverse-spec-magnum/08-driver-magnum-cluster-api_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.