Skip to content

fix(postgres): run init-job in main phase and wait for the superuser secret - #3923

Closed
IvanHunters wants to merge 2 commits into
mainfrom
fix/postgres-init-job-superuser-race
Closed

IvanHunters wants to merge 2 commits into
mainfrom
fix/postgres-init-job-superuser-race

Conversation

@IvanHunters

Copy link
Copy Markdown
Collaborator

What this PR does

Fixes #3921.

The postgres chart's <release>-init-job (the users/databases/roles reconciler) mounted the CNPG-managed <release>-superuser secret as a post-install,post-upgrade Helm hook. That secret is created asynchronously by the operator, which caused two problems:

  • On a fresh install the hook Pod raced the operator and hit FailedMount / CreateContainerConfigError, and Helm blocks on hook completion, so a slow CNPG bootstrap could burn the hook timeout and roll the release back.
  • As a post-upgrade hook the Job never ran while the release was UpgradeFailed, so role/database convergence silently stopped until the release recovered.

This is the same anti-pattern already addressed in apps/kubernetes (talos-reconcile #3145, bootstrap-token #3875 / #3887), tracked by the umbrella #2497.

Change

  • Move the Job out of the Helm hook lifecycle into a main-phase resource.
  • Gate it with a wait-for-superuser init container behind an optional: true secret volume, so the Pod waits in the init phase until the operator publishes the secret instead of failing the mount. The init container polls the mounted file (no API access, no RBAC), with a deadline below the HelmRelease install timeout so a stuck bootstrap surfaces as CrashLoopBackOff.
  • Give the Job a content-hash name suffix, because a main-phase immutable Job cannot be patched in place across revisions.
  • Preserve the bootstrap.recovery skip and the ttlSecondsAfterFinished GC.

Out of scope: this PR does not add helm-install-disable-wait to the postgres AppDef, so a main-phase Job still gates release readiness the same way the hook did. Changing readiness semantics is a broader decision left to a separate discussion.

Existing installs

An upgrade replaces the old hook Job (<release>-init-job) with a new main-phase Job (<release>-init-job-<hash>). The old hook Job is no longer managed by the release, but it self-collects via its existing ttlSecondsAfterFinished once finished.

Downstream repositories

  • No downstream repository is affected by this change

The diff only touches the chart's Job template and its unit test; values.yaml, the values schema, and CRDs are unchanged, so no downstream repository tracks it.

Release note

fix(postgres): the init-job now runs as a main-phase Job that waits for the CNPG superuser secret, fixing a fresh-install race and ensuring role/database reconciliation continues on an UpgradeFailed release

@github-actions github-actions Bot added area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files labels Aug 20, 2026
@coderabbitai

coderabbitai Bot commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a3f8e9a5-930e-42b1-8217-f728879d05eb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

…secret

The users/databases/roles reconciler Job mounted the CNPG-managed
<release>-superuser secret as a post-install,post-upgrade hook. The secret
is created asynchronously by the operator, so the hook Pod raced it and hit
FailedMount / CreateContainerConfigError on a fresh install, and as a
post-upgrade hook it stopped reconciling entirely while the release was
UpgradeFailed.

Move the Job to the main phase and gate it with a wait-for-superuser init
container behind an optional secret volume, so the Pod waits in init until
the operator publishes the secret instead of failing the mount. The Job name
now carries a content-hash suffix because a main-phase immutable Job cannot be
patched in place across revisions.

The bootstrap.recovery skip and the ttlSecondsAfterFinished GC behaviour are
preserved.

Signed-off-by: IvanHunters <[email protected]>
@IvanHunters
IvanHunters force-pushed the fix/postgres-init-job-superuser-race branch from 6241bd5 to ed1bc76 Compare August 20, 2026 11:12
The init-job now carries a content-hash name suffix, so consumers that
waited on the fixed name `<release>-init-job` broke:
- the chainsaw postgres suite asserted and deleted the Job by name
- the backup example (examples/backups/postgres/run-all.sh) waited on it

Give the Job stable selector labels (component=init-job, instance=<release>)
and match it by those everywhere instead of by name.

Signed-off-by: IvanHunters <[email protected]>
@github-actions

Copy link
Copy Markdown

This PR has had no activity for 60 days and was marked lifecycle/stale.
It will be closed in 14 days unless commented or labelled lifecycle/frozen.

@github-actions github-actions Bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale label Oct 20, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Closed because no activity followed the lifecycle/stale warning.
Reopen if the change is still wanted.

@github-actions github-actions Bot added the lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed label Nov 4, 2026
@github-actions github-actions Bot closed this Nov 4, 2026
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) kind/bug Categorizes issue or PR as related to a bug lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

postgres: init-job hook mounts operator-managed superuser secret without waiting, racing CNPG on fresh install

1 participant