Skip to content

fix(keycloak): use barman-capable system image when backups enabled - #3306

Closed
Andrey Kolkov (androndo) wants to merge 2 commits into
mainfrom
fix/keycloak-backup-system-image
Closed

fix(keycloak): use barman-capable system image when backups enabled#3306
Andrey Kolkov (androndo) wants to merge 2 commits into
mainfrom
fix/keycloak-backup-system-image

Conversation

@androndo

@androndo Andrey Kolkov (androndo) commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Problem

The Keycloak DB backup added in #3174 uses the in-tree native spec.backup.barmanObjectStore, whose barman-cloud-* binaries ship only in the CloudNativePG system image variant. Since #2342 keycloak-db is pinned to the standard variant (17.7-standard-trixie), which omits those binaries — so with backups enabled:

LastBackupFailed: exec: "barman-cloud-backup": executable file not found in $PATH

Base backups fail and WAL archiving can't run (the latter also risks WAL accumulation blocking recycling). This is the keycloak facet of #3300.

Fix

In templates/db.yaml, pin the barman-capable system variant only when backups are enabled (backup.enabled + backup.destinationPath); otherwise keep standard. One-line variant switch, gated, fully documented inline.

Verification

On a freedom-portal cluster (CNPG 1.27, PostgreSQL 17.7):

  • standard-trixie + native barman → barman-cloud-backup: executable file not found (base backup fails).
  • system-trixie + native barman → CNPG Backup completed, LastBackupSucceeded=True, ContinuousArchiving=True, WAL archived to S3 (barman-cloud-wal-archive runs).

helm unittest 48/48 pass (incl. new tests/db_backup_image_test.yaml locking the variant gate: backups off → standard, on+destination → system, on+empty-destination → standard); helm template shows standard-trixie with backups off and system-trixie with backups on.

Note for air-gapped installs

Enabling backups now pulls a new tag, ghcr.io/cloudnative-pg/postgresql:17.7-system-trixie, reachable via a runtime backup.enabled flip. Mirrors that only carry 17.7-standard-trixie must also mirror 17.7-system-trixie, otherwise the first base backup fails on image pull.

Temporary bridge

system is deprecated in CNPG 1.27 (removed in 1.29). This is a stopgap so keycloak backups work today; it should be removed once Postgres backups migrate to the Barman Cloud Plugin — see #3300 (which covers the same issue for the cozy-default-cnpg strategy and apps/postgres).

Refs #3300, #2342, #3174.

Release note

fix(keycloak): pin the barman-capable CNPG `system` image for keycloak-db when backups are enabled

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved Keycloak database backup compatibility by dynamically selecting the correct PostgreSQL image variant when backups are enabled and a non-empty backup destination path is configured.
    • If the backup destination path is missing or empty, deployments continue using the standard database image and omit the backup object-store destination settings.
  • Tests
    • Added Helm test coverage to verify database image variant rendering based on backup enablement and destination path configuration.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a failure in Keycloak database backups where the 'standard' container image lacked the necessary Barman binaries. By dynamically switching to the 'system' image variant when backups are enabled, the fix ensures that base backups and WAL archiving function correctly. This is a temporary measure pending a migration to the Barman Cloud Plugin.

Highlights

  • Image Variant Selection: Updated the Keycloak database template to dynamically select the 'system' image variant when backups are enabled, ensuring the presence of required Barman binaries.
  • Conditional Logic: Implemented a conditional check that switches between 'system' and 'standard' image variants based on the configuration of backup settings.
  • Documentation: Added detailed inline comments explaining the necessity of the 'system' variant for native Barman backups and noting its temporary nature due to upcoming deprecation.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug labels Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Keycloak Postgres CNPG template selects the system image variant when backups have a non-empty destination path, retains standard otherwise, and adds Helm tests for these cases.

Changes

Keycloak CNPG backup image selection

Layer / File(s) Summary
Backup-aware image selection and validation
packages/system/keycloak/templates/db.yaml, packages/system/keycloak/tests/db_backup_image_test.yaml
The Helm template derives the image variant from backup configuration, and tests backup-disabled, configured-destination, and empty-destination rendering behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 3300 — Covers selecting the CNPG system image for Keycloak’s native Barman backups.

Possibly related PRs

Suggested reviewers: lexfrei, lllamnyp, sircthulhu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: selecting the barman-capable system image when backups are enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/keycloak-backup-system-image

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) backport Should change be backported on previous release labels Jul 15, 2026
@github-actions github-actions Bot added the size/S This PR changes 10-29 lines, ignoring generated files label Jul 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Keycloak database template to conditionally select the 'system' PostgreSQL image variant instead of 'standard' when backups are enabled, ensuring the availability of barman-cloud binaries. The review feedback highlights two important issues: a regex matching bug that bypasses the variant switch for non-17 PostgreSQL versions if the image already has a suffix, and potential template rendering errors from using Sprig's 'ternary' function with non-boolean values. The feedback suggests stripping the suffix first and using a standard 'if' block for safety.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +19 to +21
{{- $backupOn := and .Values.backup.enabled (not (empty .Values.backup.destinationPath)) }}
{{- $variant := ternary "system" "standard" $backupOn }}
imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-{{ $variant }}-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-%s-trixie" $image $variant }}{{ else }}{{ $image }}{{ end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two issues with the current implementation:

  1. Variant Switch Bypass: If $image already contains a suffix like -standard-trixie or -system-trixie (which is common for existing clusters or the default pinned image), the regex :[0-9]+\.[0-9]+$ will not match because of the trailing suffix. As a result, for any non-17 PostgreSQL version (e.g., 16.3-standard-trixie), the template will fall through to the else block and output {{ $image }} directly, meaning the variant will not be switched to system even when backups are enabled.
  2. Ternary Type Safety: Sprig's ternary function expects a strict bool as its third argument. If .Values.backup.enabled or .Values.backup.destinationPath evaluates to a non-boolean type (such as nil or a string), it can cause a template rendering error. Using a standard if block is safer and more idiomatic.

We can resolve both issues by stripping the existing suffix first to get a clean $baseImage, and using a standard if block to set the $variant.

  {{- $baseImage := regexReplaceAll "-(standard|system)-trixie$" $image "" }}
  {{- $variant := "standard" }}
  {{- if and .Values.backup.enabled .Values.backup.destinationPath }}
  {{- $variant = "system" }}
  {{- end }}
  imageName: {{ if regexMatch ":17\\." $baseImage }}ghcr.io/cloudnative-pg/postgresql:17.7-{{ $variant }}-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $baseImage }}{{ printf "%s-%s-trixie" $baseImage $variant }}{{ else }}{{ $image }}{{ end }}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/system/keycloak/templates/db.yaml`:
- Line 21: Update the image selection expression around imageName to recognize
existing -standard-trixie and -system-trixie suffixes, replace that variant with
$variant for non-17 images, and preserve any digest suffix. Keep the existing
special handling for PostgreSQL 17 and unchanged behavior for images without a
recognized PostgreSQL tag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c8937649-9b3f-405a-af2a-c6513e3e0016

📥 Commits

Reviewing files that changed from the base of the PR and between 77389d6 and 892bad8.

📒 Files selected for processing (1)
  • packages/system/keycloak/templates/db.yaml

*/}}
{{- $backupOn := and .Values.backup.enabled (not (empty .Values.backup.destinationPath)) }}
{{- $variant := ternary "system" "standard" $backupOn }}
imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-{{ $variant }}-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-%s-trixie" $image $variant }}{{ else }}{{ $image }}{{ end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Replace the variant on already-suffixed image tags.

The else if branch only matches bare tags such as :18.0. On a later reconciliation, lookup may return ...:18.0-standard-trixie; for non-17 versions this falls through to $image, so enabling backups still deploys the standard variant and Barman backups fail. Normalize existing -standard-trixie/-system-trixie suffixes and replace only the variant, preserving any digest if present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/system/keycloak/templates/db.yaml` at line 21, Update the image
selection expression around imageName to recognize existing -standard-trixie and
-system-trixie suffixes, replace that variant with $variant for non-17 images,
and preserve any digest suffix. Keep the existing special handling for
PostgreSQL 17 and unchanged behavior for images without a recognized PostgreSQL
tag.

The Keycloak DB backup (#3174) uses the in-tree native `barmanObjectStore`,
whose `barman-cloud-*` binaries ship ONLY in the CNPG `system` image variant.
Since #2342 the DB is pinned to the `standard` variant, which omits them — so
with backups enabled a base backup fails `barman-cloud-backup: executable file
not found` and WAL archiving cannot run (also risks WAL accumulation).

Pin the barman-capable `system` variant only when backups are enabled
(backup.enabled + destinationPath); otherwise keep `standard`. Verified on a
freedom-portal cluster: with `system-trixie` the CNPG Backup completes and WAL
archiving works to S3; with `standard-trixie` it fails as above.

TEMPORARY bridge: `system` is deprecated in CNPG 1.27 (removed in 1.29). Remove
this once Postgres backups migrate to the Barman Cloud Plugin — see #3300.

Refs #3300, #2342, #3174.

Signed-off-by: Andrey Kolkov <androndo@gmail.com>
@androndo
Andrey Kolkov (androndo) force-pushed the fix/keycloak-backup-system-image branch from 892bad8 to 0b10d4b Compare July 15, 2026 10:27
The image-variant switch in templates/db.yaml pins the barman-capable CNPG
`system` image exactly when native barmanObjectStore backups render; a
regression there silently drops backups to a barman-less `standard` image
(#3300). The package is otherwise covered by helm unittest, but db.yaml and
this new branching logic had none.

Add tests/db_backup_image_test.yaml locking input -> rendered spec.imageName:
backups off -> standard, enabled with a destination -> system, and enabled
with an empty destinationPath -> standard (the two-part gate). Each case also
asserts the barmanObjectStore block co-renders with the system image, so the
variant switch and the object-store gate cannot drift apart.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
@github-actions github-actions Bot added size/M This PR changes 30-99 lines, ignoring generated files and removed size/S This PR changes 10-29 lines, ignoring generated files labels Jul 15, 2026
@IvanHunters

Copy link
Copy Markdown
Collaborator

Verdict

LGTM with non-blocking notes

The image-variant switch is correctly root-caused, minimally scoped, gated byte-identically to the barmanObjectStore render, and test-locked; the only gap is a missing required release-note block.

Findings

[MINOR] PR body — missing required release-note fenced block

The PR body replaces the template with a custom Problem/Fix/Verification structure and drops the ### Release note section entirely, so no release-note fenced block is present. CONTRIBUTING / .github/pull_request_template.md require it. Add a filled block, e.g. fix(keycloak): pin the barman-capable CNPG system image for keycloak-db when backups are enabled. (The template's Downstream-repositories checklist was also dropped, but no downstream repo is affected by a packages/system/keycloak template change, so that part is immaterial.)

Caveats

  • Phase 5b/A (existing-customer upgrade): No migration script is required. The change is a pure template edit and the image swap is applied by the CNPG operator via rolling update, not by Helm state manipulation. Verified from the ternary at db.yaml:19-21: clusters with backup.enabled=false (the default and the majority) keep rendering 17.7-standard-trixie unchanged, so upgrade causes zero image churn for them. For a cluster that already had backups enabled (currently broken on standard), the upgrade flips imageName from 17.7-standard-trixie to 17.7-system-trixie, which triggers a CNPG rolling image change / primary switchover: a brief DB-connection blip for the IdP. This is the intended remediation, but operators should expect the switchover on the first reconcile after upgrade. The same switchover fires in reverse if backups are later disabled.
  • Phase 5b/B (fresh install): Verified no new _cluster/_namespace keys, no PackageSource/bundle/cozyrds/cert-manager/CRD surface touched, and values.yaml is untouched (so no make generate / values.schema.json drift). Fresh install with backups off renders standard (unchanged behaviour); with backups on renders system (author-verified on CNPG 1.27). Image pullability for air-gapped installs: the system variant is a new tag now reachable via a runtime backup.enabled flip; mirrors that pull only ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie will fail a base backup until 17.7-system-trixie is also mirrored. Worth documenting alongside the backup feature.
  • CNPG version: confirmed packages/system/postgres-operator appVersion is 1.27.1, so the system tag exists today; the inline TEMPORARY comment and #3300 reference correctly capture the CNPG-1.29 removal deadline, so the workaround's expiry is surfaced.

Recommended follow-ups

@androndo

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Addressed the [MINOR] finding: the PR body now carries the required release-note fenced block (fix(keycloak): pin the barman-capable CNPG system image for keycloak-db when backups are enabled). Also folded your air-gapped caveat into the body as a short "Note for air-gapped installs" (mirrors must carry 17.7-system-trixie once backups are enabled), and corrected the test count to 48/48 after the added db_backup_image_test.yaml.

The apps/postgres sibling case stays scoped to #3300 as noted — no change here.

@IvanHunters

Copy link
Copy Markdown
Collaborator

Verdict

LGTM with non-blocking notes

No blocking defects found after active falsification attempts (gate-disagreement renders, template mutation testing, full input-class enumeration of the imageName expression, upgrade/rollback tracing); two MINOR gaps remain, both non-blocking.

Findings

[MINOR] packages/system/keycloak/templates/db.yaml:21 - variant switch is silently skipped for every non-:17.* image class while the barman block still renders

Enumerated all input classes of $image (live spec.imageName via lookup, or the hardcoded default) through a harness chart. With backups enabled: :17.* images (any registry, any suffix, even digest-pinned) rewrite to 17.7-system-trixie; bare :X.Y images get -system-trixie appended; but suffixed non-17 images (16.9-standard-trixie, 18.1-standard-trixie), digest-only references (@sha256:...), :latest, and bare :17 (no minor) fall through unchanged. For those, spec.backup.barmanObjectStore (line 33) still renders against a barman-less image, reproducing the exact barman-cloud-backup: executable file not found failure this PR fixes, with no render-time signal. Reachability is narrow but not zero: migration 37 (packages/core/platform/images/migrations/migrations/37:63-66) rewrites bare non-17 tags to X.Y-standard-trixie on live clusters, which lands precisely in the else branch, and the migration's own comment anticipates :18.1. Today's chart-managed keycloak-db fleet is all :17.* (chart history only ever wrote nothing, :17.7, 17.7-standard-trixie), so this is a forward-looking gap, not a regression. Suggested minimal hardening: apply the variant substitution in the second branch's sibling case too (e.g. regexReplaceAll "-standard-" $image (printf "-%s-" $variant) in the else branch), or at least narrow the overclaiming comment in tests/db_backup_image_test.yaml:4-9 ("system image is present exactly when the barmanObjectStore renders" holds only for the :17. branch).

[MINOR] packages/system/keycloak/templates/db.yaml:9-18 and PR body - the rolling-restart side effect of toggling backup.enabled is not named

Flipping backup.enabled (either direction) now changes spec.imageName, which CNPG handles as a rolling update of keycloak-db (standby first, then primary switchover). The PR body's air-gapped note mentions the new image pull on a runtime flip but neither it nor the inline comment states that enabling/disabling backups now restarts the IdP database. Standard CNPG semantics and non-disruptive with 2 instances, but the tradeoff should be named for operators; one sentence in the values.yaml backup.enabled comment or the inline block would close it.

Claim mismatches

[PARTIAL] "pin the barman-capable system variant only when backups are enabled" - holds for all chart-managed image states, but not universally: the else-branch classes above keep their variant while backups still render (see Finding 1, harness outputs).

[UNVERIFIABLE] "system is deprecated in CNPG 1.27 (removed in 1.29)" - upstream sources do not confirm the 1.29 date. cloudnative-pg/postgres-containers README: system images "are deprecated and will be removed once in-core support for Barman Cloud in CloudNativePG is phased out" (no version named). CNPG 1.27 backup docs: barmanObjectStore "deprecated starting with v1.26", removal "in a future release". The inline comment's "deprecated in CNPG 1.27" is also off by one minor (deprecation landed in 1.26). Cosmetic, but worth correcting the comment so the removal trigger is not tied to a version number upstream has not committed to.

Caveats

  • Gate lockstep verified two ways: (a) six adversarial helm template renders (destinationPath as bool true, number 0, string "0", null; enabled as string "false" and number 1) - the variant gate (line 19) and the barman render gate (line 33) agreed in every case; (b) semantically, Go-template truthiness coincides with not (empty x) for every YAML-representable type, so the two gates cannot disagree. The (not (empty ...)) spelling is redundant relative to line 33's bare form but harmless.
  • Test non-vacuity verified by mutation: three template mutations (variant forced to always-standard, always-system, gate reduced to enabled only) each flip the new suite to FAIL (1-2 failing tests). Branches 2 and 3 of the imageName expression are not covered and cannot be: helm-unittest provides no way to stub lookup, so $existingCluster is always nil in tests. Inherent framework gap, documented here rather than fixable in the PR.
  • Existing-customer upgrade (Phase 5b-A): no migration script needed - the flip happens at Helm render, spec.imageName is mutable (proven in-tree: migration 37 kubectl-patches it on live clusters), and standard-to-system at the same 17.7 is a plain CNPG rolling update with no data-compat or major-version-guard concern. Customers below platform version 37 upgrading with backups on get two image changes (migration 37 pins standard-trixie, then the HR render flips to system) - transient, converges. Backups-off clusters render a byte-identical image string, zero churn. Rollback is clean: the previous chart's expression maps 17.7-system-trixie back to 17.7-standard-trixie (branch 1 match), no one-way state.
  • Fresh install (Phase 5b-B): defaults unchanged (backups off, standard). Backups-on fresh install pulls ghcr.io/cloudnative-pg/postgresql:17.7-system-trixie - verified pullable (manifest HTTP 200 on ghcr.io). No in-repo mirror list needs updating: hack/nightly-mirror.sh covers cozystack-owned images only; the PR-body air-gapped note is the correct vehicle. Shipped CNPG operator is 1.27.1 (packages/system/postgres-operator/charts/cloudnative-pg/Chart.yaml), where both the system variant and native barmanObjectStore still function.
  • Sibling scan: harbor, seaweedfs-db, monitoring (grafana/alerta) share the same imageName expression but none of them render barmanObjectStore, so no sibling needs the same fix; the apps/postgres facet is explicitly deferred to CNPG backups broken on 1.6: standard image variant lacks barman-cloud but backups use native barmanObjectStore #3300.
  • The bootstrap chart-lint render error (index of untyped nil on _cluster) is the known runtime-injected cozystack-values artifact, not a defect in this PR.
  • Chart has no values.schema.json (system-tier package), and the PR touches no values.yaml/Chart.yaml, so no make generate obligation. Release-note block present.

Recommended follow-ups

@IvanHunters

Copy link
Copy Markdown
Collaborator

Cluster-side validation (dev3, CNPG operator 1.27.3)

Tested the fix live in an isolated throwaway namespace (did not touch the live keycloak-db). Summary: the fix behaves as claimed, and the root-cause failure is reproducible on the old image.

Negative control (the cleanest proof). Same Cluster with barmanObjectStore enabled but imageName forced back to 17.7-standard-trixie: the WAL archiver fails immediately, before any network call, with

unexpected failure invoking barman-cloud-wal-archive: exec: "barman-cloud-wal-archive": executable file not found in $PATH

which is verbatim the failure this PR fixes.

On 17.7-system-trixie (rendered when backups are on): barman-cloud-backup, barman-cloud-wal-archive, and barman-cloud-check-wal-archive are all present in /usr/local/bin/, and CNPG invokes the archiver with the expected flags. A Backup CR (method: barmanObjectStore) reached running and genuinely called barman-cloud-backup; it did not reach completed, but only because the dev3 in-cluster S3 (SeaweedFS) had exhausted its volume pool (Max:18, Free:0) and could not allocate a volume for the new bucket. That is a dev3 infra limit, not a code issue.

Render / gate / upgrade. Backups off renders 17.7-standard-trixie unchanged (no regression); backups on renders 17.7-system-trixie + barmanObjectStore. helm unittest passes 48/48; inverting the ternary makes the new suite fail (the gate is real, not cosmetic). The standard -> system image flip was a clean CNPG rolling update (~30s, no wedge).

CNPG deprecation, confirmed live. The admission webhook on apply warned: Native support for Barman Cloud backups and recovery is deprecated and will be completely removed in CloudNativePG 1.29.0 — a direct confirmation of the inline TEMPORARY comment and the #3300 removal path.

One additional MINOR (operational, not a defect in this PR)

Since this PR activates the barmanObjectStore path for keycloak-db: CNPG/barman-cloud has no hard timeout on the exec'd archiver process. If the S3 backend is unreachable or slow, barman-cloud-wal-archive holds up pg_ctl stop, so it delays any subsequent cluster change, not just backups. In testing, a restart on a stuck S3 endpoint hung ~5 minutes (until smart escalated to fast) instead of ~30s. Worth a note for operators, alongside the existing air-gapped and rolling-restart caveats.

@androndo Andrey Kolkov (androndo) added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress label Jul 16, 2026
Andrey Kolkov (androndo) added a commit that referenced this pull request Jul 16, 2026
The keycloak-db backup added in #3174 uses the in-tree native
spec.backup.barmanObjectStore, whose barman-cloud-* binaries ship only in the
CNPG system image variant; keycloak-db is pinned to the standard variant, so
base backups fail with 'barman-cloud-backup: executable file not found'. The
proposed workaround (#3306) switches keycloak-db to the deprecated system image
variant when backups are enabled.

Migrate keycloak-db to the barman-cloud plugin instead, matching the rest of
this PR: render spec.plugins referencing a barmancloud.cnpg.io ObjectStore (the
S3/barman config moves there) and a method=plugin ScheduledBackup, keeping the
Cluster on the standard image (the plugin runs the barman tooling in a sidecar).
This removes the need for the system-variant workaround entirely, so #3306 can
be closed. #3300.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Andrey Kolkov (androndo) added a commit that referenced this pull request Jul 16, 2026
The keycloak-db backup added in #3174 uses the in-tree native
spec.backup.barmanObjectStore, whose barman-cloud-* binaries ship only in the
CNPG system image variant; keycloak-db is pinned to the standard variant, so
base backups fail with 'barman-cloud-backup: executable file not found'. The
proposed workaround (#3306) switches keycloak-db to the deprecated system image
variant when backups are enabled.

Migrate keycloak-db to the barman-cloud plugin instead, matching the rest of
this PR: render spec.plugins referencing a barmancloud.cnpg.io ObjectStore (the
S3/barman config moves there) and a method=plugin ScheduledBackup, keeping the
Cluster on the standard image (the plugin runs the barman tooling in a sidecar).
This removes the need for the system-variant workaround entirely, so #3306 can
be closed. #3300.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Andrey Kolkov (androndo) added a commit that referenced this pull request Jul 21, 2026
<!-- Thank you for making a contribution! Here are some tips for you:
- Use Conventional Commits for the PR title: `type(scope): description`
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
- Scopes are not an exhaustive list — pick the most specific scope for
the change and extend the list when a genuinely new area appears.
Examples:
- System components: dashboard, platform, operator, cilium, kube-ovn,
linstor, fluxcd, cluster-api
- Managed apps: postgres, mariadb, redis, kafka, clickhouse,
virtual-machine, kubernetes
- Development and maintenance: api, hack, tests, ci, docs, maintenance
- Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or
add a `BREAKING CHANGE:` footer
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->


## What this PR does

Fixes #3300. Migrates CNPG Postgres backups off the deprecated native
`spec.backup.barmanObjectStore` (removed in CNPG 1.29; the
`barman-cloud-*` binaries it needs are absent from the `standard` image
variant keycloak-db pins, and the bare system-flavor tags apps/postgres
pins are deprecated upstream) onto the [CloudNativePG Barman Cloud
plugin](https://github.com/cloudnative-pg/plugin-barman-cloud), across
every Postgres backup surface: `apps/postgres`, `system/keycloak`, and
the `cozy-default-cnpg` BackupClass strategy driver. The chart renders
`spec.plugins` + a `barmancloud.cnpg.io/ObjectStore` CR; the
backup-controller driver SSA-applies an `ObjectStore` and patches
`spec.plugins`; `Backup`/`ScheduledBackup` use `method: plugin`. The
`postgres-operator` chart vendors and co-locates the
`plugin-barman-cloud` operator (with its cert-manager-issued mTLS) so
CNPG can discover it.

One platform-level change is required for the plugin to run and ships
with this PR (see the upgrade notes in
`docs/operations/backup-classes.md` and the release note below): the
CloudNativePG operator is bumped to 1.28.1 (also fixing an operator/CRD
version skew that broke all backups). The other prerequisite — the
LINSTOR scheduler admission webhook stripping
`initContainers[].restartPolicy` cluster-wide, which broke the plugin's
restartable sidecar — is already fixed on `main` (f4aef73 re-vendors
`linstor-scheduler` to upstream chart 0.3.1 / extender v0.3.6, which
keeps the webhook and stops stripping unknown pod fields), so after the
rebase this PR no longer touches `linstor-scheduler`; just do not hold
that package back on an older version when rolling out the plugin.

Supersedes #3306 (the keycloak `system`-image workaround): keycloak-db
now backs up via the plugin on the `standard` image, so that stopgap is
no longer needed.

### Screenshots

<!-- REQUIRED for UI changes: attach screenshots or screen recordings
demonstrating
the visual impact of your changes. PRs with UI changes without
screenshots will not be merged. -->

### Downstream repositories

<!--
Cozystack is upstream for repositories that are NOT kept in sync with it
automatically, and nothing in CI compares the two sides, so a change
here can break them silently.

Which change forces what, and which file to touch, is the trigger map in
docs/agents/contributing.md under "Downstream Repositories". Walk it
before you tick anything.

IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM
TO FILL IN:

1. Walk the trigger map against the actual diff of this PR, file by
file. Do not decide from the PR title or from your memory of what you
changed.
2. For every repository you tick, open the follow-up PR there and link
it on the same line. A ticked box with no link claims work that does not
exist, which is worse than an empty box. Search that repository for an
open PR or issue covering it first, and link that instead of filing a
duplicate.
3. When the follow-up is out of scope, or needs a decision that is not
yours to make, open an issue in that repository instead, link that, and
say so in the PR body. Do not push a speculative PR into another
repository just to fill a line here.
4. Do not tick "No downstream repository is affected" to make the
checklist go away. If you are unsure, leave every box empty and say so
in the PR body, so a human decides.
-->

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up: docs/operations/backup-classes.md changed; a website mirror
follow-up is warranted (not yet opened).
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:

### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same `type(scope):` prefix as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
fix(backups): migrate CNPG Postgres backups to the CloudNativePG Barman Cloud plugin

Postgres backups (apps/postgres, system/keycloak, and the cozy-default-cnpg BackupClass strategy) now use the CloudNativePG Barman Cloud plugin (spec.plugins + a barmancloud.cnpg.io/ObjectStore, method: plugin) instead of the deprecated native spec.backup.barmanObjectStore (removed in CNPG 1.29; the barman-cloud-* binaries it needs are absent from the standard image variant keycloak-db pins, and the bare system-flavor tags apps/postgres pins are deprecated upstream). The barman-cloud plugin operator is installed alongside the CNPG operator.

One platform-level change rides along and requires operator attention on upgrade:
- The CloudNativePG operator is bumped to 1.28.1 (fleet-wide minor upgrade); this also fixes an operator-newer-than-its-CRDs skew that made the operator report "instance manager was restarted during backup" and fail every backup. The vendored chart ships the CNPG CRDs as ordinary release manifests (crds.create), so helm upgrade updates them with the operator; the skew came from the image.tag pin outrunning the chart's CRDs, which this PR removes.
- The plugin's restartable sidecar requires the linstor-scheduler admission webhook that no longer strips initContainers[].restartPolicy (upstream chart 0.3.1 / extender v0.3.6, shipped separately on main); do not hold the linstor-scheduler package back on an older version when rolling out the plugin.
```

Close #3300, #3246

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

* **New Features**
* Switched PostgreSQL CNPG backups/restores to the plugin-based Barman
Cloud workflow, using dedicated ObjectStore resources for backup and
recovery.
* Added the Barman Cloud CNPG-I plugin chart (deployment, TLS, RBAC,
leader election).
* **Bug Fixes**
* Improved backup/restore attachment messaging when the CNPG Cluster
isn’t ready yet.
* Preserves server-name behavior to avoid WAL-archive prefix issues;
clarified endpoint CA handling.
* **Changes**
* Helm integration no longer uses the legacy
`spec.backup.barmanObjectStore` path; updated gating, credential
projection, and ObjectStore-related RBAC/cleanup.
* Removed the linstor-scheduler admission webhook; updated
CloudNativePG/operator versions and CRDs.
* **Tests**
* Updated controller and Helm-unittest checks for the plugin flow;
added/extended end-to-end backup/restore coverage.
* **Documentation**
* Expanded upgrade/migration and backup documentation; updated backup
example materials and comments.
<!-- 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

area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review backport Should change be backported on previous release do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress kind/bug Categorizes issue or PR as related to a bug size/M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants