Files
cozystack/examples/backups/postgres/cleanup.sh
Andrey KolkovandClaude Opus 4.8 5bcdb8cfb8 fix(postgres): let in-place restore re-bootstrap instead of wedging
An in-place RestoreJob (targetApplicationRef omitted) re-bootstraps the
Postgres app under its own name. On stock v1.6.2 it never comes back up,
for two independent reasons in the same restore patch - both surface only
in place, because a to-copy restore targets a different app.

1. Archive-vs-recovery serverName collision. The driver set the restored
   cluster's WAL-archive serverName equal to the recovery source
   (bootstrap.serverName = bootstrap.oldName = sourceServerName) while the
   chart pinned the archiver serverName to the release name. In place those
   coincide, so the cluster archived onto the source's own WAL prefix and
   barman-cloud-check-wal-archive refused to start ("Expected empty
   archive"). Fixed by giving the restored cluster a fresh
   bootstrap.newServerName, keyed by the RestoreJob UID (unique per
   restore, stable across reconciles); the chart archives there while
   externalClusters still recovers from bootstrap.serverName. This is what
   the manual CNPG strategies hit (serverName defaults to the cluster
   name); the cozy-default flow dodged it (serverName is <ns>-<app>).

2. useSystemBucket guard. The restore populates explicit S3 coordinates
   (destinationPath / s3CredentialsSecret / endpointCA) but left
   backup.useSystemBucket=true, so the chart's "bootstrap.enabled is
   incompatible with useSystemBucket" guard failed the HelmRelease upgrade
   and the cluster never re-rendered. This is what the cozy-default
   (system-bucket) flow hits on an in-place restore. Fixed by clearing
   useSystemBucket in the restore patch, since the app is now on the
   explicit-creds path. The driver's app view (postgresapp.Backup) gains
   the field, without omitempty so a false survives the merge patch.

Both are exercised only by an in-place restore; the postgres backup e2e
drove only to-copy, so neither surfaced in CI. A step 50 in-place restore
now guards reason 1 (manual-strategy flow); reason 2 is covered by a Go
unit assertion (a system-bucket in-place e2e needs the platform bucket in
CI and is left as a follow-up).

Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-25 17:31:53 +04:00

56 lines
2.7 KiB
Bash
Executable File

#!/bin/bash
# Best-effort teardown of everything the demo creates. Idempotent;
# missing resources are skipped silently.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/00-helpers.sh"
print_header "Cleanup"
# The CNPG driver suspends the source/target Postgres HelmRelease while a
# RestoreJob runs. If the demo was aborted mid-restore the HR is left
# suspended; deleting the RestoreJob without resuming it first strands the app.
# Resume both best-effort BEFORE deleting the RestoreJobs.
for app in "$PG_SRC_NAME" "$PG_TARGET_NAME"; do
if kubectl -n "$NAMESPACE" get hr "postgres-${app}" >/dev/null 2>&1; then
log_substep "Resuming HelmRelease postgres-${app} (no-op if not suspended)..."
kubectl -n "$NAMESPACE" patch hr "postgres-${app}" --type=merge \
-p '{"spec":{"suspend":false}}' >/dev/null || true
fi
done
log_substep "Deleting RestoreJobs..."
kubectl -n "$NAMESPACE" delete restorejob.backups.cozystack.io \
"$RESTOREJOB_TOCOPY_NAME" "$RESTOREJOB_PITR_NAME" "$RESTOREJOB_UNREACHABLE_NAME" \
"$RESTOREJOB_INPLACE_NAME" --ignore-not-found
log_substep "Deleting Plan + BackupJob + derived Backup artefacts..."
kubectl -n "$NAMESPACE" delete plan.backups.cozystack.io "$PLAN_NAME" --ignore-not-found
kubectl -n "$NAMESPACE" delete backupjob.backups.cozystack.io \
"$BACKUPJOB_NAME" "$BACKUPJOB_POSTMARKER_NAME" --ignore-not-found
# Only the Backups of THIS demo's apps — never `--all`: on a shared cluster the
# namespace can hold Backup artefacts of other applications and flows.
for b in $(kubectl -n "$NAMESPACE" get backups.backups.cozystack.io \
-o jsonpath='{range .items[*]}{.metadata.name} {.spec.applicationRef.name}{"\n"}{end}' 2>/dev/null |
awk -v src="$PG_SRC_NAME" -v tgt="$PG_TARGET_NAME" '$2 == src || $2 == tgt {print $1}'); do
kubectl -n "$NAMESPACE" delete backups.backups.cozystack.io "$b" --ignore-not-found
done
log_substep "Deleting Postgres apps..."
kubectl -n "$NAMESPACE" delete postgres.apps.cozystack.io "$PG_SRC_NAME" "$PG_TARGET_NAME" --ignore-not-found
log_substep "Deleting per-app backup Secrets..."
kubectl -n "$NAMESPACE" delete secret \
"${PG_SRC_NAME}-cnpg-backup-creds" "${PG_SRC_NAME}-cnpg-backup-ca" \
"${PG_TARGET_NAME}-cnpg-backup-creds" "${PG_TARGET_NAME}-cnpg-backup-ca" --ignore-not-found
log_substep "Deleting Bucket..."
kubectl -n "$NAMESPACE" delete bucket.apps.cozystack.io "$BUCKET_NAME" --ignore-not-found
log_substep "Deleting BackupClass + CNPG strategy (cluster-scoped)..."
kubectl delete backupclass.backups.cozystack.io "$BACKUPCLASS_NAME" --ignore-not-found
kubectl delete cnpg.strategy.backups.cozystack.io "$STRATEGY_NAME" --ignore-not-found
log_success "Cleanup complete."