feat: backup_trilium.sh - backup local automatise de la base
Etage 1 de la strategie de backup (reco n1 de l audit). Copie coherente via ETAPI (jamais de SQLite a chaud - le WAL faisait 4 Mo), sortie du dossier Docker, verification d integrite avec suppression si KO, rotation 30, chmod 600. Tache DSM quotidienne 03h00 en root (dossier backup en 700).
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
# backup_trilium.sh - Backup local horodate de la base Trilium (etage 1).
|
||||
# Execute en ROOT par le planificateur DSM (le dossier backup/ est en 700 uid 1000).
|
||||
# 1) demande a Trilium une copie coherente via ETAPI (jamais de copie SQLite a chaud)
|
||||
# 2) la sort du dossier Docker vers /volume1/backups/trilium, horodatee
|
||||
# 3) verifie l integrite du fichier copie
|
||||
# 4) garde les 30 derniers
|
||||
# Sortie : "OK ..." ou "ERREUR ..." (pour alerte mail DSM).
|
||||
|
||||
BASE=/volume1/homes/Master/App/Context_continuity
|
||||
PY=$BASE/venv/bin/python3
|
||||
SRC=/volume1/docker/trilium/backup/backup-quotidien.db
|
||||
DEST=/volume1/backups/trilium
|
||||
URL=http://localhost:4292
|
||||
GARDER=30
|
||||
|
||||
STAMP=$(date +%Y%m%d_%H%M)
|
||||
CIBLE=$DEST/trilium_$STAMP.db
|
||||
|
||||
TOKEN=$(grep '^TRILIUM_TOKEN=' $BASE/.env | cut -d= -f2- | tr -d '"' | tr -d "'")
|
||||
if [ -z "$TOKEN" ]; then echo "ERREUR token ETAPI introuvable dans $BASE/.env"; exit 1; fi
|
||||
|
||||
mkdir -p $DEST
|
||||
|
||||
# 1. Demander a Trilium de regenerer la copie (nom dedie : n ecrase pas daily/weekly/monthly)
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" -X PUT "$URL/etapi/backup/quotidien" -H "Authorization: $TOKEN" --max-time 60)
|
||||
if [ "$CODE" != "204" ]; then echo "ERREUR ETAPI backup HTTP $CODE"; exit 1; fi
|
||||
|
||||
# 2. Verifier que le fichier existe et vient d etre ecrit, puis le sortir du dossier Docker
|
||||
if [ ! -f "$SRC" ]; then echo "ERREUR fichier source absent : $SRC"; exit 1; fi
|
||||
find "$SRC" -mmin -5 | grep -q . || { echo "ERREUR source non regeneree (plus de 5 min)"; exit 1; }
|
||||
cp "$SRC" "$CIBLE" || { echo "ERREUR copie vers $CIBLE"; exit 1; }
|
||||
|
||||
# 3. Verifier l integrite de la COPIE (un backup non verifie n est pas un backup)
|
||||
INTEG=$($PY -c "import sqlite3,sys
|
||||
try:
|
||||
c=sqlite3.connect('$CIBLE')
|
||||
r=c.execute('PRAGMA integrity_check').fetchone()[0]
|
||||
n=c.execute('SELECT count(*) FROM notes').fetchone()[0]
|
||||
c.close()
|
||||
print('%s|%d' % (r,n))
|
||||
except Exception as e:
|
||||
print('erreur|%s' % e)")
|
||||
RESU=$(echo "$INTEG" | cut -d'|' -f1)
|
||||
NBNOTES=$(echo "$INTEG" | cut -d'|' -f2)
|
||||
if [ "$RESU" != "ok" ]; then rm -f "$CIBLE"; echo "ERREUR integrite KO ($INTEG) - copie supprimee"; exit 1; fi
|
||||
|
||||
# 4. Rotation : garder les N plus recents
|
||||
cd $DEST || exit 1
|
||||
ls -1t trilium_*.db 2>/dev/null | tail -n +$((GARDER+1)) | while read f; do rm -f "$f"; done
|
||||
|
||||
chmod 600 "$CIBLE"
|
||||
TAILLE=$(du -h "$CIBLE" | cut -f1)
|
||||
RESTANT=$(ls -1 trilium_*.db 2>/dev/null | wc -l)
|
||||
echo "OK $CIBLE ($TAILLE, $NBNOTES notes, $RESTANT backups conserves)"
|
||||
Reference in New Issue
Block a user