From 515aac415a8d88dcf068cca30c345640bcadb63b Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Wed, 30 Sep 2026 02:51:19 -0400 Subject: [PATCH] restauration : la section d'une base passe a psql par l'entree standard postgres ne lit pas le repertoire jetable de root ; trouve en repetition sur data-sql-01 de Technolibre. Le test l'exige desormais. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 14 ++++++++++++-- roles/client_backup/templates/restaurer.sh.j2 | 4 +++- scripts/tests/test_restauration.py | 7 ++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6d7717..e23cc39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,8 +45,18 @@ refuser d'écraser, bloquer puis libérer la sauvegarde, et couper la section d' le `DROP DATABASE postgres;`. Le test a trouvé un défaut avant tout déploiement : une apostrophe dans `${c:-…}`, que bash lit comme un guillemet ouvrant. -**Pas encore éprouvé par une reconstruction réelle** : validé par `ansible-lint` (0 remarque), -`--syntax-check`, `make test`. L'épreuve est la prochaine reconstruction. +**Déployé sur Technolibre** (runner, `deployer-tout`) : 13 hôtes, 0 échec. Chaque jeu vivant +reconnu `en_place` (rien écrasé) ; les deux serveurs web, vides, ont pris le chemin +`a_restaurer` depuis leur instantané d'avant. `make sauvegarder-maintenant` : les 8 dépôts +passent la garde. Répétitions sur les vraies données, sans rien toucher : annuaire à blanc +(12 entrées rejouables depuis `71fb5481`), courriel remis dans un répertoire jetable. + +**La répétition a trouvé un défaut** : `psql` tourne en `postgres`, qui ne lit pas le +répertoire jetable de root (0700) — en reconstruction, la base serait restée vide et le +déploiement aurait échoué. La section passe désormais par l'entrée standard ; le test +l'exige. + +**Pas encore éprouvé par une reconstruction réelle** : l'épreuve est la prochaine. ## 2026-09-30 (46) — Technolibre : l'état d'avant la reconstruction remis en place, sans reconstruire diff --git a/roles/client_backup/templates/restaurer.sh.j2 b/roles/client_backup/templates/restaurer.sh.j2 index bb3bc13..7b01843 100644 --- a/roles/client_backup/templates/restaurer.sh.j2 +++ b/roles/client_backup/templates/restaurer.sh.j2 @@ -246,8 +246,10 @@ cmd_base() { -c "ALTER DATABASE ${cible} OWNER TO ${proprio};" # UNE SEULE TRANSACTION : une erreur au milieu laisse une base VIDE, que la prochaine # passe retentera — pas une base a moitie chargee qu'on prendrait pour la bonne. + # Par l'ENTREE STANDARD, pas `-f` : psql tourne en `postgres`, qui ne peut pas lire le + # repertoire jetable de root (0700). Trouve en repetition sur data-sql-01, 2026-09-30. runuser -u postgres -- psql -X -q --single-transaction -v ON_ERROR_STOP=1 \ - -d "${cible}" -f "${section}" >/dev/null + -d "${cible}" < "${section}" >/dev/null echo "RESTAURE ${INSTANTANE} : base ${nom} -> ${cible}, $(tables "${cible}") table(s)." } diff --git a/scripts/tests/test_restauration.py b/scripts/tests/test_restauration.py index d150a03..df30fd1 100644 --- a/scripts/tests/test_restauration.py +++ b/scripts/tests/test_restauration.py @@ -127,11 +127,15 @@ esac """) # PostgreSQL : on journalise, on garde la section rejouee ; toute base est vierge. executable(bin_ / "runuser", '#!/bin/bash\nwhile [[ "$1" != "--" ]]; do shift; done; shift; exec "$@"\n') + # Sans `-c`, psql lit la section sur son entree standard : c'est ainsi que l'outil + # doit la lui passer (`postgres` ne lit pas le repertoire jetable de root). executable(bin_ / "psql", f"""#!/bin/bash echo "psql $*" >> "{log}/pg" +avec_c=0 while (( $# )); do - case "$1" in -f) cp "$2" "{log}/section.sql"; shift 2;; -c) [[ "$2" == select* ]] && echo 0; shift 2;; *) shift;; esac + case "$1" in -f) echo "psql -f INTERDIT" >> "{log}/pg"; shift 2;; -c) avec_c=1; [[ "$2" == select* ]] && echo 0; shift 2;; *) shift;; esac done +if (( ! avec_c )); then cat > "{log}/section.sql"; fi """) executable(bin_ / "pg_dump", '#!/bin/bash\necho dump\n') executable(bin_ / "dropdb", f'#!/bin/bash\necho "dropdb $*" >> "{log}/pg"\n') @@ -181,6 +185,7 @@ done "la section s'arrete avant le DROP DATABASE postgres, et ne deborde sur aucune autre base") pg = (log / "pg").read_text() verifier("--single-transaction" in pg, "la base est rejouee en une seule transaction") + verifier("INTERDIT" not in pg, "la section passe par l'entree standard, jamais par `psql -f`") r = lancer("base", "inexistante") verifier(r.returncode == 0 and "ABSENTE" in r.stdout, "une base absente de l'instantane est dite, pas inventee")