Change history — magnum — branch stable/2026.2
Branch
stable/2026.2@1910928b7d9f— range22.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 foropenkeel-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
driveron 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
| # | Commit | Date | Category | Change | Bug | Impact | For openkeel-magnum |
|---|---|---|---|---|---|---|---|
| 4 | c73f9e152598 | 2026-03-15 | fix | boot_volume_size label accepted as a string | 2144473 | 01 § templates/clusters (root-disk rule) | reproduce: labels are strings |
| 9 | 598067b4ea71 | 2026-04-08 | fix (perf) | no more Keystone authentication on every DB query and policy check | 2137018 | 03; superseded by #22 | none (trusts gone) |
| 10 | e791b7c5077f | 2026-04-08 | fix (perf) | one RPC client per process instead of per request | 2137018 | 03 § RabbitMQ | design note |
| 11 | 2036ac2fb3b1 | 2026-04-08 | fix (perf) | nodegroups read once per as_dict(); templates prefetched for cluster lists | 2137018 | 07 § 9 | reproduce the batching |
| 14 | a414fcfc11a1 | 2026-04-24 | fix | template create: Glance 404/403 now return ImageNotFound/ImageNotAuthorized instead of being swallowed | — | 02 | reproduce |
| 17 | 2e1821ea4357 | 2026-05-08 | upgrade | eventlet dropped; oslo.service threading back end | — | 05 (executor) | n/a (Go) |
| 19, 25–30 | ec6f71811181… 6f9ae1900b7e | 2026-05-12/14 | upgrade | Barbican, Octavia, Keystone, Cinder, Glance, Neutron, Nova clients replaced by openstacksdk; per-client TLS and api_version options removed | — | 03 § outbound REST; config | config names |
| 21 | 31b84327db88 | 2026-05-13 | upgrade | **Heat driver (k8s_fedora_coreos_v1) removed**, with the Heat special cases of the conductor | — | 01, 05, 08 | the driver contract of 08 |
| 22 | 7999e015e05f | 2026-05-13 | upgrade / security | Keystone trusts removed: trustee users, trust columns, trustee policy rules | — | 01 (policies), 03 (schema), 07 § 6 | do not implement trustees |
| 23, 41 | cb50432c88d4, 0c6e7d490664 | 2026-05-13/26 | maintenance | contrib drivers and Heat templates removed (−20 k lines) | — | — | — |
| 31 | 78d090e65f2b | 2026-05-14 | upgrade | legacy [keystone_authtoken] admin credentials no longer used; service user only from [keystone_auth] | — | 03, 07 § 6 | config |
| 32 | 34283af5be6a | 2026-05-15 | fix | labels copied: creating a nodegroup no longer alters the cluster's labels | 2129739 | 01 § nodegroups | reproduce |
| 33, 35 | e502c5c7d477, 2e8be7e1fb07 | 2026-05-15/18 | upgrade (reverted) | stack_id dropped then restored: drivers use it as the unique back-end cluster name | — | 01, 08 | keep stack_id |
| 34, 36, 43 | 29b153e640a8, 0ac676a512fc, c8977af49acf | 2026-05-16/28 | fix | regressions of the openstacksdk switch: Barbican payload, null expiration, quota project check | 2152790, 2153128 | 03 (Barbican), 01 § quotas | — |
| 37 | f9bf09c6019d | 2026-05-20 | feature | microversion 1.13: cluster_id replaces stack_id in responses | — | 01, 07 § 2.2, § 4 | reproduce exactly |
| 42 | ddbdddf062ca | 2026-05-27 | feature | hidden templates enforced (invisible to non-admins, unusable for new clusters) | — | 01 § templates, clusters | reproduce |
| 47 | cb49cb1a2a4b | 2026-06-22 | feature | **driver on templates** and [drivers]/default_driver | — | 01, 07 § 3.1 | reproduce |
| 55 | 1d42edb2cbd8 | 2026-07-15 | feature | clearer ClusterTypeNotSupported; new ClusterTypeBetaNotEnabled | — | 02 | reproduce messages |
| 57 | 34738d90ac6a | 2026-07-17 | feature | microversion 1.14: node_labels, node_taints on nodegroups | — | 01, 03 (migration) | reproduce, gate at 1.14 |
| 59 | 23a43e879d5e | 2026-08-08 | fix | image without os_distro → clear OSDistroFieldNotFound | — | 02 | reproduce |
| 6, 12, 49, 51 | d1a9057dada4, a7a9b09514c5, 70310efe73de, 39dc334e6dde | 2026-03/07 | refactor | oslo.versionedobjects and Alembic deprecations; stdlib importlib.metadata | — | none | — |
| 13 | 9807c1a9f075 | 2026-04-24 | feature (logs) | loaded drivers logged at DEBUG on API and conductor start | — | 02 § logs | optional |
| 15, 48, 53, 54 | cdb19fce44b3, 85bf08a4a9e5, f0c33e48ac56, b07e02daf9a3 | 2026-05/07 | dependencies | Python ≥ 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 raisedTypeError, a 500. The value is now converted withstrutils.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).
- #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
- 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 → 403ImageNotAuthorized(magnum/api/validation.py:80). An image withoutos_distro→ 400OSDistroFieldNotFound(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.Connectionper 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_fileandinsecureare removed: TLS for outbound calls now comes from the keystoneauth session options. Error mapping moved toopenstack.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_v1driver (also known asHeat-baseddriver) 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.driversis now empty (pyproject.toml:69). - In the conductor, the special handling of Heat exceptions was removed:
heatclient.exc.HTTPNotFoundfromdelete_clusterused 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:HTTPNotFoundused to destroy the nodegroup row. HTTPConflictused to raiseOperationInProgress/NgOperationInProgress, which are now never raised.HTTPBadRequestused to become a 400InvalidParameterValue; it now goes through unchanged.
- The template-create deprecation warning for
fedora-coreoswas removed. The 500 oncoreosimages (01) is older: commit5c0c278(2024-01-31, "Drop k8s_coreos_v1 driver") deleted the_coreos_deprecation_noteattribute but kept the code that uses it. The bug was already in 2026.1, so it is not a regression of this cycle.
- The in-tree driver, its Heat templates and the
- 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_deleteandnodegroup_deletehave no not-found path), 02 (exceptions never raised), 08 (magnum-cluster-api still raisesheatclient.exc.HTTPNotFoundwhen a nodegroup's MachineDeployment is gone,magnum-cluster-api:magnum_cluster_api/driver.py:714: with 2026.2 that **ends inDELETE_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 frommagnum/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
HTTPNotFoundused to play.
22. Keystone trusts removed — upgrade, security
- Commit:
7999e015e05f— −853 lines. Migrationd7e6a4d39fe4dropscluster.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_useranddeny_cluster_userrules (not domain_id:%(trustee_domain_id)s). - All of this is gone. The
*_deny_cluster_userrules 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.
- Each Heat cluster used to get a trustee user in a dedicated domain, with a password stored in clear text in
- 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 (
d7e6a4d39fe4thenb3e1cf4a2d5e). - 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_urlreads[keystone_auth]/auth_url, then[keystone_authtoken]/www_authenticate_uri(magnum/common/keystone.py:40);auth_uriand thev2.0→v3rewrite 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 raiseAuthorizationFailure"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 migrationa0f9c3a8e1b2droppingstack_idfromclusterandnodegroup), reverted by2e8be7e1fb07(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
a0f9c3a8e1b2during those three days has lost the column and records a revision that no longer exists, somagnum-db-manage upgradefails 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 astext/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/quotascalled a keystoneclient method that no longer existed, giving a 500. It now usesget_project, and a missing project is a 404ProjectNotFoundagain (magnum/api/validation.py:148). - Impact on the specification: 03 § outbound REST (Barbican frame:
payload_content_type: text/plain, noexpiration), 01 § quotas.
37. Microversion 1.13: cluster_id — feature
- Commit:
f9bf09c6019d. Release note:cluster_idreplacesstack_idin cluster responses from 1.13;stack_idis deprecated. - Before / after: at ≥ 1.13 every cluster response, list and detail, carries
cluster_idand omitsstack_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 exposestack_id. - Client impact: clients that send
latestand readstack_idlose 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:
hiddenexisted 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:publishnow covers thehiddenflag 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: requestdriver→ imagemagnum_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 (400ClusterDriverNotSupported, 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
driverfor compatibility and refuse unknown names.
55. Driver error messages — feature
- Commit:
1d42edb2cbd8.ClusterTypeNotSupportednow lists the supported tuples, or "none (no cluster drivers are loaded)". A matching but disabled beta driver raises the newClusterTypeBetaNotEnabled(magnum/drivers/common/driver.py:137). - Impact on the specification: 02 catalogue.
57. Microversion 1.14: node labels and taints — feature
- Commit:
34738d90ac6a— migrationb3e1cf4a2d5e(node_labelsJSON dict,node_taintsJSON list onnodegroup). 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
MachineDeploymentnode 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
| Commit | Subject | Why it is usually not carried over |
|---|---|---|
85df8c24881b, 993132789e24, 5145c1a592af, f7ddcfd967e2, 4df4d5752f27 | devstack and docs | test environment only |
b5941f365a1e, b0fe3adfbcec | release bookkeeping, translations | per release |
c62b9e62d1b7, ec08b8b22b80, f3c5268e10b0, e80888839bf6, 04d0a9831e5b | test and lint dependencies | tooling |
b212d6e67959, 476effcbead6, 0527433edff8, dad144ed49a6, f55672e1e9d7, 1910928b7d9f | CI jobs for magnum-cluster-api and magnum-capi-helm | CI only; they show that both CAPI drivers are tested upstream against 2026.2 |
7fdd0e2ca07f, 4ce1fed395a6 | stop forcing [oslo_policy] enforce_scope in tests/devstack | test configuration (oslo.policy enforces scope by default) |
cb50432c88d4, 0c6e7d490664 | contrib drivers and Heat templates removed | dead code after #21 |
68f935fa9995 | version history formatting | docs |
cdb19fce44b3, 85bf08a4a9e5, f0c33e48ac56, b07e02daf9a3 | Python ≥ 3.11, pyproject.toml | packaging |
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_idand microversion 1.13; - enforce hidden templates and the
driverresolution 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.