Skip to content

feat: add label selector to the Cluster scale subresource - #8996

Merged
gbartolini merged 10 commits into
cloudnative-pg:mainfrom
sebv004:feat/add-vpa-support
Jun 4, 2026
Merged

gbartolini merged 10 commits into
cloudnative-pg:mainfrom
sebv004:feat/add-vpa-support

Conversation

@sebv004

@sebv004 sebv004 commented Oct 29, 2025 •

Copy link
Copy Markdown
Contributor

Add VPA Support for CloudNativePG Clusters

Summary

This PR enables Vertical Pod Autoscaler (VPA) to discover and monitor CloudNativePG database pods by exposing the pod label selector through the Cluster CRD's scale subresource.

Problem Statement

Currently, VPA cannot provide resource recommendations for CNPG Cluster resources. When attempting to create a VPA targeting a CNPG Cluster, the VPA fails with the following errors:

status:
  conditions:
  - type: ConfigUnsupported
    status: "True"
    message: "Cannot read targetRef. Reason: Unhandled targetRef postgresql.cnpg.io/v1 / Cluster / <name>, 
              last error Resource has an empty selector for scale sub-resource"
  - type: NoPodsMatched
    status: "True"
  - type: RecommendationProvided
    status: "False"

The root cause is that the Cluster CRD's scale subresource does not expose a pod selector, which VPA requires to discover which pods are managed by the resource.

Solution

This PR implements VPA support by:

  1. Adding SelectorLabels field to ClusterStatus to store the pod label selector
  2. Populating the selector in the cluster controller with the labels that CNPG already applies to pods:
    cnpg.io/cluster=<cluster-name>,cnpg.io/podRole=instance
    
  3. Exposing the selector through the scale subresource by adding labelSelectorPath: .status.selectorLabels

Changes Made

1. API Changes (api/v1/cluster_types.go)

  • Added SelectorLabels string field to ClusterStatus struct
  • Updated kubebuilder marker to include selectorpath=.status.selectorLabels in the scale subresource configuration

2. Controller Changes (internal/controller/cluster_status.go)

  • Modified updateResourceStatus() to populate cluster.Status.SelectorLabels during reconciliation
  • Selector format: "cnpg.io/cluster=<name>,cnpg.io/podRole=instance"

3. CRD Changes (config/crd/bases/postgresql.cnpg.io_clusters.yaml)

  • Added labelSelectorPath: .status.selectorLabels to the scale subresource
  • Added selectorLabels field definition to the status schema

Testing

Comprehensive testing was performed in a KIND cluster with VPA installed:

Before Fix (Unpatched CNPG 1.27.1)

Scale subresource response:

{
  "status": {
    "replicas": 1
    // No "selector" field
  }
}

VPA Status:

  • ❌ ConfigUnsupported: True
  • ❌ NoPodsMatched: True
  • ❌ RecommendationProvided: False
  • ❌ No recommendations

After Fix (Patched CNPG)

Scale subresource response:

{
  "status": {
    "replicas": 1,
    "selector": "cnpg.io/cluster=test-database,cnpg.io/podRole=instance"
  }
}

VPA Status:

  • ✅ RecommendationProvided: True
  • ✅ No errors
  • ✅ Actual CPU and memory recommendations provided

VPA Recommender logs confirm successful pod discovery:

I1029 14:49:55.115536 cluster_feeder.go:432] "Using selector" 
  selector="cnpg.io/cluster=test-database,cnpg.io/podRole=instance" 
  vpa="test-db/test-database-vpa"
I1029 14:49:55.124309 checkpoint_writer.go:114] "Saved checkpoint for VPA" 
  vpa="test-db/test-database-vpa" container="postgres"

Backward Compatibility

This change is fully backward compatible:

  • Only adds new fields, does not modify existing behavior
  • The selector labels match the existing labels CNPG already applies to database pods
  • Clusters created before this change will have their selectorLabels populated on next reconciliation
  • No migration or manual intervention required

Use Case

Users can now create VPAs for CNPG database clusters to get automatic resource recommendations:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-database-vpa
  namespace: default
spec:
  targetRef:
    apiVersion: postgresql.cnpg.io/v1
    kind: Cluster
    name: my-database
  updatePolicy:
    updateMode: "Off"

VPA will now successfully discover the database pods and provide recommendations for CPU and memory sizing.

Benefits

  1. Automatic Resource Optimization: Users can leverage VPA to right-size their database resources
  2. Cost Efficiency: Better resource allocation based on actual usage patterns
  3. Operational Excellence: Reduces manual effort in capacity planning
  4. Standard Kubernetes Integration: Works with existing VPA deployments

Related Issues

This addresses the long-standing limitation where VPA could not be used with CNPG Cluster resources, requiring users to either:

  • Manually monitor and adjust resources
  • Create workarounds with custom label selectors
  • Use VPA with StatefulSets directly (bypassing the Cluster abstraction)

Checklist

  • Changes are backward compatible
  • API changes include proper documentation comments
  • CRD manifests regenerated with make manifests
  • Deepcopy code regenerated with make generate
  • Tested in a real Kubernetes cluster with VPA
  • No changes to existing functionality
  • Labels used match existing CNPG pod labels

Additional Notes

The implementation uses the existing labels that CNPG applies to all database pods:

  • cnpg.io/cluster: identifies which cluster the pod belongs to
  • cnpg.io/podRole: set to "instance" for database pods

This ensures consistency with CNPG's existing labelling scheme and makes the selector reliable for pod discovery.

Commit message

The Cluster scale subresource exposed spec.instances and status.instances but no selector. Standard Kubernetes tooling expects the scale subresource to publish a label selector identifying the pods it counts; without one, autoscalers cannot map a Cluster to its instance pods.

Populate a status.selector field and wire it into the scale subresource:

  • Add the status.selector field, set it from updateResourceStatus via the new Cluster.GetInstancesSelector(), which returns the canonical serialised selector (cluster=<name>,role=instance) built with labels.SelectorFromSet.
  • Add selectorpath=.status.selector to the +kubebuilder:subresource:scale marker and regenerate the CRD and API docs.

This makes a Cluster a valid targetRef for the Vertical Pod Autoscaler (VPA), which can now observe the instance pods and emit CPU/memory recommendations, and lets a HorizontalPodAutoscaler (HPA) scale spec.instances.

Document recommended VPA usage (recommendation-only updateMode: Off, with a warning against Auto/Recreate/Initial to avoid ping-pong restarts against the operator's drift reconciliation) and HPA caveats for a stateful database. Add a unit test that verifies the selector format and that it matches the labels applied to every instance pod.

Closes #2574

@sebv004
sebv004 requested a review from a team October 29, 2025 15:08
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Oct 29, 2025
@cnpg-bot cnpg-bot added backport-requested ◀️ This pull request should be backported to all supported releases release-1.25 labels Oct 29, 2025
@github-actions

Copy link
Copy Markdown
Contributor

❗ By default, the pull request is configured to backport to all release branches.

  • To stop backporting this pr, remove the label: backport-requested ◀️ or add the label 'do not backport'
  • To stop backporting this pr to a certain release branch, remove the specific branch label: release-x.y

@dosubot dosubot Bot added enhancement 🪄 New feature or request ok to merge 👌 This PR can be merged labels Oct 29, 2025
@sebv004
sebv004 force-pushed the feat/add-vpa-support branch from b821e17 to 16a759a Compare October 30, 2025 08:12
@sebv004 sebv004 changed the title feat: Add VPA support by exposing label selector in scale subresource fix: Enable VPA support by exposing label selector in scale subresource Oct 30, 2025
@sebv004

sebv004 commented Oct 30, 2025

Copy link
Copy Markdown
Contributor Author

Changed from feat: to fix: because this addresses incomplete implementation of the scale subresource. The scale subresource existed but was missing the labelSelectorPath required for proper Kubernetes interoperability with standard tooling like VPA. This is fixing compatibility with standard K8s components rather than adding entirely new functionality.

@sebv004
sebv004 force-pushed the feat/add-vpa-support branch 2 times, most recently from 4469f64 to d7b495f Compare October 30, 2025 11:58
@slocke716

Copy link
Copy Markdown

Is there traction on getting this reviewed? I would absolutely love this!

@slocke716

Copy link
Copy Markdown

Changed from feat: to fix: because this addresses incomplete implementation of the scale subresource. The scale subresource existed but was missing the labelSelectorPath required for proper Kubernetes interoperability with standard tooling like VPA. This is fixing compatibility with standard K8s components rather than adding entirely new functionality.

Hi @sebv004 , would this move along faster if you explicitly added a maintainer as a reviewer?

@sebv004

sebv004 commented Dec 3, 2025

Copy link
Copy Markdown
Contributor Author

Changed from feat: to fix: because this addresses incomplete implementation of the scale subresource. The scale subresource existed but was missing the labelSelectorPath required for proper Kubernetes interoperability with standard tooling like VPA. This is fixing compatibility with standard K8s components rather than adding entirely new functionality.

Hi @sebv004 , would this move along faster if you explicitly added a maintainer as a reviewer?

Hi, I'm not allowed to assign myself a reviewer.
I'm sorry I'm no more focused on this, I let it open, I hope it will be merged ...

@sdesbure

sdesbure commented Dec 5, 2025

Copy link
Copy Markdown

I don't know how to help but for me it would be interesting (mainly to have "recommended" values for requests and limits)

@JohnRMacGowan

JohnRMacGowan commented Jan 28, 2026 •

Copy link
Copy Markdown

I see this was tagged for release 1.28 @mnencia , but doesn't look like it made it in. Any updates by chance on eta for this? Very excited feature that would be super helpful.

@rittikdasgupta

Copy link
Copy Markdown

Any updates on the ETA for this release? We're actively waiting on VPA support for CNPG as it's a key dependency for our scaling efforts.

@JohnRMacGowan

Copy link
Copy Markdown

@mnencia I am sure your busy, if there is anything that can be done to help move this along please let us know as would love to see this soon.

@lukasgabriel

Copy link
Copy Markdown

This would be extremely valuable to have! I would be happy to help with remaining testing if it means that this can be added soon.

@armru
armru force-pushed the feat/add-vpa-support branch from 5a7bcef to 6c09445 Compare May 28, 2026 09:08
@armru
armru requested a review from jsilvela as a code owner May 28, 2026 09:08
@dosubot dosubot Bot removed the size:S This PR changes 10-29 lines, ignoring generated files. label May 28, 2026
@gbartolini

Copy link
Copy Markdown
Contributor

Apologies, I had wrongly assigned the pooler's counterpart issue to this PR. Fixed it now with #2574

@gbartolini gbartolini removed this from the 1.30.0 milestone Jun 4, 2026
@gbartolini

Copy link
Copy Markdown
Contributor

This can be backported too IMO.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jun 4, 2026
sebv004 and others added 9 commits June 4, 2026 11:25
This fixes compatibility with Vertical Pod Autoscaler (VPA) by properly
implementing the scale subresource selector field, which is required for
VPA to discover and monitor CloudNativePG database pods.

Problem:
VPA was unable to provide resource recommendations for CNPG Cluster resources
because the scale subresource did not expose a pod selector. VPA requires this
selector to discover which pods are managed by a resource, resulting in:
- ConfigUnsupported: True
- NoPodsMatched: True
- RecommendationProvided: False

Root Cause:
The scale subresource was implemented but incomplete - it was missing the
labelSelectorPath configuration required for proper Kubernetes interoperability.

Solution:
1. Added SelectorLabels field to ClusterStatus to store the pod label selector
2. Modified cluster controller to populate this field with pod labels:
   "cnpg.io/cluster=<name>,cnpg.io/podRole=instance"
3. Updated CRD scale subresource configuration to expose the selector via
   labelSelectorPath pointing to .status.selectorLabels

Implementation:
- API: Added SelectorLabels string field to ClusterStatus struct
- Controller: Populates selectorLabels during cluster status reconciliation
- CRD: Added labelSelectorPath to scale subresource configuration

Testing:
Validated with VPA in a KIND cluster. After the fix:
- Scale subresource correctly exposes:
  status.selector="cnpg.io/cluster=<name>,cnpg.io/podRole=instance"
- VPA successfully discovers database pods
- VPA provides resource recommendations (CPU/memory)
- RecommendationProvided: True with actual recommendations

This change is backward compatible as it only adds new fields and does not
modify existing behavior. The selector labels match the existing labels that
CNPG already applies to database pods.

Fixes: VPA compatibility with CNPG Cluster resources
Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Sebastien Villanueva <[email protected]>
Add a contract assertion that the scale-subresource selector format
(cnpg.io/cluster=<name>,cnpg.io/podRole=instance) parses as a valid
Kubernetes label selector and matches the labels that the operator
applies to instance pods. This locks in the contract that VPA/HPA
rely on for pod discovery.

Signed-off-by: Armando Ruocco <[email protected]>
Build on the VPA support work with naming and idiom cleanups:

- Rename ClusterStatus.SelectorLabels to Selector. Kubernetes scalable
  types (ScaleStatus.Selector) use "selector" for the serialized label
  selector; matching the convention now avoids a deprecation cycle
  later.
- Build the serialized selector with labels.SelectorFromSet instead of
  hand-rolled fmt.Sprintf. The helper sorts requirements by key, so
  the output stays deterministic.
- Regenerate the Cluster CRD and the API reference documentation and
  refresh the spellcheck wordlist accordingly.

Signed-off-by: Armando Ruocco <[email protected]>
Add a Vertical Pod Autoscaler section to the resource-management page
explaining that a Cluster is now a valid VPA targetRef, recommending
the recommendation-only updateMode, and warning that actively mutating
modes (Auto, Recreate, Initial) fight CloudNativePG's pod-spec drift
detection. Include a brief HPA caveat for completeness.

Signed-off-by: Armando Ruocco <[email protected]>
The unit test for the scale-subresource selector re-derived the expected
selector string with fmt.Sprintf and only checked it against pod labels.
It never invoked the operator's selector-building code, so deleting or
breaking that code would have left the test green.

Extract the selector construction into Cluster.GetInstancesSelector()
(mirroring the adjacent GetServiceReadName/GetServiceReadWriteName helpers
that updateResourceStatus already uses) and assert the test against that
production method. A mutation that changes the selected labels now fails
the test, which previously passed.

Signed-off-by: Armando Ruocco <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
The committed VPA warning described active update modes as causing
ping-pong restarts, with the operator detecting drift from a VPA-mutated
pod and re-creating it. CloudNativePG does not behave that way: drift
detection compares the stored pod-spec annotation against a target
rebuilt from spec.resources and never reads a pod's live resources, so
an active VPA mode silently diverges the running pod from spec.resources
instead of triggering a rollout.

Reword the warning around that divergence: a shared_buffers value sized
against the declared memory request stops matching the pod's real
limits, and the default primary PodDisruptionBudget blocks eviction of
the primary so VPA stalls. Also scope the HPA webhook-floor caveat to
synchronous replicas, fix the VPA documentation link, and point
per-container recommendations at the postgres container.

Assisted-by: Claude
Signed-off-by: Marco Nenciarini <[email protected]>
@mnencia
mnencia force-pushed the feat/add-vpa-support branch from a7baa04 to 3316393 Compare June 4, 2026 09:25
The kubernetes/autoscaler repository still uses master as its default
branch, so the VPA documentation link tripped the woke check. Add the
same wokeignore comment the cluster-autoscaler link in scheduling.md
already uses.

Assisted-by: Claude
Signed-off-by: Marco Nenciarini <[email protected]>
@gbartolini
gbartolini merged commit 946085b into cloudnative-pg:main Jun 4, 2026
35 checks passed
cnpg-bot pushed a commit that referenced this pull request Jun 4, 2026
The `Cluster` scale subresource exposed `spec.instances` and
`status.instances` but no selector. Standard Kubernetes tooling expects
the scale subresource to publish a label selector identifying the pods
it counts; without one, autoscalers cannot map a `Cluster` to its
instance pods.

Populate a `status.selector` field and wire it into the scale
subresource:

- Add the `status.selector` field, set it from `updateResourceStatus`
via the new `Cluster.GetInstancesSelector()`, which returns the
canonical serialised selector (`cluster=<name>,role=instance`) built
with `labels.SelectorFromSet`.
- Add `selectorpath=.status.selector` to the
`+kubebuilder:subresource:scale` marker and regenerate the CRD and API
docs.

This makes a `Cluster` a valid `targetRef` for the Vertical Pod
Autoscaler (`VPA`), which can now observe the instance pods and emit
CPU/memory recommendations, and lets a `HorizontalPodAutoscaler` (`HPA`)
scale `spec.instances`.

Document recommended `VPA` usage (recommendation-only `updateMode: Off`,
with a warning against `Auto`/`Recreate`/`Initial` to avoid ping-pong
restarts against the operator's drift reconciliation) and `HPA` caveats
for a stateful database. Add a unit test that verifies the selector
format and that it matches the labels applied to every instance pod.

Closes #2574

Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Armando Ruocco <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
Signed-off-by: Marco Nenciarini <[email protected]>
Co-authored-by: Armando Ruocco <[email protected]>
Co-authored-by: Gabriele Bartolini <[email protected]>
Co-authored-by: Marco Nenciarini <[email protected]>
(cherry picked from commit 946085b)
cnpg-bot pushed a commit that referenced this pull request Jun 4, 2026
The `Cluster` scale subresource exposed `spec.instances` and
`status.instances` but no selector. Standard Kubernetes tooling expects
the scale subresource to publish a label selector identifying the pods
it counts; without one, autoscalers cannot map a `Cluster` to its
instance pods.

Populate a `status.selector` field and wire it into the scale
subresource:

- Add the `status.selector` field, set it from `updateResourceStatus`
via the new `Cluster.GetInstancesSelector()`, which returns the
canonical serialised selector (`cluster=<name>,role=instance`) built
with `labels.SelectorFromSet`.
- Add `selectorpath=.status.selector` to the
`+kubebuilder:subresource:scale` marker and regenerate the CRD and API
docs.

This makes a `Cluster` a valid `targetRef` for the Vertical Pod
Autoscaler (`VPA`), which can now observe the instance pods and emit
CPU/memory recommendations, and lets a `HorizontalPodAutoscaler` (`HPA`)
scale `spec.instances`.

Document recommended `VPA` usage (recommendation-only `updateMode: Off`,
with a warning against `Auto`/`Recreate`/`Initial` to avoid ping-pong
restarts against the operator's drift reconciliation) and `HPA` caveats
for a stateful database. Add a unit test that verifies the selector
format and that it matches the labels applied to every instance pod.

Closes #2574

Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Armando Ruocco <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
Signed-off-by: Marco Nenciarini <[email protected]>
Co-authored-by: Armando Ruocco <[email protected]>
Co-authored-by: Gabriele Bartolini <[email protected]>
Co-authored-by: Marco Nenciarini <[email protected]>
(cherry picked from commit 946085b)
cnpg-bot pushed a commit that referenced this pull request Jun 4, 2026
The `Cluster` scale subresource exposed `spec.instances` and
`status.instances` but no selector. Standard Kubernetes tooling expects
the scale subresource to publish a label selector identifying the pods
it counts; without one, autoscalers cannot map a `Cluster` to its
instance pods.

Populate a `status.selector` field and wire it into the scale
subresource:

- Add the `status.selector` field, set it from `updateResourceStatus`
via the new `Cluster.GetInstancesSelector()`, which returns the
canonical serialised selector (`cluster=<name>,role=instance`) built
with `labels.SelectorFromSet`.
- Add `selectorpath=.status.selector` to the
`+kubebuilder:subresource:scale` marker and regenerate the CRD and API
docs.

This makes a `Cluster` a valid `targetRef` for the Vertical Pod
Autoscaler (`VPA`), which can now observe the instance pods and emit
CPU/memory recommendations, and lets a `HorizontalPodAutoscaler` (`HPA`)
scale `spec.instances`.

Document recommended `VPA` usage (recommendation-only `updateMode: Off`,
with a warning against `Auto`/`Recreate`/`Initial` to avoid ping-pong
restarts against the operator's drift reconciliation) and `HPA` caveats
for a stateful database. Add a unit test that verifies the selector
format and that it matches the labels applied to every instance pod.

Closes #2574

Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Sebastien Villanueva <[email protected]>
Signed-off-by: Armando Ruocco <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
Signed-off-by: Marco Nenciarini <[email protected]>
Co-authored-by: Armando Ruocco <[email protected]>
Co-authored-by: Gabriele Bartolini <[email protected]>
Co-authored-by: Marco Nenciarini <[email protected]>
(cherry picked from commit 946085b)
@slocke716

Copy link
Copy Markdown

This is excellent! Thank you for implementing! Are there any gotchas that I should be concerned about using vpa on my clusters? I know this will not automatically update any postgres settings for instance but it seems like just increasing memory and cpu should suffice for most traffic surges

renovate Bot added a commit to sdwilsh/ansible-playbooks that referenced this pull request Jul 7, 2026
##### [\`v1.29.2\`](https://github.com/cloudnative-pg/cloudnative-pg/releases/tag/v1.29.2)

**Release date:** Jun 29, 2026

##### Important changes

- Updated the deprecation notice for native (in-tree) Barman Cloud support to reflect that it will now be removed in CloudNativePG 1.31.0, rather than 1.30.0. Users are still encouraged to migrate to the Barman Cloud Plugin. ([#11083](cloudnative-pg/cloudnative-pg#11083)) <!-- 1.29 1.28 -->

- The `cluster` reference is now immutable on the `Database`, `Pooler`, `Publication`, `Subscription`, and `ScheduledBackup` resources. Pointing one of these objects at a different cluster has no well-defined semantics and previously left the controllers in an inconsistent state; the update is now rejected at the API server via a CEL validation rule. ([#10743](cloudnative-pg/cloudnative-pg#10743)) <!-- 1.29 1.28 1.25 -->

##### Enhancements

- Enabled `pg_upgrade` in-place major upgrades to PostgreSQL 19 or later for clusters that use Image Volume extensions, building on the extension-path support added to `pg_upgrade` in PostgreSQL 19. During the upgrade `Job`, the source- and target-version extension images are mounted side by side, so the old server keeps its libraries and a failed upgrade reverts cleanly. ([#10366](cloudnative-pg/cloudnative-pg#10366)) <!-- 1.29 -->

- Added a label selector to the `Cluster` scale subresource (`status.selector`), making a `Cluster` a valid `targetRef` for the Vertical Pod Autoscaler (VPA) and Horizontal Pod Autoscaler (HPA), which can now map a `Cluster` to its instance pods. Contributed by [@sebv004](https://github.com/sebv004). ([#8996](cloudnative-pg/cloudnative-pg#8996)) <!-- 1.29 1.28 1.25 -->

- The operator now emits a `Warning` `PrimaryStatusCheckFailed` event on the `Cluster` when the primary pod is `Ready` from the kubelet perspective but the operator's `/pg/status` check fails and failover is deferred, giving users visibility into the deferral via `kubectl describe cluster`. ([#10509](cloudnative-pg/cloudnative-pg#10509)) <!-- 1.29 1.28 1.25 -->

- The operator now reloads a CNPG-i plugin automatically when its pods are rolled: it watches the `EndpointSlices` backing plugin `Services` and re-enqueues every cluster using the plugin once the new pods become `Ready`, so an upgraded plugin is picked up without waiting for the next resync. ([#10836](cloudnative-pg/cloudnative-pg#10836)) <!-- 1.29 1.28 1.25 -->

##### Security and Supply Chain

- **`CVE-2026-55769` / `GHSA-x8c2-3p4r-v9r6`: `search_path` pinning on operator-issued connections**: a database owner could plant overloaded built-in operators in the `public` schema and alter the `search_path` so that operator introspection probes, running as the cluster superuser, resolved those overloads before `pg_catalog`, a `CWE-426` privilege-escalation chain (same class as `CVE-2018-1058`) that could lead to in-pod RCE via `COPY ... FROM PROGRAM`. The operator now pins `search_path = pg_catalog, public, pg_temp` on every pooled connection so it ships in the startup message and takes precedence over tenant-controlled defaults. ([#10774](cloudnative-pg/cloudnative-pg#10774), [`GHSA-x8c2-3p4r-v9r6`](GHSA-x8c2-3p4r-v9r6)) <!-- 1.29 1.28 1.25 -->

- **`CVE-2026-55765` / `GHSA-w3gf-xc94-wvmj`: operator-side SCRAM-SHA-256 password encoding**: the operator now SCRAM-SHA-256 encodes cleartext role passwords before issuing `CREATE`/`ALTER ROLE ... PASSWORD`, so the literal PostgreSQL parses (and that extensions such as `pg_stat_statements` or `pgaudit` may capture) is the SCRAM verifier rather than the cleartext secret. Pre-hashed (MD5 or SCRAM) values are forwarded unchanged, and the per-Secret annotation `cnpg.io/passwordPassthrough: "enabled"` opts out. ([#10724](cloudnative-pg/cloudnative-pg#10724), [`GHSA-w3gf-xc94-wvmj`](GHSA-w3gf-xc94-wvmj)) <!-- 1.29 1.28 1.25 -->

##### Changes

- Added support for Kubernetes 1.36. ([#10900](cloudnative-pg/cloudnative-pg#10900)) <!-- 1.29 1.28 -->

- Updated the default PostgreSQL version to 18.4. ([#10719](cloudnative-pg/cloudnative-pg#10719)) <!-- 1.29 1.28 1.25 -->

- Updated the Kubernetes versions used to test the operator on public cloud providers. ([#10720](cloudnative-pg/cloudnative-pg#10720), <!-- 1.29 1.28 1.25 --> [#10563](cloudnative-pg/cloudnative-pg#10563), <!-- 1.29 1.28 1.25 --> [#11033](cloudnative-pg/cloudnative-pg#11033)) <!-- 1.29 1.28 1.25 -->

##### Fixes

- Fixed `spec.postgresql.parameters` accepting keys that are not valid PostgreSQL parameter names, which could inject arbitrary directives into `postgresql.conf`; key names are now validated by the webhook. ([#11029](cloudnative-pg/cloudnative-pg#11029)) <!-- 1.29 1.28 1.25 -->

- Fixed declarative `Database`, `Publication`, and `Subscription` objects reporting a stale primary-side status forever after their cluster was demoted to a replica; the controller now re-checks the replica condition and watches the `Cluster` so a demotion is detected promptly. ([#10871](cloudnative-pg/cloudnative-pg#10871)) <!-- 1.29 1.28 1.25 -->

- Fixed non-sequential pod names (for example `-1`, `-3`) caused by the instance serial counter being advanced before the corresponding `Job` and PVCs were created; the bump is now persisted only after those resources exist. ([#10491](cloudnative-pg/cloudnative-pg#10491)) <!-- 1.29 1.28 1.25 -->

- Fixed a switchover deadlock when a WAL-archiver plugin was enabled on an existing cluster: with `primaryUpdateMethod: switchover` the primary could not be rolled out because a clean demotion needs the archiver sidecar that is still missing. The operator now recreates the primary Pod in place so the sidecar is injected and archiving resumes. The check also covers plugins that inject the archiver as a native sidecar (an init container with `restartPolicy: Always`), such as the Barman Cloud plugin. ([#11032](cloudnative-pg/cloudnative-pg#11032), <!-- 1.29 1.28 1.25 --> [#11059](cloudnative-pg/cloudnative-pg#11059)) <!-- 1.29 1.28 1.25 -->

- Fixed a cluster staying in `Setting up primary` indefinitely when the instance-creation Job exhausted its backoff limit; the operator now detects the terminal Job failure and marks the cluster unrecoverable, naming the failed Job and pointing to its logs. ([#11035](cloudnative-pg/cloudnative-pg#11035)) <!-- 1.29 1.28 1.25 -->

- Fixed deletion of a `Database`, `Publication`, or `Subscription` getting stuck in `Terminating` on a replica cluster, where the replica gate ran before the finalizer reconciler and the finalizer was never released. On a replica the PostgreSQL object is left to the primary cluster. ([#10853](cloudnative-pg/cloudnative-pg#10853)) <!-- 1.29 1.28 1.25 -->

- Fixed a conflicting duplicate `Database` or `Subscription` with a `delete` reclaim policy dropping the PostgreSQL object owned by the surviving CR; the drop is now gated on a recorded reconciliation. ([#10870](cloudnative-pg/cloudnative-pg#10870)) <!-- 1.29 1.28 1.25 -->

- Fixed the `postgres` superuser being left locked out after superuser access was disabled and then re-enabled, because the cached secret version was not invalidated and the password was never re-applied. Diagnosed by [@mhartmann-jaconi](https://github.com/mhartmann-jaconi). ([#10834](cloudnative-pg/cloudnative-pg#10834)) <!-- 1.29 1.28 1.25 -->

- Fixed backups getting stuck in the `started` phase when the instance manager running them was restarted (for example by the in-place upgrade following an operator upgrade) before the backup reached `running`; the reconciliation is now rescheduled so the lost session is detected. ([#10859](cloudnative-pg/cloudnative-pg#10859)) <!-- 1.29 1.28 -->

- Fixed `exec`/`attach` streaming to negotiate WebSocket with a SPDY fallback, restoring compatibility both with Kubernetes versions that have removed SPDY and with platforms such as OpenShift that reject WebSocket exec upgrades. Contributed by [@bartscheers](https://github.com/bartscheers). ([#10876](cloudnative-pg/cloudnative-pg#10876), [#10933](cloudnative-pg/cloudnative-pg#10933)) <!-- 1.29 -->

- Fixed resource leaks when concurrent `Backup` objects raced: backups now run in strict creation-time order, so an already-executing backup is never preempted by a newer one and its replication slot and PostgreSQL session are no longer orphaned on the primary. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10747](cloudnative-pg/cloudnative-pg#10747)) <!-- 1.29 1.28 1.25 -->

- Fixed role reconciliation clearing the password on a PostgreSQL role when the referenced Secret could not be fetched; the role is now left untouched until the Secret becomes available, and per-action errors are aggregated for better visibility. ([#10053](cloudnative-pg/cloudnative-pg#10053)) <!-- 1.29 1.28 1.25 -->

- Fixed a bootstrap failure where a metrics-exporter setup error (commonly a duplicate-key race with the controller) rolled back `streaming_replica` creation and wedged replica joins. The metrics-exporter step now runs in a separate transaction. Contributed by [@BlaiseAntony](https://github.com/BlaiseAntony). ([#10749](cloudnative-pg/cloudnative-pg#10749)) <!-- 1.29 1.28 1.25 -->

- Fixed a `ScheduledBackup` controller loop that occurred when a `Backup` was created but its status patch never landed; the controller now adopts an existing `Backup` for the next iteration instead of looping on `AlreadyExists`. ([#10612](cloudnative-pg/cloudnative-pg#10612)) <!-- 1.29 1.28 1.25 -->

- Fixed a nil-pointer panic when reconciling a `Pooler` whose `Cluster` has been deleted. ([#10667](cloudnative-pg/cloudnative-pg#10667)) <!-- 1.29 1.28 -->

- Fixed bootstrap log handling so that all named log pipes (`postgres`, `postgres.csv`, and `postgres.json`) get consumers during `WithActiveInstance`, preventing regular files from being created in place of the named pipes. ([#10043](cloudnative-pg/cloudnative-pg#10043)) <!-- 1.29 1.28 1.25 -->

- Fixed generation of invalid IPv6 URLs by wrapping the address in square brackets. Contributed by [@Infinoid](https://github.com/Infinoid). ([#10682](cloudnative-pg/cloudnative-pg#10682)) <!-- 1.29 1.28 1.25 -->

- Fixed an external cluster plugin still being treated as active when its configuration set `enabled: false`. ([#10932](cloudnative-pg/cloudnative-pg#10932)) <!-- 1.29 1.28 1.25 -->

- Fixed a race during bootstrap recovery from an object store where the restore job could read a stale `Cluster` (primary not yet recorded and timeline still unset) and have its `.history` files rejected by the split-brain guard. When this happened, recovery stopped at the base backup's timeline and silently dropped transactions committed on later timelines. History files are now allowed while the cluster timeline is unset. Contributed by [@dennispidun](https://github.com/dennispidun). ([#10818](cloudnative-pg/cloudnative-pg#10818)) <!-- 1.29 1.28 1.25 -->

- Fixed a cache race during cluster creation when the server and client CA resolve to the same Secret (the default): a stale informer cache triggered a redundant `Create` that failed with `AlreadyExists` and could leave the cluster stuck in `Unable to create required cluster objects`. The operator now reuses the already-fetched CA Secret when the names match. ([#10989](cloudnative-pg/cloudnative-pg#10989)) <!-- 1.29 1.28 1.25 -->

- Fixed the `pg_basebackup` bootstrap path overwriting or failing on a pre-existing `PGDATA` (for example after a replica Pod restart) by enforcing the same pre-flight directory check already applied by the other bootstrap methods; this also protects statically provisioned PVCs from being silently overwritten. ([#11006](cloudnative-pg/cloudnative-pg#11006)) <!-- 1.29 1.28 1.25 -->

- Fixed the `Cluster` phase flapping between `Healthy` and a plugin-failure phase when a post-reconcile plugin hook returned an error; the `Healthy` phase is now registered as the last step of a successful reconciliation, so a loop that ends in a plugin error never reports `Healthy`. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10421](cloudnative-pg/cloudnative-pg#10421)) <!-- 1.29 1.28 1.25 -->

- Fixed stale certificate data and partial reads after an external server's Secret was rotated (for example a CA bundle shrinking from two certificates to one): the file is now written atomically, so libpq always reads either the old or the new value, never a mix. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10975](cloudnative-pg/cloudnative-pg#10975)) <!-- 1.29 1.28 1.25 -->

- Fixed plugin connectivity to use the plugin `Service` FQDN instead of its short name, avoiding failures when a cluster-level proxy is automatically injected into pods. Contributed by [@kdautrey](https://github.com/kdautrey). ([#10921](cloudnative-pg/cloudnative-pg#10921)) <!-- 1.29 1.28 1.25 -->

- Fixed excessive operator log noise from the per-request `Cluster` create/update validation webhook messages, now logged at `debug` instead of `info`. ([#10984](cloudnative-pg/cloudnative-pg#10984)) <!-- 1.29 1.28 1.25 -->

- Fixed a first-primary bootstrap deadlock where a status-patch conflict after the data PVC was created but before the initialization Job was started left the orphan Pending PVC counted as an instance, blocking the bootstrap gate; the PVC-state reconciler now recreates the bootstrap Job reusing the assigned serial. ([#11039](cloudnative-pg/cloudnative-pg#11039)) <!-- 1.29 1.28 1.25 -->

- Fixed external cluster names and secret selector references being joined into filesystem paths without validation, letting a `..` component or path separator escape the external secrets directory when the instance manager dumps connection material; these values are now rejected at the validating webhook and re-checked at the write site. Reported by [@r0binak](https://github.com/r0binak). ([#11045](cloudnative-pg/cloudnative-pg#11045)) <!-- 1.29 1.28 1.25 -->

- Fixed a backup getting stuck in `pending` forever: the concurrent-backup gate ran on every reconcile and could overwrite an already-completed phase written asynchronously by the instance manager. The gate now runs only while the backup phase is still unset or `pending`. ([#11056](cloudnative-pg/cloudnative-pg#11056)) <!-- 1.29 -->

- Fixed a declarative `VolumeSnapshot` backup being permanently marked as failed when a stale cache made the operator re-create a snapshot it had already provisioned, failing with `AlreadyExists`. The operator now tolerates the collision when the existing snapshot carries this backup's label and adopts it; a collision with a foreign snapshot still surfaces as an error. ([#11071](cloudnative-pg/cloudnative-pg#11071)) <!-- 1.29 1.28 1.25 -->

- Fixed a volume snapshot backup being discarded on a transient instance-manager connection error (for example a dial timeout from a brief pod-network disruption) during the finalize step, even when its snapshots were already provisioned; such network errors are now retried instead of treated as terminal. ([#11069](cloudnative-pg/cloudnative-pg#11069)) <!-- 1.29 1.28 1.25 -->

- Fixed a replica switchover losing its `status.demotionToken` when a reconcile was requeued between storing the token and cleaning up the transition metadata (for example a cleanup patch failing against a flaky webhook); the empty no-change token is no longer patched back over the stored value. ([#11075](cloudnative-pg/cloudnative-pg#11075)) <!-- 1.29 1.28 1.25 -->

- `cnpg` plugin:

  - Fixed `kubectl cnpg psql` on Windows, where execution relied on a Unix-only system call and failed with "not supported by windows"; Windows now launches `kubectl exec` as a child process. Contributed by [@Utkarsh-sharma47](https://github.com/Utkarsh-sharma47). ([#10972](cloudnative-pg/cloudnative-pg#10972)) <!-- 1.29 1.28 1.25 -->

  - Fixed an unbounded memory leak in `kubectl cnpg logs -f` on busy clusters, where a per-log-group timer was never released; timers are now reused across iterations. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10976](cloudnative-pg/cloudnative-pg#10976)) <!-- 1.29 1.28 1.25 -->
sdwilsh pushed a commit to sdwilsh/ansible-playbooks that referenced this pull request Jul 7, 2026
##### [\`v1.30.0\`](https://github.com/cloudnative-pg/cloudnative-pg/releases/tag/v1.30.0)

**Release date:** Jun 29, 2026

##### Important changes

- Updated the deprecation notice for native (in-tree) Barman Cloud support to reflect that it will now be removed in CloudNativePG 1.31.0, rather than 1.30.0. Users are still encouraged to migrate to the Barman Cloud Plugin. ([#11083](cloudnative-pg/cloudnative-pg#11083)) <!-- 1.29 1.28 -->

- The `cluster` reference is now immutable on the `Database`, `Pooler`, `Publication`, `Subscription`, and `ScheduledBackup` resources. Pointing one of these objects at a different cluster has no well-defined semantics and previously left the controllers in an inconsistent state; the update is now rejected at the API server via a CEL validation rule. ([#10743](cloudnative-pg/cloudnative-pg#10743)) <!-- 1.29 1.28 1.25 -->

##### Features

- **Primary `Lease` for safe primary election**: introduced a Kubernetes `Lease` object (named after the cluster) that acts as a mutex serializing primary promotion: the instance manager must hold the lease before acting as primary and releases it on clean shutdown so replicas can promote without waiting for the full TTL. Timings are configurable via the new `.spec.primaryLease` stanza. The lease is a promotion gate, not a fence. Primary isolation remains responsible for fencing. ([#10627](cloudnative-pg/cloudnative-pg#10627))

- **`DatabaseRole` CRD for declarative role management**: introduced a `DatabaseRole` custom resource that manages a PostgreSQL role as a standalone Kubernetes object, instead of declaring it inline in the `Cluster`'s `.spec.managed.roles` stanza. Each role gets its own lifecycle, status, and RBAC, which suits GitOps workflows and lets role definitions live next to the applications that own them. The spec reuses the same `RoleConfiguration` structure as the inline method, so migrating a role is a matter of moving the stanza into its own manifest. A `databaseRoleReclaimPolicy` field (`retain`, the default, or `delete`) controls what happens to the role when the resource is deleted, mirroring persistent volumes. ([#6155](cloudnative-pg/cloudnative-pg#6155))

- **TLS client certificates for declarative roles**: a `DatabaseRole` can now include a `clientCertificate` block to have the operator automatically generate and renew a TLS client certificate, signed by the cluster's client CA and stored in a `<databaserole-name>-client-cert` Secret. This enables password-free PostgreSQL `cert` authentication; the Secret is cleaned up when the feature is disabled or the `DatabaseRole` is deleted. ([#10896](cloudnative-pg/cloudnative-pg#10896))

- **PgBouncer image management via image catalogs**: the `Pooler` resource can now reference an entry in an `ImageCatalog` or `ClusterImageCatalog` through the new `spec.pgbouncer.imageCatalogRef` field, centralizing PgBouncer image management. When a catalog entry is updated, all referencing `Poolers` are automatically reconciled and roll out the new image without any change to their spec. The resolved image is reported in `status.image`, and a new `status.phase` (`active`, `paused`, `inactive`, or `failed`), also surfaced as a `Phase` column in `kubectl get pooler`, summarizes the lifecycle. ([#10568](cloudnative-pg/cloudnative-pg#10568))

##### Enhancements

- Enabled `pg_upgrade` in-place major upgrades to PostgreSQL 19 or later for clusters that use Image Volume extensions, building on the extension-path support added to `pg_upgrade` in PostgreSQL 19. During the upgrade `Job`, the source- and target-version extension images are mounted side by side, so the old server keeps its libraries and a failed upgrade reverts cleanly. ([#10366](cloudnative-pg/cloudnative-pg#10366)) <!-- 1.29 -->

- Added TLS support for the `Pooler` metrics endpoint via `.spec.monitoring.tls.enabled`. When enabled, the metrics server is served over HTTPS, reusing the certificate and key from `.spec.pgbouncer.clientTLSSecret` and reloading it on every handshake to support rotation without a restart; the generated `PodMonitor` scrapes over `https` accordingly. ([#10466](cloudnative-pg/cloudnative-pg#10466))

- Added a label selector to the `Cluster` scale subresource (`status.selector`), making a `Cluster` a valid `targetRef` for the Vertical Pod Autoscaler (VPA) and Horizontal Pod Autoscaler (HPA), which can now map a `Cluster` to its instance pods. Contributed by [@sebv004](https://github.com/sebv004). ([#8996](cloudnative-pg/cloudnative-pg#8996)) <!-- 1.29 1.28 1.25 -->

- The operator now emits a `Warning` `PrimaryStatusCheckFailed` event on the `Cluster` when the primary pod is `Ready` from the kubelet perspective but the operator's `/pg/status` check fails and failover is deferred, giving users visibility into the deferral via `kubectl describe cluster`. ([#10509](cloudnative-pg/cloudnative-pg#10509)) <!-- 1.29 1.28 1.25 -->

- Added the `ENABLE_WEBHOOK_NAMESPACE_SUFFIX` flag, which suffixes the operator's webhook configuration names with `-<OPERATOR_NAMESPACE>` so that multiple operator instances can coexist on the same cluster. The operator only looks up these configurations; users must create and maintain them. Contributed by [@maxlengdell](https://github.com/maxlengdell). ([#10420](cloudnative-pg/cloudnative-pg#10420)) <!-- 1.29 1.28 1.25 -->

- The operator now reloads a CNPG-i plugin automatically when its pods are rolled: it watches the `EndpointSlices` backing plugin `Services` and re-enqueues every cluster using the plugin once the new pods become `Ready`, so an upgraded plugin is picked up without waiting for the next resync. ([#10836](cloudnative-pg/cloudnative-pg#10836)) <!-- 1.29 1.28 1.25 -->

- Instance serial numbers are now assigned by reusing the lowest free slot among existing instance names, instead of always incrementing a global counter. Pod and PVC names stay stable across instance recreation (for example, an instance recreated after a node drain comes back with the same name), and serials freed by deleted instances are reclaimed. A new `Initialized` cluster condition reports whether the cluster has completed its first bootstrap, and `status.latestGeneratedNode` is deprecated: it is no longer written, but is preserved on the CRD for backward compatibility. ([#10548](cloudnative-pg/cloudnative-pg#10548))

- Defaulting and validation now run during reconciliation as a fallback when admission webhooks are unavailable, or configured to ignore failures, so the operator no longer reconciles invalid or incomplete specs. Missing defaults are applied directly, and validation failures are surfaced in the resource status instead of failing silently later. ([#10874](cloudnative-pg/cloudnative-pg#10874))

##### Security

- **`CVE-2026-55769` / `GHSA-x8c2-3p4r-v9r6`: `search_path` pinning on operator-issued connections**: a database owner could plant overloaded built-in operators in the `public` schema and alter the `search_path` so that operator introspection probes, running as the cluster superuser, resolved those overloads before `pg_catalog`, a `CWE-426` privilege-escalation chain (same class as `CVE-2018-1058`) that could lead to in-pod RCE via `COPY ... FROM PROGRAM`. The operator now pins `search_path = pg_catalog, public, pg_temp` on every pooled connection so it ships in the startup message and takes precedence over tenant-controlled defaults. ([#10774](cloudnative-pg/cloudnative-pg#10774), [`GHSA-x8c2-3p4r-v9r6`](GHSA-x8c2-3p4r-v9r6)) <!-- 1.29 1.28 1.25 -->

- **`GHSA-7qwx-x8ff-3px9`: authenticated operator-to-instance-manager calls**: the instance manager's remote webserver relied on network isolation rather than authentication for its operator-only control endpoints, so any party able to reach the pod's status port could invoke them, disrupting backup orchestration and WAL archival and reading operational metadata. (The upgrade endpoint is SHA-256-pinned, so this did not permit arbitrary code execution.) The operator now generates an in-memory ECDSA P-256 client certificate at startup and reconciles its SHA-256 fingerprint into the cluster status; the instance manager rejects requests to sensitive endpoints that do not present a matching certificate. This hardening is not backported; earlier releases should continue to restrict the status port with a `NetworkPolicy`. ([#10579](cloudnative-pg/cloudnative-pg#10579), [`GHSA-7qwx-x8ff-3px9`](GHSA-7qwx-x8ff-3px9))

- **`CVE-2026-55765` / `GHSA-w3gf-xc94-wvmj`: operator-side SCRAM-SHA-256 password encoding**: the operator now SCRAM-SHA-256 encodes cleartext role passwords before issuing `CREATE`/`ALTER ROLE ... PASSWORD`, so the literal PostgreSQL parses (and that extensions such as `pg_stat_statements` or `pgaudit` may capture) is the SCRAM verifier rather than the cleartext secret. Pre-hashed (MD5 or SCRAM) values are forwarded unchanged, and the per-Secret annotation `cnpg.io/passwordPassthrough: "enabled"` opts out. ([#10724](cloudnative-pg/cloudnative-pg#10724), [`GHSA-w3gf-xc94-wvmj`](GHSA-w3gf-xc94-wvmj)) <!-- 1.29 1.28 1.25 -->

##### Changes

- Added support for Kubernetes 1.36. ([#10900](cloudnative-pg/cloudnative-pg#10900)) <!-- 1.29 1.28 -->

- Updated the default PostgreSQL version to 18.4. ([#10719](cloudnative-pg/cloudnative-pg#10719)) <!-- 1.29 1.28 1.25 -->

- Updated the Kubernetes versions used to test the operator on public cloud providers. ([#10720](cloudnative-pg/cloudnative-pg#10720), <!-- 1.29 1.28 1.25 --> [#10563](cloudnative-pg/cloudnative-pg#10563), <!-- 1.29 1.28 1.25 --> [#11033](cloudnative-pg/cloudnative-pg#11033)) <!-- 1.29 1.28 1.25 -->

##### Fixes

- Fixed declarative `Database`, `Publication`, and `Subscription` objects reporting a stale primary-side status forever after their cluster was demoted to a replica; the controller now re-checks the replica condition and watches the `Cluster` so a demotion is detected promptly. ([#10871](cloudnative-pg/cloudnative-pg#10871)) <!-- 1.29 1.28 1.25 -->

- Fixed non-sequential pod names (for example `-1`, `-3`) caused by the instance serial counter being advanced before the corresponding `Job` and PVCs were created; the bump is now persisted only after those resources exist. ([#10491](cloudnative-pg/cloudnative-pg#10491)) <!-- 1.29 1.28 1.25 -->

- Fixed deletion of a `Database`, `Publication`, or `Subscription` getting stuck in `Terminating` on a replica cluster, where the replica gate ran before the finalizer reconciler and the finalizer was never released. On a replica the PostgreSQL object is left to the primary cluster. ([#10853](cloudnative-pg/cloudnative-pg#10853)) <!-- 1.29 1.28 1.25 -->

- Fixed a conflicting duplicate `Database` or `Subscription` with a `delete` reclaim policy dropping the PostgreSQL object owned by the surviving CR; the drop is now gated on a recorded reconciliation. ([#10870](cloudnative-pg/cloudnative-pg#10870)) <!-- 1.29 1.28 1.25 -->

- Fixed the `postgres` superuser being left locked out after superuser access was disabled and then re-enabled, because the cached secret version was not invalidated and the password was never re-applied. Diagnosed by [@mhartmann-jaconi](https://github.com/mhartmann-jaconi). ([#10834](cloudnative-pg/cloudnative-pg#10834)) <!-- 1.29 1.28 1.25 -->

- Fixed backups getting stuck in the `started` phase when the instance manager running them was restarted (for example by the in-place upgrade following an operator upgrade) before the backup reached `running`; the reconciliation is now rescheduled so the lost session is detected. ([#10859](cloudnative-pg/cloudnative-pg#10859)) <!-- 1.29 1.28 -->

- Fixed `exec`/`attach` streaming to negotiate WebSocket with a SPDY fallback, restoring compatibility both with Kubernetes versions that have removed SPDY and with platforms such as OpenShift that reject WebSocket exec upgrades. Contributed by [@bartscheers](https://github.com/bartscheers). ([#10876](cloudnative-pg/cloudnative-pg#10876), [#10933](cloudnative-pg/cloudnative-pg#10933)) <!-- 1.29 -->

- Fixed resource leaks when concurrent `Backup` objects raced: backups now run in strict creation-time order, so an already-executing backup is never preempted by a newer one and its replication slot and PostgreSQL session are no longer orphaned on the primary. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10747](cloudnative-pg/cloudnative-pg#10747)) <!-- 1.29 1.28 1.25 -->

- Fixed role reconciliation clearing the password on a PostgreSQL role when the referenced Secret could not be fetched; the role is now left untouched until the Secret becomes available, and per-action errors are aggregated for better visibility. ([#10053](cloudnative-pg/cloudnative-pg#10053)) <!-- 1.29 1.28 1.25 -->

- Fixed a bootstrap failure where a metrics-exporter setup error (commonly a duplicate-key race with the controller) rolled back `streaming_replica` creation and wedged replica joins. The metrics-exporter step now runs in a separate transaction. Contributed by [@BlaiseAntony](https://github.com/BlaiseAntony). ([#10749](cloudnative-pg/cloudnative-pg#10749)) <!-- 1.29 1.28 1.25 -->

- Fixed a `ScheduledBackup` controller loop that occurred when a `Backup` was created but its status patch never landed; the controller now adopts an existing `Backup` for the next iteration instead of looping on `AlreadyExists`. ([#10612](cloudnative-pg/cloudnative-pg#10612)) <!-- 1.29 1.28 1.25 -->

- Fixed a nil-pointer panic when reconciling a `Pooler` whose `Cluster` has been deleted. ([#10667](cloudnative-pg/cloudnative-pg#10667)) <!-- 1.29 1.28 -->

- Fixed bootstrap log handling so that all named log pipes (`postgres`, `postgres.csv`, and `postgres.json`) get consumers during `WithActiveInstance`, preventing regular files from being created in place of the named pipes. ([#10043](cloudnative-pg/cloudnative-pg#10043)) <!-- 1.29 1.28 1.25 -->

- Fixed generation of invalid IPv6 URLs by wrapping the address in square brackets. Contributed by [@Infinoid](https://github.com/Infinoid). ([#10682](cloudnative-pg/cloudnative-pg#10682)) <!-- 1.29 1.28 1.25 -->

- Fixed an external cluster plugin still being treated as active when its configuration set `enabled: false`. ([#10932](cloudnative-pg/cloudnative-pg#10932)) <!-- 1.29 1.28 1.25 -->

- Fixed a race during bootstrap recovery from an object store where the restore job could read a stale `Cluster` (primary not yet recorded and timeline still unset) and have its `.history` files rejected by the split-brain guard. When this happened, recovery stopped at the base backup's timeline and silently dropped transactions committed on later timelines. History files are now allowed while the cluster timeline is unset. Contributed by [@dennispidun](https://github.com/dennispidun). ([#10818](cloudnative-pg/cloudnative-pg#10818)) <!-- 1.29 1.28 1.25 -->

- Fixed a race where deleting an instance's PVCs could leave the instance permanently stuck: if the data PVC was removed while a WAL PVC was still terminating, the operator recreated the instance bound to the terminating volume, leaving the Pod unschedulable and blocking all further reconciliation. The operator now waits for terminating PVCs to be fully removed before recreating or reattaching an instance, and surfaces the wait through a log line and the cluster phase. ([#11017](cloudnative-pg/cloudnative-pg#11017))

- Fixed a cache race during cluster creation when the server and client CA resolve to the same Secret (the default): a stale informer cache triggered a redundant `Create` that failed with `AlreadyExists` and could leave the cluster stuck in `Unable to create required cluster objects`. The operator now reuses the already-fetched CA Secret when the names match. ([#10989](cloudnative-pg/cloudnative-pg#10989)) <!-- 1.29 1.28 1.25 -->

- Fixed the `pg_basebackup` bootstrap path overwriting or failing on a pre-existing `PGDATA` (for example after a replica Pod restart) by enforcing the same pre-flight directory check already applied by the other bootstrap methods; this also protects statically provisioned PVCs from being silently overwritten. ([#11006](cloudnative-pg/cloudnative-pg#11006)) <!-- 1.29 1.28 1.25 -->

- Fixed the `Cluster` phase flapping between `Healthy` and a plugin-failure phase when a post-reconcile plugin hook returned an error; the `Healthy` phase is now registered as the last step of a successful reconciliation, so a loop that ends in a plugin error never reports `Healthy`. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10421](cloudnative-pg/cloudnative-pg#10421)) <!-- 1.29 1.28 1.25 -->

- Fixed stale certificate data and partial reads after an external server's Secret was rotated (for example a CA bundle shrinking from two certificates to one): the file is now written atomically, so libpq always reads either the old or the new value, never a mix. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10975](cloudnative-pg/cloudnative-pg#10975)) <!-- 1.29 1.28 1.25 -->

- Fixed plugin connectivity to use the plugin `Service` FQDN instead of its short name, avoiding failures when a cluster-level proxy is automatically injected into pods. Contributed by [@kdautrey](https://github.com/kdautrey). ([#10921](cloudnative-pg/cloudnative-pg#10921)) <!-- 1.29 1.28 1.25 -->

- Fixed excessive operator log noise from the per-request `Cluster` create/update validation webhook messages, now logged at `debug` instead of `info`. ([#10984](cloudnative-pg/cloudnative-pg#10984)) <!-- 1.29 1.28 1.25 -->

- Fixed `spec.postgresql.parameters` accepting keys that are not valid PostgreSQL parameter names, which could inject arbitrary directives into `postgresql.conf`; key names are now validated by the webhook. ([#11029](cloudnative-pg/cloudnative-pg#11029)) <!-- 1.29 1.28 1.25 -->

- Fixed a switchover deadlock when a WAL-archiver plugin was enabled on an existing cluster: with `primaryUpdateMethod: switchover` the primary could not be rolled out because a clean demotion needs the archiver sidecar that is still missing. The operator now recreates the primary Pod in place so the sidecar is injected and archiving resumes. The check also covers plugins that inject the archiver as a native sidecar (an init container with `restartPolicy: Always`), such as the Barman Cloud plugin. ([#11032](cloudnative-pg/cloudnative-pg#11032), <!-- 1.29 1.28 1.25 --> [#11059](cloudnative-pg/cloudnative-pg#11059)) <!-- 1.29 1.28 1.25 -->

- Fixed a cluster staying in `Setting up primary` indefinitely when the instance-creation Job exhausted its backoff limit; the operator now detects the terminal Job failure and marks the cluster unrecoverable, naming the failed Job and pointing to its logs. ([#11035](cloudnative-pg/cloudnative-pg#11035)) <!-- 1.29 1.28 1.25 -->

- Fixed a first-primary bootstrap deadlock where a status-patch conflict after the data PVC was created but before the initialization Job was started left the orphan Pending PVC counted as an instance, blocking the bootstrap gate; the PVC-state reconciler now recreates the bootstrap Job reusing the assigned serial. ([#11039](cloudnative-pg/cloudnative-pg#11039)) <!-- 1.29 1.28 1.25 -->

- Fixed external cluster names and secret selector references being joined into filesystem paths without validation, letting a `..` component or path separator escape the external secrets directory when the instance manager dumps connection material; these values are now rejected at the validating webhook and re-checked at the write site. Reported by [@r0binak](https://github.com/r0binak). ([#11045](cloudnative-pg/cloudnative-pg#11045)) <!-- 1.29 1.28 1.25 -->

- Fixed a backup getting stuck in `pending` forever: the concurrent-backup gate ran on every reconcile and could overwrite an already-completed phase written asynchronously by the instance manager. The gate now runs only while the backup phase is still unset or `pending`. ([#11056](cloudnative-pg/cloudnative-pg#11056)) <!-- 1.29 -->

- Fixed a declarative `VolumeSnapshot` backup being permanently marked as failed when a stale cache made the operator re-create a snapshot it had already provisioned, failing with `AlreadyExists`. The operator now tolerates the collision when the existing snapshot carries this backup's label and adopts it; a collision with a foreign snapshot still surfaces as an error. ([#11071](cloudnative-pg/cloudnative-pg#11071)) <!-- 1.29 1.28 1.25 -->

- Fixed a volume snapshot backup being discarded on a transient instance-manager connection error (for example a dial timeout from a brief pod-network disruption) during the finalize step, even when its snapshots were already provisioned; such network errors are now retried instead of treated as terminal. ([#11069](cloudnative-pg/cloudnative-pg#11069)) <!-- 1.29 1.28 1.25 -->

- Fixed a replica switchover losing its `status.demotionToken` when a reconcile was requeued between storing the token and cleaning up the transition metadata (for example a cleanup patch failing against a flaky webhook); the empty no-change token is no longer patched back over the stored value. ([#11075](cloudnative-pg/cloudnative-pg#11075)) <!-- 1.29 1.28 1.25 -->

- `cnpg` plugin:

  - Fixed `kubectl cnpg psql` on Windows, where execution relied on a Unix-only system call and failed with "not supported by windows"; Windows now launches `kubectl exec` as a child process. Contributed by [@Utkarsh-sharma47](https://github.com/Utkarsh-sharma47). ([#10972](cloudnative-pg/cloudnative-pg#10972)) <!-- 1.29 1.28 1.25 -->

  - Fixed an unbounded memory leak in `kubectl cnpg logs -f` on busy clusters, where a per-log-group timer was never released; timers are now reused across iterations. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10976](cloudnative-pg/cloudnative-pg#10976)) <!-- 1.29 1.28 1.25 -->

##### Supported versions

- Kubernetes 1.36, 1.35, and 1.34
- PostgreSQL 18, 17, 16, 15, and 14
  - PostgreSQL 18.4 is the default image
  - PostgreSQL 14 support ends on November 12, 2026

---
##### [\`v1.29.2\`](https://github.com/cloudnative-pg/cloudnative-pg/releases/tag/v1.29.2)

**Release date:** Jun 29, 2026

##### Important changes

- Updated the deprecation notice for native (in-tree) Barman Cloud support to reflect that it will now be removed in CloudNativePG 1.31.0, rather than 1.30.0. Users are still encouraged to migrate to the Barman Cloud Plugin. ([#11083](cloudnative-pg/cloudnative-pg#11083)) <!-- 1.29 1.28 -->

- The `cluster` reference is now immutable on the `Database`, `Pooler`, `Publication`, `Subscription`, and `ScheduledBackup` resources. Pointing one of these objects at a different cluster has no well-defined semantics and previously left the controllers in an inconsistent state; the update is now rejected at the API server via a CEL validation rule. ([#10743](cloudnative-pg/cloudnative-pg#10743)) <!-- 1.29 1.28 1.25 -->

##### Enhancements

- Enabled `pg_upgrade` in-place major upgrades to PostgreSQL 19 or later for clusters that use Image Volume extensions, building on the extension-path support added to `pg_upgrade` in PostgreSQL 19. During the upgrade `Job`, the source- and target-version extension images are mounted side by side, so the old server keeps its libraries and a failed upgrade reverts cleanly. ([#10366](cloudnative-pg/cloudnative-pg#10366)) <!-- 1.29 -->

- Added a label selector to the `Cluster` scale subresource (`status.selector`), making a `Cluster` a valid `targetRef` for the Vertical Pod Autoscaler (VPA) and Horizontal Pod Autoscaler (HPA), which can now map a `Cluster` to its instance pods. Contributed by [@sebv004](https://github.com/sebv004). ([#8996](cloudnative-pg/cloudnative-pg#8996)) <!-- 1.29 1.28 1.25 -->

- The operator now emits a `Warning` `PrimaryStatusCheckFailed` event on the `Cluster` when the primary pod is `Ready` from the kubelet perspective but the operator's `/pg/status` check fails and failover is deferred, giving users visibility into the deferral via `kubectl describe cluster`. ([#10509](cloudnative-pg/cloudnative-pg#10509)) <!-- 1.29 1.28 1.25 -->

- The operator now reloads a CNPG-i plugin automatically when its pods are rolled: it watches the `EndpointSlices` backing plugin `Services` and re-enqueues every cluster using the plugin once the new pods become `Ready`, so an upgraded plugin is picked up without waiting for the next resync. ([#10836](cloudnative-pg/cloudnative-pg#10836)) <!-- 1.29 1.28 1.25 -->

##### Security and Supply Chain

- **`CVE-2026-55769` / `GHSA-x8c2-3p4r-v9r6`: `search_path` pinning on operator-issued connections**: a database owner could plant overloaded built-in operators in the `public` schema and alter the `search_path` so that operator introspection probes, running as the cluster superuser, resolved those overloads before `pg_catalog`, a `CWE-426` privilege-escalation chain (same class as `CVE-2018-1058`) that could lead to in-pod RCE via `COPY ... FROM PROGRAM`. The operator now pins `search_path = pg_catalog, public, pg_temp` on every pooled connection so it ships in the startup message and takes precedence over tenant-controlled defaults. ([#10774](cloudnative-pg/cloudnative-pg#10774), [`GHSA-x8c2-3p4r-v9r6`](GHSA-x8c2-3p4r-v9r6)) <!-- 1.29 1.28 1.25 -->

- **`CVE-2026-55765` / `GHSA-w3gf-xc94-wvmj`: operator-side SCRAM-SHA-256 password encoding**: the operator now SCRAM-SHA-256 encodes cleartext role passwords before issuing `CREATE`/`ALTER ROLE ... PASSWORD`, so the literal PostgreSQL parses (and that extensions such as `pg_stat_statements` or `pgaudit` may capture) is the SCRAM verifier rather than the cleartext secret. Pre-hashed (MD5 or SCRAM) values are forwarded unchanged, and the per-Secret annotation `cnpg.io/passwordPassthrough: "enabled"` opts out. ([#10724](cloudnative-pg/cloudnative-pg#10724), [`GHSA-w3gf-xc94-wvmj`](GHSA-w3gf-xc94-wvmj)) <!-- 1.29 1.28 1.25 -->

##### Changes

- Added support for Kubernetes 1.36. ([#10900](cloudnative-pg/cloudnative-pg#10900)) <!-- 1.29 1.28 -->

- Updated the default PostgreSQL version to 18.4. ([#10719](cloudnative-pg/cloudnative-pg#10719)) <!-- 1.29 1.28 1.25 -->

- Updated the Kubernetes versions used to test the operator on public cloud providers. ([#10720](cloudnative-pg/cloudnative-pg#10720), <!-- 1.29 1.28 1.25 --> [#10563](cloudnative-pg/cloudnative-pg#10563), <!-- 1.29 1.28 1.25 --> [#11033](cloudnative-pg/cloudnative-pg#11033)) <!-- 1.29 1.28 1.25 -->

##### Fixes

- Fixed `spec.postgresql.parameters` accepting keys that are not valid PostgreSQL parameter names, which could inject arbitrary directives into `postgresql.conf`; key names are now validated by the webhook. ([#11029](cloudnative-pg/cloudnative-pg#11029)) <!-- 1.29 1.28 1.25 -->

- Fixed declarative `Database`, `Publication`, and `Subscription` objects reporting a stale primary-side status forever after their cluster was demoted to a replica; the controller now re-checks the replica condition and watches the `Cluster` so a demotion is detected promptly. ([#10871](cloudnative-pg/cloudnative-pg#10871)) <!-- 1.29 1.28 1.25 -->

- Fixed non-sequential pod names (for example `-1`, `-3`) caused by the instance serial counter being advanced before the corresponding `Job` and PVCs were created; the bump is now persisted only after those resources exist. ([#10491](cloudnative-pg/cloudnative-pg#10491)) <!-- 1.29 1.28 1.25 -->

- Fixed a switchover deadlock when a WAL-archiver plugin was enabled on an existing cluster: with `primaryUpdateMethod: switchover` the primary could not be rolled out because a clean demotion needs the archiver sidecar that is still missing. The operator now recreates the primary Pod in place so the sidecar is injected and archiving resumes. The check also covers plugins that inject the archiver as a native sidecar (an init container with `restartPolicy: Always`), such as the Barman Cloud plugin. ([#11032](cloudnative-pg/cloudnative-pg#11032), <!-- 1.29 1.28 1.25 --> [#11059](cloudnative-pg/cloudnative-pg#11059)) <!-- 1.29 1.28 1.25 -->

- Fixed a cluster staying in `Setting up primary` indefinitely when the instance-creation Job exhausted its backoff limit; the operator now detects the terminal Job failure and marks the cluster unrecoverable, naming the failed Job and pointing to its logs. ([#11035](cloudnative-pg/cloudnative-pg#11035)) <!-- 1.29 1.28 1.25 -->

- Fixed deletion of a `Database`, `Publication`, or `Subscription` getting stuck in `Terminating` on a replica cluster, where the replica gate ran before the finalizer reconciler and the finalizer was never released. On a replica the PostgreSQL object is left to the primary cluster. ([#10853](cloudnative-pg/cloudnative-pg#10853)) <!-- 1.29 1.28 1.25 -->

- Fixed a conflicting duplicate `Database` or `Subscription` with a `delete` reclaim policy dropping the PostgreSQL object owned by the surviving CR; the drop is now gated on a recorded reconciliation. ([#10870](cloudnative-pg/cloudnative-pg#10870)) <!-- 1.29 1.28 1.25 -->

- Fixed the `postgres` superuser being left locked out after superuser access was disabled and then re-enabled, because the cached secret version was not invalidated and the password was never re-applied. Diagnosed by [@mhartmann-jaconi](https://github.com/mhartmann-jaconi). ([#10834](cloudnative-pg/cloudnative-pg#10834)) <!-- 1.29 1.28 1.25 -->

- Fixed backups getting stuck in the `started` phase when the instance manager running them was restarted (for example by the in-place upgrade following an operator upgrade) before the backup reached `running`; the reconciliation is now rescheduled so the lost session is detected. ([#10859](cloudnative-pg/cloudnative-pg#10859)) <!-- 1.29 1.28 -->

- Fixed `exec`/`attach` streaming to negotiate WebSocket with a SPDY fallback, restoring compatibility both with Kubernetes versions that have removed SPDY and with platforms such as OpenShift that reject WebSocket exec upgrades. Contributed by [@bartscheers](https://github.com/bartscheers). ([#10876](cloudnative-pg/cloudnative-pg#10876), [#10933](cloudnative-pg/cloudnative-pg#10933)) <!-- 1.29 -->

- Fixed resource leaks when concurrent `Backup` objects raced: backups now run in strict creation-time order, so an already-executing backup is never preempted by a newer one and its replication slot and PostgreSQL session are no longer orphaned on the primary. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10747](cloudnative-pg/cloudnative-pg#10747)) <!-- 1.29 1.28 1.25 -->

- Fixed role reconciliation clearing the password on a PostgreSQL role when the referenced Secret could not be fetched; the role is now left untouched until the Secret becomes available, and per-action errors are aggregated for better visibility. ([#10053](cloudnative-pg/cloudnative-pg#10053)) <!-- 1.29 1.28 1.25 -->

- Fixed a bootstrap failure where a metrics-exporter setup error (commonly a duplicate-key race with the controller) rolled back `streaming_replica` creation and wedged replica joins. The metrics-exporter step now runs in a separate transaction. Contributed by [@BlaiseAntony](https://github.com/BlaiseAntony). ([#10749](cloudnative-pg/cloudnative-pg#10749)) <!-- 1.29 1.28 1.25 -->

- Fixed a `ScheduledBackup` controller loop that occurred when a `Backup` was created but its status patch never landed; the controller now adopts an existing `Backup` for the next iteration instead of looping on `AlreadyExists`. ([#10612](cloudnative-pg/cloudnative-pg#10612)) <!-- 1.29 1.28 1.25 -->

- Fixed a nil-pointer panic when reconciling a `Pooler` whose `Cluster` has been deleted. ([#10667](cloudnative-pg/cloudnative-pg#10667)) <!-- 1.29 1.28 -->

- Fixed bootstrap log handling so that all named log pipes (`postgres`, `postgres.csv`, and `postgres.json`) get consumers during `WithActiveInstance`, preventing regular files from being created in place of the named pipes. ([#10043](cloudnative-pg/cloudnative-pg#10043)) <!-- 1.29 1.28 1.25 -->

- Fixed generation of invalid IPv6 URLs by wrapping the address in square brackets. Contributed by [@Infinoid](https://github.com/Infinoid). ([#10682](cloudnative-pg/cloudnative-pg#10682)) <!-- 1.29 1.28 1.25 -->

- Fixed an external cluster plugin still being treated as active when its configuration set `enabled: false`. ([#10932](cloudnative-pg/cloudnative-pg#10932)) <!-- 1.29 1.28 1.25 -->

- Fixed a race during bootstrap recovery from an object store where the restore job could read a stale `Cluster` (primary not yet recorded and timeline still unset) and have its `.history` files rejected by the split-brain guard. When this happened, recovery stopped at the base backup's timeline and silently dropped transactions committed on later timelines. History files are now allowed while the cluster timeline is unset. Contributed by [@dennispidun](https://github.com/dennispidun). ([#10818](cloudnative-pg/cloudnative-pg#10818)) <!-- 1.29 1.28 1.25 -->

- Fixed a cache race during cluster creation when the server and client CA resolve to the same Secret (the default): a stale informer cache triggered a redundant `Create` that failed with `AlreadyExists` and could leave the cluster stuck in `Unable to create required cluster objects`. The operator now reuses the already-fetched CA Secret when the names match. ([#10989](cloudnative-pg/cloudnative-pg#10989)) <!-- 1.29 1.28 1.25 -->

- Fixed the `pg_basebackup` bootstrap path overwriting or failing on a pre-existing `PGDATA` (for example after a replica Pod restart) by enforcing the same pre-flight directory check already applied by the other bootstrap methods; this also protects statically provisioned PVCs from being silently overwritten. ([#11006](cloudnative-pg/cloudnative-pg#11006)) <!-- 1.29 1.28 1.25 -->

- Fixed the `Cluster` phase flapping between `Healthy` and a plugin-failure phase when a post-reconcile plugin hook returned an error; the `Healthy` phase is now registered as the last step of a successful reconciliation, so a loop that ends in a plugin error never reports `Healthy`. Contributed by [@GabriFedi97](https://github.com/GabriFedi97). ([#10421](cloudnative-pg/cloudnative-pg#10421)) <!-- 1.29 1.28 1.25 -->

- Fixed stale certificate data and partial reads after an external server's Secret was rotated (for example a CA bundle shrinking from two certificates to one): the file is now written atomically, so libpq always reads either the old or the new value, never a mix. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10975](cloudnative-pg/cloudnative-pg#10975)) <!-- 1.29 1.28 1.25 -->

- Fixed plugin connectivity to use the plugin `Service` FQDN instead of its short name, avoiding failures when a cluster-level proxy is automatically injected into pods. Contributed by [@kdautrey](https://github.com/kdautrey). ([#10921](cloudnative-pg/cloudnative-pg#10921)) <!-- 1.29 1.28 1.25 -->

- Fixed excessive operator log noise from the per-request `Cluster` create/update validation webhook messages, now logged at `debug` instead of `info`. ([#10984](cloudnative-pg/cloudnative-pg#10984)) <!-- 1.29 1.28 1.25 -->

- Fixed a first-primary bootstrap deadlock where a status-patch conflict after the data PVC was created but before the initialization Job was started left the orphan Pending PVC counted as an instance, blocking the bootstrap gate; the PVC-state reconciler now recreates the bootstrap Job reusing the assigned serial. ([#11039](cloudnative-pg/cloudnative-pg#11039)) <!-- 1.29 1.28 1.25 -->

- Fixed external cluster names and secret selector references being joined into filesystem paths without validation, letting a `..` component or path separator escape the external secrets directory when the instance manager dumps connection material; these values are now rejected at the validating webhook and re-checked at the write site. Reported by [@r0binak](https://github.com/r0binak). ([#11045](cloudnative-pg/cloudnative-pg#11045)) <!-- 1.29 1.28 1.25 -->

- Fixed a backup getting stuck in `pending` forever: the concurrent-backup gate ran on every reconcile and could overwrite an already-completed phase written asynchronously by the instance manager. The gate now runs only while the backup phase is still unset or `pending`. ([#11056](cloudnative-pg/cloudnative-pg#11056)) <!-- 1.29 -->

- Fixed a declarative `VolumeSnapshot` backup being permanently marked as failed when a stale cache made the operator re-create a snapshot it had already provisioned, failing with `AlreadyExists`. The operator now tolerates the collision when the existing snapshot carries this backup's label and adopts it; a collision with a foreign snapshot still surfaces as an error. ([#11071](cloudnative-pg/cloudnative-pg#11071)) <!-- 1.29 1.28 1.25 -->

- Fixed a volume snapshot backup being discarded on a transient instance-manager connection error (for example a dial timeout from a brief pod-network disruption) during the finalize step, even when its snapshots were already provisioned; such network errors are now retried instead of treated as terminal. ([#11069](cloudnative-pg/cloudnative-pg#11069)) <!-- 1.29 1.28 1.25 -->

- Fixed a replica switchover losing its `status.demotionToken` when a reconcile was requeued between storing the token and cleaning up the transition metadata (for example a cleanup patch failing against a flaky webhook); the empty no-change token is no longer patched back over the stored value. ([#11075](cloudnative-pg/cloudnative-pg#11075)) <!-- 1.29 1.28 1.25 -->

- `cnpg` plugin:

  - Fixed `kubectl cnpg psql` on Windows, where execution relied on a Unix-only system call and failed with "not supported by windows"; Windows now launches `kubectl exec` as a child process. Contributed by [@Utkarsh-sharma47](https://github.com/Utkarsh-sharma47). ([#10972](cloudnative-pg/cloudnative-pg#10972)) <!-- 1.29 1.28 1.25 -->

  - Fixed an unbounded memory leak in `kubectl cnpg logs -f` on busy clusters, where a per-log-group timer was never released; timers are now reused across iterations. Contributed by [@Anand-240](https://github.com/Anand-240). ([#10976](cloudnative-pg/cloudnative-pg#10976)) <!-- 1.29 1.28 1.25 -->
scooby87 added a commit to cozystack/cozystack that referenced this pull request Aug 26, 2026
…scale-subresource selector (#3951)

## What this PR does

Bumps the vendored `cloudnative-pg` chart from 0.27.1 to 0.29.0
(operator + CRDs from 1.28.1-patched-to-1.28.2 up to 1.30.0) and drops
the hand-maintained `patches/cloudnative-pg-1.28.2.patch` entirely —
0.29.0 is a published chart, so the version-alignment patch is no longer
needed.

**Why this is required.** Database read-replica autoscaling (community
proposal `design-proposals/database-horizontal-autoscaling`) drives the
CNPG `Cluster` scale subresource with a stock HPA (via KEDA). That only
works when the subresource serves `status.selector`, which
[cloudnative-pg#8996](cloudnative-pg/cloudnative-pg#8996)
added and shipped in CNPG 1.28.4 / 1.29.2 / 1.30.0. cozystack shipped
1.28.2, whose scale subresource has no selector, so the HPA fails with
`InvalidSelector`.

**Why 1.30.0 and not 1.28.4.** The floor is ≥ 1.28.4, but the upstream
chart repo publishes no chart for 1.28.4 (the 1.28 line stops at chart
0.27.1 / appVersion 1.28.1), so 1.28.4 could only be reached by
hand-patching the 0.27.1 chart's operator image and CRDs up to the
backport. A live PoC on a dev cluster proved that path is broken: the
1.28.4 operator running under the 0.27.1 (1.28.1) chart templates
crash-loops on a missing RBAC grant it needs but the older chart does
not provide — `endpointslices.discovery.k8s.io is forbidden: ... cannot
list resource "endpointslices"` — so `status.selector` is never
populated and the HPA still cannot scale. 1.30.0 (chart 0.29.0) is the
only published chart that carries the selector together with matching
RBAC/CRDs/templates, and the 1.28 line is EOL (2026-06-30), so 1.30.0
also keeps us on a supported release. cozystack uses the barman-cloud
plugin (not native barman, removed in 1.31) and no CNPG Poolers, so the
1.30 deprecations and the known pooler bug do not apply.

**Validation on a dev cluster (CNPG 1.30.0).** Operator rolls out clean
(no crashloop, the `endpointslices` RBAC error is gone); all existing
`Cluster` objects return to Ready; `/scale` now returns a populated
`status.selector` (`cnpg.io/cluster=<name>,cnpg.io/podRole=instance`);
an HPA pointed at a `Cluster` no longer reports `InvalidSelector`
(`AbleToScale=True, SucceededGetScale`); psql connectivity and streaming
replication verified.

The version-guard unittest is updated to 1.30.0 and now also asserts the
clusters CRD scale subresource carries `labelSelectorPath:
.status.selector`.

### Downstream repositories

Walked the trigger map in `docs/agents/contributing.md` against the
diff, file by file. The change touches only the vendored
`cloudnative-pg` operator chart (CRDs, RBAC, values), the package
`Makefile`, and the version-guard test. The `packages/apps/postgres` app
and its `version` enums are unchanged,
`packages/core/platform/values.yaml` is unchanged, and the
`clusters.postgresql.cnpg.io` CRD is not one the terraform provider
types by hand (it travels as opaque JSON). No downstream repository
restates anything this diff changes.

- [x] No downstream repository is affected by this change

### Release note

```release-note
fix(postgres-operator): bump CloudNativePG to 1.30.0 so the Cluster scale subresource serves status.selector, enabling HPA-driven read-replica autoscaling (previously the HPA failed with InvalidSelector on 1.28.2)
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Upgraded the CloudNativePG operator and Helm chart to 1.30.0/0.29.0.
* Added expanded image catalogs, pooler settings, pod selectors,
scheduling options, monitoring TLS, and LZ4 backup compression.
* Improved permissions for database roles, endpoint slices, and lease
monitoring.

* **Bug Fixes**
* Strengthened configuration validation and removed the deprecated
workload reference option.
  * Updated compatibility requirements to Kubernetes 1.29 or newer.

* **Documentation**
* Expanded installation, configuration, verification, upgrade, and
uninstall guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
kvaps pushed a commit to cozystack/cozystack that referenced this pull request Sep 7, 2026
…scale-subresource selector (#3951)

## What this PR does

Bumps the vendored `cloudnative-pg` chart from 0.27.1 to 0.29.0
(operator + CRDs from 1.28.1-patched-to-1.28.2 up to 1.30.0) and drops
the hand-maintained `patches/cloudnative-pg-1.28.2.patch` entirely —
0.29.0 is a published chart, so the version-alignment patch is no longer
needed.

**Why this is required.** Database read-replica autoscaling (community
proposal `design-proposals/database-horizontal-autoscaling`) drives the
CNPG `Cluster` scale subresource with a stock HPA (via KEDA). That only
works when the subresource serves `status.selector`, which
[cloudnative-pg#8996](cloudnative-pg/cloudnative-pg#8996)
added and shipped in CNPG 1.28.4 / 1.29.2 / 1.30.0. cozystack shipped
1.28.2, whose scale subresource has no selector, so the HPA fails with
`InvalidSelector`.

**Why 1.30.0 and not 1.28.4.** The floor is ≥ 1.28.4, but the upstream
chart repo publishes no chart for 1.28.4 (the 1.28 line stops at chart
0.27.1 / appVersion 1.28.1), so 1.28.4 could only be reached by
hand-patching the 0.27.1 chart's operator image and CRDs up to the
backport. A live PoC on a dev cluster proved that path is broken: the
1.28.4 operator running under the 0.27.1 (1.28.1) chart templates
crash-loops on a missing RBAC grant it needs but the older chart does
not provide — `endpointslices.discovery.k8s.io is forbidden: ... cannot
list resource "endpointslices"` — so `status.selector` is never
populated and the HPA still cannot scale. 1.30.0 (chart 0.29.0) is the
only published chart that carries the selector together with matching
RBAC/CRDs/templates, and the 1.28 line is EOL (2026-06-30), so 1.30.0
also keeps us on a supported release. cozystack uses the barman-cloud
plugin (not native barman, removed in 1.31) and no CNPG Poolers, so the
1.30 deprecations and the known pooler bug do not apply.

**Validation on a dev cluster (CNPG 1.30.0).** Operator rolls out clean
(no crashloop, the `endpointslices` RBAC error is gone); all existing
`Cluster` objects return to Ready; `/scale` now returns a populated
`status.selector` (`cnpg.io/cluster=<name>,cnpg.io/podRole=instance`);
an HPA pointed at a `Cluster` no longer reports `InvalidSelector`
(`AbleToScale=True, SucceededGetScale`); psql connectivity and streaming
replication verified.

The version-guard unittest is updated to 1.30.0 and now also asserts the
clusters CRD scale subresource carries `labelSelectorPath:
.status.selector`.

### Downstream repositories

Walked the trigger map in `docs/agents/contributing.md` against the
diff, file by file. The change touches only the vendored
`cloudnative-pg` operator chart (CRDs, RBAC, values), the package
`Makefile`, and the version-guard test. The `packages/apps/postgres` app
and its `version` enums are unchanged,
`packages/core/platform/values.yaml` is unchanged, and the
`clusters.postgresql.cnpg.io` CRD is not one the terraform provider
types by hand (it travels as opaque JSON). No downstream repository
restates anything this diff changes.

- [x] No downstream repository is affected by this change

### Release note

```release-note
fix(postgres-operator): bump CloudNativePG to 1.30.0 so the Cluster scale subresource serves status.selector, enabling HPA-driven read-replica autoscaling (previously the HPA failed with InvalidSelector on 1.28.2)
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Upgraded the CloudNativePG operator and Helm chart to 1.30.0/0.29.0.
* Added expanded image catalogs, pooler settings, pod selectors,
scheduling options, monitoring TLS, and LZ4 backup compression.
* Improved permissions for database roles, endpoint slices, and lease
monitoring.

* **Bug Fixes**
* Strengthened configuration validation and removed the deprecated
workload reference option.
  * Updated compatibility requirements to Kubernetes 1.29 or newer.

* **Documentation**
* Expanded installation, configuration, verification, upgrade, and
uninstall guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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 enhancement 🪄 New feature or request lgtm This PR has been approved by a maintainer ok to merge 👌 This PR can be merged release-1.28 size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Support the scale sub-resource for Clusters

10 participants