feat(erp): manifeste d'exercice, rejeu à blanc, gardes manquantes, trunk réconcilié (#92)
Co-authored-by: Gabriel Radureau <[email protected]>
This commit was merged in pull request #92.
This commit is contained in:
@@ -35,6 +35,14 @@ PG_IMAGE="postgres:16-alpine"
|
||||
DOC_ROOT="/var/www/documents" # dolibarr_main_data_root
|
||||
TMP_PROD_SECRET="prod-db-ro-temp" # transient copy of prod creds, deleted on exit
|
||||
|
||||
# ATTENTION — NE JAMAIS ÉDITER CE FICHIER PENDANT QU'IL S'EXÉCUTE.
|
||||
# Bash lit ses scripts au fil de l'eau : modifier le fichier en cours de route
|
||||
# décale les offsets et corrompt l'exécution. Constaté le 2026-08-14 — un
|
||||
# refresh-from-prod en cours s'est mis à afficher les messages de blank_sandbox
|
||||
# puis a fini sur « syntax error ». Le travail était fait, mais la trace mentait
|
||||
# sur ce qui tournait : sur un script qui purge des bases, c'est inacceptable.
|
||||
# Attendre la fin, ou éditer une copie.
|
||||
|
||||
log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
|
||||
die() { printf '\033[1;31mABORT:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
@@ -173,9 +181,111 @@ sync_documents() {
|
||||
log "Documents synced. (For a one-shot logo only, scope the tar to mycompany/logos.)"
|
||||
}
|
||||
|
||||
# --- mode vierge -------------------------------------------------------------
|
||||
# Vide la base du bac à sable pour qu'un rejeu d'exercice reparte de zéro.
|
||||
# `refresh-from-prod` réimporterait précisément les défauts que le rejeu doit
|
||||
# corriger : reconstruire suppose donc une base vide, pas iso-prod.
|
||||
#
|
||||
# CETTE COMMANDE N'EST QU'UNE ÉTAPE. Seule, elle laisse le bac à sable sans
|
||||
# schéma — Dolibarr sert alors une page de login sur une base vide. La chaîne
|
||||
# complète, déjà outillée dans test/ :
|
||||
#
|
||||
# 1. sandbox-lifecycle.sh blank --yes purge la base, retire install.lock
|
||||
# 2. cd test && deno run -A main.ts pilote l'installeur (/install/), la
|
||||
# société, l'affichage et les modules
|
||||
# 3. touch install.lock dans le pod reverrouille (recette du test/README.md)
|
||||
# 4. deno run -A provisionSandbox.ts agent d'écriture, droits, clé API
|
||||
#
|
||||
# CE QUI REND L'OPÉRATION SÛRE : elle est ANNULABLE. `refresh-from-prod` restaure
|
||||
# un bac à sable iso-prod en trois minutes. On peut donc casser sans regret — et
|
||||
# c'est la seule raison pour laquelle une commande qui détruit une base entière
|
||||
# est acceptable ici.
|
||||
#
|
||||
# Elle ne vise QUE $SB_NS. Le namespace de production n'apparaît nulle part dans
|
||||
# cette fonction, et la garde de cluster refuse tout contexte qui n'est pas le
|
||||
# homelab.
|
||||
blank_sandbox() {
|
||||
[ "${1:-}" = "--yes" ] || die "blank détruit toutes les données du bac à sable — relancer avec --yes"
|
||||
trap restore_state EXIT
|
||||
|
||||
log "Pause du self-heal ArgoCD (sinon le scale-to-0 est repris en quelques secondes)"
|
||||
set_selfheal false
|
||||
|
||||
log "erp-sandbox à 0 réplique (accès exclusif à la base)"
|
||||
K scale deploy erp-sandbox -n "$SB_NS" --replicas=0 >/dev/null
|
||||
K wait --for=delete pod -l app.kubernetes.io/instance=erp-sandbox -n "$SB_NS" --timeout=120s >/dev/null 2>&1 || true
|
||||
|
||||
log "Job de purge (DROP OWNED, aucune restauration)"
|
||||
K delete job sandbox-blank -n "$SB_NS" --ignore-not-found >/dev/null 2>&1 || true
|
||||
K apply -f - >/dev/null <<EOF
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata: { name: sandbox-blank, namespace: $SB_NS }
|
||||
spec:
|
||||
backoffLimit: 0
|
||||
ttlSecondsAfterFinished: 900
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: blank
|
||||
image: $PG_IMAGE
|
||||
env:
|
||||
- { name: SB_PGUSER, valueFrom: { secretKeyRef: { name: vso-db-credentials, key: username } } }
|
||||
- { name: SB_PGPASSWORD, valueFrom: { secretKeyRef: { name: vso-db-credentials, key: password } } }
|
||||
- { name: PGHOST, value: "$PGHOST" }
|
||||
- { name: PGSSLMODE, value: "disable" }
|
||||
command: ["/bin/sh","-c"]
|
||||
args:
|
||||
- |
|
||||
set -eu
|
||||
Q() { PGPASSWORD=\$SB_PGPASSWORD psql -h "\$PGHOST" -U "\$SB_PGUSER" -d $SB_DB -tAc "\$1"; }
|
||||
# Ceinture ET bretelles : on refuse d'agir si la base courante n'est
|
||||
# pas celle du bac à sable. Une purge sur la mauvaise base ne se
|
||||
# rattrape pas par un refresh.
|
||||
CUR=\$(Q 'select current_database()')
|
||||
[ "\$CUR" = "$SB_DB" ] || { echo "ABORT: base courante '\$CUR' au lieu de $SB_DB"; exit 1; }
|
||||
echo "cible=\$CUR role=$SB_ROLE"
|
||||
AVANT=\$(Q "select count(*) from pg_tables where schemaname='public' and tablename like 'llx_%'")
|
||||
echo "tables llx_ avant purge : \$AVANT"
|
||||
PGPASSWORD=\$SB_PGPASSWORD psql -h "\$PGHOST" -U "\$SB_PGUSER" -d $SB_DB -v ON_ERROR_STOP=1 \\
|
||||
-c "DROP OWNED BY $SB_ROLE CASCADE;"
|
||||
APRES=\$(Q "select count(*) from pg_tables where schemaname='public' and tablename like 'llx_%'")
|
||||
echo "tables llx_ après purge : \$APRES"
|
||||
[ "\$APRES" -eq 0 ] || { echo "ABORT: \$APRES tables subsistent — purge incomplète"; exit 1; }
|
||||
echo "DONE."
|
||||
EOF
|
||||
K wait --for=condition=complete job/sandbox-blank -n "$SB_NS" --timeout=180s >/dev/null 2>&1 \
|
||||
|| die "le Job de purge n'a pas abouti — voir : K logs -n $SB_NS job/sandbox-blank"
|
||||
K logs -n "$SB_NS" job/sandbox-blank | sed 's/^/ /'
|
||||
K delete job sandbox-blank -n "$SB_NS" --ignore-not-found >/dev/null 2>&1 || true
|
||||
|
||||
# Le verrou d'installation vit sur le VOLUME DOCUMENTS, que la purge de la base
|
||||
# ne touche pas. Tant qu'il est là, Dolibarr saute l'installeur et sert une page
|
||||
# de login sur un schéma inexistant : l'instance a l'air vivante et ne l'est pas.
|
||||
# Le retirer laisse l'entrypoint de l'image réinstaller un schéma neuf.
|
||||
log "Retrait du verrou d'installation (sinon Dolibarr sert un login sur une base sans schéma)"
|
||||
K scale deploy erp-sandbox -n "$SB_NS" --replicas=1 >/dev/null
|
||||
K wait --for=condition=ready pod -l app.kubernetes.io/instance=erp-sandbox -n "$SB_NS" --timeout=180s >/dev/null 2>&1 || true
|
||||
POD=$(sb_pod)
|
||||
[ -n "$POD" ] && K exec -n "$SB_NS" "$POD" -- rm -f /var/www/documents/install.lock >/dev/null 2>&1 || true
|
||||
|
||||
log "Redémarrage pour déclencher l'installation"
|
||||
K rollout restart deploy erp-sandbox -n "$SB_NS" >/dev/null
|
||||
K rollout status deploy erp-sandbox -n "$SB_NS" --timeout=300s >/dev/null 2>&1 || true
|
||||
|
||||
log "Réarmement du self-heal ArgoCD"
|
||||
set_selfheal true
|
||||
|
||||
log "Base vidée et verrou retiré. Vérifier que le schéma se reconstruit :"
|
||||
log " curl -s https://erp-sandbox.arcodange.lab/api/index.php/status"
|
||||
log "Annulation à tout moment : $0 refresh-from-prod"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
refresh-from-prod) assert_arcodange_cluster; refresh_from_prod ;;
|
||||
blank) assert_arcodange_cluster; shift; blank_sandbox "${1:-}" ;;
|
||||
sync-documents) assert_arcodange_cluster; sync_documents ;;
|
||||
refresh) assert_arcodange_cluster; refresh_from_prod; sync_documents ;;
|
||||
*) echo "usage: $0 {refresh-from-prod|sync-documents|refresh}" >&2; exit 2 ;;
|
||||
*) echo "usage: $0 {refresh-from-prod|sync-documents|refresh|blank --yes}" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user