Change history — CloudKitty — branch stable/2026.2
Branch
stable/2026.2@0685cc330e83— repository https://opendev.org/openstack/cloudkitty — analysed on 2026-11-09
- Range:
24.0.0..stable/2026.2(bf6195a4cd4b..0685cc330e83), i.e. the whole 2026.2 development cycle since the 2026.1 release, 32 non-merge commits. The automatic range (sincestable/2026.2left master,95b73e36cb2c..0685cc330e83) holds only the two release-bot commits #31 and #32, so it was widened on purpose. - Target: none given. No commit is marked present/absent; the carry-over plan lists every non-maintenance commit in application order.
- Raw facts: [
_inventory/history_stable-2026.2.md](_inventory/history_stable-2026.2.md) and.json(trailers, files, release notes, overlaps). - Categories (corrected after reading the diffs): 2 security-relevant hardening, 4 fixes, 4 features, 2 upgrade, 1 configuration-sample, 1 refactor, 18 maintenance. The script's categories were adjusted where noted ("category corrected").
Summary
| # | Commit | Date | Category | Change | Bug / story | Impact on this spec |
|---|---|---|---|---|---|---|
| 3 | 68796c97046d | 2026-03-04 | config sample | auth_section and the other keystoneauth options are listed in the sample for collector_gnocchi, fetcher_gnocchi, fetcher_keystone, storage_gnocchi | — | 03 § 3.2, § 4 (documentation only) |
| 5 | 22807c7eca9c | 2026-03-18 | fix (performance; category corrected) | rating rules are no longer loaded for deactivated scopes | — | 05 § 1, 03 § 2.3 |
| 7 | 20bbf9d55c15 | 2026-03-31 | hardening | new [storage_influxdb]/timeout (60 s) on Flux HTTP queries | — | 03 § 5.1 |
| 10 | 1a54c8ac4035 | 2026-02-18 | feature | new Aetos collector (Prometheus behind Keystone auth); Prometheus code split into base + concrete classes | spec 966753 | 00, 03 § 3.3 |
| 11 | a45fbeeab049 | 2026-01-27 | feature | Loki structured metadata: always written; used in queries when [storage_loki]/use_structured_metadata = true | — | 03 § 5.3 |
| 12 | 63ecb1e71a38 | 2026-04-09 | upgrade | the cloudkitty-api WSGI script and cloudkitty/api/app.wsgi are removed; use cloudkitty.wsgi.api:application | — | 00 Processes |
| 15 | 13c0dcfe707a | 2026-04-09 | packaging (category corrected) | setup.cfg metadata, scripts and entry points moved to pyproject.toml | — | 00 (entry points now cited in pyproject.toml) |
| 16 | f213c4dd4a68 | 2026-05-02 | upgrade | Python ≥ 3.11 (3.10 dropped), 3.14 added | — | runtime |
| 20 | 43ecd5406fba | 2026-05-12 | config sample (category corrected) | sample image.size metric gets force_granularity: 300 | — | 03 § 3.2 |
| 24 | 4cb28f198375 | 2026-05-26 | fix | POST /v2/scope with active=false no longer answers 500 | — | 01 § 6.4, 02 § 2.5 |
| 25 | 5bb59c0048c2 | 2026-06-18 | fix (data loss) | a failed Loki push now raises PushError, so the period is retried instead of being marked processed | — | 02 § 3, 03 § 5.3 |
| 26 | 349cda233a7f | 2026-06-19 | fix (behaviour change; category corrected) | Loki entries are timestamped with the period start instead of the period end | — | 03 § 5.3 |
| 28 | 1ed51c37e5b3 | 2026-08-24 | fix | revert of a 2024 ES/OpenSearch fix that conflicted with a later one; /v2/summary with a type filter works again on ES/OS | story 2011868 | 03 § 5.2 |
| 29 | 47205370cb85 | 2026-08-29 | refactor | typo fix: filter_unecessary_measurements → filter_unnecessary_measurements, log text occured → occurred | — | 02 § 3 (log text) |
Change specifications
3. List the keystoneauth options of four sections — config sample
- What changed:
list_optsnow addsks_loading.get_session_conf_options()andget_auth_common_conf_options()tocollector_gnocchi,fetcher_gnocchi,fetcher_keystoneandstorage_gnocchi(cloudkitty/common/config.py:47-68,cloudkitty/common/config.py:82-86). These options were already registered and honoured at run time (cloudkitty/collector/gnocchi.py:78-79,cloudkitty/fetcher/keystone.py:46-47); onlyoslo-config-generatoroutput changes, notablyauth_sectionnow appears in the sample. - Why: the generated
cloudkitty.conf.sampleand the configuration reference were missing them. - Upgrade impact: none at run time.
- Carrying it over: standalone, no prerequisite. Only worth it if the target ships a generated sample.
5. Do not load rating rules for deactivated scopes — fix (performance)
- Before:
Worker.__init__and every iteration ofWorker.runcalledrefresh_rating_rules(), i.e. the full hashmap and pyscripts rule load (03 § 2.3), **even for scopes that are then skipped becauseactiveis false**. - After: the call moves to the start of
do_execute_scope_processing(cloudkitty/orchestrator.py:418-419), which runs only once the active check has passed (cloudkitty/orchestrator.py:406-415). Rules are still reloaded for every period processed, because rules carry validity windows and each period must be rated with the rules valid at its start (commit message). - Impact on this spec: 05 § 1 step 5 describes the new order. The SQL load per scope cycle (03 § 2.3) now applies only to active scopes with a ready period.
- Upgrade impact: none; lower database load on deployments with many deactivated scopes.
- Carrying it over: 3 lines in
cloudkitty/orchestrator.py; no test in the commit. Conflicts are unlikely unless the target refactoredWorker.
7. Timeout on InfluxDB v2 HTTP queries — hardening
- What changed: new
[storage_influxdb]/timeout(float, 60 s, min 0) (cloudkitty/storage/v2/influx.py:89-93), passed to therequests.postthat sends Flux queries (cloudkitty/storage/v2/influx.py:707-717). - Why: a stuck InfluxDB froze API requests and processor workers; bandit B113 (request without timeout).
- Scope, read from the code: only the Flux query path of the InfluxDB 2 client uses it. The InfluxDB 1 client (
influxdb.InfluxDBClient,cloudkitty/storage/v2/influx.py:133-141) and the v2 write/delete APIs (InfluxDBClient(timeout=query_timeout),cloudkitty/storage/v2/influx.py:516-520) are unchanged [inferred: they keep their library defaults]. - Upgrade impact: a Flux query longer than 60 s now fails (500 on the API, retry on the processor) where it used to wait.
- Carrying it over: standalone; release note
releasenotes/notes/influxdb-timeout-57aba639d07b8c8b.yaml.
10. Aetos collector — feature
- What changed:
- The Prometheus collector and client are split into
PrometheusCollectorBase/PrometheusClientBaseand concrete classes (cloudkitty/collector/prometheus_base.py:63-229,cloudkitty/common/prometheus_client_base.py:18-54), without behaviour change to the PromQL built (cloudkitty/collector/prometheus_base.py:116-174). - New
aetoscollector: same queries, sent through python-observabilityclient over a keystoneauth session to themetric-storageendpoint of the catalogue (cloudkitty/collector/aetos.py:27-83,cloudkitty/common/aetos_client.py:28-75); new section[collector_aetos]withinterface(public) andregion_name, plus keystoneauth options. - Entry point
aetos(pyproject.toml:55); new requirementpython-observabilityclient>=1.1.0(requirements.txt:39).
- The Prometheus collector and client are split into
- Why: rate from Prometheus without exposing it unauthenticated (spec https://review.opendev.org/c/openstack/cloudkitty-specs/+/966753).
- Impact on this spec: 03 § 3.3. Aetos errors from python-observabilityclient (
PrometheusAPIClientError) are wrapped intoPrometheusResponseError, thenCollectError(cloudkitty/common/aetos_client.py:56-75,cloudkitty/collector/prometheus_base.py:196-202). - Upgrade impact: none unless
[collect]/collector = aetos; the Prometheus fetcher's import path changed (cloudkitty/fetcher/prometheus.py:18-19), which matters only to out-of-tree code importing the old names. - Carrying it over: large (≈ 900 lines with tests); prerequisite for any later Prometheus fix that touches
cloudkitty/collector/prometheus_base.py. Requires an Aetos release supporting thetimeandtimeoutquery parameters (commit message).
11. Loki structured metadata — feature
- What changed:
- Every pushed entry now carries structured metadata for
type,user,unit,flavor_namewhen present (cloudkitty/storage/v2/loki/client.py:30,cloudkitty/storage/v2/loki/client.py:346-365). - New
[storage_loki]/use_structured_metadata(false) (cloudkitty/storage/v2/loki/__init__.py:92-99). When true, queries filter on those fields before| json, other filters becomegroupby_<key>="…"after| json, and totals read indexed fields directly from the stream (cloudkitty/storage/v2/loki/client.py:108-182,cloudkitty/storage/v2/loki/client.py:414-425). - Query building is factored into
_build_query, shared by retrieve and delete (cloudkitty/storage/v2/loki/client.py:271-302).
- Every pushed entry now carries structured metadata for
- Why: query performance on Loki 3.0+.
- Upgrade impact: requires Loki ≥ 3.0 for the write side **[inferred: older Loki rejects the third element of a
valuesentry]**; enable the query option only once data written without metadata has expired (commit message). Multi-valued filters keep only their first value (cloudkitty/storage/v2/loki/client.py:140-141). - Carrying it over: prerequisite of #25 and #26 (same file). Apply in order 11 → 25 → 26.
12. Remove the pbr WSGI script — upgrade
- What changed:
cloudkitty/api/app.wsgi, thewsgi_scriptsentrycloudkitty-apiand the mod_wsgi install page are removed. The supported entry point is the modulecloudkitty.wsgi.api:application(cloudkitty/wsgi/api.py:19-24), added in 2025. - Upgrade impact (release note
releasenotes/notes/rm-wsgi-scripts-b944f2957bb7f480.yaml): deployment tools must point uWSGI/gunicorn atcloudkitty.wsgi.api:application, or ship their own.wsgifile for mod_wsgi. - Carrying it over: packaging change; depends on the target's build system (#15).
15. Move packaging to pyproject.toml — packaging
- What changed: project metadata, console scripts (
pyproject.toml:34-38) and every stevedore namespace (pyproject.toml:40-79) move fromsetup.cfgtopyproject.toml; no entry point is added or removed by this commit. - Upgrade impact: none for operators; packagers need a recent setuptools/pbr.
- Carrying it over: rewrite rather than cherry-pick if the target's
setup.cfgdiffers.
16. Python ≥ 3.11 — upgrade
requires-python = ">=3.11" (pyproject.toml:15); 3.14 added to the classifiers. Upgrade note: 3.10 hosts must be upgraded first. Not to be carried to an older branch.
20. Sample image.size granularity — config sample
force_granularity: 300 is added to the sample image.size metric (etc/cloudkitty/metrics.yml:29-32), matching Gnocchi's default archive policy; without it the Gnocchi collector asks for granularity 3600 (cloudkitty/collector/gnocchi.py:115), which a 300 s archive policy cannot serve. Existing deployments must update their own metric file; nothing changes automatically.
24. POST /v2/scope with active=false — fix
- Before: the handler created the scope, then re-read it with
get_all(identifier=…), whose defaultactive=1hides inactive scopes →IndexError→ 500, although the row was created. - After: the re-read passes
active=None(cloudkitty/api/v2/scope/state.py:270-272); the API returns 200 with the created scope. - Remaining gap (read from the code): the duplicate check before creation still uses the default
active=1(cloudkitty/api/v2/scope/state.py:249), so creating a scope whose id exists but is inactive is not refused by the API and ends on the table's unique key or in a second row for another fetcher/collector [inferred]. - Carrying it over: one line; standalone.
25. Raise on Loki push failure — fix (data loss)
- Before: a non-204 answer from
POST /pushwas only logged; the orchestrator then advancedlast_processed_timestamp, so the period's rated data was lost silently. - After:
PushError(status_code, text)is raised (cloudkitty/storage/v2/loki/client.py:234-241,cloudkitty/storage/v2/loki/exceptions.py:36-42);internal_runlogs it and retries the scope at the next loop (cloudkitty/orchestrator.py:716-725). - Side effect: pushes also happen from
add_pointwhen a buffer fills (cloudkitty/storage/v2/loki/client.py:367-370); a failure there now aborts the frame part-way, and the retry re-pushes the points already accepted [inferred: duplicates in Loki]. - Carrying it over: after #11.
26. Loki entry timestamp = period start — fix (behaviour change)
- Before: each entry was timestamped with the period end; queries over
[begin, end)returned the data of the previous period and Loki rejected entries whose end was in the future. - After: the period start (
cloudkitty/storage/v2/loki/client.py:324-327);endstays in the JSON line. - Upgrade impact: data written before and after the upgrade are offset by one period: a query, a reprocessing purge or a scope reset spanning the upgrade time sees the boundary period twice or misses it [inferred]. Consider reprocessing the periods around the upgrade.
- Carrying it over: after #11; one line.
28. Revert the 2024 ES/OpenSearch total fix — fix
- What changed:
ElasticsearchClient.totalandOpenSearchClient.totalno longer wrapmetric_typesinto a list themselves;_build_mustalready does it since677fc286f7fe(2025-10-01, part of24.0.0) (cloudkitty/storage/v2/elasticsearch/client.py:70-86). - Why: with both changes, a list given by
/v2/summarybecame[[type]]and every summary filtered bytypefailed (story 2011868). The removed release note was the one of the reverted fix (story 2011128). - Carrying it over: only if the target has both
2613a4251485and677fc286f7fe; otherwise skip it.
29. Typo fixes — refactor
Renames the static method GnocchiCollector.filter_unecessary_measurements to filter_unnecessary_measurements (cloudkitty/collector/gnocchi.py:459-460, cloudkitty/collector/gnocchi.py:496-497) and fixes a WARNING text. Breaks only out-of-tree code calling the old name. Log-based alerts on occured must be updated.
Maintenance-only changes
| # | Commit | Subject | Why it is usually not carried over |
|---|---|---|---|
| 1 | 75ce6403504f | devstack: Modernize authinfos options | devstack plugin |
| 2 | a6c77db6a16c | devstack: Use common function to manage keystoneauth options | devstack plugin |
| 4 | 405a9cbfd311 | Update master for stable/2026.1 | release bot (reno index) |
| 6 | 8f97464a363d | Remove unnecessary direct dependency on Pygments | requirements hygiene |
| 8 | 302180bfd391 | Drop unnecessary direct dependency on kombu | test requirements |
| 9 | 8de59c149cf1 | Fix missing oslo.policy options | unit-test fixture only |
| 13 | 10ee031e6768 | Update loki to newer upstream release for testing | CI |
| 14 | c7b9b74a40ce | zuul: Use ansible variable to configure tempest plugins | CI |
| 17 | f6bf20dc094e | Use pip to install from sources | devstack |
| 18 | aac92543e040 | Doc: define fetchers endpoints in to pyproject.toml | documentation |
| 19 | 03bc6be72967 | Doc: use the code-block directive for code | documentation |
| 21 | 5206e90693d1 | doc: Update Ubuntu package information | documentation |
| 22 | 2245e71c30f3 | doc: Use dnf in CentOS/RHEL | documentation |
| 23 | 89a8140ef453 | Skip tempest job for irrelevant files | CI |
| 27 | 40323f7428af | doc: Warn that aggregation_method must match the archive policy (bug 2160102) | documentation; operationally relevant: a Gnocchi aggregation_method absent from the archive policy returns no data |
| 30 | 678e139ddf41 | Fix CI tests | CI |
| 31 | d775ce1d2ce4 | Update .gitreview for stable/2026.2 | release bot |
| 32 | 0685cc330e83 | Update TOX_CONSTRAINTS_FILE for stable/2026.2 | release bot |
Carry-over plan
No target was given, so presence was not checked. In application order (oldest author date first, Loki chain kept together), for a target branched before 24.0.0's successor:
git cherry-pick -x a45fbeeab049 # 11 Loki structured metadata (prerequisite of 25, 26)
git cherry-pick -x 1a54c8ac4035 # 10 Aetos collector (needs python-observabilityclient>=1.1.0)
git cherry-pick -x 68796c97046d # 3 keystoneauth options in the config sample
git cherry-pick -x 22807c7eca9c # 5 no rule loading for deactivated scopes
git cherry-pick -x 20bbf9d55c15 # 7 InfluxDB timeout
git cherry-pick -x 43ecd5406fba # 20 sample image.size granularity
git cherry-pick -x 4cb28f198375 # 24 POST /v2/scope active=false
git cherry-pick -x 5bb59c0048c2 # 25 Loki push failure raises
git cherry-pick -x 349cda233a7f # 26 Loki timestamp = period start (behaviour change)
git cherry-pick -x 1ed51c37e5b3 # 28 ES/OS revert (only if 2613a4251485 and 677fc286f7fe are both present)
git cherry-pick -x 47205370cb85 # 29 typo fixes
Left out on purpose: #12, #15, #16 (packaging and runtime policy of the 2026.2 release, to be decided per target).
For OpenKeel, none of these needs carrying over (OpenKeel does not ship CloudKitty); they matter as behaviour to match or avoid if openkeel-pricing aims at CloudKitty API compatibility: #24 and #26 change observable API/storage results, #25 shows the expected retry semantics when the storage refuses a write.
Source: reverse-spec-cloudkitty/06-change-history_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.