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

Reverse-spec · Services

magnum — Change history

Change history — magnum — branch stable/2026.2

Branch stable/2026.2 @ 1910928b7d9f — range 22.0.0.0rc1..stable/2026.2 (af5b7a0b81c0..1910928b7d9f, 60 non-merge commits) — target: none (OpenKeel has no Magnum code yet; the "In target" column is replaced by what each change means for openkeel-magnum) — analysed on 2026-11-09

Range. The local clone has no master branch, so the automatic base is the latest tag before HEAD: 22.0.0.0rc1, the start of the 2026.2 cycle. HEAD is tagged 23.0.0 (git describe), and 23.0.0.0rc1..stable/2026.2 is empty. The range is therefore the whole 2026.2 development cycle. The stable branch has received no backport since the release. Raw facts (files, trailers, release notes, options, migrations, a cherry-pick plan for every commit) are in [_inventory/history_stable-2026.2.md](_inventory/history_stable-2026.2.md).

What 2026.2 is about. Five themes:

  • removal of everything Heat-based: driver, trusts, templates, contrib;
  • the switch of every OpenStack client to openstacksdk, which caused three regressions, fixed during the cycle;
  • the switch from eventlet to native threads;
  • a performance fix for the API under load;
  • small API features: microversions 1.13 and 1.14, hidden templates, an explicit driver on templates, clearer driver errors.

Categories below were corrected after reading the diffs: the script classified the openstacksdk migrations as "other" and several CI changes as "feature" or "fix".

Summary

#CommitDateCategoryChangeBugImpactFor openkeel-magnum
4c73f9e1525982026-03-15fixboot_volume_size label accepted as a string214447301 § templates/clusters (root-disk rule)reproduce: labels are strings
9598067b4ea712026-04-08fix (perf)no more Keystone authentication on every DB query and policy check213701803; superseded by #22none (trusts gone)
10e791b7c5077f2026-04-08fix (perf)one RPC client per process instead of per request213701803 § RabbitMQdesign note
112036ac2fb3b12026-04-08fix (perf)nodegroups read once per as_dict(); templates prefetched for cluster lists213701807 § 9reproduce the batching
14a414fcfc11a12026-04-24fixtemplate create: Glance 404/403 now return ImageNotFound/ImageNotAuthorized instead of being swallowed—02reproduce
172e1821ea43572026-05-08upgradeeventlet dropped; oslo.service threading back end—05 (executor)n/a (Go)
19, 25–30ec6f71811181… 6f9ae1900b7e2026-05-12/14upgradeBarbican, Octavia, Keystone, Cinder, Glance, Neutron, Nova clients replaced by openstacksdk; per-client TLS and api_version options removed—03 § outbound REST; configconfig names
2131b84327db882026-05-13upgrade**Heat driver (k8s_fedora_coreos_v1) removed**, with the Heat special cases of the conductor—01, 05, 08the driver contract of 08
227999e015e05f2026-05-13upgrade / securityKeystone trusts removed: trustee users, trust columns, trustee policy rules—01 (policies), 03 (schema), 07 § 6do not implement trustees
23, 41cb50432c88d4, 0c6e7d4906642026-05-13/26maintenancecontrib drivers and Heat templates removed (−20 k lines)———
3178d090e65f2b2026-05-14upgradelegacy [keystone_authtoken] admin credentials no longer used; service user only from [keystone_auth]—03, 07 § 6config
3234283af5be6a2026-05-15fixlabels copied: creating a nodegroup no longer alters the cluster's labels212973901 § nodegroupsreproduce
33, 35e502c5c7d477, 2e8be7e1fb072026-05-15/18upgrade (reverted)stack_id dropped then restored: drivers use it as the unique back-end cluster name—01, 08keep stack_id
34, 36, 4329b153e640a8, 0ac676a512fc, c8977af49acf2026-05-16/28fixregressions of the openstacksdk switch: Barbican payload, null expiration, quota project check2152790, 215312803 (Barbican), 01 § quotas—
37f9bf09c6019d2026-05-20featuremicroversion 1.13: cluster_id replaces stack_id in responses—01, 07 § 2.2, § 4reproduce exactly
42ddbdddf062ca2026-05-27featurehidden templates enforced (invisible to non-admins, unusable for new clusters)—01 § templates, clustersreproduce
47cb49cb1a2a4b2026-06-22feature**driver on templates** and [drivers]/default_driver—01, 07 § 3.1reproduce
551d42edb2cbd82026-07-15featureclearer ClusterTypeNotSupported; new ClusterTypeBetaNotEnabled—02reproduce messages
5734738d90ac6a2026-07-17featuremicroversion 1.14: node_labels, node_taints on nodegroups—01, 03 (migration)reproduce, gate at 1.14
5923a43e879d5e2026-08-08fiximage without os_distro → clear OSDistroFieldNotFound—02reproduce
6, 12, 49, 51d1a9057dada4, a7a9b09514c5, 70310efe73de, 39dc334e6dde2026-03/07refactoroslo.versionedobjects and Alembic deprecations; stdlib importlib.metadata—none—
139807c1a9f0752026-04-24feature (logs)loaded drivers logged at DEBUG on API and conductor start—02 § logsoptional
15, 48, 53, 54cdb19fce44b3, 85bf08a4a9e5, f0c33e48ac56, b07e02daf9a32026-05/07dependenciesPython ≥ 3.11, packaging moved to pyproject.toml (entry points now there)—00 § processes—

Change specifications

4. boot_volume_size label accepted as a string — fix

  • Commit: c73f9e152598 — review https://review.opendev.org/q/I246494a4e32018465c7092d22ffa5f09bbaf179a — bug 2144473.
  • Before / after: labels are strings on the wire. With labels.boot_volume_size = "0", the root-disk check compared a string with an integer and raised TypeError, a 500. The value is now converted with strutils.validate_integer; a non-integer is a 400 (magnum/api/attr_validator.py:184).
  • Impact on the specification: 01 § POST clustertemplates rule 8 and § POST clusters rule 9 describe the fixed behaviour.
  • Carrying it over: standalone, no test change.

9, 10, 11. API performance under load — fix

  • Commits: 598067b4ea71, e791b7c5077f, 2036ac2fb3b1 — related bug 2137018 (API latency under load).
  • Before / after:
    • #9: every tenant-filtered DB query and every policy enforcement used to authenticate to Keystone as an admin, to find the trustee domain. The domain is now read from [trust]/trustee_domain_id, or looked up once per process. #22 then removed the whole mechanism.
    • #10: each API request created a new RPCClient, with a new RabbitMQ connection. Clients are now cached per (topic, server, timeout) (magnum/common/rpc_service.py:78).
    • #11: Cluster.as_dict() read the nodegroups four times; it now reads them once (magnum/objects/cluster.py:386). Cluster lists prefetch one template per distinct id (magnum/api/controllers/v1/cluster.py:308).
  • Impact on the specification: 03 § RabbitMQ (client cache), 07 § 9 (list cost). No API change.
  • For openkeel-magnum: the batching (one template read per page, one nodegroup read per cluster) is a non-functional requirement.

14 and 59. Image checks on template create — fix

  • Commits: a414fcfc11a1 (2026-04-24), 23a43e879d5e (2026-08-08).
  • Before / after: driver resolution read the image and swallowed every exception, so a missing or forbidden image ended in a confusing "cluster type not supported". Now Glance 404 → 400 ImageNotFound, 403 → 403 ImageNotAuthorized (magnum/api/validation.py:80). An image without os_distro → 400 OSDistroFieldNotFound (magnum/api/validation.py:87). Other Glance errors are still swallowed (magnum/api/validation.py:85).
  • Impact on the specification: 02 catalogue (rows ImageNotFound, ImageNotAuthorized, OSDistroFieldNotFound), 07 § 3.1.

17. eventlet dropped — upgrade

  • Commit: 2e1821ea4357 (authored 2025-08-25, merged 2026-05-08).
  • Before / after: Magnum ran under eventlet monkey-patching (green threads, executor='eventlet'). It now selects oslo.service's threading back end at import (magnum/__init__.py), with native threads; the RPC server uses the default executor. If another library has already selected eventlet, a warning is emitted and eventlet stays.
  • Upgrade / operations: drivers must be thread-safe. magnum-cluster-api v0.39.0 detects which mode it runs in (08 § Overview). Concurrency in the conductor is now bounded by thread pools, not green threads [inferred].
  • For openkeel-magnum: none; documents why 05 says "threading".

19, 25–30. Every OpenStack client replaced by openstacksdk — upgrade

  • Commits: ec6f71811181 (Barbican), c84e592b747b (Octavia), 319aca3b4606 (Keystone), e5a2d367135c (Cinder), 6bfa09f39755 (Glance), a293fffb5ff2 (Neutron), 6f9ae1900b7e (Nova), 2026-05-12 to 05-14.
  • Before / after: python-*client libraries are replaced by one openstack.connection.Connection per service, built on the keystoneauth session (magnum/common/clients.py). The options [cinder|glance|nova|neutron]/api_version (where it existed), ca_file, cert_file, key_file and insecure are removed: TLS for outbound calls now comes from the keystoneauth session options. Error mapping moved to openstack.exceptions (NotFoundException, ForbiddenException, DuplicateResource), with the same Magnum exceptions on top (magnum/api/attr_validator.py:37).
  • Upgrade / operations: configuration files that still set the removed options are ignored (oslo.config warns about unknown options [inferred]).
  • Regressions introduced and fixed in the same cycle: #34, #36 and #43 below.

21. Heat driver removed — upgrade

  • Commit: 31b84327db88 — review https://review.opendev.org/q/I8f2133576a9e658f5b28c1287a12837fae2776db — −11 249 lines in 55 files. Release note: "k8s_fedora_coreos_v1 driver (also known as Heat-based driver) has been dropped following earlier deprecation."
  • Before / after:
    • The in-tree driver, its Heat templates and the [heat] and [cluster_heat] option groups are gone. magnum.drivers is now empty (pyproject.toml:69).
    • In the conductor, the special handling of Heat exceptions was removed:
      • heatclient.exc.HTTPNotFound from delete_cluster used to delete certificates, trusts, nodegroups and the cluster row immediately and notify success. It is now an ordinary failure: DELETE_FAILED.
      • The same applies to delete_nodegroup: HTTPNotFound used to destroy the nodegroup row.
      • HTTPConflict used to raise OperationInProgress / NgOperationInProgress, which are now never raised.
      • HTTPBadRequest used to become a 400 InvalidParameterValue; it now goes through unchanged.
    • The template-create deprecation warning for fedora-coreos was removed. The 500 on coreos images (01) is older: commit 5c0c278 (2024-01-31, "Drop k8s_coreos_v1 driver") deleted the _coreos_deprecation_note attribute but kept the code that uses it. The bug was already in 2026.1, so it is not a regression of this cycle.
  • Why: the Heat driver was deprecated in 2025.1 in favour of the Cluster API drivers.
  • Impact on the specification: 01 (no driver means ClusterTypeNotSupported), 05 (cluster_delete and nodegroup_delete have no not-found path), 02 (exceptions never raised), 08 (magnum-cluster-api still raises heatclient.exc.HTTPNotFound when a nodegroup's MachineDeployment is gone, magnum-cluster-api:magnum_cluster_api/driver.py:714: with 2026.2 that **ends in DELETE_FAILED** instead of removing the row. This confirms 08 § 11).
  • Upgrade / operations: clusters created with the Heat driver can no longer be managed. Their template's driver no longer exists, so every action and the status poller fail with ClusterDriverNotSupported [inferred from magnum/drivers/common/driver.py:134]. They must be migrated or deleted before upgrading from 2026.1. The Heat stacks themselves remain in Heat.
  • For openkeel-magnum: do not reproduce any Heat path. If OpenKeel keeps a "driver" abstraction, it should keep an explicit "already gone" result for delete operations, the role HTTPNotFound used to play.

22. Keystone trusts removed — upgrade, security

  • Commit: 7999e015e05f — −853 lines. Migration d7e6a4d39fe4 drops cluster.trust_id, trustee_username, trustee_user_id, trustee_password (magnum/db/sqlalchemy/alembic/versions/d7e6a4d39fe4_drop_trust_columns.py).
  • Before / after:
    • Each Heat cluster used to get a trustee user in a dedicated domain, with a password stored in clear text in cluster.trustee_password, and a trust from the creator. In-cluster components (cloud provider, autoscaler, auto-healer) used these credentials to call Magnum and OpenStack.
    • The database filter used to recognise trustee users and map them to their cluster's project; the policies had cluster_user and deny_cluster_user rules (not domain_id:%(trustee_domain_id)s).
    • All of this is gone. The *_deny_cluster_user rules keep their names but now equal the plain member/reader rules (magnum/common/policies/base.py:127), which is why 07 § 6 says they deny nothing.
    • The [trust] option group is removed.
  • Why: Heat was the only user. The Cluster API drivers use application credentials instead (08 § 6).
  • Impact on the specification: 01 (policies), 03 (schema), 07 § 6, schema head (d7e6a4d39fe4 then b3e1cf4a2d5e).
  • Upgrade / operations: the migration drops the columns, but the trustee users and trusts are not deleted from Keystone [inferred: no cleanup code in the commit]. Operators should delete the trustee domain's users manually after the upgrade.

31. Legacy keystonemiddleware credentials no longer used — upgrade

  • Commit: 78d090e65f2b. Release note: the service user must be configured in [keystone_auth]; Magnum no longer falls back to [keystone_authtoken] admin_user / admin_password / admin_tenant_name.
  • Before / after: KeystoneClientV3.auth_url reads [keystone_auth]/auth_url, then [keystone_authtoken]/www_authenticate_uri (magnum/common/keystone.py:40); auth_uri and the v2.0→v3 rewrite are gone. The auth middleware now receives the merged paste configuration (magnum/api/middleware/auth_token.py:67).
  • Upgrade / operations: a deployment without [keystone_auth] credentials fails at the first service-user call: the periodic tasks and the Barbican admin client raise AuthorizationFailure "Keystone API connection failed: no password or token found." (magnum/common/keystone.py:76).

32. Labels copied instead of shared — fix

  • Commit: 34283af5be6a — bug 2129739.
  • Before / after: the template's labels dict was assigned to the cluster, and the cluster's dict to the nodegroup, without copying. Merging labels into a new nodegroup therefore modified the cluster's labels in memory, and in the database if the cluster was saved afterwards. Every assignment now copies (magnum/api/controllers/v1/cluster.py:545, magnum/api/controllers/v1/nodegroup.py:482, magnum/conductor/utils.py:164).
  • Impact on the specification: the inheritance rules of 07 § 3.2 describe the fixed behaviour.

33 and 35. stack_id removed, then restored — upgrade, reverted

  • Commits: e502c5c7d477 (2026-05-15, adds migration a0f9c3a8e1b2 dropping stack_id from cluster and nodegroup), reverted by 2e8be7e1fb07 (2026-05-18, deletes the migration file).
  • Why reverted: the Cluster API drivers store their unique back-end cluster name in stack_id (magnum-capi-helm: <name>-<random>; magnum-cluster-api: kube-<random>, 08 § 1), and it is used in OpenStack resource names.
  • Net effect: none in the release. A database that ran a0f9c3a8e1b2 during those three days has lost the column and records a revision that no longer exists, so magnum-db-manage upgrade fails on it [inferred].
  • For openkeel-magnum: keep the column. #37 exposes it as cluster_id.

34, 36, 43. Regressions of the openstacksdk switch — fix

  • #34 29b153e640a8 (bug 2152790): openstacksdk sends secrets as JSON, so byte payloads (PEM certificates) failed serialisation. Every cluster creation with the Barbican back end failed between #19 and #34. Payloads are now decoded and sent as text/plain (magnum/common/cert_manager/barbican_cert_manager.py:81).
  • #36 0ac676a512fc (bug 2153128): Barbican rejects "expiration": null, so the field is now omitted when unset (magnum/common/cert_manager/barbican_cert_manager.py:87).
  • #43 c8977af49acf (bug 2153128): POST /v1/quotas called a keystoneclient method that no longer existed, giving a 500. It now uses get_project, and a missing project is a 404 ProjectNotFound again (magnum/api/validation.py:148).
  • Impact on the specification: 03 § outbound REST (Barbican frame: payload_content_type: text/plain, no expiration), 01 § quotas.

37. Microversion 1.13: cluster_id — feature

  • Commit: f9bf09c6019d. Release note: cluster_id replaces stack_id in cluster responses from 1.13; stack_id is deprecated.
  • Before / after: at ≥ 1.13 every cluster response, list and detail, carries cluster_id and omits stack_id. Below 1.13 nothing changes. Both are read-only (magnum/api/controllers/v1/cluster.py:211, magnum/api/controllers/v1/cluster.py:283). Nodegroups still expose stack_id.
  • Client impact: clients that send latest and read stack_id lose it, including the auto-healer through gophercloud (07 § 4).
  • For openkeel-magnum: reproduce exactly, including the asymmetry with nodegroups.

42. Hidden templates enforced — feature

  • Commit: ddbdddf062ca. Release note: admins can hide a template so that no new cluster uses it, while existing clusters keep working.
  • Before / after:
    • hidden existed but was not enforced: hidden public templates were listed to everyone.
    • Now non-admins do not see hidden templates of other projects in lists (magnum/db/sqlalchemy/api.py:301) or by id (404, magnum/api/controllers/v1/cluster_template.py:389), and cannot create clusters from a hidden template (403, magnum/api/controllers/v1/cluster.py:534).
    • clustertemplate:publish now covers the hidden flag too (magnum/common/policies/cluster_template.py:151).
  • Impact on the specification: 01 § templates and § POST clusters rule 6.

47. driver on templates and [drivers]/default_driver — feature

  • Commit: cb49cb1a2a4b. Release note gives the resolution order: request driver → image magnum_driver → [drivers]/default_driver → first driver alphabetically.
  • Before / after: the driver was only taken from the image property (or left empty). Now the API accepts driver (1–255 characters, previously 0–255), resolves it in that order, validates it and stores it (magnum/api/validation.py:66, magnum/drivers/common/driver.py:166). A configured default that is not installed is an error (400 ClusterDriverNotSupported, logged).
  • Impact on the specification: 01 § POST clustertemplates rule 5, 07 § 3.1. The API cluster-create check still ignores the stored name (01 rule 2).
  • For openkeel-magnum: with a single back end (Cluster API), accept and store driver for compatibility and refuse unknown names.

55. Driver error messages — feature

  • Commit: 1d42edb2cbd8. ClusterTypeNotSupported now lists the supported tuples, or "none (no cluster drivers are loaded)". A matching but disabled beta driver raises the new ClusterTypeBetaNotEnabled (magnum/drivers/common/driver.py:137).
  • Impact on the specification: 02 catalogue.

57. Microversion 1.14: node labels and taints — feature

  • Commit: 34738d90ac6a — migration b3e1cf4a2d5e (node_labels JSON dict, node_taints JSON list on nodegroup). Release note: "surfaced from REST API microversion 1.14"; applying them to nodes is the driver's responsibility.
  • Before / after: worker nodegroups accept Kubernetes labels and taints, validated against the kubelet's restricted namespaces and the taint grammar (magnum/api/controllers/v1/nodegroup.py:78, magnum/api/controllers/v1/nodegroup.py:103). The maximum microversion becomes 1.14 (magnum/api/controllers/versions.py:43).
  • Spec/code mismatch: the handlers check no version, so the fields are accepted from 1.9 (01 § nodegroups). magnum-cluster-api v0.39.0 does not read these fields [inferred: no reference in 08's mapping].
  • For openkeel-magnum: gate at 1.14 and map them to MachineDeployment node labels and taints.

6, 12, 49, 51. Library deprecations — refactor

object_backport → object_backport_versions (magnum/conductor/api.py:151); remotable_classmethod replaced; Alembic MigrationManager replaced with the Alembic API; importlib_metadata → importlib.metadata (magnum/drivers/common/driver.py:16). No behaviour change, but the indirection RPC method name changed: an API older than 2026.2 talking to a 2026.2 conductor would call a method that no longer exists [inferred].

Maintenance-only changes

CommitSubjectWhy it is usually not carried over
85df8c24881b, 993132789e24, 5145c1a592af, f7ddcfd967e2, 4df4d5752f27devstack and docstest environment only
b5941f365a1e, b0fe3adfbcecrelease bookkeeping, translationsper release
c62b9e62d1b7, ec08b8b22b80, f3c5268e10b0, e80888839bf6, 04d0a9831e5btest and lint dependenciestooling
b212d6e67959, 476effcbead6, 0527433edff8, dad144ed49a6, f55672e1e9d7, 1910928b7d9fCI jobs for magnum-cluster-api and magnum-capi-helmCI only; they show that both CAPI drivers are tested upstream against 2026.2
7fdd0e2ca07f, 4ce1fed395a6stop forcing [oslo_policy] enforce_scope in tests/devstacktest configuration (oslo.policy enforces scope by default)
cb50432c88d4, 0c6e7d490664contrib drivers and Heat templates removeddead code after #21
68f935fa9995version history formattingdocs
cdb19fce44b3, 85bf08a4a9e5, f0c33e48ac56, b07e02daf9a3Python ≥ 3.11, pyproject.tomlpackaging

Carry-over plan

There is no target project, so nothing is cherry-picked. For an older Magnum branch (2026.1), the full git cherry-pick -x list, in application order, is in [_inventory/history_stable-2026.2.md](_inventory/history_stable-2026.2.md) § "Carry-over plan". Two rules apply when using it:

  • #19 and #25–30 must be taken together with #34, #36 and #43, or the Barbican back end and the quota API break;
  • never take #33 without #35.

For openkeel-magnum the useful output of this history is a set of requirements, already folded into 07:

  • keep stack_id and microversion 1.13;
  • enforce hidden templates and the driver resolution order;
  • gate microversion 1.14;
  • copy labels on inheritance;
  • no trustees and no Heat paths;
  • an explicit "already gone" result for deletions.

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