client_backup : un depot verrouille n est plus une panne

Les quatre scripts qui touchent au depot appellent restic avec
--retry-lock (client_backup_attente_verrou, 30 min) : deux minuteurs
partis ensemble ne fabriquent plus de faux critique (aucun instantane,
depot corrompu). Eprouve sur un depot jetable, dans les deux sens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-10-04 14:27:11 -04:00
parent 7976df08d5
commit 1167cc12e0
6 changed files with 59 additions and 0 deletions

View file

@ -1,5 +1,35 @@
# CHANGELOG — Set-OPS
## 2026-10-04 (74) — Un dépôt verrouillé n'est plus une panne
**Constaté en vérifiant (73)** : lancées ensemble sur `web-dorsal-01`, la vérification du
dépôt et le contrôle de restauration se sont gênés. Le `restic check` tenait le verrou
exclusif, et la sonde a rapporté « AUCUN INSTANTANE lisible » (critique) pendant 20 s. Les
minuteurs peuvent faire de même sans personne : `Persistent=true` rattrape au démarrage tout
ce qui a été manqué, d'un coup, et le contrôle du dimanche (04:00 + jusqu'à 60 min) peut
croiser la vérification de 05:00. restic refuse aussitôt un dépôt verrouillé ; la sonde
concluait à l'absence, ou le contrôle à la corruption.
**Fait** (`client_backup`) : les quatre scripts qui touchent au dépôt (sauvegarde,
vérification, contrôle de restauration, `setops-restaurer`) appellent restic à travers une
fonction qui ajoute `--retry-lock {{ client_backup_attente_verrou }}` (30 min par défaut ;
le plus long des occupants est le contrôle de restauration). Les unités sont `oneshot`, sans
délai d'expiration : l'attente n'est pas coupée.
**Éprouvé** sur un dépôt jetable (`/var/tmp`, `web-dorsal-01` de Technolibre, retiré
ensuite), le verrou tenu par un vrai processus restic, scripts rendus avec le rapport
remplacé par un `echo` :
| | sans attente | avec attente |
|---|---|---|
| contrôle de restauration face à un verrou partagé (`backup` en cours) | critique « DEPOT CORROMPU OU ILLISIBLE », 0 s | attend 17 s, puis vérifie |
| vérification du dépôt face à un verrou exclusif (`check` en cours) | critique « AUCUN INSTANTANE lisible », 1 s | attend, puis « OK », 8 s |
Deux essais d'abord ne prouvaient rien et ont été écartés : un dépôt vide se vérifie trop vite
pour qu'un verrou dure, et `backup --dry-run` n'en pose aucun.
**Validation** : `--syntax-check` de `client_backup.yml`, `ansible-lint` (0 violation).
## 2026-10-04 (73) — Un instantané vide dit pourquoi
**Demande de l'exploitant** : l'avertissement convient quand il n'y a rien à sauvegarder ;

View file

@ -133,6 +133,11 @@ client_backup_restauration_part: "10%"
# nouvelle, Icinga passe le service au rouge (voir `serveur_icinga_fraicheur_restauration`).
client_backup_ttl_restauration: 691200
# Combien de temps un script attend un depot verrouille par un autre (`restic --retry-lock`)
# avant d'echouer. Le plus long des occupants est le controle de restauration ; il relit
# 10 % du depot et le restaure entier.
client_backup_attente_verrou: "30m"
# --- LA RESTAURATION DANS LA RECONSTRUCTION (2026-09-30) ----------------------------
#
# Jusqu'ici une reconstruction repartait d'un etat NEUF : les instantanes se restauraient

View file

@ -39,6 +39,12 @@ set -euo pipefail
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
# UN VERROU N'EST PAS UNE PANNE (2026-10-04). La sauvegarde, la verification du depot, le
# controle de restauration et `setops-restaurer` partagent ce depot ; leurs minuteurs peuvent
# partir ensemble (`Persistent=true` rattrape au demarrage tout ce qui a ete manque). Sans
# attente, restic refuse aussitot un depot verrouille, et une sonde concluait « aucun
# instantane » ou « depot corrompu ». On attend le verrou au lieu de conclure.
restic() { command restic --retry-lock {{ client_backup_attente_verrou }} "$@"; }
MOI="{{ inventory_hostname }}"
MARQUES="{{ client_backup_restauration_marques }}"
MISE_DE_COTE="{{ client_backup_restauration_mise_de_cote }}"

View file

@ -4,6 +4,12 @@
set -euo pipefail
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
# UN VERROU N'EST PAS UNE PANNE (2026-10-04). La sauvegarde, la verification du depot, le
# controle de restauration et `setops-restaurer` partagent ce depot ; leurs minuteurs peuvent
# partir ensemble (`Persistent=true` rattrape au demarrage tout ce qui a ete manque). Sans
# attente, restic refuse aussitot un depot verrouille, et une sonde concluait « aucun
# instantane » ou « depot corrompu ». On attend le verrou au lieu de conclure.
restic() { command restic --retry-lock {{ client_backup_attente_verrou }} "$@"; }
# 0. UN ETAT D'AVANT ATTEND-IL ? (2026-09-30)
# Sur une machine reconstruite, tant que l'etat de l'incarnation precedente n'a ete ni

View file

@ -14,6 +14,12 @@
set -uo pipefail
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
# UN VERROU N'EST PAS UNE PANNE (2026-10-04). La sauvegarde, la verification du depot, le
# controle de restauration et `setops-restaurer` partagent ce depot ; leurs minuteurs peuvent
# partir ensemble (`Persistent=true` rattrape au demarrage tout ce qui a ete manque). Sans
# attente, restic refuse aussitot un depot verrouille, et une sonde concluait « aucun
# instantane » ou « depot corrompu ». On attend le verrou au lieu de conclure.
restic() { command restic --retry-lock {{ client_backup_attente_verrou }} "$@"; }
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
API="https://{{ client_backup_icinga_hote }}.{{ domaine_interne }}:5665"
TTL={{ client_backup_ttl_icinga }}

View file

@ -19,6 +19,12 @@
set -uo pipefail
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
# UN VERROU N'EST PAS UNE PANNE (2026-10-04). La sauvegarde, la verification du depot, le
# controle de restauration et `setops-restaurer` partagent ce depot ; leurs minuteurs peuvent
# partir ensemble (`Persistent=true` rattrape au demarrage tout ce qui a ete manque). Sans
# attente, restic refuse aussitot un depot verrouille, et une sonde concluait « aucun
# instantane » ou « depot corrompu ». On attend le verrou au lieu de conclure.
restic() { command restic --retry-lock {{ client_backup_attente_verrou }} "$@"; }
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
API="https://{{ client_backup_icinga_hote }}.{{ domaine_interne }}:5665"
TTL={{ client_backup_ttl_restauration }}