fix(pgbouncer): bind `SHOW STATS` columns by name by AdzerKI · Pull Request #11366 · cloudnative-pg/cloudnative-pg · GitHub
Skip to content

fix(pgbouncer): bind SHOW STATS columns by name - #11366

Merged
gbartolini merged 3 commits into
cloudnative-pg:mainfrom
AdzerKI:pgbouncer-stats-by-column
Sep 9, 2026
Merged

gbartolini merged 3 commits into
cloudnative-pg:mainfrom
AdzerKI:pgbouncer-stats-by-column

Conversation

@AdzerKI

@AdzerKI AdzerKI commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

The collector picked its scan layout from the number of columns returned by SHOW STATS, and the gate that wrote the server assignment gauges (statColsCount == 16) matched none of the scan branches. On the 17-column path, those two values were scanned and discarded, while the parse-count gauges (never scanned there) were exported as zeros.

Bind each scan destination to its column name instead, ignoring columns the collector does not know, so a new PgBouncer column can no longer shift the values of the others. total_server_assignment_count and avg_server_assignment_count start being exported as a result, so add them to the sample output in the documentation, and correct the help text of the total, which described a duration rather than a count.

Also reset the two avg parse-count gauges, which were shadowed by their total counterparts and kept stale values across scrapes.

Closes #11365

@AdzerKI
AdzerKI requested a review from a team as a code owner August 24, 2026 11:20
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 24, 2026
@cnpg-bot cnpg-bot added backport-requested ◀️ This pull request should be backported to all supported releases release-1.28 release-1.29 release-1.30 labels Aug 24, 2026
@dosubot dosubot Bot added the bug 🐛 Something isn't working label Aug 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@AdzerKI

AdzerKI commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on main, tests in pkg/management/pgbouncer/metricsserver pass. Anything else needed from my side before this can get a review?

@armru

armru commented Sep 8, 2026

Copy link
Copy Markdown
Member

/test

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@armru, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/34214384372

@armru
armru force-pushed the pgbouncer-stats-by-column branch from c9ad559 to b4c3cc3 Compare September 8, 2026 10:25
armru added a commit that referenced this pull request Sep 8, 2026
`collectShowPools` chooses its scan layout from the number of columns
`SHOW POOLS` returns, with a case for 16, one for 17 and a 12 destination
fallback for anything else. Every layout PgBouncer currently reports is
covered: 17 columns since 1.24, 16 from 1.18, and the fallback is already
unreachable given CloudNativePG requires 1.19 or later. The next release
that adds a column, however, lands in the fallback, and the scan then
fails on every row. The failure would not even read as missing data: the
error branch falls through to the gauge writes, publishing every pool
metric from unpopulated locals as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from a single table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. Columns this version does not know are read and
discarded, and a column PgBouncer stops reporting leaves its gauge
without children rather than a fabricated zero. This is what #11366 does
for `SHOW STATS`, where the same switch already broke on 1.24.

Two consequences of the hand-written lists go with it, neither observable
today. `Describe` and `Reset` both omit `load_balance_hosts`: nothing
surfaces because the metrics endpoint registers a plain registry, whose
`Gather` skips the unregistered-descriptor check, and the gauge's stale
value is always zero. That is because PgBouncer reports the column as
text holding `disable` or `round-robin`, and null for a single-host pool,
while the scan expects an integer; the generated `[databases]` section
never configures more than one host, so the column is always null in
practice. Encode it the way `pool_mode` already is and correct its help
text, which described a count of hosts.

The sample scrape in the documentation still carries the scan error for
that column fixed in #6810, so drop it.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
@armru
armru force-pushed the pgbouncer-stats-by-column branch from b4c3cc3 to 34ddd97 Compare September 8, 2026 10:31
armru added a commit that referenced this pull request Sep 8, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 12 destination
fallback, and the scan then fails on every row. It would not read as
missing data either: the error branch falls through to the gauge writes,
so each pool metric is published as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from one table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. #11366 does the same for `SHOW STATS`, where that
switch already broke on 1.24.

`load_balance_hosts` comes along. PgBouncer reports it as text holding
`disable` or `round-robin`, and null for a single-host pool, while the
scan expected an integer; the generated `[databases]` section never
configures more than one host, so nothing surfaces today. Encode it the
way `pool_mode` already is, correct its help text, which described a
count of hosts, and drop the scan error fixed in #6810 from the docs
sample.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
armru added a commit that referenced this pull request Sep 8, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13 destination
fallback, and the scan then fails on every row. It would not read as
missing data either: the error branch falls through to the gauge writes,
so each pool metric is published as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from one table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. #11366 does the same for `SHOW STATS`, where that
switch already broke on 1.24.

`load_balance_hosts` comes along. PgBouncer reports it as text holding
`disable` or `round-robin`, and null for a single-host pool, while the
scan expected an integer; the generated `[databases]` section never
configures more than one host, so nothing surfaces today. Encode it the
way `pool_mode` already is, correct its help text, which described a
count of hosts, and drop the scan error fixed in #6810 from the docs
sample.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
@armru
armru force-pushed the pgbouncer-stats-by-column branch from 34ddd97 to cf21d44 Compare September 8, 2026 10:43
@armru

armru commented Sep 8, 2026

Copy link
Copy Markdown
Member

/test

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@armru, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/34217082593

@cnpg-bot cnpg-bot added the ok to merge 👌 This PR can be merged label Sep 8, 2026
@gbartolini
gbartolini force-pushed the pgbouncer-stats-by-column branch from cf21d44 to 74bd2c3 Compare September 9, 2026 09:16
@gbartolini gbartolini changed the title fix(pgbouncer): bind SHOW STATS columns by name fix(pgbouncer): bind SHOW STATS columns by name Sep 9, 2026
AdzerKI and others added 3 commits September 9, 2026 12:35
PgBouncer keeps adding columns to SHOW STATS, and the collector picked the
scan layout from the column count. A build with a column count it does not
know about drops every stats metric and logs a scan error on each scrape.

Bind the destinations to the column names instead, skipping columns the
collector does not know. Also reset the two avg parse-count gauges that
were shadowed by their total counterparts.

Signed-off-by: AdzerKI <silver_cat@list.ru>
The gauge writes for `total_server_assignment_count` and
`avg_server_assignment_count` were gated on a `SHOW STATS` column count
of 16, which no PgBouncer release reports: 15 up to 1.22, 17 in 1.23, 23
since 1.24. Neither metric has therefore ever appeared in a scrape, and
the sample in the documentation was captured without them. Both start
being exported with this branch, so add them.

The help text for the total also described a duration, while the column
counts how many times a server was assigned to a client. Correct it,
matching what PgBouncer's own documentation says.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Only two of the twenty-two column-to-gauge mappings are asserted, so a
misspelled key in the table drops one metric with no scan error and no
log line. That is the failure this branch removes from the column count,
and it would reappear one map entry lower.

Feed a row carrying every column name PgBouncer 1.25.2 reports, each with
a distinct value, and assert every gauge receives the value of its own
column.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
@gbartolini
gbartolini force-pushed the pgbouncer-stats-by-column branch from 74bd2c3 to 1753105 Compare September 9, 2026 10:35
@gbartolini

Copy link
Copy Markdown
Contributor

@gbartolini
gbartolini merged commit 590dccc into cloudnative-pg:main Sep 9, 2026
29 checks passed
cnpg-bot pushed a commit that referenced this pull request Sep 9, 2026
The collector picked its scan layout from the number of columns returned
by `SHOW STATS`, and the gate that wrote the server assignment gauges
(`statColsCount == 16`) matched none of the scan branches. On the
17-column path, those two values were scanned and discarded, while the
parse-count gauges (never scanned there) were exported as zeros.

Bind each scan destination to its column name instead, ignoring columns
the collector does not know, so a new PgBouncer column can no longer
shift the values of the others. `total_server_assignment_count` and
`avg_server_assignment_count` start being exported as a result, so add
them to the sample output in the documentation, and correct the help
text of the total, which described a duration rather than a count.

Also reset the two avg parse-count gauges, which were shadowed by their
total counterparts and kept stale values across scrapes.

Closes #11365

Signed-off-by: AdzerKI <silver_cat@list.ru>
Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Co-authored-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
(cherry picked from commit 590dccc)
cnpg-bot pushed a commit that referenced this pull request Sep 9, 2026
The collector picked its scan layout from the number of columns returned
by `SHOW STATS`, and the gate that wrote the server assignment gauges
(`statColsCount == 16`) matched none of the scan branches. On the
17-column path, those two values were scanned and discarded, while the
parse-count gauges (never scanned there) were exported as zeros.

Bind each scan destination to its column name instead, ignoring columns
the collector does not know, so a new PgBouncer column can no longer
shift the values of the others. `total_server_assignment_count` and
`avg_server_assignment_count` start being exported as a result, so add
them to the sample output in the documentation, and correct the help
text of the total, which described a duration rather than a count.

Also reset the two avg parse-count gauges, which were shadowed by their
total counterparts and kept stale values across scrapes.

Closes #11365

Signed-off-by: AdzerKI <silver_cat@list.ru>
Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Co-authored-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
(cherry picked from commit 590dccc)
cnpg-bot pushed a commit that referenced this pull request Sep 9, 2026
The collector picked its scan layout from the number of columns returned
by `SHOW STATS`, and the gate that wrote the server assignment gauges
(`statColsCount == 16`) matched none of the scan branches. On the
17-column path, those two values were scanned and discarded, while the
parse-count gauges (never scanned there) were exported as zeros.

Bind each scan destination to its column name instead, ignoring columns
the collector does not know, so a new PgBouncer column can no longer
shift the values of the others. `total_server_assignment_count` and
`avg_server_assignment_count` start being exported as a result, so add
them to the sample output in the documentation, and correct the help
text of the total, which described a duration rather than a count.

Also reset the two avg parse-count gauges, which were shadowed by their
total counterparts and kept stale values across scrapes.

Closes #11365

Signed-off-by: AdzerKI <silver_cat@list.ru>
Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Co-authored-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
(cherry picked from commit 590dccc)
litaocdl pushed a commit that referenced this pull request Sep 10, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13 destination
fallback, and the scan then fails on every row. It would not read as
missing data either: the error branch falls through to the gauge writes,
so each pool metric is published as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from one table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. #11366 does the same for `SHOW STATS`, where that
switch already broke on 1.24.

`load_balance_hosts` comes along. PgBouncer reports it as text holding
`disable` or `round-robin`, and null for a single-host pool, while the
scan expected an integer; the generated `[databases]` section never
configures more than one host, so nothing surfaces today. Encode it the
way `pool_mode` already is, correct its help text, which described a
count of hosts, and drop the scan error fixed in #6810 from the docs
sample.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
mnencia pushed a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13 destination
fallback, and the scan then fails on every row. It would not read as
missing data either: the error branch falls through to the gauge writes,
so each pool metric is published as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from one table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. #11366 does the same for `SHOW STATS`, where that
switch already broke on 1.24.

`load_balance_hosts` comes along. PgBouncer reports it as text holding
`disable` or `round-robin`, and null for a single-host pool, while the
scan expected an integer; the generated `[databases]` section never
configures more than one host, so nothing surfaces today. Encode it the
way `pool_mode` already is, correct its help text, which described a
count of hosts, and drop the scan error fixed in #6810 from the docs
sample.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
mnencia added a commit that referenced this pull request Sep 14, 2026
Same gap as the SHOW POOLS collector: a column PgBouncer renames
falls through the by-name bind with no log line. #11366 added
the by-name bind for SHOW STATS; this closes the gap it shares
with SHOW POOLS.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
mnencia pushed a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13 destination
fallback, and the scan then fails on every row. It would not read as
missing data either: the error branch falls through to the gauge writes,
so each pool metric is published as a genuine zero under empty `database`
and `user` labels.

Bind each column to its gauge by name instead, from one table that
`Describe`, `Reset`, `Collect` and the scan derive from, and skip the row
when the scan fails. #11366 does the same for `SHOW STATS`, where that
switch already broke on 1.24.

`load_balance_hosts` comes along. PgBouncer reports it as text holding
`disable` or `round-robin`, and null for a single-host pool, while the
scan expected an integer; the generated `[databases]` section never
configures more than one host, so nothing surfaces today. Encode it the
way `pool_mode` already is, correct its help text, which described a
count of hosts, and drop the scan error fixed in #6810 from the docs
sample.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
mnencia added a commit that referenced this pull request Sep 14, 2026
Same gap as the SHOW POOLS collector: a column PgBouncer renames
falls through the by-name bind with no log line. #11366 added
the by-name bind for SHOW STATS; this closes the gap it shares
with SHOW POOLS.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
mnencia added a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13-destination
fallback, and the scan fails on every row. The error branch falls
through to the gauge writes anyway, so each pool metric ends up
published as zero, under empty `database` and `user` labels.

Bind each column to its gauge by name instead. One table now drives
`Describe`, `Reset`, `Collect`, and the scan, and a row is skipped when
its scan fails. #11366 does the same for `SHOW STATS`, where this
already broke on 1.24. This PR doesn't depend on it.

`load_balance_hosts` also needed a fix. PgBouncer reports it as text:
`disable` or `round-robin`, and null for a single-host pool. The scan
expected an integer instead. CNPG's generated `[databases]` section
never configures more than one host, so this never showed up in
practice. It's now encoded the same way `pool_mode` already is. The help
text no longer describes a host count, and the docs sample drops the
scan error that #6810 fixed.

A column PgBouncer renames instead of adds still disappears silently
under the by-name bind. Log it as a warning, here and in the
already-merged `SHOW STATS` collector from #11366, so a rename shows up
in the logs instead of just vanishing. A new test also checks that one
pool's row failing to scan doesn't blank out the pools that scan fine
right after it.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
cnpg-bot pushed a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13-destination
fallback, and the scan fails on every row. The error branch falls
through to the gauge writes anyway, so each pool metric ends up
published as zero, under empty `database` and `user` labels.

Bind each column to its gauge by name instead. One table now drives
`Describe`, `Reset`, `Collect`, and the scan, and a row is skipped when
its scan fails. #11366 does the same for `SHOW STATS`, where this
already broke on 1.24. This PR doesn't depend on it.

`load_balance_hosts` also needed a fix. PgBouncer reports it as text:
`disable` or `round-robin`, and null for a single-host pool. The scan
expected an integer instead. CNPG's generated `[databases]` section
never configures more than one host, so this never showed up in
practice. It's now encoded the same way `pool_mode` already is. The help
text no longer describes a host count, and the docs sample drops the
scan error that #6810 fixed.

A column PgBouncer renames instead of adds still disappears silently
under the by-name bind. Log it as a warning, here and in the
already-merged `SHOW STATS` collector from #11366, so a rename shows up
in the logs instead of just vanishing. A new test also checks that one
pool's row failing to scan doesn't blank out the pools that scan fine
right after it.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
(cherry picked from commit d2c5ccd)
cnpg-bot pushed a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13-destination
fallback, and the scan fails on every row. The error branch falls
through to the gauge writes anyway, so each pool metric ends up
published as zero, under empty `database` and `user` labels.

Bind each column to its gauge by name instead. One table now drives
`Describe`, `Reset`, `Collect`, and the scan, and a row is skipped when
its scan fails. #11366 does the same for `SHOW STATS`, where this
already broke on 1.24. This PR doesn't depend on it.

`load_balance_hosts` also needed a fix. PgBouncer reports it as text:
`disable` or `round-robin`, and null for a single-host pool. The scan
expected an integer instead. CNPG's generated `[databases]` section
never configures more than one host, so this never showed up in
practice. It's now encoded the same way `pool_mode` already is. The help
text no longer describes a host count, and the docs sample drops the
scan error that #6810 fixed.

A column PgBouncer renames instead of adds still disappears silently
under the by-name bind. Log it as a warning, here and in the
already-merged `SHOW STATS` collector from #11366, so a rename shows up
in the logs instead of just vanishing. A new test also checks that one
pool's row failing to scan doesn't blank out the pools that scan fine
right after it.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
(cherry picked from commit d2c5ccd)
cnpg-bot pushed a commit that referenced this pull request Sep 14, 2026
`collectShowPools` picks its scan layout from the number of columns
`SHOW POOLS` returns. Every layout PgBouncer reports today is covered,
but the next release that adds a column falls into the 13-destination
fallback, and the scan fails on every row. The error branch falls
through to the gauge writes anyway, so each pool metric ends up
published as zero, under empty `database` and `user` labels.

Bind each column to its gauge by name instead. One table now drives
`Describe`, `Reset`, `Collect`, and the scan, and a row is skipped when
its scan fails. #11366 does the same for `SHOW STATS`, where this
already broke on 1.24. This PR doesn't depend on it.

`load_balance_hosts` also needed a fix. PgBouncer reports it as text:
`disable` or `round-robin`, and null for a single-host pool. The scan
expected an integer instead. CNPG's generated `[databases]` section
never configures more than one host, so this never showed up in
practice. It's now encoded the same way `pool_mode` already is. The help
text no longer describes a host count, and the docs sample drops the
scan error that #6810 fixed.

A column PgBouncer renames instead of adds still disappears silently
under the by-name bind. Log it as a warning, here and in the
already-merged `SHOW STATS` collector from #11366, so a rename shows up
in the logs instead of just vanishing. A new test also checks that one
pool's row failing to scan doesn't blank out the pools that scan fine
right after it.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
(cherry picked from commit d2c5ccd)
renovate Bot added a commit to sdwilsh/ansible-playbooks that referenced this pull request Sep 24, 2026
##### [\`v1.30.1\`](https://github.com/cloudnative-pg/cloudnative-pg/releases/tag/v1.30.1)

**Release date:** Sep 23, 2026

##### Enhancements

- Added `restoreAdditionalCommandArgs` to `.barmanObjectStore.data` for in-tree Barman Cloud recoveries, so custom flags are forwarded to `barman-cloud-restore` during recovery. ([#11278](cloudnative-pg/cloudnative-pg#11278)) <!-- 1.29 1.28 -->

- Plugin authors no longer need to re-derive whether an empty WAL archive should be treated as an error: the operator now computes the `check_empty_wal_archive` decision once and passes it to CNPG-I plugins on both WAL archiving and restore hooks. ([#11216](cloudnative-pg/cloudnative-pg#11216)) <!-- 1.29 1.28 -->

- Allowed setting the `ssl_ecdh_curve` PostgreSQL parameter in `.spec.postgresql.parameters`. It was previously rejected by the validating webhook even though the operator does not manage it. Contributed by [@Jamstah](https://github.com/Jamstah). ([#11308](cloudnative-pg/cloudnative-pg#11308)) <!-- 1.29 1.28 -->

- Added support for setting `auth_user` in `spec.pgbouncer.parameters` to override the user PgBouncer uses for its `auth_query` connection, instead of always deriving it from the `authQuerySecret`. Useful with a custom `authQuerySecret` where the role to authenticate as differs from the one implied by the Secret. Contributed by [@jonasbadstuebner](https://github.com/jonasbadstuebner). ([#10899](cloudnative-pg/cloudnative-pg#10899)) <!-- 1.29 1.28 -->

- Fixed PgBouncer metrics silently reporting zero when PgBouncer adds or reorders columns: `SHOW STATS` and `SHOW POOLS` results are now matched by column name instead of by position. Contributed by [@AdzerKI](https://github.com/AdzerKI) (`SHOW STATS`). ([#11366](cloudnative-pg/cloudnative-pg#11366), [#11464](cloudnative-pg/cloudnative-pg#11464)) <!-- 1.29 1.28 -->

- `cnpg` plugin:

  - Added a `--dry-run` option to the `backup` command that prints the `Backup` resource that would be created, without creating it. ([#11233](cloudnative-pg/cloudnative-pg#11233)) <!-- 1.29 1.28 -->

##### Security and Supply Chain

- Fixed a webhook validation bypass where an absolute extension path with an embedded `..` traversal (e.g. `/a/../../../../etc`) was accepted because only the raw path was checked; such paths still escaped the extension's mount point once resolved at runtime. Affected entries are now resolved and rejected/skipped consistently across admission, the major-upgrade job, and already-persisted Cluster specs. Contributed by [@Anand-240](https://github.com/Anand-240). ([#11210](cloudnative-pg/cloudnative-pg#11210)) <!-- 1.29 1.28 -->

- Updated `google.golang.org/grpc` to v1.83.1, fixing [CVE-2026-84304](https://nvd.nist.gov/vuln/detail/CVE-2026-84304) / GHSA-vp52-pcj8-j9qc (gRPC-Go heap memory exhaustion via HTTP/2 DATA frame fragmentation). ([#11394](cloudnative-pg/cloudnative-pg#11394)) <!-- 1.29 1.28 -->

##### Changes

- Updated the default PostgreSQL operand image to 18.6-system-trixie. ([#11257](cloudnative-pg/cloudnative-pg#11257)) <!-- 1.29 1.28 -->

- Moved the operator's own base image from Debian 12 (bookworm) to Debian 13 (trixie), now that Debian 12 has moved to LTS-only maintenance. ([#11193](cloudnative-pg/cloudnative-pg#11193)) <!-- 1.29 1.28 -->

##### Fixes

- Demoted an unreachable old primary immediately during failover, instead of waiting on checkpoint and fast-shutdown attempts that could never complete. Previously, an old primary whose PostgreSQL had become unresponsive was never shut down, so it could never rejoin the cluster as a replica of the new primary. The shutdown is now requested without blocking the reconciler, though demotion can still take up to a minute or more if PostgreSQL keeps ignoring shutdown signals. ([#11347](cloudnative-pg/cloudnative-pg#11347)) <!-- 1.29 1.28 -->

- Fixed failover and Pod recreation getting stuck while any instance in the cluster was fenced. A fenced instance kept reporting itself as healthy on its status endpoint even though its Pod was permanently not Ready, which blocked the readiness guard, the primary-election logic, and the Pod-reattachment gate from reacting to an unrelated failure elsewhere in the cluster, leaving it stalled until someone manually removed the fencing. All three now recognize and skip fenced instances. ([#11274](cloudnative-pg/cloudnative-pg#11274)) <!-- 1.29 1.28 -->

- Fixed a failover that could stall forever or get silently reverted. While a failover was pending, the reconciler could skip checking whether it was ready to complete, or mistake the pending state for a missing Pod and reset the target primary back to the unhealthy one. It now keeps progressing a pending failover and completes it once the WAL receivers are down, rechecking quorum safety right before promoting in case it changed while waiting. ([#11336](cloudnative-pg/cloudnative-pg#11336)) <!-- 1.29 1.28 -->

- Fixed the designated-primary sort in `PostgresqlStatusList` so a tie on LSN no longer sorts it out of order. If the designated primary's Pod later disappeared from the status list, this could have led the operator to promote the wrong standby. ([#11494](cloudnative-pg/cloudnative-pg#11494)) <!-- 1.29 1.28 -->

- Gated PostgreSQL startup on the instance manager actually holding the primary `Lease`, closing a window where a restarting or rescheduled primary could start accepting writes before acquiring the lease. Lease acquisition now happens during instance initialization, strictly before PostgreSQL is allowed to start, instead of only later in the reconciliation loop once the instance was already reported ready. ([#11356](cloudnative-pg/cloudnative-pg#11356))

- Bounded the primary lease take-over `Get` call to the lease's `RenewDeadline`, so a call against an unreachable API server now fails fast and retries instead of blocking indefinitely. Left unbounded, the same stalled call could also delay a primary's own lease renewal after a transient API server blip, risking an unwanted takeover by another instance once the lease appeared to expire. ([#11350](cloudnative-pg/cloudnative-pg#11350))

- Stopped abandoning a fast shutdown after 60 seconds. The request carried no explicit timeout, so `pg_ctl` fell back to its own implicit 60-second limit, and the instance manager, being PID 1 in the container, took PostgreSQL down mid-shutdown regardless of a larger configured `stopDelay`. The fast phase now waits for the full `stopDelay` instead. ([#11263](cloudnative-pg/cloudnative-pg#11263)) <!-- 1.29 1.28 -->

- Waited for certificate status before refreshing secrets during bootstrap. ([#11450](cloudnative-pg/cloudnative-pg#11450)) <!-- 1.29 1.28 -->

- Fixed in-tree Barman Cloud recovery ignoring `wal.maxParallel` and `wal.restoreAdditionalCommandArgs`, fetching WAL one segment at a time instead of using the configured parallelism. ([#11105](cloudnative-pg/cloudnative-pg#11105)) <!-- 1.29 1.28 -->

- Honored the `unrecoverable` annotation on pending and terminating instances. ([#11241](cloudnative-pg/cloudnative-pg#11241)) <!-- 1.29 1.28 -->

- Honored `Backup.spec.online` when finalizing VolumeSnapshot-based backups, so a cold backup is no longer reported as online in status. ([#11276](cloudnative-pg/cloudnative-pg#11276)) <!-- 1.29 1.28 -->

- Set `--no-data-checksums` explicitly when `.spec.postgresql.dataChecksums` is `false` on PostgreSQL 18+, which now enables checksums by default in `initdb`. Contributed by [@evan314159](https://github.com/evan314159). ([#11488](cloudnative-pg/cloudnative-pg#11488)) <!-- 1.29 1.28 -->

- Stopped discarding `.spec.inheritedMetadata` labels on PVC reconciliation; they were applied before, and then overwritten by, the operator's own labels. Contributed by [@GellertBabel](https://github.com/GellertBabel). ([#11499](cloudnative-pg/cloudnative-pg#11499)) <!-- 1.29 1.28 -->

- Stopped `Pooler` and `DatabaseRole` from recreating their owned resources after being marked for deletion, which could block an external finalizer (e.g. ArgoCD foreground deletion) waiting for those resources to disappear. Contributed by [@mjlshen](https://github.com/mjlshen). ([#11359](cloudnative-pg/cloudnative-pg#11359)) <!-- 1.29 1.28 -->

- Handled a `NULL` `stats_reset` value in the `pg_stat_wal` metric, which could occasionally break Prometheus scraping on PostgreSQL 18 clusters. Contributed by [@HoniSanders](https://github.com/HoniSanders). ([#11207](cloudnative-pg/cloudnative-pg#11207)) <!-- 1.29 1.28 -->

- Recovered log streaming when a stale non-FIFO file blocked the log pipe. ([#11246](cloudnative-pg/cloudnative-pg#11246)) <!-- 1.29 1.28 -->

- Stopped sampling logs of the Pods' processes, so no log lines are silently dropped. ([#11131](cloudnative-pg/cloudnative-pg#11131)) <!-- 1.29 1.28 -->

- Stopped caching Helm release Secrets in the operator, which could spike memory usage and crashloop the operator on clusters with large Helm releases installed alongside it. ([#11211](cloudnative-pg/cloudnative-pg#11211)) <!-- 1.29 1.28 -->

- Re-ran owned-resource finalizer cleanup after an operator restart, so a namespace deleted while the operator was down doesn't hang in `Terminating` forever. ([#11215](cloudnative-pg/cloudnative-pg#11215)) <!-- 1.29 1.28 -->

- Fixed rejoining replicas taking a long time to complete `pg_rewind` when WAL prefetching (`wal.maxParallel > 1`) was enabled. ([#11204](cloudnative-pg/cloudnative-pg#11204)) <!-- 1.29 1.28 -->

- Treated a PostgreSQL instance rejecting connections as started up in probes. ([#11152](cloudnative-pg/cloudnative-pg#11152)) <!-- 1.29 1.28 -->

- Stopped issuing a redundant PATCH on every reconciliation when a cluster's `pvcTemplate` set `volumeAttributesClass`. Contributed by [@andrew-farries](https://github.com/andrew-farries). ([#11196](cloudnative-pg/cloudnative-pg#11196)) <!-- 1.29 1.28 -->

- Stopped halting replication slot reconciliation at the first failing slot. ([#11119](cloudnative-pg/cloudnative-pg#11119)) <!-- 1.29 1.28 -->

- During rollouts, compared the running configuration hash, rather than the on-disk one, avoiding unnecessary switchovers. ([#11130](cloudnative-pg/cloudnative-pg#11130)) <!-- 1.29 1.28 -->

- Retried `VolumeSnapshot` errors until the deadline, instead of giving up early. ([#11132](cloudnative-pg/cloudnative-pg#11132)) <!-- 1.29 1.28 -->

- Symlinked `pg_wal` to the WAL volume during plugin-based recovery, instead of replaying WAL onto the data volume, which could exhaust it on a large point-in-time recovery. ([#11127](cloudnative-pg/cloudnative-pg#11127)) <!-- 1.29 1.28 -->

- Corrected grammar in `PhaseUpgradeDelayed` status messages. Contributed by [@Utkarsh-sharma47](https://github.com/Utkarsh-sharma47). ([#11065](cloudnative-pg/cloudnative-pg#11065)) <!-- 1.29 1.28 -->

- CloudNativePG Interface (CNPG-I):

  - Reported the Postgres capabilities of a plugin correctly. ([#11447](cloudnative-pg/cloudnative-pg#11447)) <!-- 1.29 1.28 -->
  - Prevented the plugin status field from flapping on Cluster reconciliation. Contributed by [@sharifmshaker](https://github.com/sharifmshaker). ([#11386](cloudnative-pg/cloudnative-pg#11386)) <!-- 1.29 1.28 -->
  - Replaced a finalizer with in-memory cleanup on Service deletion. This avoids namespaces hanging in `Terminating` state when the operator and its plugins run in the same namespace. Contributed by [@maxlengdell](https://github.com/maxlengdell). ([#10940](cloudnative-pg/cloudnative-pg#10940)) <!-- 1.29 -->

- `cnpg` plugin:

  - Used UTC time zone for the default backup name. ([#11329](cloudnative-pg/cloudnative-pg#11329)) <!-- 1.29 1.28 -->
  - Deleted PVCs before Pods in `cnpg destroy`, avoiding a race that could leave dangling PVCs needing a second invocation to clean up. Contributed by [@daanvinken](https://github.com/daanvinken). ([#10847](cloudnative-pg/cloudnative-pg#10847)) <!-- 1.29 1.28 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-requested ◀️ This pull request should be backported to all supported releases bug 🐛 Something isn't working ok to merge 👌 This PR can be merged release-1.28 release-1.30 size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: pooler stats metrics disappear when PgBouncer adds a SHOW STATS column

4 participants