2020
2121NAMESPACE=" postgres-test"
2222export CLUSTER_NAME=" pg-cluster"
23- DATA_SIZE_GB=2
23+ DATA_SIZE_GB=3
2424SCALE_FACTOR=$(( DATA_SIZE_GB * 70 )) # pgbench scale: ~15MB per scale factor
2525
2626# Colors for output
@@ -33,6 +33,44 @@ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
3333log_warn () { echo -e " ${YELLOW} [WARN]${NC} $1 " ; }
3434log_error () { echo -e " ${RED} [ERROR]${NC} $1 " ; }
3535
36+ S3_ENDPOINT=" http://s3proxy-python-frontproxy.s3proxy:80"
37+ S3_WAL_CHECK_POD=" s3-wal-check"
38+
39+ ensure_s3_wal_checker () {
40+ if kubectl get pod -n " $NAMESPACE " " $S3_WAL_CHECK_POD " > /dev/null 2>&1 ; then
41+ kubectl wait -n " $NAMESPACE " --for=condition=Ready " pod/${S3_WAL_CHECK_POD} " --timeout=120s
42+ return
43+ fi
44+ kubectl run " $S3_WAL_CHECK_POD " --restart=Never -n " $NAMESPACE " \
45+ --image=amazon/aws-cli:2.15.0 \
46+ --overrides=' {"spec":{"containers":[{"name":"' " $S3_WAL_CHECK_POD " ' ","image":"amazon/aws-cli:2.15.0","command":["sleep","3600"],"envFrom":[{"secretRef":{"name":"s3-credentials"}}]}]}}'
47+ kubectl wait -n " $NAMESPACE " --for=condition=Ready " pod/${S3_WAL_CHECK_POD} " --timeout=120s
48+ }
49+
50+ wait_for_end_wal_in_s3 () {
51+ local end_wal=" $1 "
52+ local timeline_prefix=" ${end_wal: 0: 16} "
53+ local wal_object=" pg-cluster/wals/${timeline_prefix} /${end_wal} .gz"
54+
55+ log_info " Waiting for backup end WAL in S3: ${wal_object} "
56+ ensure_s3_wal_checker
57+
58+ local deadline=$(( SECONDS + 600 ))
59+ while [ " $SECONDS " -lt " $deadline " ]; do
60+ if kubectl exec -n " $NAMESPACE " " $S3_WAL_CHECK_POD " -- sh -c "
61+ export AWS_ACCESS_KEY_ID=\$ ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=\$ ACCESS_SECRET_KEY
62+ aws --endpoint-url ${S3_ENDPOINT} s3 ls s3://postgres-backups/${wal_object} >/dev/null 2>&1
63+ " ; then
64+ log_info " ✓ End WAL archived: ${end_wal} .gz"
65+ return 0
66+ fi
67+ sleep 5
68+ done
69+
70+ log_error " Timeout waiting for end WAL ${end_wal} .gz in S3"
71+ return 1
72+ }
73+
3674cleanup () {
3775 log_info " Cleaning up..."
3876 kubectl delete namespace " $NAMESPACE " --ignore-not-found --wait=false || true
@@ -218,41 +256,63 @@ log_info "Backup completed!"
218256kubectl get backup -n " $NAMESPACE " ${CLUSTER_NAME} -backup-1 -o yaml | grep -A5 " status:"
219257
220258# ============================================================================
221- # STEP 5: Verify encryption + Delete cluster + Create new cluster (ALL PARALLEL)
259+ # STEP 4b: Assert the s3proxy pods survived (the OOM we are gating against)
260+ # ============================================================================
261+ log_info " === Checking s3proxy pods were not OOM-killed during backup ==="
262+ oom_found=0
263+ for p in $( kubectl get pods -n s3proxy -l app.kubernetes.io/name=s3proxy-python,app.kubernetes.io/component=server -o name) ; do
264+ rc=$( kubectl get -n s3proxy " $p " -o jsonpath=' {.status.containerStatuses[0].restartCount}' 2> /dev/null || echo 0)
265+ reason=$( kubectl get -n s3proxy " $p " -o jsonpath=' {.status.containerStatuses[0].lastState.terminated.reason}' 2> /dev/null || echo " " )
266+ log_info " $p restarts=${rc:- 0} lastTerminated=${reason:- none} "
267+ if [ " ${reason} " = " OOMKilled" ] || [ " ${rc:- 0} " -gt 0 ]; then oom_found=1; fi
268+ done
269+ if [ " $oom_found " -eq 1 ]; then
270+ log_error " s3proxy was OOM-killed/restarted during backup"
271+ exit 1
272+ fi
273+ log_info " ✓ s3proxy survived the backup"
274+
275+ # ============================================================================
276+ # STEP 4c: Wait for backup end WAL to reach S3 (restore needs it)
277+ # CNPG may mark backup completed before the archiver uploads the final segment.
222278# ============================================================================
223- log_info " === Step 5: Parallel - verify encryption, delete old, create new ==="
279+ END_WAL=$( kubectl get backup -n " $NAMESPACE " " ${CLUSTER_NAME} -backup-1" -o jsonpath=' {.status.endWal}' )
280+ if [ -z " $END_WAL " ]; then
281+ log_error " Backup status.endWal is empty"
282+ exit 1
283+ fi
284+ log_info " === Step 4c: Waiting for end WAL ${END_WAL} in S3 ==="
285+ wait_for_end_wal_in_s3 " $END_WAL "
286+
287+ # ============================================================================
288+ # STEP 5: Verify encryption, restore, then delete source cluster
289+ # Keep the source cluster alive until end WAL is archived and restore succeeds.
290+ # ============================================================================
291+ log_info " === Step 5: Verify encryption and restore from backup ==="
224292
225- # 1. Start encryption verification in background
226293verify_encryption " postgres-backups" " " " $NAMESPACE " " .gz|.tar|.backup|.data" &
227294VERIFY_PID=$!
228295
229- # 2. Delete old cluster in background
230- (
231- kubectl delete cluster -n " $NAMESPACE " ${CLUSTER_NAME} --wait
232- kubectl wait --namespace " $NAMESPACE " \
233- --for=delete pod -l cnpg.io/cluster=${CLUSTER_NAME} \
234- --timeout=300s || true
235- log_info " ✓ Old cluster deleted"
236- ) &
237- DELETE_PID=$!
238-
239- # 3. Create new cluster immediately (different name, can coexist)
240- log_info " Creating restored cluster (parallel with deletion)..."
296+ log_info " Creating restored cluster..."
241297envsubst < " ${SCRIPT_DIR} /templates/postgres-cluster-restore.yaml" | kubectl apply -n " $NAMESPACE " -f -
242298
243- # Wait for all parallel operations
244299wait $VERIFY_PID || { log_error " Encryption verification failed" ; exit 1; }
245300log_info " ✓ Encryption verified"
246301
247- wait $DELETE_PID || { log_error " Old cluster deletion failed" ; exit 1; }
248-
249302log_info " Waiting for restored cluster to be ready..."
250303kubectl wait --namespace " $NAMESPACE " \
251304 --for=condition=Ready cluster/${CLUSTER_NAME} -restored \
252305 --timeout=1800s
253306
254307log_info " Restored cluster is ready!"
255308
309+ log_info " Deleting source cluster (no longer needed)..."
310+ kubectl delete cluster -n " $NAMESPACE " " ${CLUSTER_NAME} " --wait
311+ kubectl wait --namespace " $NAMESPACE " \
312+ --for=delete pod -l " cnpg.io/cluster=${CLUSTER_NAME} " \
313+ --timeout=300s || true
314+ log_info " ✓ Old cluster deleted"
315+
256316# ============================================================================
257317# STEP 6: Validate restored data
258318# ============================================================================
0 commit comments