Files

72 lines
3.0 KiB
Bash
Raw Permalink Normal View History

#!/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"
# 5. Push off-site vers Proton Drive (n echoue PAS le backup local si KO)
REMOTE="proton:Backups/trilium"
OFFSITE="offsite:KO"
if command -v rclone >/dev/null 2>&1; then
if rclone copy "$CIBLE" "$REMOTE/" --max-duration 5m >/dev/null 2>&1; then
# rotation distante : garder les N plus recents
rclone lsf "$REMOTE/" 2>/dev/null | grep '^trilium_.*\.db$' | sort -r | tail -n +$((GARDER+1)) | while read f; do
rclone deletefile "$REMOTE/$f" >/dev/null 2>&1
done
NBREMOTE=$(rclone lsf "$REMOTE/" 2>/dev/null | grep -c '^trilium_.*\.db$')
OFFSITE="offsite:OK($NBREMOTE)"
fi
else
OFFSITE="offsite:rclone-absent"
fi
TAILLE=$(du -h "$CIBLE" | cut -f1)
RESTANT=$(ls -1 trilium_*.db 2>/dev/null | wc -l)
echo "OK $CIBLE ($TAILLE, $NBNOTES notes, $RESTANT locaux, $OFFSITE)"