fix : t 001 a 020 fait

This commit is contained in:
2026-03-19 09:21:45 +01:00
parent e68c99a8b3
commit 11f69a9eda
18 changed files with 137 additions and 75 deletions

View File

@@ -291,7 +291,7 @@ crontab -e
Ajouter :
```bash
0 19 * * * /home/<USER>/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh >> /var/log/vaultwarden_backup.log 2>&1
0 19 * * * /home/<USER>/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh 2>&1
```
Signification :

View File

@@ -41,6 +41,10 @@ set +a
: "${REMOTE_USER:?Variable REMOTE_USER manquante dans .env}"
: "${REMOTE_HOST:?Variable REMOTE_HOST manquante dans .env}"
: "${REMOTE_DIR:?Variable REMOTE_DIR manquante dans .env}"
[[ "$REMOTE_DIR" =~ ^[a-zA-Z0-9/_.-]+$ ]] || {
echo "ERROR: Variable REMOTE_DIR invalide dans .env" >&2
exit 1
}
: "${SSH_KEY:?Variable SSH_KEY manquante dans .env}"
: "${BACKUP_REMOTE_SSH_PORT:=22}"
: "${SSH_CONNECT_TIMEOUT:=10}"
@@ -151,6 +155,20 @@ require_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "commande requise absente : $1"
}
#######################################
# Verrou d'execution
#######################################
LOCK_DIR="/tmp/vaultwarden_backup.lock.d"
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
fail "Backup deja en cours"
fi
cleanup() {
rm -rf -- "$LOCK_DIR"
}
trap cleanup EXIT
#######################################
# Vérifications préalables
#######################################

View File

@@ -120,12 +120,20 @@ Un modèle est fourni :
global.env.exemple
```
Ce fichier concerne la configuration legacy de `RecetteScripts`.
Utilisation :
```bash
cp global.env.exemple global.env
```
Pour la configuration de `RebuildBdd`, voir la documentation dédiée :
```bash
RebuildBdd/README.md
```
## Configuration locale
* Chaque module peut contenir son propre `.env`

View File

@@ -137,6 +137,9 @@ PGUSER_SUPERUSER="${PGUSER_SUPERUSER:-no}"
POSTGRES_PACKAGE_LIST="${POSTGRES_PACKAGE_LIST:-postgresql postgresql-client postgresql-contrib}"
POSTGRES_SERVICE_NAME="${POSTGRES_SERVICE_NAME:-postgresql}"
SUDO_BIN="${SUDO_BIN:-sudo}"
read -r -a POSTGRES_PACKAGES <<< "$POSTGRES_PACKAGE_LIST"
[[ "${#POSTGRES_PACKAGES[@]}" -gt 0 ]] || fail "POSTGRES_PACKAGE_LIST vide"
export PGPASSWORD
@@ -159,7 +162,7 @@ if ! require_cmd psql || ! require_cmd pg_restore || ! require_cmd createdb || !
log "PostgreSQL absent : installation en cours..."
"$SUDO_BIN" apt update >/dev/null 2>&1 || fail "échec de apt update"
"$SUDO_BIN" apt install -y $POSTGRES_PACKAGE_LIST >/dev/null 2>&1 || fail "échec de l'installation PostgreSQL"
"$SUDO_BIN" apt install -y "${POSTGRES_PACKAGES[@]}" >/dev/null 2>&1 || fail "échec de l'installation PostgreSQL"
POSTGRES_INSTALLED="yes"
log "Installation PostgreSQL terminée."
else

View File

@@ -92,6 +92,7 @@ to_bool_yes_no() {
v="${v,,}"
case "$v" in
yes|y|oui|o|true|1) echo "yes" ;;
# Valeur vide traitée comme "no" pour conserver le comportement historique.
no|n|non|false|0|"") echo "no" ;;
*) return 1 ;;
esac

View File

@@ -8,18 +8,18 @@ RESTORE_ROLES=yes
# Dépôt scripts
GLOBAL_REPO_URL=git@gitea.example.tld:team/RebuildBdd.git
GLOBAL_REPO_BRANCH=main
# Backup central
GLOBAL_BACKUP_REMOTE_USER=backup
GLOBAL_BACKUP_REMOTE_HOST=192.168.1.60
GLOBAL_BACKUP_REMOTE_PORT=22
GLOBAL_BACKUP_REMOTE_BASE_DIR=/home/backup/backups
# Clé SSH de lecture backup copiée sur les cibles
GLOBAL_BACKUP_SSH_PRIVATE_KEY=/home/matteo/.ssh/id_ed25519_backup_readonly
GLOBAL_BACKUP_SSH_PUBLIC_KEY=/home/matteo/.ssh/id_ed25519_backup_readonly.pub
GLOBAL_BACKUP_KNOWN_HOSTS_STRICT=yes
GLOBAL_REPO_BRANCH=main
# Backup central
GLOBAL_BACKUP_REMOTE_USER=backup
GLOBAL_BACKUP_REMOTE_HOST=<BACKUP_HOST>
GLOBAL_BACKUP_REMOTE_PORT=22
GLOBAL_BACKUP_REMOTE_BASE_DIR=/home/backup/backups
# Clé SSH de lecture backup copiée sur les cibles
GLOBAL_BACKUP_SSH_PRIVATE_KEY=/home/<LOCAL_USER>/.ssh/id_ed25519_backup_readonly
GLOBAL_BACKUP_SSH_PUBLIC_KEY=/home/<LOCAL_USER>/.ssh/id_ed25519_backup_readonly.pub
GLOBAL_BACKUP_KNOWN_HOSTS_STRICT=yes
# Defaults PostgreSQL
GLOBAL_PGHOST=127.0.0.1
@@ -35,4 +35,4 @@ GLOBAL_BOOTSTRAP_ALLOW_PASSWORDLESS_SUDO=yes
GLOBAL_AUTO_INSTALL_POSTGRES=yes
GLOBAL_AUTO_CREATE_PGUSER=yes
GLOBAL_PGUSER_SUPERUSER=no
GLOBAL_AUTO_CONFIGURE_SUDOERS=no
GLOBAL_AUTO_CONFIGURE_SUDOERS=no

View File

@@ -3,25 +3,25 @@
###############################################################################
# SSH bootstrap cible
TARGET_HOST=192.168.1.60
TARGET_HOST=<TARGET_HOST>
TARGET_PORT=22
TARGET_BOOTSTRAP_USER=backup_liot
TARGET_BOOTSTRAP_SSH_KEY=/home/matteo/.ssh/id_ed25519_target_prod
TARGET_RUNTIME_USER=backup_liot
TARGET_BOOTSTRAP_USER=<BOOTSTRAP_USER>
TARGET_BOOTSTRAP_SSH_KEY=/home/<LOCAL_USER>/.ssh/id_ed25519_target_prod
TARGET_RUNTIME_USER=<RUNTIME_USER>
# Bootstrap
TARGET_ENABLE_BOOTSTRAP=yes
TARGET_BOOTSTRAP_ALLOW_PASSWORDLESS_SUDO=yes
# Repo local cible
TARGET_REPO_DIR=/home/backup_liot/RebuildBdd
TARGET_ENV_FILE=/home/backup_liot/RebuildBdd/.env
TARGET_REPO_DIR=/home/<RUNTIME_USER>/RebuildBdd
TARGET_ENV_FILE=/home/<RUNTIME_USER>/RebuildBdd/.env
# PostgreSQL cible
TARGET_ENV_NAME=PROD
TARGET_PGHOST=127.0.0.1
TARGET_PGPORT=5432
TARGET_PGUSER=backup_liot
TARGET_PGUSER=<PGUSER>
TARGET_PGPASSWORD=change_me_pg_password
TARGET_DBS="sirh inventory ferme"
@@ -29,9 +29,9 @@ TARGET_DBS="sirh inventory ferme"
TARGET_BACKUP_SUBDIR=bdd-prod
# Logs / tmp / ssh cible
TARGET_BACKUP_LOG_DIR=/home/backup_liot/logs/rebuild_bdd
TARGET_LOCAL_RESTORE_BASE_DIR=/home/backup_liot/RebuildBdd/restore_tmp
TARGET_SSH_KEY=/home/backup_liot/.ssh/id_ed25519_backup_readonly
TARGET_BACKUP_LOG_DIR=/home/<RUNTIME_USER>/logs/rebuild_bdd
TARGET_LOCAL_RESTORE_BASE_DIR=/home/<RUNTIME_USER>/RebuildBdd/restore_tmp
TARGET_SSH_KEY=/home/<RUNTIME_USER>/.ssh/id_ed25519_backup_readonly
# Options cible
TARGET_REMOTE_ROLES_DIR_NAME=user

View File

@@ -3,25 +3,25 @@
###############################################################################
# SSH bootstrap cible
TARGET_HOST=192.168.1.50
TARGET_HOST=<TARGET_HOST>
TARGET_PORT=22
TARGET_BOOTSTRAP_USER=backup_liot
TARGET_BOOTSTRAP_SSH_KEY=/home/matteo/.ssh/id_ed25519_target_test
TARGET_RUNTIME_USER=backup_liot
TARGET_BOOTSTRAP_USER=<BOOTSTRAP_USER>
TARGET_BOOTSTRAP_SSH_KEY=/home/<LOCAL_USER>/.ssh/id_ed25519_target_test
TARGET_RUNTIME_USER=<RUNTIME_USER>
# Bootstrap
TARGET_ENABLE_BOOTSTRAP=yes
TARGET_BOOTSTRAP_ALLOW_PASSWORDLESS_SUDO=yes
# Repo local cible
TARGET_REPO_DIR=/home/backup_liot/RebuildBdd
TARGET_ENV_FILE=/home/backup_liot/RebuildBdd/.env
TARGET_REPO_DIR=/home/<RUNTIME_USER>/RebuildBdd
TARGET_ENV_FILE=/home/<RUNTIME_USER>/RebuildBdd/.env
# PostgreSQL cible
TARGET_ENV_NAME=RECETTE
TARGET_PGHOST=127.0.0.1
TARGET_PGPORT=5432
TARGET_PGUSER=backup_liot
TARGET_PGUSER=<PGUSER>
TARGET_PGPASSWORD=change_me_pg_password
TARGET_DBS="sirh inventory ferme"
@@ -29,9 +29,9 @@ TARGET_DBS="sirh inventory ferme"
TARGET_BACKUP_SUBDIR=bdd-recette
# Logs / tmp / ssh cible
TARGET_BACKUP_LOG_DIR=/home/backup_liot/logs/rebuild_bdd
TARGET_LOCAL_RESTORE_BASE_DIR=/home/backup_liot/RebuildBdd/restore_tmp
TARGET_SSH_KEY=/home/backup_liot/.ssh/id_ed25519_backup_readonly
TARGET_BACKUP_LOG_DIR=/home/<RUNTIME_USER>/logs/rebuild_bdd
TARGET_LOCAL_RESTORE_BASE_DIR=/home/<RUNTIME_USER>/RebuildBdd/restore_tmp
TARGET_SSH_KEY=/home/<RUNTIME_USER>/.ssh/id_ed25519_backup_readonly
# Options cible
TARGET_REMOTE_ROLES_DIR_NAME=user

View File

@@ -110,14 +110,14 @@ Usage :
```bash
./create-target-config.sh \
--target test \
--host 192.168.1.50 \
--host <TARGET_HOST> \
--port 22 \
--bootstrap-user backup_liot \
--bootstrap-user <BOOTSTRAP_USER> \
--bootstrap-key /home/user/.ssh/id_ed25519_target_test \
--runtime-user backup_liot \
--repo-dir /home/backup_liot/RebuildBdd \
--runtime-user <RUNTIME_USER> \
--repo-dir /home/<RUNTIME_USER>/RebuildBdd \
--env-name RECETTE \
--pguser backup_liot \
--pguser <PGUSER> \
--pgpassword secret \
--dbs "sirh inventory ferme" \
--backup-subdir bdd-recette
@@ -443,7 +443,7 @@ Exemple :
"environment": "RECETTE",
"database": "sirh",
"dump_file": "/home/backup/backups/bdd-recette/sirh/sirh_2026-03-16_19-00-01.dump",
"log_file": "/home/backup_liot/logs/rebuild_bdd/restore_recette_web_001_2026-03-17_09-10-00.log"
"log_file": "/home/<RUNTIME_USER>/logs/rebuild_bdd/restore_recette_web_001_2026-03-17_09-10-00.log"
}
```
@@ -459,7 +459,7 @@ Exemple :
"environment": "RECETTE",
"database": "sirh",
"dump_file": "/home/backup/backups/bdd-recette/sirh/sirh_2026-03-16_19-00-01.dump",
"log_file": "/home/backup_liot/logs/rebuild_bdd/restore_recette_web_001_2026-03-17_09-10-00.log"
"log_file": "/home/<RUNTIME_USER>/logs/rebuild_bdd/restore_recette_web_001_2026-03-17_09-10-00.log"
}
```
@@ -500,7 +500,7 @@ TARGET_BACKUP_LOG_DIR
Exemple :
```bash
/home/backup_liot/logs/rebuild_bdd/
/home/<RUNTIME_USER>/logs/rebuild_bdd/
```
Le chemin du log est renvoyé dans le JSON final.
@@ -537,14 +537,14 @@ Avant mise en production, tester au minimum :
```bash
./create-target-config.sh \
--target test \
--host 192.168.1.50 \
--host <TARGET_HOST> \
--port 22 \
--bootstrap-user backup_liot \
--bootstrap-key /home/matteo/.ssh/id_ed25519_target_test \
--runtime-user backup_liot \
--repo-dir /home/backup_liot/RebuildBdd \
--bootstrap-user <BOOTSTRAP_USER> \
--bootstrap-key /home/<LOCAL_USER>/.ssh/id_ed25519_target_test \
--runtime-user <RUNTIME_USER> \
--repo-dir /home/<RUNTIME_USER>/RebuildBdd \
--env-name RECETTE \
--pguser backup_liot \
--pguser <PGUSER> \
--pgpassword secret \
--dbs "sirh inventory ferme" \
--backup-subdir bdd-recette
@@ -578,5 +578,3 @@ Le projet permet désormais une utilisation :
* intégrée au web ;
avec préparation des cibles, exécution non interactive et retour JSON.
```

View File

@@ -94,6 +94,7 @@ to_bool_yes_no() {
v="${v,,}"
case "$v" in
yes|y|oui|o|true|1) echo "yes" ;;
# Valeur vide traitée comme "no" pour conserver le comportement historique.
no|n|non|false|0|"") echo "no" ;;
*) return 1 ;;
esac
@@ -385,6 +386,13 @@ log "Correction des permissions SSH côté cible"
ssh "${SSH_OPTS[@]}" "$REMOTE" "$REMOTE_SSH_PERMS_CMD" \
|| fail "échec de correction des permissions SSH sur la cible"
STRICT_OPTION="yes"
case "${TARGET_BACKUP_KNOWN_HOSTS_STRICT_VALUE,,}" in
yes|y|oui|o|true|1) STRICT_OPTION="yes" ;;
no|n|non|false|0) STRICT_OPTION="no" ;;
*) fail "TARGET_BACKUP_KNOWN_HOSTS_STRICT invalide" ;;
esac
REMOTE_KNOWN_HOSTS_CMD="
set -euo pipefail
@@ -406,13 +414,6 @@ log "Ajout du serveur de backup dans known_hosts côté cible"
ssh "${SSH_OPTS[@]}" "$REMOTE" "$REMOTE_KNOWN_HOSTS_CMD" \
|| fail "échec de préparation known_hosts sur la cible"
STRICT_OPTION="yes"
case "${TARGET_BACKUP_KNOWN_HOSTS_STRICT_VALUE,,}" in
yes|y|oui|o|true|1) STRICT_OPTION="yes" ;;
no|n|non|false|0) STRICT_OPTION="no" ;;
*) fail "TARGET_BACKUP_KNOWN_HOSTS_STRICT invalide" ;;
esac
REMOTE_BACKUP_TEST_CMD="
set -euo pipefail

View File

@@ -79,6 +79,7 @@ to_bool_yes_no() {
v="${v,,}"
case "$v" in
yes|y|oui|o|true|1) echo "yes" ;;
# Valeur vide traitée comme "no" pour conserver le comportement historique.
no|n|non|false|0|"") echo "no" ;;
*) return 1 ;;
esac

View File

@@ -121,6 +121,7 @@ to_bool_yes_no() {
v="${v,,}"
case "$v" in
yes|y|oui|o|true|1) echo "yes" ;;
# Valeur vide traitée comme "no" pour conserver le comportement historique.
no|n|non|false|0|"") echo "no" ;;
*) return 1 ;;
esac

View File

@@ -88,6 +88,7 @@ to_bool_yes_no() {
v="${v,,}"
case "$v" in
yes|y|oui|o|true|1) echo "yes" ;;
# Valeur vide traitée comme "no" pour conserver le comportement historique.
no|n|non|false|0|"") echo "no" ;;
*) return 1 ;;
esac

View File

@@ -292,9 +292,6 @@ CHECK APP RECETTE 🟢
# 7. Script : rebuild-bdd-recette.sh
Script :
## Objectif
Restaurer une base PostgreSQL à partir dun dump distant.

View File

@@ -18,7 +18,8 @@ umask 077
# 6. exporte les rôles PostgreSQL ;
# 7. dump chaque base au format personnalisé PostgreSQL ;
# 8. transfère chaque fichier vers le serveur distant ;
# 9. applique une rotation distante sur 10 jours ;
# 9. applique une rotation distante selon BACKUP_RETENTION_DAYS
# (10 jours par défaut) ;
# 10. envoie un bilan sur Discord :
# - 1 message global si tout est OK ;
# - en cas derreur partielle :
@@ -50,6 +51,10 @@ set +a
#######################################
: "${ENV_NAME:?Variable ENV_NAME manquante}"
[[ "$ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]] || {
echo "Variable ENV_NAME invalide : $ENV_NAME" >&2
exit 1
}
: "${PGHOST:?Variable PGHOST manquante}"
: "${PGPORT:?Variable PGPORT manquante}"
: "${PGUSER:?Variable PGUSER manquante}"
@@ -58,6 +63,10 @@ set +a
: "${BACKUP_REMOTE_USER:?Variable BACKUP_REMOTE_USER manquante}"
: "${BACKUP_REMOTE_HOST:?Variable BACKUP_REMOTE_HOST manquante}"
: "${BACKUP_REMOTE_DIR:?Variable BACKUP_REMOTE_DIR manquante}"
[[ "$BACKUP_REMOTE_DIR" =~ ^[a-zA-Z0-9/_.-]+$ ]] || {
echo "Variable BACKUP_REMOTE_DIR invalide : $BACKUP_REMOTE_DIR" >&2
exit 1
}
: "${SSH_KEY:?Variable SSH_KEY manquante}"
: "${SSH_TIMEOUT:?Variable SSH_TIMEOUT manquante}"
: "${BACKUP_LOG_DIR:?Variable BACKUP_LOG_DIR manquante}"
@@ -87,7 +96,7 @@ for DB in "${DBS_ARRAY[@]}"; do
done
IA_SSH="${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}"
RETENTION_DAYS=10
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-10}"
BACKUP_REMOTE_SSH_PORT="${BACKUP_REMOTE_SSH_PORT:-22}"
BACKUP_KNOWN_HOSTS_STRICT="${BACKUP_KNOWN_HOSTS_STRICT:-yes}"
BACKUP_KNOWN_HOSTS_FILE="${BACKUP_KNOWN_HOSTS_FILE:-${HOME}/.ssh/known_hosts}"

View File

@@ -44,13 +44,23 @@ set +a
: "${CHECK_MAX_TIME:?Variable CHECK_MAX_TIME manquante}"
: "${APP_URLS:?Variable APP_URLS manquante}"
[[ "$CHECK_CONNECT_TIMEOUT" =~ ^[0-9]+$ ]] || {
echo "ERROR: Variable CHECK_CONNECT_TIMEOUT invalide" >&2
exit 1
}
[[ "$CHECK_MAX_TIME" =~ ^[0-9]+$ ]] || {
echo "ERROR: Variable CHECK_MAX_TIME invalide" >&2
exit 1
}
#######################################
# Sites à vérifier
#######################################
read -r -a SITES <<< "$APP_URLS"
SCHEME="http"
SCHEME="${APP_SCHEME:-http}"
CONNECT_TIMEOUT="${CHECK_CONNECT_TIMEOUT}"
MAX_TIME="${CHECK_MAX_TIME}"
@@ -75,6 +85,16 @@ DISCORD_PING="${DISCORD_PING:-@here}"
SUMMARY_LINES=()
FAILURES=0
TMPFILES=()
cleanup() {
local tmpfile
for tmpfile in "${TMPFILES[@]}"; do
[[ -n "$tmpfile" ]] || continue
rm -f -- "$tmpfile"
done
}
trap cleanup EXIT
#######################################
# Logging
@@ -158,6 +178,7 @@ check_site() {
local http_code curl_exit err
local stderr
stderr="$(mktemp)"
TMPFILES+=("$stderr")
http_code="$(
curl -sS -o /dev/null \
@@ -170,15 +191,12 @@ check_site() {
if [[ "$curl_exit" -ne 0 ]]; then
err="$(head -n 1 "$stderr" | tr -d '\r')"
rm -f "$stderr"
log_line "DOWN" "$host" "curl exit=$curl_exit : ${err:-"(aucun)"}"
add_summary_line "$host" "DOWN" "DOWN - curl"
return 1
fi
rm -f "$stderr"
if [[ "$http_code" =~ ^[0-9]{3}$ ]]; then
if [[ "$http_code" -ge 200 && "$http_code" -le 399 ]]; then
log_line "OK" "$host" "HTTP $http_code"

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
umask 077
###############################################################################
# rebuild-bdd-recette.sh
@@ -49,6 +50,10 @@ set +a
# Variables obligatoires
###############################################################################
: "${ENV_NAME:?Variable ENV_NAME manquante}"
[[ "$ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]] || {
echo "Variable ENV_NAME invalide : $ENV_NAME" >&2
exit 1
}
: "${PGHOST:?Variable PGHOST manquante}"
: "${PGPORT:?Variable PGPORT manquante}"
: "${PGUSER:?Variable PGUSER manquante}"
@@ -110,6 +115,7 @@ cleanup() {
"${FILTERED_ROLES_FILE:-}" \
"${ROLES_CREATE_LIST:-}" \
"${ROLES_APPLY_FILE:-}"
rm -rf "${LOCAL_RESTORE_DIR:-}" 2>/dev/null || true
}
trap cleanup EXIT
@@ -150,14 +156,14 @@ build_excluded_roles_regex() {
# Envoi Discord
#
# Envoi simple d'un message texte via webhook Discord.
# Si WEBHOOK_URL n'est pas défini, on ignore silencieusement l'envoi.
# Si DISCORD_WEBHOOK_URL n'est pas défini, on ignore silencieusement l'envoi.
###############################################################################
send_discord_message() {
local message="$1"
local payload=""
[[ -n "$DISCORD_WEBHOOK_URL" ]] || {
log "WEBHOOK_URL non défini : notification Discord ignorée."
log "DISCORD_WEBHOOK_URL non défini : notification Discord ignorée."
return 0
}

View File

@@ -89,6 +89,7 @@ SSH_TIMEOUT=10
#############################################
# Nombre de jours de conservation des sauvegardes
# Utilisé par backup-bdd-recette.sh et backup-vaultwarden.sh
BACKUP_RETENTION_DAYS=10
@@ -96,12 +97,11 @@ BACKUP_RETENTION_DAYS=10
# APPLICATIONS À SURVEILLER
#############################################
# Liste des applications à vérifier
APPS="
ferme.malio-dev.fr
inventory.malio-dev.fr
sirh.malio-dev.fr
"
# Liste des applications à vérifier (séparées par espace)
APP_URLS="ferme.malio-dev.fr inventory.malio-dev.fr sirh.malio-dev.fr"
# Schéma utilisé pour les applications surveillées
APP_SCHEME="http"
#############################################