Pass Nextcloud backup restore drill for Forgejo (T09)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 9s

Decrypt production forgejo-dump artifact, restore 14 repos in isolated
namespace, and harden restore script for large chunked copy and drill mailer stub.
This commit is contained in:
tegwick 2026-07-07 22:44:55 +02:00
parent 8ea13a065b
commit 1da9c3269b
3 changed files with 74 additions and 15 deletions

View file

@ -14,6 +14,26 @@ PROD_POD="${PROD_POD:-$(kubectl get pods -n forgejo -l app.kubernetes.io/instanc
step() { echo "==> $*"; }
# kubectl cp drops large archives (~686M) via websocket EOF; split and reassemble.
copy_backup_to_pod() {
local src="$1" dest_ns="$2" dest_pod="$3" dest_path="$4" container="$5"
local size chunk_dir
size="$(stat -c%s "${src}")"
if [[ "${size}" -lt 104857600 ]]; then
kubectl cp "${src}" "${dest_ns}/${dest_pod}:${dest_path}" -c "${container}"
return
fi
step "Chunked copy (${size} bytes) to pod"
chunk_dir="$(mktemp -d)"
trap 'rm -rf "${chunk_dir}"' RETURN
split -b 48m -a 3 "${src}" "${chunk_dir}/part-"
for part in "${chunk_dir}"/part-*; do
kubectl cp "${part}" "${dest_ns}/${dest_pod}:/backup/$(basename "${part}")" -c "${container}"
done
kubectl exec -n "${dest_ns}" "${dest_pod}" -c "${container}" -- \
sh -c "cat /backup/part-* > '${dest_path}' && rm -f /backup/part-*"
}
if [[ "${DRILL_CLEAN}" == "1" ]]; then
step "Clean prior drill namespace ${NS}"
kubectl delete namespace "${NS}" --wait=true --timeout=5m || true
@ -69,7 +89,8 @@ spec:
emptyDir: {}
EOF
kubectl wait --for=condition=Ready pod/forgejo-restore-import -n "${NS}" --timeout=3m
kubectl cp "${BACKUP_LOCAL}" "${NS}/forgejo-restore-import:/backup/forgejo-drill-backup.zip" -c restore
copy_backup_to_pod "${BACKUP_LOCAL}" "${NS}" forgejo-restore-import \
/backup/forgejo-drill-backup.zip restore
DB_PASS="$(kubectl get secret forgejo-db-credentials -n "${NS}" -o jsonpath='{.data.password}' | base64 -d)"
kubectl exec -n "${NS}" forgejo-restore-import -c restore -- env POSTGRES_PASSWORD="${DB_PASS}" sh -c '
set -eu
@ -89,19 +110,25 @@ kubectl delete pod forgejo-restore-import -n "${NS}" --wait=true
step "Deploy isolated Forgejo release"
cd "${HOME}/railiance-apps"
DB_PASS="$(kubectl get secret forgejo-db-credentials -n "${NS}" -o jsonpath='{.data.password}' | base64 -d)"
# Restore namespace has no OpenBao/ESO mailer secret — stub for chart init.
kubectl create secret generic forgejo-mailer -n "${NS}" \
--from-literal=MAILER_PASSWD=restore-drill-local-only \
--dry-run=client -o yaml | kubectl apply -f -
helm upgrade --install forgejo-restore gitea-charts/gitea --version 12.5.0 \
--namespace "${NS}" --create-namespace \
-f helm/forgejo-values.yaml \
-f helm/forgejo-registry-values.yaml \
--set strategy.type=Recreate \
--set persistence.enabled=true \
--set persistence.existingClaim=forgejo-restore-data \
--set gitea.config.database.HOST=forgejo-db-restore-rw.${NS}.svc.cluster.local:5432 \
--set gitea.config.database.PASSWD="${DB_PASS}" \
--set gitea.config.server.DOMAIN=forgejo-restore.local \
--set gitea.config.server.ROOT_URL=http://forgejo-restore.local:3000/ \
--set gitea.config.mailer.ENABLED=false \
--set gitea.admin.password=restore-drill-local-only \
--set ingress.enabled=false \
--wait --timeout=10m
--wait --timeout=20m
unset DB_PASS
step "Post-restore checks via port-forward"