Repository navigation
Conversation
Contributor
|
❗ By default, the pull request is configured to backport to all release branches.
|
Member
|
/test |
Contributor
|
@mnencia, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/24845281640 |
Member
|
/test |
Contributor
|
@armru, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/25119501627 |
Member
|
/test |
Contributor
|
@armru, here's the link to the E2E on CNPG workflow run: https://github.com/cloudnative-pg/cloudnative-pg/actions/runs/25373433733 |
NiccoloFei
force-pushed
the
dev/10049
branch
4 times, most recently
from
May 20, 2026 11:59
1d4d57c to
520748a
Compare
Signed-off-by: Niccolò Fei <[email protected]>
Setting PATH and LD_LIBRARY_PATH in the container spec clobbers the image defaults and any custom values, breaking command resolution for system binaries like cp and pg_config. Move the env setup to the upgrade execute command at runtime, appending extension paths to the existing environment, consistent with how buildPostgresEnv handles it for running instances. Signed-off-by: Marco Nenciarini <[email protected]>
The upgrade pod was reconstructing the new-version extension list by cloning Status.PGDataImageInfo.Extensions and prepending the "upgrade-target-" prefix. That only worked when the target image's layout matched the source image's; any divergence in LdLibraryPath, BinPath, ExtensionControlPath, or DynamicLibraryPath left LD_LIBRARY_PATH/PATH (setupExtensionEnvironment) and the new-pgdata extension_control_path/dynamic_library_path GUCs (prepareConfigurationFiles) pointing at paths that don't exist. Persist the reconciler's catalog-resolved extension list in a new Status.TargetPGDataImageInfo field, set before the upgrade Job is created and cleared on completion or rollback. The pod reads from there instead of guessing. Signed-off-by: Marco Nenciarini <[email protected]>
pg_upgrade starts both old and new PostgreSQL servers, but setupExtensionEnvironment only extended LD_LIBRARY_PATH and PATH. Any extension providing custom Env entries (e.g. PYTHONPATH for plpython, PERL5LIB for plperl) saw them applied by buildPostgresEnv during steady state but silently dropped during the upgrade. Move setExtensionEnvVars from pkg/management/postgres to pkg/utils/extensions as the exported SetEnvVars. buildPostgresEnv keeps calling it; setupExtensionEnvironment now calls it too, operating on an envmap.EnvironmentMap that is written back to the process env so child servers inherit the values. Signed-off-by: Marco Nenciarini <[email protected]>
PostgreSQL 19+ emits an update_extensions.sql script when the target cluster has extensions whose default_version is newer than the version pg_upgrade left installed. Until the script runs, pg_catalog metadata stays at the old version and SQL-level extension objects can diverge from the loaded .so. The script currently survives moveDataInPlace and lands in pgData, but nothing tells the user it's there. Log its presence and path when the upgrade completes, so the DBA can apply the updates manually. Signed-off-by: Marco Nenciarini <[email protected]>
Prefixing target-version extension names with upgrade-target- left a collision class: a cluster with an extension named upgrade-target-foo clashed with the prefixed copy of foo during a major upgrade. Move the distinction from the extension name to the volume name and mount path. Target-version extensions become new-<name> mounted under /new-extensions, which cannot overlap with ext-<name> for any user-chosen extension name. Also lifts the name length cap from 44 to 59. Signed-off-by: Marco Nenciarini <[email protected]>
…nment Three previously-separate commits all touched the upgrade pod's setupExtensionEnvironment helper. Squashed together because they together leave the function in a coherent state and individually they were small reviewer pieces that no longer need separate atomicity in git history. * Treat both `Status.PGDataImageInfo == nil` and `Status.TargetPGDataImageInfo == nil` as contract violations and surface them as errors. The reconciler refuses to schedule a major upgrade unless `PGDataImageInfo` is set, so an upgrade Job pod observing nil indicates a violated invariant - not a "no extensions" case to silently skip. * Surface `envmap.Parse` failures: it returns a partial map plus an error if any entry is malformed, and we were discarding the error. Log a warning and proceed with the entries that did parse so a malformed runtime env does not silently drop entries. * Iterate envMap deterministically before calling os.Setenv. Go map iteration is randomized, which made log output non-reproducible and meant a partial os.Setenv failure left the process environment in a different shape on each retry, complicating debugging. Signed-off-by: Armando Ruocco <[email protected]>
When a user requests a major version upgrade, reconcileImage Case 3 sets Status.Image to the new image but leaves PGDataImageInfo unchanged. If the user then reverts the spec before the upgrade Job is created, the next reconcileImage invocation compares the reverted spec against PGDataImageInfo.Image (now matching) and short-circuits at Case 2 without resetting Status.Image. The result: Status.Image stays pointing at the upgrade target indefinitely, and any pod the reconciler creates in that window pulls the wrong image. Reset Status.Image to PGDataImageInfo.Image in the early-return path of majorupgrade.Reconcile, mirroring the reset already done by handleRollbackIfNeeded once the Job exists. The two patches are batched so a no-op rollback (no target persisted, image already correct) issues no API call. The clearing logic is extracted into a `clearStaleUpgradeTarget` helper so the early-return remains a single-line guard plus one call and the conditional patch composition lives somewhere with a dedicated godoc explaining when each branch fires. Signed-off-by: Armando Ruocco <[email protected]>
The configuration generator already branched on
OperationType_TYPE_UPGRADE to choose the mount base directory, but the
extension list itself was still read from
Status.PGDataImageInfo.Extensions regardless. The upgrade caller had
to deep-copy the cluster and overwrite PGDataImageInfo.Extensions with
TargetPGDataImageInfo.Extensions on the copy so the loop would pick up
the right entries - a leaky pattern that left two coupled pieces of
"use new extensions" knowledge spread across caller and callee.
Move the selection into a single helper inside the config generator:
upgrade mode reads from TargetPGDataImageInfo, steady-state reads from
PGDataImageInfo, and a missing TargetPGDataImageInfo during upgrade is
now an explicit error rather than a silent fallback. The caller in
prepareConfigurationFiles shrinks accordingly; an inline comment
points readers at the helper that owns the OperationType-based
branching.
Two follow-on cleanups land alongside:
* Rename the local `extensions` in Reconcile and createMajorUpgradeJob
to `targetExts`. It was shadowing the imported package of the same
name; both functions only happened to compile because no remaining
code in those scopes called `extensions.X` from the package.
* Strengthen the godoc on selectAdditionalExtensions to spell out the
caller invariant ("TYPE_UPGRADE callers MUST populate
TargetPGDataImageInfo first") so future TYPE_UPGRADE consumers
(plugin hooks, restoration jobs) preserve it.
Signed-off-by: Armando Ruocco <[email protected]>
…and Event PostgreSQL 19+ emits an update_extensions.sql script in PGDATA when the target cluster has extensions whose default_version is newer than what pg_upgrade installed. Until the script runs, pg_catalog metadata diverges from the loaded shared libraries. The previous approach (logging it to the upgrade Job's stdout) lost the message within seconds: the operator deletes the Job with foreground propagation on completion, taking pod logs with it. Make the signal durable and visible to monitoring: * Add ClusterConditionType `MajorUpgradeExtensionUpdatesPending` and ConditionReason `ExtensionUpdatesPending` to the API. * From inside `instance upgrade execute`, when the script is detected after a successful upgrade, set the condition to True with a Message field naming the in-pod path AND the primary pod name (since the path is only reachable via `kubectl exec`) plus a reminder that the script must be applied in every database that uses the affected extensions. * Clear the condition at the start of the next major upgrade so a stale message from a prior upgrade does not survive into a later one that might not emit the script. * From `majorVersionUpgradeHandleCompletion`, after the completion patch lands and syncs server-side conditions back into the in-memory cluster, emit a Warning Event using the same Reason and the condition's Message. The condition is the durable signal, the Event is the ephemeral counterpart that monitoring/alerting pipelines watching `kubectl get events` will pick up. The patcher function itself is named `recordPendingExtensionUpdates` to reflect that its primary effect is persisting state on the Cluster object (logging is secondary). Tests cover both the firing case and the absence case so we do not spam Events on every successful upgrade. Signed-off-by: Armando Ruocco <[email protected]>
… manifests The 59-character upper bound on ExtensionConfiguration.Name had no context next to it, but it is load-bearing: the operator embeds the sanitized name in Kubernetes Volume names that must fit RFC 1123's 63-character label limit, and the four-character "ext-" / "new-" prefixes (steady state and major upgrade respectively) consume the other four characters. Document the math at all three sites: the kubebuilder marker, the steady-state volume namer, and the upgrade-target volume namer. A future change to either prefix now has a paper trail back to the API constraint that must move with it. Includes the deterministic regen output from `make manifests` and `make apidoc` propagating the godoc into CRD descriptions and the rendered API reference. Signed-off-by: Armando Ruocco <[email protected]>
Document major-upgrade extension behavior that previously lived only in code and commit messages: * Dual mount layout: source-version extensions stay at /extensions/<name> while target-version copies are mounted at /new-extensions/<name>, so pg_upgrade can dump from the old server and restore into the new one without either set's libraries going missing. * Custom-env precedence: LD_LIBRARY_PATH and PATH are extended with both sets, but extensions[].env entries follow last-writer-wins; the target copy applies after the source copy. Operators that need the source-version semantic to survive the upgrade window should use distinct variable names per major version (PYTHONPATH_PG15 / PYTHONPATH_PG16) rather than relying on ordering. * update_extensions.sql post-upgrade workflow: explain the new MajorUpgradeExtensionUpdatesPending cluster condition, where the script path is published, the in-pod nature of the path (PGDATA is mounted on the pod, not the host), and provide both a self-contained `psql -f` form and a per-database loop using pg_database. The script semantics are hedged because PostgreSQL 19's emitted form may contain `\connect` directives covering every database; review the script and pick the appropriate invocation. The operator clears the condition automatically at the start of the next major upgrade; manual `kubectl edit` shown for clearing it sooner. Wordlist additions for `prepends` and `TTY` to satisfy spellcheck. Signed-off-by: Armando Ruocco <[email protected]>
The branch ships five interlocking fixes for major upgrades when image-
volume extensions are in play. Each subsystem gets unit coverage so
regressions in any individual layer fail fast.
* `pkg/utils/extensions`: pin the cross-call merge semantics that
setupExtensionEnvironment relies on during a major upgrade -
${image_root} expands against the call-specific baseDir, and a
target-version env var overrides a same-named source-version one.
Direct coverage for AppendPaths (empty existing, empty extra, both
empty, multi-element extra) and for CollectLibraryPaths /
CollectBinPaths path normalization.
* `pkg/management/postgres`: cover selectAdditionalExtensions across
steady state, upgrade, missing-target-during-upgrade error, and
missing-PGDataImageInfo cases.
* `pkg/reconciler/majorupgrade`: cover Reconcile's early-revert path -
clears stale TargetPGDataImageInfo, resets stale Status.Image, and
skips the API call when there is nothing to change. Cover
handleRollbackIfNeeded clearing TargetPGDataImageInfo on rollback
after the Job exists. Cover the Event-firing case at completion
(when the upgrade pod recorded the pending-updates condition) and
the absence case so we do not spam Events on every successful
upgrade.
* `pkg/resources/status`: pkg had unit coverage for
SetClusterReadyCondition, SetPhase, SetImage, SetPGDataImageInfo,
and SetTimelineID, but neither SetTargetPGDataImageInfo (added
earlier in this branch) nor the new RemoveCondition transaction had
any. Add table-style tests for both, including the no-op paths
(clearing a nil target, removing an absent condition, removing from
a nil conditions slice).
* `internal/cmd/manager/instance/upgrade/execute`: pkg had no tests at
all; the recent additions to it - the setupExtensionEnvironment
contract checks and recordPendingExtensionUpdates - were riding on
integration tests for the underlying helpers plus build/vet.
setupExtensionEnvironment's two error paths (missing PGDataImageInfo,
missing TargetPGDataImageInfo) and the no-extensions happy path are
pinned. recordPendingExtensionUpdates covers no-op-when-script-absent,
condition set with expected Type/Reason/Message including the script
path and pod name and "kubectl exec" hint and per-database reminder,
and the file-check error path.
* `pkg/postgres`: the earlier "fix: apply extension custom env vars
during upgrade" added a baseDir argument to ExpandEnvPlaceholders,
pushing two of its test invocations past golangci-lint's 120-column
limit. Wrap the shared call in a closure so each test reads as one
assertion rather than one long line; behavior is identical.
Signed-off-by: Armando Ruocco <[email protected]>
PatchConditionsWithOptimisticLock retries on conflict but bubbles up other transient errors (network blips, throttling, 5xx). The upgrade Job pod is deleted seconds after recordPendingExtensionUpdates returns because the operator tears the Job down with foreground propagation, so any failure that lost the patch ALSO took the pod log with it - the DBA would have no signal that update_extensions.sql is sitting in PGDATA waiting for them. Wrap the patch in retry.OnError with a new IsTransientAPIError predicate (added to pkg/resources/retry alongside the existing RetryAlways) covering Conflict, ServerTimeout, request Timeout, TooManyRequests, ServiceUnavailable, and InternalError. Permanent errors (Forbidden, Unauthorized, NotFound, BadRequest) still fail fast so misconfiguration does not burn the backoff budget. Tests cover both the predicate (DescribeTable for retriable + permanent error families) and the call site (interceptor returns ServiceUnavailable for the first two attempts and the patch eventually succeeds with the condition set; permanent error fails on the first attempt with no retry). Signed-off-by: Armando Ruocco <[email protected]>
Drop tests that exercise stdlib or Go-language semantics rather than the wrapper's own logic, and the micro-optimization in setupExtensionEnvironment that gated each os.Setenv call on a pre-call clone of the env map. * pkg/resources/status/transactions_test.go: drop "overwrites existing" cases for SetPhase, SetImage, SetPGDataImageInfo - they verify Go's = operator on a struct field. Drop SetTimelineID "resets to 1 after major upgrade" - identical body to "sets the cluster timeline ID" with a different value, and the name implied upgrade-awareness the helper does not have. Drop RemoveCondition "is a no-op on a nil conditions slice" - tests meta.RemoveStatusCondition's nil-safety, not ours. * pkg/resources/retry_test.go: shrink the IsTransientAPIError table from twelve entries to six. One representative entry per family (conflict, 5xx, internal; vs forbidden, validation, nil) pins the contract; the rest duplicated client-go's coverage of the apierrors helpers. * pkg/utils/extensions/extensions_test.go::AppendPaths: eight assertions across an eight-line helper with three branches. Keep one assertion per branch. * internal/cmd/manager/instance/upgrade/execute/cmd.go: drop the maps.Clone(envMap) + per-key delta-skip in setupExtensionEnvironment. os.Setenv on the ~100 entries we touch costs microseconds; the optimization saved nothing observable. The deterministic sorted iteration is preserved - that is the real reproducibility win the surrounding code wanted. Net -82 lines, no behavior change. make checks clean except for the pre-existing histogram.go gosec finding. Signed-off-by: Armando Ruocco <[email protected]>
Signed-off-by: Niccolò Fei <[email protected]>
This condition should be made generic and should not be strictly tied with major upgrades. The idea is to move it to its own patch and re-implement it to notify about extensions updates availability, covering also standard extension updates instead of firing the condition only during major upgrades. We could interrogate pg_catalog directly instead of relying on the presence of update_extensions.sql. Signed-off-by: Niccolò Fei <[email protected]>
Signed-off-by: Niccolò Fei <[email protected]>
The ext-/new- volume-name prefixes are why ExtensionConfiguration.Name is capped at MaxLength=59. Assert a max-length name still yields an RFC 1123 compliant volume name through both sanitizers, and check the prefixes rather than a single hand-picked name for disjointness. Signed-off-by: Marco Nenciarini <[email protected]>
The derivation, internal function names and maintainer note belong with the code: the prefix-vs-MaxLength accounting already lives in pkg/specs.SanitizeExtensionNameForVolume and is now enforced by a test. Keep the CRD field description to the user-facing constraint. Signed-off-by: Marco Nenciarini <[email protected]>
Signed-off-by: Gabriele Bartolini <[email protected]>
When a major upgrade `Job` completed, the operator recorded the upgraded cluster's extension set by re-resolving it from the image catalog. A catalog change made after the Job started (for example an `ImageCatalog` edit) could make that resolution fail and push the cluster into `PhaseImageCatalogError`, even though `pg_upgrade` had already physically rebuilt `PGDATA` against the previously resolved set. Carry forward the extension set that `Reconcile` resolves and persists in `Status.TargetPGDataImageInfo` before creating the Job: that is the exact set the Job mounted and `pg_upgrade` built against, so it is authoritative at completion time. When the field is absent — a Job created by an older operator and completing across an operator upgrade — completion falls back to resolving from the catalog, preserving the previous behavior. Assisted-by: Claude Signed-off-by: Gabriele Bartolini <[email protected]>
cnpg-bot
pushed a commit
that referenced
this pull request
Jun 16, 2026
…10366) This patch, together with the `pg_upgrade` extension support committed into PostgreSQL 19 (https://commitfest.postgresql.org/patch/6562/), enables in-place major upgrades via `pg_upgrade` for clusters that use Image Volume extensions. During the upgrade `Job`, the source-version and target-version extension images are mounted side by side. Source-version extensions stay at the steady-state `/extensions/<name>` path, so the old server keeps its existing shared libraries and a failed upgrade reverts cleanly. Target-version extensions are mounted under a dedicated `/new-extensions/<name>` tree with a distinct `new-` volume-name prefix, so the two sets never collide regardless of the extension name. The new `PGDATA` is configured with `dynamic_library_path` and `extension_control_path` pointing at the `/new-extensions` mounts. `LD_LIBRARY_PATH`, `PATH` and each extension's custom environment variables are provided for both sets, with target-version entries applied after source-version ones. When the target extensions ship a newer default version than the one `pg_upgrade` leaves installed, `pg_upgrade` writes an `update_extensions.sql` script into the primary `PGDATA`. The operator logs its location so it can be applied once the cluster is back online. Closes #10049 Assisted-by: Claude Signed-off-by: Niccolò Fei <[email protected]> Signed-off-by: Marco Nenciarini <[email protected]> Signed-off-by: Armando Ruocco <[email protected]> Signed-off-by: Gabriele Bartolini <[email protected]> Co-authored-by: Marco Nenciarini <[email protected]> Co-authored-by: Armando Ruocco <[email protected]> Co-authored-by: Gabriele Bartolini <[email protected]> (cherry picked from commit ca62cc5)
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 -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This patch, together with the
pg_upgradeextension support committed into PostgreSQL 19 (https://commitfest.postgresql.org/patch/6562/), enables in-place major upgrades viapg_upgradefor clusters that use Image Volume extensions.During the upgrade
Job, the source-version and target-version extension images are mounted side by side. Source-version extensions stay at the steady-state/extensions/<name>path, so the old server keeps its existing shared libraries and a failed upgrade reverts cleanly. Target-version extensions are mounted under a dedicated/new-extensions/<name>tree with a distinctnew-volume-name prefix, so the two sets never collide regardless of the extension name.The new
PGDATAis configured withdynamic_library_pathandextension_control_pathpointing at the/new-extensionsmounts.LD_LIBRARY_PATH,PATHand each extension's custom environment variables are provided for both sets, with target-version entries applied after source-version ones.When the target extensions ship a newer default version than the one
pg_upgradeleaves installed,pg_upgradewrites anupdate_extensions.sqlscript into the primaryPGDATA. The operator logs its location so it can be applied once the cluster is back online.Closes #10049
Assisted-by: Claude