Erreur32 revised this gist 4 months ago. Go to revision
1 file changed, 482 insertions, 168 deletions
Backup-Home-docker.tar.gz.sh
| @@ -1,38 +1,47 @@ | |||
| 1 | 1 | #!/bin/bash | |
| 2 | 2 | ||
| 3 | + | # Backup complet Docker + (CasaOS si présent) + Portainer | |
| 4 | + | # + export docker-compose + rapport HTML + index | |
| 5 | + | # + last/ + rotation + publication WEB (HTML only) | |
| 6 | + | ||
| 3 | 7 | ############################# | |
| 4 | 8 | # CONFIG | |
| 5 | 9 | ############################# | |
| 6 | 10 | ||
| 7 | - | # Backup complet des data docker , casaos et portainer | |
| 8 | - | # avec liste de tous les compose files des containers classés par répertoire. | |
| 9 | - | ||
| 10 | - | ||
| 11 | - | # Répertoire contenant tes containers | |
| 12 | 11 | SOURCE_DIR="/home/docker" | |
| 13 | 12 | ||
| 14 | - | # Répertoire où stocker les sauvegardes | |
| 15 | - | BACKUP_DIR="/home/backup/docker" | |
| 16 | - | ||
| 17 | - | # Nombre max de backups à conserver (dossiers datés) | |
| 13 | + | # Base des backups datés | |
| 14 | + | BACKUP_DIR="/home/backup/docker/compose" | |
| 18 | 15 | MAX_BACKUPS=3 | |
| 19 | 16 | ||
| 20 | - | # Date interne (pour logs / JSON) | |
| 21 | 17 | DATE_RAW="$(date +'%Y%m%d_%H%M%S')" | |
| 22 | - | # Date pour le dossier de backup (format humain demandé) | |
| 23 | 18 | DATE_DIR="$(date +'%Y.%m.%d_%H-%M-%S')" | |
| 24 | 19 | ||
| 25 | - | # Dossier de ce backup | |
| 20 | + | # Dossier daté du run courant | |
| 26 | 21 | RUN_DIR="$BACKUP_DIR/$DATE_DIR" | |
| 27 | 22 | ||
| 28 | - | # Fichiers TAR dans le dossier de ce backup | |
| 23 | + | # Dossier "dernier backup" | |
| 24 | + | LAST_DIR="$BACKUP_DIR/last" | |
| 25 | + | ||
| 26 | + | # Archives dans le dossier daté | |
| 29 | 27 | BACKUP_FILE="$RUN_DIR/docker_backup.tar.gz" | |
| 30 | 28 | CASAOS_FULL_TAR="$RUN_DIR/casaos_full_backup.tar.gz" | |
| 31 | 29 | ||
| 32 | - | # Dossier où l'on met les compose / configs | |
| 30 | + | # Dossier de configs / compose dans le run | |
| 33 | 31 | CONFIG_DIR="$RUN_DIR" | |
| 34 | 32 | ||
| 35 | - | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR pour le tar Docker) | |
| 33 | + | # Logs | |
| 34 | + | LOG_FILE="/var/log/docker_backup.log" | |
| 35 | + | ||
| 36 | + | # Rapports HTML | |
| 37 | + | HTML_REPORT="$RUN_DIR/report.html" | |
| 38 | + | HTML_REPORT_LAST="$LAST_DIR/report.html" | |
| 39 | + | HTML_INDEX_LAST="$LAST_DIR/index.html" | |
| 40 | + | ||
| 41 | + | # Publication WEB (HTML uniquement) | |
| 42 | + | WEB_PUBLIC_DIR="/home/www-adm1n/docker_compose" | |
| 43 | + | ||
| 44 | + | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR) | |
| 36 | 45 | EXCLUDE_DIRS=( | |
| 37 | 46 | "docker_var_lib" | |
| 38 | 47 | "1_Backups" | |
| @@ -41,17 +50,42 @@ EXCLUDE_DIRS=( | |||
| 41 | 50 | "yt-dl/video/*" | |
| 42 | 51 | ) | |
| 43 | 52 | ||
| 44 | - | # LOGS | |
| 45 | - | LOG_FILE="/var/log/docker_backup.log" | |
| 53 | + | ############################# | |
| 54 | + | # MODE TTY / CRON | |
| 55 | + | ############################# | |
| 56 | + | ||
| 57 | + | # Si pas de terminal (cron), on désactive les couleurs | |
| 58 | + | if [ -t 1 ]; then | |
| 59 | + | USE_COLORS=1 | |
| 60 | + | else | |
| 61 | + | USE_COLORS=0 | |
| 62 | + | fi | |
| 46 | 63 | ||
| 47 | 64 | ############################# | |
| 48 | 65 | # COULEURS | |
| 49 | 66 | ############################# | |
| 50 | - | NC="\e[0m" | |
| 51 | - | GREEN="\e[32m" | |
| 52 | - | YELLOW="\e[33m" | |
| 53 | - | CYAN="\e[36m" | |
| 54 | - | RED="\e[31m" | |
| 67 | + | if [ "$USE_COLORS" = "1" ]; then | |
| 68 | + | NC="\e[0m" | |
| 69 | + | GREEN="\e[32m" | |
| 70 | + | YELLOW="\e[33m" | |
| 71 | + | CYAN="\e[36m" | |
| 72 | + | RED="\e[31m" | |
| 73 | + | else | |
| 74 | + | NC="" | |
| 75 | + | GREEN="" | |
| 76 | + | YELLOW="" | |
| 77 | + | CYAN="" | |
| 78 | + | RED="" | |
| 79 | + | fi | |
| 80 | + | ||
| 81 | + | ############################# | |
| 82 | + | # DÉTECTION CASAOS | |
| 83 | + | ############################# | |
| 84 | + | ||
| 85 | + | CASAOS_PRESENT=0 | |
| 86 | + | if [ -d "/var/lib/casaos" ] || [ -d "$SOURCE_DIR/casaos_data" ] || command -v casaos >/dev/null 2>&1; then | |
| 87 | + | CASAOS_PRESENT=1 | |
| 88 | + | fi | |
| 55 | 89 | ||
| 56 | 90 | ############################# | |
| 57 | 91 | # FONCTIONS | |
| @@ -75,29 +109,42 @@ format_time() { | |||
| 75 | 109 | ||
| 76 | 110 | check_pigz() { | |
| 77 | 111 | if ! command -v pigz >/dev/null 2>&1; then | |
| 78 | - | echo -e "${YELLOW}pigz n'est pas installé. Voulez-vous l’installer ? (y/n)${NC}" | |
| 79 | - | read rep | |
| 80 | - | if [ "$rep" = "y" ]; then | |
| 81 | - | sudo apt update && sudo apt install -y pigz || { | |
| 82 | - | echo -e "${RED}Échec de l’installation de pigz. Abandon.${NC}" | |
| 112 | + | log_message "pigz n'est pas installé." | |
| 113 | + | ||
| 114 | + | if [ "$USE_COLORS" = "1" ]; then | |
| 115 | + | echo -e "${YELLOW}pigz n'est pas installé. Voulez-vous l’installer ? (y/n)${NC}" | |
| 116 | + | read -r rep | |
| 117 | + | if [ "$rep" = "y" ]; then | |
| 118 | + | sudo apt update && sudo apt install -y pigz || { | |
| 119 | + | echo -e "${RED}Échec installation pigz. Abandon.${NC}" | |
| 120 | + | exit 1 | |
| 121 | + | } | |
| 122 | + | else | |
| 123 | + | echo -e "${RED}pigz requis. Abandon.${NC}" | |
| 83 | 124 | exit 1 | |
| 84 | - | } | |
| 125 | + | fi | |
| 85 | 126 | else | |
| 86 | - | echo -e "${RED}pigz est requis pour ce script. Abandon.${NC}" | |
| 127 | + | echo "ERREUR: pigz requis (mode cron non-interactif)." | |
| 87 | 128 | exit 1 | |
| 88 | 129 | fi | |
| 89 | 130 | fi | |
| 90 | 131 | } | |
| 91 | 132 | ||
| 92 | 133 | rotate_backups() { | |
| 93 | - | log_message "Rotation des anciens backups (conserver les $MAX_BACKUPS plus récents)..." | |
| 134 | + | log_message "Rotation backups (max $MAX_BACKUPS)..." | |
| 94 | 135 | ||
| 95 | - | # On ne garde que les dossiers datés dans BACKUP_DIR | |
| 96 | - | mapfile -t backups_dirs < <(ls -1td "$BACKUP_DIR"/*/ 2>/dev/null || true) | |
| 136 | + | # Liste uniquement les dossiers datés, ignore last/ | |
| 137 | + | mapfile -t backups_dirs < <( | |
| 138 | + | find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 139 | + | ! -name "last" \ | |
| 140 | + | -printf "%T@ %p\n" 2>/dev/null \ | |
| 141 | + | | sort -nr \ | |
| 142 | + | | awk '{print $2}' | |
| 143 | + | ) | |
| 97 | 144 | ||
| 98 | 145 | if [ "${#backups_dirs[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 99 | 146 | for d in "${backups_dirs[@]:$MAX_BACKUPS}"; do | |
| 100 | - | log_message "Suppression ancien backup (dossier) : $d" | |
| 147 | + | log_message "Suppression ancien backup : $d" | |
| 101 | 148 | rm -rf "$d" | |
| 102 | 149 | done | |
| 103 | 150 | fi | |
| @@ -107,6 +154,140 @@ get_size() { | |||
| 107 | 154 | du -sh "$1" 2>/dev/null | awk '{print $1}' | |
| 108 | 155 | } | |
| 109 | 156 | ||
| 157 | + | html_escape() { | |
| 158 | + | sed -e 's/&/\&/g' \ | |
| 159 | + | -e 's/</\</g' \ | |
| 160 | + | -e 's/>/\>/g' | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | html_line() { | |
| 164 | + | # $1=label $2=value $3=emoji $4=class | |
| 165 | + | echo "<div class='row $4'><span class='emoji'>$3</span><span class='label'>$1</span><span class='value'>$2</span></div>" >> "$HTML_REPORT" | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | ||
| 169 | + | html_container_table() { | |
| 170 | + | local dirs | |
| 171 | + | dirs=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 172 | + | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 173 | + | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 174 | + | ! -path "$SOURCE_DIR/portainer" \ | |
| 175 | + | 2>/dev/null) | |
| 176 | + | ||
| 177 | + | if [ -z "$dirs" ]; then | |
| 178 | + | echo "<div class='empty'>Aucun dossier Docker trouvé.</div>" >> "$HTML_REPORT" | |
| 179 | + | return | |
| 180 | + | fi | |
| 181 | + | ||
| 182 | + | echo "<div class='tblwrap'><table class='tbl'>" >> "$HTML_REPORT" | |
| 183 | + | echo "<thead><tr><th>📦 Container</th><th>📏 Taille</th><th>📁 Chemin</th></tr></thead>" >> "$HTML_REPORT" | |
| 184 | + | echo "<tbody>" >> "$HTML_REPORT" | |
| 185 | + | ||
| 186 | + | # tri par taille desc | |
| 187 | + | du -sh $dirs 2>/dev/null | sort -hr | while read -r size path; do | |
| 188 | + | name="$(basename "$path")" | |
| 189 | + | esc_path="$(echo "$path" | html_escape)" | |
| 190 | + | echo "<tr><td><b>$name</b></td><td>$size</td><td><code>$esc_path</code></td></tr>" >> "$HTML_REPORT" | |
| 191 | + | done | |
| 192 | + | ||
| 193 | + | echo "</tbody></table></div>" >> "$HTML_REPORT" | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | ||
| 197 | + | generate_index_html() { | |
| 198 | + | local base_dir="$1" | |
| 199 | + | local output_file="$2" | |
| 200 | + | ||
| 201 | + | cat > "$output_file" <<EOF | |
| 202 | + | <!doctype html> | |
| 203 | + | <html lang="fr"> | |
| 204 | + | <head> | |
| 205 | + | <meta charset="utf-8"> | |
| 206 | + | <title>Index Backups Docker</title> | |
| 207 | + | <style> | |
| 208 | + | body{font-family:Arial,sans-serif;background:#0b1220;color:#e5e7eb;margin:0;padding:24px} | |
| 209 | + | .card{background:#111827;border:1px solid #1f2937;border-radius:12px;padding:16px;max-width:980px;margin:auto} | |
| 210 | + | h1{margin:0 0 12px;font-size:22px} | |
| 211 | + | a{color:#93c5fd;text-decoration:none} | |
| 212 | + | a:hover{text-decoration:underline} | |
| 213 | + | hr{border:0;border-top:1px solid #1f2937;margin:12px 0} | |
| 214 | + | .toolbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:12px} | |
| 215 | + | .btn{display:inline-block;padding:8px 12px;border-radius:10px;background:#0f172a;border:1px solid #1f2937} | |
| 216 | + | .btn:hover{background:#111c33} | |
| 217 | + | .item{padding:10px;border-radius:12px;margin:8px 0;background:#0f172a;border:1px solid #1f2937} | |
| 218 | + | .row{display:flex;justify-content:space-between;gap:12px;align-items:center;flex-wrap:wrap} | |
| 219 | + | .left{display:flex;gap:10px;align-items:center} | |
| 220 | + | .badge{font-size:12px;padding:4px 8px;border-radius:999px;background:#1f2937} | |
| 221 | + | .badge-ok{background:#052e16;color:#86efac;border:1px solid #14532d} | |
| 222 | + | .badge-warn{background:#451a03;color:#fcd34d;border:1px solid #92400e} | |
| 223 | + | .meta{color:#94a3b8;font-size:12px;margin-top:6px} | |
| 224 | + | small{color:#94a3b8} | |
| 225 | + | .note{color:#94a3b8;font-size:12px;margin-top:10px} | |
| 226 | + | </style> | |
| 227 | + | </head> | |
| 228 | + | <body> | |
| 229 | + | <div class="card"> | |
| 230 | + | <h1>📦 Index des Backups Docker</h1> | |
| 231 | + | <small>Dossier backups: $base_dir</small> | |
| 232 | + | ||
| 233 | + | <div class="toolbar"> | |
| 234 | + | <a class="btn" href="./report.html">📌 Ouvrir le LAST</a> | |
| 235 | + | </div> | |
| 236 | + | ||
| 237 | + | <div class="note"> | |
| 238 | + | ℹ️ Les backups datés ne sont pas exposés sur le web (sécurité). | |
| 239 | + | Seul le rapport <b>LAST</b> est accessible. | |
| 240 | + | </div> | |
| 241 | + | ||
| 242 | + | <hr> | |
| 243 | + | EOF | |
| 244 | + | ||
| 245 | + | # Liste dossiers datés (ignore last) | |
| 246 | + | find "$base_dir" -mindepth 1 -maxdepth 1 -type d ! -name "last" 2>/dev/null \ | |
| 247 | + | | sort -r \ | |
| 248 | + | | while read -r d; do | |
| 249 | + | ||
| 250 | + | name="$(basename "$d")" | |
| 251 | + | tarfile="$d/docker_backup.tar.gz" | |
| 252 | + | report="$d/report.html" | |
| 253 | + | ||
| 254 | + | mtime="$(date -r "$d" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo 'N/A')" | |
| 255 | + | ||
| 256 | + | if [ -f "$tarfile" ]; then | |
| 257 | + | tarsize="$(du -sh "$tarfile" 2>/dev/null | awk '{print $1}')" | |
| 258 | + | else | |
| 259 | + | tarsize="N/A" | |
| 260 | + | fi | |
| 261 | + | ||
| 262 | + | if [ -f "$report" ]; then | |
| 263 | + | status="OK" | |
| 264 | + | badge="badge-ok" | |
| 265 | + | else | |
| 266 | + | status="missing report" | |
| 267 | + | badge="badge-warn" | |
| 268 | + | fi | |
| 269 | + | ||
| 270 | + | cat >> "$output_file" <<EOF | |
| 271 | + | <div class="item"> | |
| 272 | + | <div class="row"> | |
| 273 | + | <div class="left"> | |
| 274 | + | <span>📄</span> | |
| 275 | + | <span><b>$name</b></span> | |
| 276 | + | </div> | |
| 277 | + | <span class="badge $badge">$status</span> | |
| 278 | + | </div> | |
| 279 | + | <div class="meta">🕒 $mtime — 🗜️ docker_backup.tar.gz : <b>$tarsize</b></div> | |
| 280 | + | </div> | |
| 281 | + | EOF | |
| 282 | + | done | |
| 283 | + | ||
| 284 | + | cat >> "$output_file" <<EOF | |
| 285 | + | </div> | |
| 286 | + | </body> | |
| 287 | + | </html> | |
| 288 | + | EOF | |
| 289 | + | } | |
| 290 | + | ||
| 110 | 291 | ############################# | |
| 111 | 292 | # DÉBUT SCRIPT | |
| 112 | 293 | ############################# | |
| @@ -116,16 +297,20 @@ SECONDS=0 | |||
| 116 | 297 | check_pigz | |
| 117 | 298 | ||
| 118 | 299 | mkdir -p "$RUN_DIR" | |
| 300 | + | mkdir -p "$BACKUP_DIR" | |
| 119 | 301 | touch "$LOG_FILE" | |
| 120 | 302 | ||
| 121 | 303 | echo -e "${CYAN}=== Backup Docker + Configs (Portainer / CasaOS) ===${NC}" | |
| 122 | - | log_message "Début sauvegarde Docker + configs Portainer & CasaOS..." | |
| 123 | - | log_message "Dossier de backup : $RUN_DIR" | |
| 304 | + | log_message "Début sauvegarde..." | |
| 305 | + | log_message "Dossier backup (run) : $RUN_DIR" | |
| 306 | + | log_message "Dossier backup (last): $LAST_DIR" | |
| 307 | + | log_message "CasaOS détecté : $CASAOS_PRESENT" | |
| 124 | 308 | ||
| 125 | 309 | ############################################## | |
| 126 | - | # 1) Sauvegarde TAR Docker via pigz + exclusions | |
| 310 | + | # 1) Archive Docker | |
| 127 | 311 | ############################################## | |
| 128 | - | log_message "Création de l’archive Docker : $BACKUP_FILE" | |
| 312 | + | ||
| 313 | + | log_message "Création archive Docker : $BACKUP_FILE" | |
| 129 | 314 | ||
| 130 | 315 | EXCLUDE_ARGS=( | |
| 131 | 316 | "--exclude=*.log" | |
| @@ -167,37 +352,44 @@ if [ $? -ne 0 ]; then | |||
| 167 | 352 | fi | |
| 168 | 353 | ||
| 169 | 354 | ############################################## | |
| 170 | - | # 2) Extraction des docker-compose | |
| 171 | - | # - CasaOS: RUN_DIR/casaos/<container>/ | |
| 172 | - | # - Docker: RUN_DIR/docker/<container>/ | |
| 355 | + | # 2) Extraction docker-compose CasaOS (si présent) | |
| 173 | 356 | ############################################## | |
| 174 | 357 | ||
| 175 | - | log_message "Extraction des docker-compose CasaOS..." | |
| 176 | - | if [ -d "$SOURCE_DIR/casaos_data" ]; then | |
| 177 | - | find "$SOURCE_DIR/casaos_data" -maxdepth 3 -type f -name "docker-compose.y*ml" | while read file; do | |
| 178 | - | container_name=$(basename "$(dirname "$file")") | |
| 179 | - | dest_dir="$CONFIG_DIR/casaos/$container_name" | |
| 180 | - | mkdir -p "$dest_dir" | |
| 181 | - | cp "$file" "$dest_dir/" | |
| 182 | - | log_message " [CasaOS] → Compose trouvé : $file" | |
| 183 | - | done | |
| 358 | + | if [ "$CASAOS_PRESENT" = "1" ]; then | |
| 359 | + | log_message "Extraction des docker-compose CasaOS..." | |
| 360 | + | if [ -d "$SOURCE_DIR/casaos_data" ]; then | |
| 361 | + | find "$SOURCE_DIR/casaos_data" -maxdepth 3 -type f -name "docker-compose.y*ml" | while read -r file; do | |
| 362 | + | container_name=$(basename "$(dirname "$file")") | |
| 363 | + | dest_dir="$CONFIG_DIR/casaos/$container_name" | |
| 364 | + | mkdir -p "$dest_dir" | |
| 365 | + | cp "$file" "$dest_dir/" | |
| 366 | + | log_message " [CasaOS] compose : $file" | |
| 367 | + | done | |
| 368 | + | fi | |
| 369 | + | else | |
| 370 | + | log_message "CasaOS non détecté → ignoré." | |
| 184 | 371 | fi | |
| 185 | 372 | ||
| 186 | - | log_message "Extraction des docker-compose Docker (hors casaos_data & dossiers exclus)..." | |
| 373 | + | ############################################## | |
| 374 | + | # 3) Extraction docker-compose Docker (hors CasaOS) | |
| 375 | + | ############################################## | |
| 376 | + | ||
| 377 | + | log_message "Extraction des docker-compose Docker..." | |
| 187 | 378 | find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| 188 | 379 | ! -path "$SOURCE_DIR/casaos_data/*" \ | |
| 189 | 380 | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 190 | - | 2>/dev/null | while read file; do | |
| 381 | + | 2>/dev/null | while read -r file; do | |
| 191 | 382 | container_name=$(basename "$(dirname "$file")") | |
| 192 | 383 | dest_dir="$CONFIG_DIR/Compose/$container_name" | |
| 193 | 384 | mkdir -p "$dest_dir" | |
| 194 | 385 | cp "$file" "$dest_dir/" | |
| 195 | - | log_message " [Docker] → Compose trouvé : $file" | |
| 386 | + | log_message " [Docker] compose : $file" | |
| 196 | 387 | done | |
| 197 | 388 | ||
| 198 | 389 | ############################################## | |
| 199 | - | # 3) Config Portainer (full) | |
| 390 | + | # 4) Backup config Portainer (si volume présent) | |
| 200 | 391 | ############################################## | |
| 392 | + | ||
| 201 | 393 | PORTAINER_CONFIG_DIR="$CONFIG_DIR/portainer" | |
| 202 | 394 | PORTAINER_FILES=0 | |
| 203 | 395 | ||
| @@ -211,197 +403,319 @@ else | |||
| 211 | 403 | fi | |
| 212 | 404 | ||
| 213 | 405 | ############################################## | |
| 214 | - | # 4) Config CasaOS (full + tar.gz) | |
| 406 | + | # 5) Backup CasaOS (config + FULL TAR) si présent | |
| 215 | 407 | ############################################## | |
| 408 | + | ||
| 216 | 409 | CASAOS_CONFIG_DIR="$CONFIG_DIR/casaos/full_config" | |
| 217 | 410 | ||
| 218 | - | if [ -d "/var/lib/casaos" ]; then | |
| 219 | - | log_message "Sauvegarde config CasaOS (full vers $CASAOS_CONFIG_DIR)..." | |
| 220 | - | mkdir -p "$CASAOS_CONFIG_DIR" | |
| 221 | - | cp -r /var/lib/casaos/* "$CASAOS_CONFIG_DIR/" 2>>"$LOG_FILE" | |
| 222 | - | fi | |
| 411 | + | if [ "$CASAOS_PRESENT" = "1" ]; then | |
| 412 | + | if [ -d "/var/lib/casaos" ]; then | |
| 413 | + | log_message "Sauvegarde config CasaOS full..." | |
| 414 | + | mkdir -p "$CASAOS_CONFIG_DIR" | |
| 415 | + | cp -r /var/lib/casaos/* "$CASAOS_CONFIG_DIR/" 2>>"$LOG_FILE" | |
| 416 | + | fi | |
| 223 | 417 | ||
| 224 | - | # Création du second tar.gz CasaOS FULL (config + volumes casaos_data) | |
| 225 | - | if [ -d "/var/lib/casaos" ] || [ -d "$SOURCE_DIR/casaos_data" ]; then | |
| 226 | 418 | CASAOS_TAR_SOURCES=() | |
| 227 | 419 | [ -d "/var/lib/casaos" ] && CASAOS_TAR_SOURCES+=( "/var/lib/casaos" ) | |
| 228 | 420 | [ -d "$SOURCE_DIR/casaos_data" ] && CASAOS_TAR_SOURCES+=( "$SOURCE_DIR/casaos_data" ) | |
| 229 | 421 | ||
| 230 | 422 | if [ "${#CASAOS_TAR_SOURCES[@]}" -gt 0 ]; then | |
| 231 | - | log_message "Création de l’archive CASAOS FULL : $CASAOS_FULL_TAR" | |
| 423 | + | log_message "Création archive CasaOS FULL : $CASAOS_FULL_TAR" | |
| 232 | 424 | tar -cf "$CASAOS_FULL_TAR" -I pigz "${CASAOS_TAR_SOURCES[@]}" 2>>"$LOG_FILE" | |
| 233 | - | if [ $? -ne 0 ]; then | |
| 234 | - | log_message "ERREUR lors de la création du tar CasaOS." | |
| 235 | - | echo -e "${RED}Erreur lors de la création de l’archive CasaOS.${NC}" | |
| 236 | - | fi | |
| 237 | 425 | fi | |
| 238 | 426 | fi | |
| 239 | 427 | ||
| 240 | 428 | ############################################## | |
| 241 | - | # 5) Comptages finaux (sur le backup courant) | |
| 429 | + | # 6) Stats + rotation | |
| 242 | 430 | ############################################## | |
| 243 | 431 | ||
| 244 | - | # Compose dans le backup (docker + CasaOS compose seulement) | |
| 245 | - | CASAOS_COMPOSE_BACKUP=$(find "$CONFIG_DIR/casaos" -maxdepth 3 -type f -name "docker-compose.y*ml" ! -path "$CASAOS_CONFIG_DIR/*" 2>/dev/null | wc -l) | |
| 246 | - | DOCKER_COMPOSE_BACKUP=$(find "$CONFIG_DIR/docker" -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l) | |
| 432 | + | CASAOS_COMPOSE_BACKUP=0 | |
| 433 | + | if [ "$CASAOS_PRESENT" = "1" ]; then | |
| 434 | + | CASAOS_COMPOSE_BACKUP=$(find "$CONFIG_DIR/casaos" -maxdepth 3 -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l) | |
| 435 | + | fi | |
| 436 | + | ||
| 437 | + | DOCKER_COMPOSE_BACKUP=$(find "$CONFIG_DIR/Compose" -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l) | |
| 247 | 438 | ||
| 248 | - | # Compose dans le dossier source (uniquement /home/docker/<container>/docker-compose.*) | |
| 249 | 439 | SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| 250 | 440 | ! -path "$SOURCE_DIR/casaos_data/*" \ | |
| 251 | 441 | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 252 | 442 | 2>/dev/null | wc -l) | |
| 253 | 443 | ||
| 254 | - | # Containers Docker "valides" | |
| 255 | 444 | CONTAINERS_DOCKER=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 256 | 445 | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 257 | 446 | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 258 | 447 | ! -path "$SOURCE_DIR/portainer" 2>/dev/null | wc -l) | |
| 259 | 448 | ||
| 260 | - | # Rotation des anciens backups (par dossiers) | |
| 261 | 449 | rotate_backups | |
| 262 | 450 | ||
| 263 | - | # Nombre total de sets de backup (dossiers datés) | |
| 264 | - | TOTAL_BACKUP_SETS=$(ls -1d "$BACKUP_DIR"/*/ 2>/dev/null | wc -l) | |
| 451 | + | TOTAL_BACKUP_SETS=$(find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d ! -name "last" 2>/dev/null | wc -l) | |
| 265 | 452 | ||
| 266 | - | # Oldest / newest backup set | |
| 267 | - | mapfile -t CURRENT_SETS < <(ls -1d "$BACKUP_DIR"/*/ 2>/dev/null | sort) | |
| 453 | + | mapfile -t CURRENT_SETS < <(find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d ! -name "last" 2>/dev/null | sort) | |
| 268 | 454 | OLDEST_DIR="${CURRENT_SETS[0]}" | |
| 269 | 455 | NEWEST_DIR="${CURRENT_SETS[${#CURRENT_SETS[@]}-1]}" | |
| 270 | 456 | ||
| 271 | 457 | DURATION="$(format_time $SECONDS)" | |
| 272 | 458 | ||
| 273 | - | # Tailles des backups courants | |
| 274 | - | TAR_SIZE=$(get_size "$BACKUP_FILE") | |
| 275 | - | CONFIG_SIZE=$(get_size "$CONFIG_DIR") | |
| 276 | - | DOCKER_CONFIG_SIZE=$(get_size "$CONFIG_DIR/docker") | |
| 459 | + | TAR_SIZE="$(get_size "$BACKUP_FILE")" | |
| 277 | 460 | ||
| 278 | - | # CasaOS full config size (copie dans RUN_DIR/casaos/full_config) | |
| 279 | - | if [ -d "$CASAOS_CONFIG_DIR" ]; then | |
| 280 | - | CASAOS_CONFIG_SIZE=$(get_size "$CASAOS_CONFIG_DIR") | |
| 281 | - | else | |
| 282 | - | CASAOS_CONFIG_SIZE="" | |
| 283 | - | fi | |
| 461 | + | CASAOS_FULL_TAR_SIZE="" | |
| 462 | + | [ -f "$CASAOS_FULL_TAR" ] && CASAOS_FULL_TAR_SIZE="$(get_size "$CASAOS_FULL_TAR")" | |
| 284 | 463 | ||
| 285 | - | # CasaOS FULL TAR size | |
| 286 | - | if [ -f "$CASAOS_FULL_TAR" ]; then | |
| 287 | - | CASAOS_FULL_TAR_SIZE=$(get_size "$CASAOS_FULL_TAR") | |
| 288 | - | else | |
| 289 | - | CASAOS_FULL_TAR_SIZE="" | |
| 290 | - | fi | |
| 464 | + | PORTAINER_CONFIG_SIZE="" | |
| 465 | + | [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ] && PORTAINER_CONFIG_SIZE="$(get_size "$PORTAINER_CONFIG_DIR")" | |
| 466 | + | ||
| 467 | + | ||
| 468 | + | ############################################## | |
| 469 | + | # 7) Génération rapport HTML (run daté) | |
| 470 | + | ############################################## | |
| 291 | 471 | ||
| 292 | - | # Portainer full config size | |
| 293 | - | if [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ]; then | |
| 294 | - | PORTAINER_CONFIG_SIZE=$(get_size "$PORTAINER_CONFIG_DIR") | |
| 472 | + | cat > "$HTML_REPORT" <<EOF | |
| 473 | + | <!doctype html> | |
| 474 | + | <html lang="fr"> | |
| 475 | + | <head> | |
| 476 | + | <meta charset="utf-8"> | |
| 477 | + | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 478 | + | <title>Backup Docker Report - $DATE_DIR</title> | |
| 479 | + | <style> | |
| 480 | + | :root{ | |
| 481 | + | --bg:#0b1220; | |
| 482 | + | --card:#111827; | |
| 483 | + | --border:#1f2937; | |
| 484 | + | --muted:#94a3b8; | |
| 485 | + | --text:#e5e7eb; | |
| 486 | + | --blue:#93c5fd; | |
| 487 | + | --ok:#22c55e; | |
| 488 | + | --warn:#f59e0b; | |
| 489 | + | --bad:#ef4444; | |
| 490 | + | --row:#0f172a; | |
| 491 | + | --row2:#0c1428; | |
| 492 | + | } | |
| 493 | + | *{box-sizing:border-box} | |
| 494 | + | body{font-family:Arial,system-ui,sans-serif;background:var(--bg);color:var(--text);margin:0;padding:22px} | |
| 495 | + | .card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;max-width:1100px;margin:auto} | |
| 496 | + | h1{margin:0 0 8px;font-size:22px} | |
| 497 | + | small{color:var(--muted)} | |
| 498 | + | hr{border:0;border-top:1px solid var(--border);margin:14px 0} | |
| 499 | + | h2{margin:16px 0 8px;font-size:15px;color:var(--blue)} | |
| 500 | + | ||
| 501 | + | .row{display:flex;gap:12px;padding:10px;border-radius:12px;align-items:center} | |
| 502 | + | .row:nth-child(odd){background:var(--row)} | |
| 503 | + | .row:nth-child(even){background:var(--row2)} | |
| 504 | + | .label{flex:1;color:#cbd5e1} | |
| 505 | + | .value{font-weight:bold;color:#f8fafc} | |
| 506 | + | .emoji{width:26px;display:inline-block} | |
| 507 | + | ||
| 508 | + | .ok{border-left:4px solid var(--ok)} | |
| 509 | + | .warn{border-left:4px solid var(--warn)} | |
| 510 | + | .bad{border-left:4px solid var(--bad)} | |
| 511 | + | .info{border-left:4px solid #3b82f6} | |
| 512 | + | ||
| 513 | + | .grid{display:grid;grid-template-columns:1fr 1fr;gap:10px} | |
| 514 | + | @media (max-width:900px){.grid{grid-template-columns:1fr}} | |
| 515 | + | ||
| 516 | + | .tblwrap{overflow:auto;border:1px solid var(--border);border-radius:14px} | |
| 517 | + | .tbl{width:100%;border-collapse:collapse;min-width:720px} | |
| 518 | + | .tbl th,.tbl td{padding:10px;border-bottom:1px solid var(--border);text-align:left;vertical-align:top} | |
| 519 | + | .tbl th{color:#cbd5e1;background:#0f172a;position:sticky;top:0} | |
| 520 | + | .tbl tr:hover td{background:#0a1020} | |
| 521 | + | code{color:#cbd5e1} | |
| 522 | + | .empty{padding:10px;color:var(--muted)} | |
| 523 | + | .footer{margin-top:14px;color:var(--muted);font-size:12px} | |
| 524 | + | .badge{display:inline-block;padding:3px 8px;border-radius:999px;border:1px solid var(--border);font-size:12px;margin-left:8px} | |
| 525 | + | .badge-ok{background:#052e16;color:#86efac;border-color:#14532d} | |
| 526 | + | .badge-warn{background:#451a03;color:#fcd34d;border-color:#92400e} | |
| 527 | + | </style> | |
| 528 | + | </head> | |
| 529 | + | <body> | |
| 530 | + | <div class="card"> | |
| 531 | + | <h1>📦 Backup Docker / CasaOS / Portainer</h1> | |
| 532 | + | <small>📅 $DATE_DIR — 🕒 $(date +'%Y-%m-%d %H:%M:%S')</small> | |
| 533 | + | ||
| 534 | + | <hr> | |
| 535 | + | ||
| 536 | + | <h2>🔧 Global</h2> | |
| 537 | + | EOF | |
| 538 | + | ||
| 539 | + | # lignes global | |
| 540 | + | html_line "Dossier backup courant" "$(echo "$RUN_DIR" | html_escape)" "📁" "info" | |
| 541 | + | html_line "Durée totale" "$DURATION" "⏱️" "info" | |
| 542 | + | html_line "Nombre de sets de backup" "$TOTAL_BACKUP_SETS" "🗂️" "info" | |
| 543 | + | ||
| 544 | + | echo "<h2>🐳 Docker</h2>" >> "$HTML_REPORT" | |
| 545 | + | html_line "Containers détectés" "$CONTAINERS_DOCKER" "🧱" "ok" | |
| 546 | + | html_line "Compose source" "$SOURCE_COMPOSE_COUNT" "📄" "info" | |
| 547 | + | html_line "Compose backup" "$DOCKER_COMPOSE_BACKUP" "📦" "info" | |
| 548 | + | html_line "Archive Docker (.tar.gz)" "$(echo "$BACKUP_FILE ($TAR_SIZE)" | html_escape)" "🗜️" "ok" | |
| 549 | + | ||
| 550 | + | echo "<h2>🏠 CasaOS</h2>" >> "$HTML_REPORT" | |
| 551 | + | if [ "$CASAOS_PRESENT" = "1" ]; then | |
| 552 | + | html_line "CasaOS détecté" "OUI" "✅" "ok" | |
| 553 | + | html_line "Compose CasaOS backup" "$CASAOS_COMPOSE_BACKUP" "📄" "info" | |
| 554 | + | if [ -f "$CASAOS_FULL_TAR" ]; then | |
| 555 | + | html_line "Archive CasaOS FULL (.tar.gz)" "$(echo "$CASAOS_FULL_TAR ($CASAOS_FULL_TAR_SIZE)" | html_escape)" "🗜️" "ok" | |
| 556 | + | else | |
| 557 | + | html_line "Archive CasaOS FULL (.tar.gz)" "Non générée" "⚠️" "warn" | |
| 558 | + | fi | |
| 295 | 559 | else | |
| 296 | - | PORTAINER_CONFIG_SIZE="" | |
| 560 | + | html_line "CasaOS détecté" "NON (ignoré)" "🚫" "warn" | |
| 297 | 561 | fi | |
| 298 | 562 | ||
| 563 | + | echo "<h2>🧭 Portainer</h2>" >> "$HTML_REPORT" | |
| 564 | + | html_line "Fichiers config Portainer" "$PORTAINER_FILES" "📁" "info" | |
| 565 | + | [ -n "$PORTAINER_CONFIG_SIZE" ] && html_line "Taille config Portainer" "$PORTAINER_CONFIG_SIZE" "📏" "info" | |
| 566 | + | ||
| 567 | + | echo "<h2>📊 Containers / Tailles (dossiers dans $SOURCE_DIR)</h2>" >> "$HTML_REPORT" | |
| 568 | + | html_container_table | |
| 569 | + | ||
| 570 | + | cat >> "$HTML_REPORT" <<EOF | |
| 571 | + | <div class="footer"> | |
| 572 | + | ✅ Rapport généré automatiquement par le script de backup.<br> | |
| 573 | + | ⚠️ Ne partage pas ce rapport publiquement : il révèle des chemins et des infos de structure. | |
| 574 | + | </div> | |
| 575 | + | </div> | |
| 576 | + | </body> | |
| 577 | + | </html> | |
| 578 | + | EOF | |
| 579 | + | ||
| 580 | + | log_message "Rapport HTML généré : $HTML_REPORT" | |
| 581 | + | ||
| 582 | + | ################## | |
| 583 | + | ||
| 584 | + | ||
| 299 | 585 | ############################################## | |
| 300 | - | # 6) RÉSUMÉS | |
| 586 | + | # 8) MAJ last/ (SANS copier les archives .gz) | |
| 301 | 587 | ############################################## | |
| 302 | 588 | ||
| 303 | - | echo -e "${GREEN}===== BACKUP TERMINÉ =====${NC}" | |
| 304 | - | echo -e "${CYAN}Dossier backup courant : ${YELLOW}$RUN_DIR${NC}" | |
| 589 | + | log_message "Mise à jour du dossier LAST : $LAST_DIR" | |
| 590 | + | ||
| 591 | + | rm -rf "$LAST_DIR" | |
| 592 | + | mkdir -p "$LAST_DIR" | |
| 593 | + | ||
| 594 | + | # HTML | |
| 595 | + | cp -f "$HTML_REPORT" "$LAST_DIR/report.html" | |
| 596 | + | ||
| 597 | + | # Compose / configs (pas d'archives) | |
| 598 | + | [ -d "$CONFIG_DIR/Compose" ] && cp -a "$CONFIG_DIR/Compose" "$LAST_DIR/" | |
| 599 | + | [ -d "$CONFIG_DIR/portainer" ] && cp -a "$CONFIG_DIR/portainer" "$LAST_DIR/" | |
| 600 | + | [ "$CASAOS_PRESENT" = "1" ] && [ -d "$CONFIG_DIR/casaos" ] && cp -a "$CONFIG_DIR/casaos" "$LAST_DIR/" | |
| 601 | + | ||
| 602 | + | # Index HTML last/ | |
| 603 | + | generate_index_html "$BACKUP_DIR" "$HTML_INDEX_LAST" | |
| 604 | + | ||
| 605 | + | log_message "LAST mis à jour ✅" | |
| 606 | + | log_message "Dernier rapport HTML : $HTML_REPORT_LAST" | |
| 607 | + | log_message "Index HTML last : $HTML_INDEX_LAST" | |
| 608 | + | ||
| 609 | + | ############################################## | |
| 610 | + | # 9) Publication WEB (HTML UNIQUEMENT) | |
| 611 | + | ############################################## | |
| 612 | + | ||
| 613 | + | log_message "Publication web (HTML only) vers : $WEB_PUBLIC_DIR" | |
| 614 | + | ||
| 615 | + | rm -rf "$WEB_PUBLIC_DIR" | |
| 616 | + | mkdir -p "$WEB_PUBLIC_DIR" | |
| 617 | + | ||
| 618 | + | ||
| 619 | + | cp -f "$LAST_DIR/report.html" "$WEB_PUBLIC_DIR/report.html" | |
| 620 | + | cp -f "$LAST_DIR/index.html" "$WEB_PUBLIC_DIR/" 2>/dev/null || true | |
| 621 | + | ||
| 622 | + | log_message "Publication web OK ✅" | |
| 623 | + | ||
| 624 | + | ############################################## | |
| 625 | + | # 10) Rapport CONSOLE | |
| 626 | + | ############################################## | |
| 627 | + | ||
| 628 | + | echo -e "${GREEN}===== BACKUP TERMINÉ ✅ =====${NC}" | |
| 305 | 629 | ||
| 306 | 630 | ############################################## | |
| 307 | 631 | # LISTE DES DOSSIERS DOCKER PAR TAILLE (ASCII) | |
| 308 | 632 | ############################################## | |
| 309 | 633 | ||
| 310 | - | echo -e "\n${CYAN}----- LISTE/TAILLE DES RÉPERTOIRES DOCKER -----${NC}" | |
| 634 | + | echo "" | |
| 635 | + | echo -e "${CYAN}----- LISTE/TAILLE DES RÉPERTOIRES DOCKER -----${NC}" | |
| 311 | 636 | ||
| 312 | 637 | DOCKER_DIRS=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 313 | 638 | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 314 | 639 | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 315 | - | ! -path "$SOURCE_DIR/portainer" 2>/dev/null) | |
| 640 | + | ! -path "$SOURCE_DIR/portainer" \ | |
| 641 | + | 2>/dev/null) | |
| 316 | 642 | ||
| 317 | 643 | if [ -z "$DOCKER_DIRS" ]; then | |
| 318 | 644 | echo -e "${YELLOW}(Aucun dossier Docker trouvé)${NC}" | |
| 319 | 645 | else | |
| 320 | - | echo -e "┌──────────────────────────┬─────────┬────────────────────────────────────────┐" | |
| 321 | - | printf "│ %-24s │ %-7s │ %-38s │\n" "Container" "Taille" "Chemin" | |
| 322 | - | echo -e "├──────────────────────────┼─────────┼────────────────────────────────────────┤" | |
| 646 | + | echo -e "${CYAN}┌──────────────────────────┬─────────┬────────────────────────────────────────┐${NC}" | |
| 647 | + | printf "${CYAN}│ %-24s │ %-7s │ %-38s │${NC}\n" "Container" "Taille" "Chemin" | |
| 648 | + | echo -e "${CYAN}├──────────────────────────┼─────────┼────────────────────────────────────────┤${NC}" | |
| 649 | + | ||
| 650 | + | # du + tri par taille desc | |
| 323 | 651 | du -sh $DOCKER_DIRS 2>/dev/null | sort -hr | while read -r size path; do | |
| 324 | 652 | name=$(basename "$path") | |
| 325 | 653 | printf "│ %-24s │ %-7s │ %-38s │\n" "$name" "$size" "$path" | |
| 326 | 654 | done | |
| 327 | - | echo -e "└──────────────────────────┴─────────┴────────────────────────────────────────┘" | |
| 328 | - | fi | |
| 329 | 655 | ||
| 330 | - | ################################# | |
| 331 | - | # DOCKER | |
| 332 | - | ################################# | |
| 333 | - | echo -e "${CYAN}\n----- DOCKER -----${NC}" | |
| 334 | - | echo -e "${CYAN}Containers Docker détectés : ${GREEN}$CONTAINERS_DOCKER${NC}" | |
| 335 | - | echo -e "${CYAN}Compose source (Docker) : ${GREEN}$SOURCE_COMPOSE_COUNT${NC}" | |
| 336 | - | echo -e "${CYAN}Compose backup (Docker) : ${GREEN}$DOCKER_COMPOSE_BACKUP${NC}" | |
| 337 | - | echo -e "${CYAN}Dossier compose Docker : ${YELLOW}$CONFIG_DIR/docker${NC}" | |
| 338 | - | echo -e "${CYAN}Taille compose Docker : ${GREEN}$DOCKER_CONFIG_SIZE${NC}" | |
| 339 | - | ||
| 340 | - | ################################# | |
| 341 | - | # CASAOS (si présent) | |
| 342 | - | ################################# | |
| 343 | - | if [ -d "$CONFIG_DIR/casaos" ] || [ -f "$CASAOS_FULL_TAR" ]; then | |
| 344 | - | echo -e "${CYAN}\n----- CASAOS -----${NC}" | |
| 345 | - | echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}" | |
| 346 | - | echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}" | |
| 347 | - | [ -n "$CASAOS_CONFIG_SIZE" ] && echo -e "${CYAN}Taille config CasaOS (full) : ${GREEN}$CASAOS_CONFIG_SIZE${NC}" | |
| 348 | - | if [ -f "$CASAOS_FULL_TAR" ]; then | |
| 349 | - | echo -e "${CYAN}Tar CasaOS FULL : ${YELLOW}$CASAOS_FULL_TAR${NC}" | |
| 350 | - | echo -e "${CYAN}Taille tar CasaOS FULL : ${GREEN}$CASAOS_FULL_TAR_SIZE${NC}" | |
| 351 | - | fi | |
| 656 | + | echo -e "${CYAN}└──────────────────────────┴─────────┴────────────────────────────────────────┘${NC}" | |
| 352 | 657 | fi | |
| 353 | 658 | ||
| 354 | - | ################################# | |
| 355 | - | # PORTAINER (si présent) | |
| 356 | - | ################################# | |
| 357 | - | if [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ]; then | |
| 358 | - | echo -e "${CYAN}\n----- PORTAINER -----${NC}" | |
| 359 | - | echo -e "${CYAN}Fichiers config Portainer : ${GREEN}$PORTAINER_FILES${NC}" | |
| 360 | - | echo -e "${CYAN}Dossier Portainer backup : ${YELLOW}$PORTAINER_CONFIG_DIR${NC}" | |
| 361 | - | [ -n "$PORTAINER_CONFIG_SIZE" ] && echo -e "${CYAN}Taille Portainer (full) : ${GREEN}$PORTAINER_CONFIG_SIZE${NC}" | |
| 659 | + | ############################################## | |
| 660 | + | ||
| 661 | + | echo -e "${CYAN}Dossier backup courant : ${YELLOW}$RUN_DIR${NC}" | |
| 662 | + | echo "" | |
| 663 | + | ||
| 664 | + | echo -e "${CYAN}----- DOCKER -----${NC}" | |
| 665 | + | echo "Containers Docker détectés : $CONTAINERS_DOCKER" | |
| 666 | + | echo "Compose source (Docker) : $SOURCE_COMPOSE_COUNT" | |
| 667 | + | echo "Compose backup (Docker) : $DOCKER_COMPOSE_BACKUP" | |
| 668 | + | echo "Archive Docker (run) : $BACKUP_FILE ($TAR_SIZE)" | |
| 669 | + | echo "" | |
| 670 | + | ||
| 671 | + | echo -e "${CYAN}----- CASAOS -----${NC}" | |
| 672 | + | if [ "$CASAOS_PRESENT" = "1" ]; then | |
| 673 | + | echo "CasaOS détecté : OUI" | |
| 674 | + | echo "Compose CasaOS backup : $CASAOS_COMPOSE_BACKUP" | |
| 675 | + | [ -f "$CASAOS_FULL_TAR" ] && echo "Archive CasaOS FULL (run) : $CASAOS_FULL_TAR ($CASAOS_FULL_TAR_SIZE)" | |
| 676 | + | else | |
| 677 | + | echo "CasaOS détecté : NON (ignoré)" | |
| 362 | 678 | fi | |
| 679 | + | echo "" | |
| 680 | + | ||
| 681 | + | echo -e "${CYAN}----- PORTAINER -----${NC}" | |
| 682 | + | echo "Fichiers config Portainer : $PORTAINER_FILES" | |
| 683 | + | [ -n "$PORTAINER_CONFIG_SIZE" ] && echo "Taille Portainer (run) : $PORTAINER_CONFIG_SIZE" | |
| 684 | + | echo "" | |
| 685 | + | ||
| 686 | + | echo -e "${CYAN}----- GLOBAL -----${NC}" | |
| 687 | + | echo "Sets de backup : $TOTAL_BACKUP_SETS" | |
| 688 | + | echo "Oldest backup : ${OLDEST_DIR:-N/A}" | |
| 689 | + | echo "Newest backup : ${NEWEST_DIR:-N/A}" | |
| 690 | + | echo "Durée totale : $DURATION" | |
| 691 | + | echo "" | |
| 692 | + | echo "HTML (run) : $HTML_REPORT" | |
| 693 | + | echo "HTML (last) : $HTML_REPORT_LAST" | |
| 694 | + | echo "WEB index : $WEB_PUBLIC_DIR/index.html" | |
| 695 | + | echo "WEB report : $WEB_PUBLIC_DIR/report.html" | |
| 696 | + | ||
| 697 | + | ############################################## | |
| 698 | + | # JSON optionnel | |
| 699 | + | ############################################## | |
| 363 | 700 | ||
| 364 | - | ################################# | |
| 365 | - | # GLOBAL | |
| 366 | - | ################################# | |
| 367 | - | echo -e "${CYAN}\n----- GLOBAL -----${NC}" | |
| 368 | - | echo -e "${CYAN}Nombre de sets de backup : ${GREEN}$TOTAL_BACKUP_SETS${NC}" | |
| 369 | - | echo -e "${CYAN}Oldest backup dir : ${YELLOW}${OLDEST_DIR:-N/A}${NC}" | |
| 370 | - | echo -e "${CYAN}Newest backup dir : ${YELLOW}${NEWEST_DIR:-N/A}${NC}" | |
| 371 | - | echo -e "${CYAN}Taille archive Docker tar.gz : ${GREEN}$TAR_SIZE${NC}" | |
| 372 | - | [ -f "$CASAOS_FULL_TAR" ] && echo -e "${CYAN}Taille archive CasaOS tar.gz : ${GREEN}$CASAOS_FULL_TAR_SIZE${NC}" | |
| 373 | - | echo -e "${CYAN}Taille dossier backup courant: ${GREEN}$CONFIG_SIZE${NC}" | |
| 374 | - | echo -e "${CYAN}Archive Docker courante : ${YELLOW}$BACKUP_FILE${NC}" | |
| 375 | - | [ -f "$CASAOS_FULL_TAR" ] && echo -e "${CYAN}Archive CasaOS courante : ${YELLOW}$CASAOS_FULL_TAR${NC}" | |
| 376 | - | echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}" | |
| 377 | - | ||
| 378 | - | ################################# | |
| 379 | - | # JSON (optionnel : ./script.sh --json) | |
| 380 | - | ################################# | |
| 381 | 701 | if [ "$1" = "--json" ]; then | |
| 382 | 702 | echo "" | |
| 383 | 703 | echo "{" | |
| 384 | 704 | echo " \"date_raw\": \"$DATE_RAW\"," | |
| 385 | 705 | echo " \"date_dir\": \"$DATE_DIR\"," | |
| 386 | 706 | echo " \"run_dir\": \"$RUN_DIR\"," | |
| 707 | + | echo " \"last_dir\": \"$LAST_DIR\"," | |
| 387 | 708 | echo " \"docker_backup_file\": \"$BACKUP_FILE\"," | |
| 388 | 709 | echo " \"docker_backup_size\": \"$TAR_SIZE\"," | |
| 710 | + | echo " \"casaos_present\": $CASAOS_PRESENT," | |
| 389 | 711 | echo " \"casaos_full_backup_file\": \"${CASAOS_FULL_TAR:-}\"," | |
| 390 | 712 | echo " \"casaos_full_backup_size\": \"${CASAOS_FULL_TAR_SIZE:-}\"," | |
| 391 | - | echo " \"docker\": {" | |
| 392 | - | echo " \"containers\": $CONTAINERS_DOCKER," | |
| 393 | - | echo " \"compose_source\": $SOURCE_COMPOSE_COUNT," | |
| 394 | - | echo " \"compose_backup\": $DOCKER_COMPOSE_BACKUP" | |
| 395 | - | echo " }," | |
| 396 | - | echo " \"casaos\": {" | |
| 397 | - | echo " \"compose_backup\": $CASAOS_COMPOSE_BACKUP" | |
| 398 | - | echo " }," | |
| 399 | - | echo " \"portainer\": {" | |
| 400 | - | echo " \"files\": $PORTAINER_FILES" | |
| 401 | - | echo " }," | |
| 713 | + | echo " \"portainer_files\": $PORTAINER_FILES," | |
| 402 | 714 | echo " \"backup_sets\": $TOTAL_BACKUP_SETS," | |
| 403 | - | echo " \"oldest_backup_dir\": \"${OLDEST_DIR:-}\"," | |
| 404 | - | echo " \"newest_backup_dir\": \"${NEWEST_DIR:-}\"," | |
| 405 | - | echo " \"duration\": \"$DURATION\"" | |
| 715 | + | echo " \"duration\": \"$DURATION\"," | |
| 716 | + | echo " \"html_report_run\": \"$HTML_REPORT\"," | |
| 717 | + | echo " \"html_report_last\": \"$HTML_REPORT_LAST\"," | |
| 718 | + | echo " \"web_index\": \"$WEB_PUBLIC_DIR/index.html\"," | |
| 719 | + | echo " \"web_report\": \"$WEB_PUBLIC_DIR/report.html\"" | |
| 406 | 720 | echo "}" | |
| 407 | 721 | fi | |
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 4 insertions
Backup-Home-docker.tar.gz.sh
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | # CONFIG | |
| 5 | 5 | ############################# | |
| 6 | 6 | ||
| 7 | + | # Backup complet des data docker , casaos et portainer | |
| 8 | + | # avec liste de tous les compose files des containers classés par répertoire. | |
| 9 | + | ||
| 10 | + | ||
| 7 | 11 | # Répertoire contenant tes containers | |
| 8 | 12 | SOURCE_DIR="/home/docker" | |
| 9 | 13 | ||
Erreur32 revised this gist 6 months ago. Go to revision
No changes
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 1 insertion, 1 deletion
Backup-Home-docker.tar.gz.sh
| @@ -185,7 +185,7 @@ find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |||
| 185 | 185 | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 186 | 186 | 2>/dev/null | while read file; do | |
| 187 | 187 | container_name=$(basename "$(dirname "$file")") | |
| 188 | - | dest_dir="$CONFIG_DIR/docker/$container_name" | |
| 188 | + | dest_dir="$CONFIG_DIR/Compose/$container_name" | |
| 189 | 189 | mkdir -p "$dest_dir" | |
| 190 | 190 | cp "$file" "$dest_dir/" | |
| 191 | 191 | log_message " [Docker] → Compose trouvé : $file" | |
Erreur32 revised this gist 6 months ago. Go to revision
No changes
Erreur32 revised this gist 6 months ago. Go to revision
No changes
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 49 insertions, 85 deletions
Backup-Home-docker.tar.gz.sh
| @@ -10,22 +10,25 @@ SOURCE_DIR="/home/docker" | |||
| 10 | 10 | # Répertoire où stocker les sauvegardes | |
| 11 | 11 | BACKUP_DIR="/home/backup/docker" | |
| 12 | 12 | ||
| 13 | - | # Nombre max de backups à conserver | |
| 14 | - | MAX_BACKUPS=5 | |
| 13 | + | # Nombre max de backups à conserver (dossiers datés) | |
| 14 | + | MAX_BACKUPS=3 | |
| 15 | 15 | ||
| 16 | - | # Date format | |
| 17 | - | DATE="$(date +'%Y%m%d_%H%M%S')" | |
| 16 | + | # Date interne (pour logs / JSON) | |
| 17 | + | DATE_RAW="$(date +'%Y%m%d_%H%M%S')" | |
| 18 | + | # Date pour le dossier de backup (format humain demandé) | |
| 19 | + | DATE_DIR="$(date +'%Y.%m.%d_%H-%M-%S')" | |
| 18 | 20 | ||
| 19 | - | # Fichier TAR final Docker | |
| 20 | - | BACKUP_FILE="$BACKUP_DIR/docker_backup_${DATE}.tar.gz" | |
| 21 | + | # Dossier de ce backup | |
| 22 | + | RUN_DIR="$BACKUP_DIR/$DATE_DIR" | |
| 21 | 23 | ||
| 22 | - | # Fichier TAR FULL CasaOS (config + volumes) | |
| 23 | - | CASAOS_FULL_TAR="$BACKUP_DIR/casaos_full_backup_${DATE}.tar.gz" | |
| 24 | + | # Fichiers TAR dans le dossier de ce backup | |
| 25 | + | BACKUP_FILE="$RUN_DIR/docker_backup.tar.gz" | |
| 26 | + | CASAOS_FULL_TAR="$RUN_DIR/casaos_full_backup.tar.gz" | |
| 24 | 27 | ||
| 25 | - | # Dossier de configs des compose à côté du TAR | |
| 26 | - | CONFIG_DIR="$BACKUP_DIR/config_${DATE}" | |
| 28 | + | # Dossier où l'on met les compose / configs | |
| 29 | + | CONFIG_DIR="$RUN_DIR" | |
| 27 | 30 | ||
| 28 | - | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR) | |
| 31 | + | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR pour le tar Docker) | |
| 29 | 32 | EXCLUDE_DIRS=( | |
| 30 | 33 | "docker_var_lib" | |
| 31 | 34 | "1_Backups" | |
| @@ -83,46 +86,20 @@ check_pigz() { | |||
| 83 | 86 | } | |
| 84 | 87 | ||
| 85 | 88 | rotate_backups() { | |
| 86 | - | log_message "Nettoyage des anciens backups (conserver les $MAX_BACKUPS plus récents)..." | |
| 87 | - | ||
| 88 | - | # TAR Docker | |
| 89 | - | mapfile -t backups_tar < <(ls -1t "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null || true) | |
| 90 | - | if [ "${#backups_tar[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 91 | - | for f in "${backups_tar[@]:$MAX_BACKUPS}"; do | |
| 92 | - | log_message "Suppression ancien backup tar Docker : $f" | |
| 93 | - | rm -f "$f" | |
| 94 | - | done | |
| 95 | - | fi | |
| 89 | + | log_message "Rotation des anciens backups (conserver les $MAX_BACKUPS plus récents)..." | |
| 96 | 90 | ||
| 97 | - | # TAR CasaOS full | |
| 98 | - | mapfile -t backups_casaos < <(ls -1t "$BACKUP_DIR"/casaos_full_backup_*.tar.gz 2>/dev/null || true) | |
| 99 | - | if [ "${#backups_casaos[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 100 | - | for f in "${backups_casaos[@]:$MAX_BACKUPS}"; do | |
| 101 | - | log_message "Suppression ancien backup tar CasaOS : $f" | |
| 102 | - | rm -f "$f" | |
| 103 | - | done | |
| 104 | - | fi | |
| 91 | + | # On ne garde que les dossiers datés dans BACKUP_DIR | |
| 92 | + | mapfile -t backups_dirs < <(ls -1td "$BACKUP_DIR"/*/ 2>/dev/null || true) | |
| 105 | 93 | ||
| 106 | - | # Dossiers config_ | |
| 107 | - | mapfile -t backups_cfg < <(ls -1td "$BACKUP_DIR"/config_* 2>/dev/null || true) | |
| 108 | - | if [ "${#backups_cfg[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 109 | - | for d in "${backups_cfg[@]:$MAX_BACKUPS}"; do | |
| 110 | - | log_message "Suppression ancien dossier config : $d" | |
| 94 | + | if [ "${#backups_dirs[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 95 | + | for d in "${backups_dirs[@]:$MAX_BACKUPS}"; do | |
| 96 | + | log_message "Suppression ancien backup (dossier) : $d" | |
| 111 | 97 | rm -rf "$d" | |
| 112 | 98 | done | |
| 113 | 99 | fi | |
| 114 | 100 | } | |
| 115 | 101 | ||
| 116 | - | human_date() { | |
| 117 | - | # Convertit 20251203_172811 → "03/12/2025 17:28:11" | |
| 118 | - | local d="$1" | |
| 119 | - | local date_part="${d:0:8}" | |
| 120 | - | local time_part="${d:9:6}" | |
| 121 | - | echo "${date_part:6:2}/${date_part:4:2}/${date_part:0:4} ${time_part:0:2}:${time_part:2:2}:${time_part:4:2}" | |
| 122 | - | } | |
| 123 | - | ||
| 124 | 102 | get_size() { | |
| 125 | - | # Taille lisible | |
| 126 | 103 | du -sh "$1" 2>/dev/null | awk '{print $1}' | |
| 127 | 104 | } | |
| 128 | 105 | ||
| @@ -134,18 +111,18 @@ SECONDS=0 | |||
| 134 | 111 | ||
| 135 | 112 | check_pigz | |
| 136 | 113 | ||
| 137 | - | mkdir -p "$BACKUP_DIR" "$CONFIG_DIR" | |
| 114 | + | mkdir -p "$RUN_DIR" | |
| 138 | 115 | touch "$LOG_FILE" | |
| 139 | 116 | ||
| 140 | 117 | echo -e "${CYAN}=== Backup Docker + Configs (Portainer / CasaOS) ===${NC}" | |
| 141 | 118 | log_message "Début sauvegarde Docker + configs Portainer & CasaOS..." | |
| 119 | + | log_message "Dossier de backup : $RUN_DIR" | |
| 142 | 120 | ||
| 143 | 121 | ############################################## | |
| 144 | 122 | # 1) Sauvegarde TAR Docker via pigz + exclusions | |
| 145 | 123 | ############################################## | |
| 146 | 124 | log_message "Création de l’archive Docker : $BACKUP_FILE" | |
| 147 | 125 | ||
| 148 | - | # Construction des arguments d'exclusion dynamiques pour le TAR Docker | |
| 149 | 126 | EXCLUDE_ARGS=( | |
| 150 | 127 | "--exclude=*.log" | |
| 151 | 128 | "--exclude=.composer" | |
| @@ -187,8 +164,8 @@ fi | |||
| 187 | 164 | ||
| 188 | 165 | ############################################## | |
| 189 | 166 | # 2) Extraction des docker-compose | |
| 190 | - | # - CasaOS: config_<date>/casaos/<container>/ | |
| 191 | - | # - Docker: config_<date>/docker/<container>/ | |
| 167 | + | # - CasaOS: RUN_DIR/casaos/<container>/ | |
| 168 | + | # - Docker: RUN_DIR/docker/<container>/ | |
| 192 | 169 | ############################################## | |
| 193 | 170 | ||
| 194 | 171 | log_message "Extraction des docker-compose CasaOS..." | |
| @@ -217,7 +194,7 @@ find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |||
| 217 | 194 | ############################################## | |
| 218 | 195 | # 3) Config Portainer (full) | |
| 219 | 196 | ############################################## | |
| 220 | - | PORTAINER_CONFIG_DIR="$CONFIG_DIR/portainer/full_config" | |
| 197 | + | PORTAINER_CONFIG_DIR="$CONFIG_DIR/portainer" | |
| 221 | 198 | PORTAINER_FILES=0 | |
| 222 | 199 | ||
| 223 | 200 | if docker volume inspect portainer_data >/dev/null 2>&1; then | |
| @@ -230,7 +207,7 @@ else | |||
| 230 | 207 | fi | |
| 231 | 208 | ||
| 232 | 209 | ############################################## | |
| 233 | - | # 4) Config CasaOS (full + second tar.gz) | |
| 210 | + | # 4) Config CasaOS (full + tar.gz) | |
| 234 | 211 | ############################################## | |
| 235 | 212 | CASAOS_CONFIG_DIR="$CONFIG_DIR/casaos/full_config" | |
| 236 | 213 | ||
| @@ -260,10 +237,9 @@ fi | |||
| 260 | 237 | # 5) Comptages finaux (sur le backup courant) | |
| 261 | 238 | ############################################## | |
| 262 | 239 | ||
| 263 | - | # Compose dans le backup (docker + casaos compose seulement) | |
| 240 | + | # Compose dans le backup (docker + CasaOS compose seulement) | |
| 264 | 241 | CASAOS_COMPOSE_BACKUP=$(find "$CONFIG_DIR/casaos" -maxdepth 3 -type f -name "docker-compose.y*ml" ! -path "$CASAOS_CONFIG_DIR/*" 2>/dev/null | wc -l) | |
| 265 | 242 | DOCKER_COMPOSE_BACKUP=$(find "$CONFIG_DIR/docker" -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l) | |
| 266 | - | TOTAL_COMPOSE_BACKUP=$((CASAOS_COMPOSE_BACKUP + DOCKER_COMPOSE_BACKUP)) | |
| 267 | 243 | ||
| 268 | 244 | # Compose dans le dossier source (uniquement /home/docker/<container>/docker-compose.*) | |
| 269 | 245 | SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| @@ -277,28 +253,25 @@ CONTAINERS_DOCKER=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |||
| 277 | 253 | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 278 | 254 | ! -path "$SOURCE_DIR/portainer" 2>/dev/null | wc -l) | |
| 279 | 255 | ||
| 280 | - | # Rotation des anciens backups (Docker tar + CasaOS tar + configs) | |
| 256 | + | # Rotation des anciens backups (par dossiers) | |
| 281 | 257 | rotate_backups | |
| 282 | 258 | ||
| 283 | - | # Nombre total de tar.gz Docker | |
| 284 | - | TOTAL_TAR_DOCKER=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | wc -l) | |
| 285 | - | # Nombre total de tar.gz CasaOS full | |
| 286 | - | TOTAL_TAR_CASAOS=$(ls -1 "$BACKUP_DIR"/casaos_full_backup_*.tar.gz 2>/dev/null | wc -l) | |
| 259 | + | # Nombre total de sets de backup (dossiers datés) | |
| 260 | + | TOTAL_BACKUP_SETS=$(ls -1d "$BACKUP_DIR"/*/ 2>/dev/null | wc -l) | |
| 287 | 261 | ||
| 288 | - | # Oldest / newest Docker après rotation | |
| 289 | - | OLDEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | head -n1) | |
| 290 | - | NEWEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | tail -n1) | |
| 262 | + | # Oldest / newest backup set | |
| 263 | + | mapfile -t CURRENT_SETS < <(ls -1d "$BACKUP_DIR"/*/ 2>/dev/null | sort) | |
| 264 | + | OLDEST_DIR="${CURRENT_SETS[0]}" | |
| 265 | + | NEWEST_DIR="${CURRENT_SETS[${#CURRENT_SETS[@]}-1]}" | |
| 291 | 266 | ||
| 292 | 267 | DURATION="$(format_time $SECONDS)" | |
| 293 | 268 | ||
| 294 | - | # Tailles des backups | |
| 269 | + | # Tailles des backups courants | |
| 295 | 270 | TAR_SIZE=$(get_size "$BACKUP_FILE") | |
| 296 | 271 | CONFIG_SIZE=$(get_size "$CONFIG_DIR") | |
| 297 | - | ||
| 298 | - | # Docker compose directory size | |
| 299 | 272 | DOCKER_CONFIG_SIZE=$(get_size "$CONFIG_DIR/docker") | |
| 300 | 273 | ||
| 301 | - | # CasaOS full config size (copie dans config_) | |
| 274 | + | # CasaOS full config size (copie dans RUN_DIR/casaos/full_config) | |
| 302 | 275 | if [ -d "$CASAOS_CONFIG_DIR" ]; then | |
| 303 | 276 | CASAOS_CONFIG_SIZE=$(get_size "$CASAOS_CONFIG_DIR") | |
| 304 | 277 | else | |
| @@ -319,15 +292,12 @@ else | |||
| 319 | 292 | PORTAINER_CONFIG_SIZE="" | |
| 320 | 293 | fi | |
| 321 | 294 | ||
| 322 | - | # Dates humaines | |
| 323 | - | HUMAN_OLDEST=$( [ -n "$OLDEST_BACKUP" ] && human_date "$(basename "$OLDEST_BACKUP" | sed 's/docker_backup_//; s/.tar.gz//')" ) | |
| 324 | - | HUMAN_NEWEST=$( [ -n "$NEWEST_BACKUP" ] && human_date "$(basename "$NEWEST_BACKUP" | sed 's/docker_backup_//; s/.tar.gz//')" ) | |
| 325 | - | ||
| 326 | 295 | ############################################## | |
| 327 | 296 | # 6) RÉSUMÉS | |
| 328 | 297 | ############################################## | |
| 329 | 298 | ||
| 330 | 299 | echo -e "${GREEN}===== BACKUP TERMINÉ =====${NC}" | |
| 300 | + | echo -e "${CYAN}Dossier backup courant : ${YELLOW}$RUN_DIR${NC}" | |
| 331 | 301 | ||
| 332 | 302 | ############################################## | |
| 333 | 303 | # LISTE DES DOSSIERS DOCKER PAR TAILLE (ASCII) | |
| @@ -366,7 +336,7 @@ echo -e "${CYAN}Taille compose Docker : ${GREEN}$DOCKER_CONFIG_SIZE${NC}" | |||
| 366 | 336 | ################################# | |
| 367 | 337 | # CASAOS (si présent) | |
| 368 | 338 | ################################# | |
| 369 | - | if [ -d "$CASAOS_CONFIG_DIR" ] || [ "$CASAOS_COMPOSE_BACKUP" -gt 0 ] || [ -f "$CASAOS_FULL_TAR" ]; then | |
| 339 | + | if [ -d "$CONFIG_DIR/casaos" ] || [ -f "$CASAOS_FULL_TAR" ]; then | |
| 370 | 340 | echo -e "${CYAN}\n----- CASAOS -----${NC}" | |
| 371 | 341 | echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}" | |
| 372 | 342 | echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}" | |
| @@ -391,17 +361,14 @@ fi | |||
| 391 | 361 | # GLOBAL | |
| 392 | 362 | ################################# | |
| 393 | 363 | echo -e "${CYAN}\n----- GLOBAL -----${NC}" | |
| 364 | + | echo -e "${CYAN}Nombre de sets de backup : ${GREEN}$TOTAL_BACKUP_SETS${NC}" | |
| 365 | + | echo -e "${CYAN}Oldest backup dir : ${YELLOW}${OLDEST_DIR:-N/A}${NC}" | |
| 366 | + | echo -e "${CYAN}Newest backup dir : ${YELLOW}${NEWEST_DIR:-N/A}${NC}" | |
| 394 | 367 | echo -e "${CYAN}Taille archive Docker tar.gz : ${GREEN}$TAR_SIZE${NC}" | |
| 395 | 368 | [ -f "$CASAOS_FULL_TAR" ] && echo -e "${CYAN}Taille archive CasaOS tar.gz : ${GREEN}$CASAOS_FULL_TAR_SIZE${NC}" | |
| 396 | - | echo -e "${CYAN}Taille dossier config : ${GREEN}$CONFIG_SIZE${NC}" | |
| 397 | - | echo -e "${CYAN}Nombre tar Docker : ${GREEN}$TOTAL_TAR_DOCKER${NC}" | |
| 398 | - | echo -e "${CYAN}Nombre tar CasaOS : ${GREEN}$TOTAL_TAR_CASAOS${NC}" | |
| 399 | - | echo -e "${CYAN}Oldest backup Docker : ${YELLOW}$OLDEST_BACKUP${NC}" | |
| 400 | - | echo -e "${CYAN}Oldest backup (human) : ${GREEN}${HUMAN_OLDEST:-N/A}${NC}" | |
| 401 | - | echo -e "${CYAN}Newest backup Docker : ${YELLOW}$NEWEST_BACKUP${NC}" | |
| 402 | - | echo -e "${CYAN}Newest backup (human) : ${GREEN}${HUMAN_NEWEST:-N/A}${NC}" | |
| 369 | + | echo -e "${CYAN}Taille dossier backup courant: ${GREEN}$CONFIG_SIZE${NC}" | |
| 403 | 370 | echo -e "${CYAN}Archive Docker courante : ${YELLOW}$BACKUP_FILE${NC}" | |
| 404 | - | echo -e "${CYAN}Dossier config courant : ${YELLOW}$CONFIG_DIR${NC}" | |
| 371 | + | [ -f "$CASAOS_FULL_TAR" ] && echo -e "${CYAN}Archive CasaOS courante : ${YELLOW}$CASAOS_FULL_TAR${NC}" | |
| 405 | 372 | echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}" | |
| 406 | 373 | ||
| 407 | 374 | ################################# | |
| @@ -410,13 +377,13 @@ echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}" | |||
| 410 | 377 | if [ "$1" = "--json" ]; then | |
| 411 | 378 | echo "" | |
| 412 | 379 | echo "{" | |
| 413 | - | echo " \"date\": \"$DATE\"," | |
| 380 | + | echo " \"date_raw\": \"$DATE_RAW\"," | |
| 381 | + | echo " \"date_dir\": \"$DATE_DIR\"," | |
| 382 | + | echo " \"run_dir\": \"$RUN_DIR\"," | |
| 414 | 383 | echo " \"docker_backup_file\": \"$BACKUP_FILE\"," | |
| 415 | 384 | echo " \"docker_backup_size\": \"$TAR_SIZE\"," | |
| 416 | 385 | echo " \"casaos_full_backup_file\": \"${CASAOS_FULL_TAR:-}\"," | |
| 417 | 386 | echo " \"casaos_full_backup_size\": \"${CASAOS_FULL_TAR_SIZE:-}\"," | |
| 418 | - | echo " \"config_dir\": \"$CONFIG_DIR\"," | |
| 419 | - | echo " \"config_size\": \"$CONFIG_SIZE\"," | |
| 420 | 387 | echo " \"docker\": {" | |
| 421 | 388 | echo " \"containers\": $CONTAINERS_DOCKER," | |
| 422 | 389 | echo " \"compose_source\": $SOURCE_COMPOSE_COUNT," | |
| @@ -428,12 +395,9 @@ if [ "$1" = "--json" ]; then | |||
| 428 | 395 | echo " \"portainer\": {" | |
| 429 | 396 | echo " \"files\": $PORTAINER_FILES" | |
| 430 | 397 | echo " }," | |
| 431 | - | echo " \"tar_docker_count\": $TOTAL_TAR_DOCKER," | |
| 432 | - | echo " \"tar_casaos_count\": $TOTAL_TAR_CASAOS," | |
| 433 | - | echo " \"oldest_backup_docker\": \"$OLDEST_BACKUP\"," | |
| 434 | - | echo " \"oldest_backup_docker_human\": \"${HUMAN_OLDEST:-N/A}\"," | |
| 435 | - | echo " \"newest_backup_docker\": \"$NEWEST_BACKUP\"," | |
| 436 | - | echo " \"newest_backup_docker_human\": \"${HUMAN_NEWEST:-N/A}\"," | |
| 398 | + | echo " \"backup_sets\": $TOTAL_BACKUP_SETS," | |
| 399 | + | echo " \"oldest_backup_dir\": \"${OLDEST_DIR:-}\"," | |
| 400 | + | echo " \"newest_backup_dir\": \"${NEWEST_DIR:-}\"," | |
| 437 | 401 | echo " \"duration\": \"$DURATION\"" | |
| 438 | 402 | echo "}" | |
| 439 | 403 | fi | |
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 77 insertions, 32 deletions
Backup-Home-docker.tar.gz.sh
| @@ -16,16 +16,19 @@ MAX_BACKUPS=5 | |||
| 16 | 16 | # Date format | |
| 17 | 17 | DATE="$(date +'%Y%m%d_%H%M%S')" | |
| 18 | 18 | ||
| 19 | - | # Fichier TAR final | |
| 19 | + | # Fichier TAR final Docker | |
| 20 | 20 | BACKUP_FILE="$BACKUP_DIR/docker_backup_${DATE}.tar.gz" | |
| 21 | 21 | ||
| 22 | + | # Fichier TAR FULL CasaOS (config + volumes) | |
| 23 | + | CASAOS_FULL_TAR="$BACKUP_DIR/casaos_full_backup_${DATE}.tar.gz" | |
| 24 | + | ||
| 22 | 25 | # Dossier de configs des compose à côté du TAR | |
| 23 | 26 | CONFIG_DIR="$BACKUP_DIR/config_${DATE}" | |
| 24 | 27 | ||
| 25 | 28 | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR) | |
| 26 | 29 | EXCLUDE_DIRS=( | |
| 27 | 30 | "docker_var_lib" | |
| 28 | - | "1_Backups" | |
| 31 | + | "1_Backups" | |
| 29 | 32 | "casaos_data/*" | |
| 30 | 33 | "nginx_proxy/data/logs/*" | |
| 31 | 34 | "yt-dl/video/*" | |
| @@ -82,11 +85,20 @@ check_pigz() { | |||
| 82 | 85 | rotate_backups() { | |
| 83 | 86 | log_message "Nettoyage des anciens backups (conserver les $MAX_BACKUPS plus récents)..." | |
| 84 | 87 | ||
| 85 | - | # TAR | |
| 88 | + | # TAR Docker | |
| 86 | 89 | mapfile -t backups_tar < <(ls -1t "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null || true) | |
| 87 | 90 | if [ "${#backups_tar[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 88 | 91 | for f in "${backups_tar[@]:$MAX_BACKUPS}"; do | |
| 89 | - | log_message "Suppression ancien backup tar : $f" | |
| 92 | + | log_message "Suppression ancien backup tar Docker : $f" | |
| 93 | + | rm -f "$f" | |
| 94 | + | done | |
| 95 | + | fi | |
| 96 | + | ||
| 97 | + | # TAR CasaOS full | |
| 98 | + | mapfile -t backups_casaos < <(ls -1t "$BACKUP_DIR"/casaos_full_backup_*.tar.gz 2>/dev/null || true) | |
| 99 | + | if [ "${#backups_casaos[@]}" -gt "$MAX_BACKUPS" ]; then | |
| 100 | + | for f in "${backups_casaos[@]:$MAX_BACKUPS}"; do | |
| 101 | + | log_message "Suppression ancien backup tar CasaOS : $f" | |
| 90 | 102 | rm -f "$f" | |
| 91 | 103 | done | |
| 92 | 104 | fi | |
| @@ -129,11 +141,11 @@ echo -e "${CYAN}=== Backup Docker + Configs (Portainer / CasaOS) ===${NC}" | |||
| 129 | 141 | log_message "Début sauvegarde Docker + configs Portainer & CasaOS..." | |
| 130 | 142 | ||
| 131 | 143 | ############################################## | |
| 132 | - | # 1) Sauvegarde TAR via pigz + exclusions | |
| 144 | + | # 1) Sauvegarde TAR Docker via pigz + exclusions | |
| 133 | 145 | ############################################## | |
| 134 | - | log_message "Création de l’archive : $BACKUP_FILE" | |
| 146 | + | log_message "Création de l’archive Docker : $BACKUP_FILE" | |
| 135 | 147 | ||
| 136 | - | # Construction des arguments d'exclusion dynamiques pour le TAR | |
| 148 | + | # Construction des arguments d'exclusion dynamiques pour le TAR Docker | |
| 137 | 149 | EXCLUDE_ARGS=( | |
| 138 | 150 | "--exclude=*.log" | |
| 139 | 151 | "--exclude=.composer" | |
| @@ -168,8 +180,8 @@ tar -cf "$BACKUP_FILE" -I pigz \ | |||
| 168 | 180 | . 2>> "$LOG_FILE" | |
| 169 | 181 | ||
| 170 | 182 | if [ $? -ne 0 ]; then | |
| 171 | - | log_message "ERREUR lors de la création du tar." | |
| 172 | - | echo -e "${RED}Erreur lors de la création de l’archive.${NC}" | |
| 183 | + | log_message "ERREUR lors de la création du tar Docker." | |
| 184 | + | echo -e "${RED}Erreur lors de la création de l’archive Docker.${NC}" | |
| 173 | 185 | exit 1 | |
| 174 | 186 | fi | |
| 175 | 187 | ||
| @@ -194,7 +206,7 @@ log_message "Extraction des docker-compose Docker (hors casaos_data & dossiers e | |||
| 194 | 206 | find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| 195 | 207 | ! -path "$SOURCE_DIR/casaos_data/*" \ | |
| 196 | 208 | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 197 | - | | while read file; do | |
| 209 | + | 2>/dev/null | while read file; do | |
| 198 | 210 | container_name=$(basename "$(dirname "$file")") | |
| 199 | 211 | dest_dir="$CONFIG_DIR/docker/$container_name" | |
| 200 | 212 | mkdir -p "$dest_dir" | |
| @@ -218,17 +230,32 @@ else | |||
| 218 | 230 | fi | |
| 219 | 231 | ||
| 220 | 232 | ############################################## | |
| 221 | - | # 4) Config CasaOS (full) | |
| 233 | + | # 4) Config CasaOS (full + second tar.gz) | |
| 222 | 234 | ############################################## | |
| 223 | 235 | CASAOS_CONFIG_DIR="$CONFIG_DIR/casaos/full_config" | |
| 224 | - | CASAOS_FILES=0 | |
| 225 | 236 | ||
| 226 | 237 | if [ -d "/var/lib/casaos" ]; then | |
| 227 | - | log_message "Sauvegarde config CasaOS (full)..." | |
| 238 | + | log_message "Sauvegarde config CasaOS (full vers $CASAOS_CONFIG_DIR)..." | |
| 228 | 239 | mkdir -p "$CASAOS_CONFIG_DIR" | |
| 229 | 240 | cp -r /var/lib/casaos/* "$CASAOS_CONFIG_DIR/" 2>>"$LOG_FILE" | |
| 230 | 241 | fi | |
| 231 | 242 | ||
| 243 | + | # Création du second tar.gz CasaOS FULL (config + volumes casaos_data) | |
| 244 | + | if [ -d "/var/lib/casaos" ] || [ -d "$SOURCE_DIR/casaos_data" ]; then | |
| 245 | + | CASAOS_TAR_SOURCES=() | |
| 246 | + | [ -d "/var/lib/casaos" ] && CASAOS_TAR_SOURCES+=( "/var/lib/casaos" ) | |
| 247 | + | [ -d "$SOURCE_DIR/casaos_data" ] && CASAOS_TAR_SOURCES+=( "$SOURCE_DIR/casaos_data" ) | |
| 248 | + | ||
| 249 | + | if [ "${#CASAOS_TAR_SOURCES[@]}" -gt 0 ]; then | |
| 250 | + | log_message "Création de l’archive CASAOS FULL : $CASAOS_FULL_TAR" | |
| 251 | + | tar -cf "$CASAOS_FULL_TAR" -I pigz "${CASAOS_TAR_SOURCES[@]}" 2>>"$LOG_FILE" | |
| 252 | + | if [ $? -ne 0 ]; then | |
| 253 | + | log_message "ERREUR lors de la création du tar CasaOS." | |
| 254 | + | echo -e "${RED}Erreur lors de la création de l’archive CasaOS.${NC}" | |
| 255 | + | fi | |
| 256 | + | fi | |
| 257 | + | fi | |
| 258 | + | ||
| 232 | 259 | ############################################## | |
| 233 | 260 | # 5) Comptages finaux (sur le backup courant) | |
| 234 | 261 | ############################################## | |
| @@ -244,19 +271,21 @@ SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name | |||
| 244 | 271 | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 245 | 272 | 2>/dev/null | wc -l) | |
| 246 | 273 | ||
| 247 | - | # Containers Docker "valides" (dossiers de premier niveau, hors exclusions évidentes) | |
| 274 | + | # Containers Docker "valides" | |
| 248 | 275 | CONTAINERS_DOCKER=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 249 | 276 | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 250 | 277 | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 251 | 278 | ! -path "$SOURCE_DIR/portainer" 2>/dev/null | wc -l) | |
| 252 | 279 | ||
| 253 | - | # Rotation des anciens backups | |
| 280 | + | # Rotation des anciens backups (Docker tar + CasaOS tar + configs) | |
| 254 | 281 | rotate_backups | |
| 255 | 282 | ||
| 256 | - | # Nombre total de tar.gz | |
| 257 | - | TOTAL_TAR=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | wc -l) | |
| 283 | + | # Nombre total de tar.gz Docker | |
| 284 | + | TOTAL_TAR_DOCKER=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | wc -l) | |
| 285 | + | # Nombre total de tar.gz CasaOS full | |
| 286 | + | TOTAL_TAR_CASAOS=$(ls -1 "$BACKUP_DIR"/casaos_full_backup_*.tar.gz 2>/dev/null | wc -l) | |
| 258 | 287 | ||
| 259 | - | # Oldest / newest après rotation | |
| 288 | + | # Oldest / newest Docker après rotation | |
| 260 | 289 | OLDEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | head -n1) | |
| 261 | 290 | NEWEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | tail -n1) | |
| 262 | 291 | ||
| @@ -269,13 +298,20 @@ CONFIG_SIZE=$(get_size "$CONFIG_DIR") | |||
| 269 | 298 | # Docker compose directory size | |
| 270 | 299 | DOCKER_CONFIG_SIZE=$(get_size "$CONFIG_DIR/docker") | |
| 271 | 300 | ||
| 272 | - | # CasaOS full config size | |
| 301 | + | # CasaOS full config size (copie dans config_) | |
| 273 | 302 | if [ -d "$CASAOS_CONFIG_DIR" ]; then | |
| 274 | 303 | CASAOS_CONFIG_SIZE=$(get_size "$CASAOS_CONFIG_DIR") | |
| 275 | 304 | else | |
| 276 | 305 | CASAOS_CONFIG_SIZE="" | |
| 277 | 306 | fi | |
| 278 | 307 | ||
| 308 | + | # CasaOS FULL TAR size | |
| 309 | + | if [ -f "$CASAOS_FULL_TAR" ]; then | |
| 310 | + | CASAOS_FULL_TAR_SIZE=$(get_size "$CASAOS_FULL_TAR") | |
| 311 | + | else | |
| 312 | + | CASAOS_FULL_TAR_SIZE="" | |
| 313 | + | fi | |
| 314 | + | ||
| 279 | 315 | # Portainer full config size | |
| 280 | 316 | if [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ]; then | |
| 281 | 317 | PORTAINER_CONFIG_SIZE=$(get_size "$PORTAINER_CONFIG_DIR") | |
| @@ -330,11 +366,15 @@ echo -e "${CYAN}Taille compose Docker : ${GREEN}$DOCKER_CONFIG_SIZE${NC}" | |||
| 330 | 366 | ################################# | |
| 331 | 367 | # CASAOS (si présent) | |
| 332 | 368 | ################################# | |
| 333 | - | if [ -d "$CASAOS_CONFIG_DIR" ] || [ "$CASAOS_COMPOSE_BACKUP" -gt 0 ]; then | |
| 369 | + | if [ -d "$CASAOS_CONFIG_DIR" ] || [ "$CASAOS_COMPOSE_BACKUP" -gt 0 ] || [ -f "$CASAOS_FULL_TAR" ]; then | |
| 334 | 370 | echo -e "${CYAN}\n----- CASAOS -----${NC}" | |
| 335 | 371 | echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}" | |
| 336 | 372 | echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}" | |
| 337 | 373 | [ -n "$CASAOS_CONFIG_SIZE" ] && echo -e "${CYAN}Taille config CasaOS (full) : ${GREEN}$CASAOS_CONFIG_SIZE${NC}" | |
| 374 | + | if [ -f "$CASAOS_FULL_TAR" ]; then | |
| 375 | + | echo -e "${CYAN}Tar CasaOS FULL : ${YELLOW}$CASAOS_FULL_TAR${NC}" | |
| 376 | + | echo -e "${CYAN}Taille tar CasaOS FULL : ${GREEN}$CASAOS_FULL_TAR_SIZE${NC}" | |
| 377 | + | fi | |
| 338 | 378 | fi | |
| 339 | 379 | ||
| 340 | 380 | ################################# | |
| @@ -351,14 +391,16 @@ fi | |||
| 351 | 391 | # GLOBAL | |
| 352 | 392 | ################################# | |
| 353 | 393 | echo -e "${CYAN}\n----- GLOBAL -----${NC}" | |
| 354 | - | echo -e "${CYAN}Taille archive tar.gz : ${GREEN}$TAR_SIZE${NC}" | |
| 394 | + | echo -e "${CYAN}Taille archive Docker tar.gz : ${GREEN}$TAR_SIZE${NC}" | |
| 395 | + | [ -f "$CASAOS_FULL_TAR" ] && echo -e "${CYAN}Taille archive CasaOS tar.gz : ${GREEN}$CASAOS_FULL_TAR_SIZE${NC}" | |
| 355 | 396 | echo -e "${CYAN}Taille dossier config : ${GREEN}$CONFIG_SIZE${NC}" | |
| 356 | - | echo -e "${CYAN}Nombre de .tar.gz : ${GREEN}$TOTAL_TAR${NC}" | |
| 357 | - | echo -e "${CYAN}Oldest backup : ${YELLOW}$OLDEST_BACKUP${NC}" | |
| 397 | + | echo -e "${CYAN}Nombre tar Docker : ${GREEN}$TOTAL_TAR_DOCKER${NC}" | |
| 398 | + | echo -e "${CYAN}Nombre tar CasaOS : ${GREEN}$TOTAL_TAR_CASAOS${NC}" | |
| 399 | + | echo -e "${CYAN}Oldest backup Docker : ${YELLOW}$OLDEST_BACKUP${NC}" | |
| 358 | 400 | echo -e "${CYAN}Oldest backup (human) : ${GREEN}${HUMAN_OLDEST:-N/A}${NC}" | |
| 359 | - | echo -e "${CYAN}Newest backup : ${YELLOW}$NEWEST_BACKUP${NC}" | |
| 401 | + | echo -e "${CYAN}Newest backup Docker : ${YELLOW}$NEWEST_BACKUP${NC}" | |
| 360 | 402 | echo -e "${CYAN}Newest backup (human) : ${GREEN}${HUMAN_NEWEST:-N/A}${NC}" | |
| 361 | - | echo -e "${CYAN}Archive courante : ${YELLOW}$BACKUP_FILE${NC}" | |
| 403 | + | echo -e "${CYAN}Archive Docker courante : ${YELLOW}$BACKUP_FILE${NC}" | |
| 362 | 404 | echo -e "${CYAN}Dossier config courant : ${YELLOW}$CONFIG_DIR${NC}" | |
| 363 | 405 | echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}" | |
| 364 | 406 | ||
| @@ -369,8 +411,10 @@ if [ "$1" = "--json" ]; then | |||
| 369 | 411 | echo "" | |
| 370 | 412 | echo "{" | |
| 371 | 413 | echo " \"date\": \"$DATE\"," | |
| 372 | - | echo " \"backup_file\": \"$BACKUP_FILE\"," | |
| 373 | - | echo " \"backup_size\": \"$TAR_SIZE\"," | |
| 414 | + | echo " \"docker_backup_file\": \"$BACKUP_FILE\"," | |
| 415 | + | echo " \"docker_backup_size\": \"$TAR_SIZE\"," | |
| 416 | + | echo " \"casaos_full_backup_file\": \"${CASAOS_FULL_TAR:-}\"," | |
| 417 | + | echo " \"casaos_full_backup_size\": \"${CASAOS_FULL_TAR_SIZE:-}\"," | |
| 374 | 418 | echo " \"config_dir\": \"$CONFIG_DIR\"," | |
| 375 | 419 | echo " \"config_size\": \"$CONFIG_SIZE\"," | |
| 376 | 420 | echo " \"docker\": {" | |
| @@ -384,11 +428,12 @@ if [ "$1" = "--json" ]; then | |||
| 384 | 428 | echo " \"portainer\": {" | |
| 385 | 429 | echo " \"files\": $PORTAINER_FILES" | |
| 386 | 430 | echo " }," | |
| 387 | - | echo " \"tar_count\": $TOTAL_TAR," | |
| 388 | - | echo " \"oldest_backup\": \"$OLDEST_BACKUP\"," | |
| 389 | - | echo " \"oldest_backup_human\": \"${HUMAN_OLDEST:-N/A}\"," | |
| 390 | - | echo " \"newest_backup\": \"$NEWEST_BACKUP\"," | |
| 391 | - | echo " \"newest_backup_human\": \"${HUMAN_NEWEST:-N/A}\"," | |
| 431 | + | echo " \"tar_docker_count\": $TOTAL_TAR_DOCKER," | |
| 432 | + | echo " \"tar_casaos_count\": $TOTAL_TAR_CASAOS," | |
| 433 | + | echo " \"oldest_backup_docker\": \"$OLDEST_BACKUP\"," | |
| 434 | + | echo " \"oldest_backup_docker_human\": \"${HUMAN_OLDEST:-N/A}\"," | |
| 435 | + | echo " \"newest_backup_docker\": \"$NEWEST_BACKUP\"," | |
| 436 | + | echo " \"newest_backup_docker_human\": \"${HUMAN_NEWEST:-N/A}\"," | |
| 392 | 437 | echo " \"duration\": \"$DURATION\"" | |
| 393 | 438 | echo "}" | |
| 394 | 439 | fi | |
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 4 insertions, 3 deletions
Backup-Home-docker.tar.gz.sh
| @@ -25,6 +25,7 @@ CONFIG_DIR="$BACKUP_DIR/config_${DATE}" | |||
| 25 | 25 | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR) | |
| 26 | 26 | EXCLUDE_DIRS=( | |
| 27 | 27 | "docker_var_lib" | |
| 28 | + | "1_Backups" | |
| 28 | 29 | "casaos_data/*" | |
| 29 | 30 | "nginx_proxy/data/logs/*" | |
| 30 | 31 | "yt-dl/video/*" | |
| @@ -306,14 +307,14 @@ DOCKER_DIRS=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |||
| 306 | 307 | if [ -z "$DOCKER_DIRS" ]; then | |
| 307 | 308 | echo -e "${YELLOW}(Aucun dossier Docker trouvé)${NC}" | |
| 308 | 309 | else | |
| 309 | - | echo -e "┌──────────────────────────┬─────────┬────────────────────────────────────────────┐" | |
| 310 | + | echo -e "┌──────────────────────────┬─────────┬────────────────────────────────────────┐" | |
| 310 | 311 | printf "│ %-24s │ %-7s │ %-38s │\n" "Container" "Taille" "Chemin" | |
| 311 | - | echo -e "├──────────────────────────┼─────────┼────────────────────────────────────────────┤" | |
| 312 | + | echo -e "├──────────────────────────┼─────────┼────────────────────────────────────────┤" | |
| 312 | 313 | du -sh $DOCKER_DIRS 2>/dev/null | sort -hr | while read -r size path; do | |
| 313 | 314 | name=$(basename "$path") | |
| 314 | 315 | printf "│ %-24s │ %-7s │ %-38s │\n" "$name" "$size" "$path" | |
| 315 | 316 | done | |
| 316 | - | echo -e "└──────────────────────────┴─────────┴────────────────────────────────────────────┘" | |
| 317 | + | echo -e "└──────────────────────────┴─────────┴────────────────────────────────────────┘" | |
| 317 | 318 | fi | |
| 318 | 319 | ||
| 319 | 320 | ################################# | |
Erreur32 revised this gist 6 months ago. Go to revision
1 file changed, 154 insertions, 31 deletions
Backup-Home-docker.tar.gz.sh
| @@ -24,6 +24,7 @@ CONFIG_DIR="$BACKUP_DIR/config_${DATE}" | |||
| 24 | 24 | ||
| 25 | 25 | # Dossiers à exclure (chemins relatifs à $SOURCE_DIR) | |
| 26 | 26 | EXCLUDE_DIRS=( | |
| 27 | + | "docker_var_lib" | |
| 27 | 28 | "casaos_data/*" | |
| 28 | 29 | "nginx_proxy/data/logs/*" | |
| 29 | 30 | "yt-dl/video/*" | |
| @@ -99,6 +100,19 @@ rotate_backups() { | |||
| 99 | 100 | fi | |
| 100 | 101 | } | |
| 101 | 102 | ||
| 103 | + | human_date() { | |
| 104 | + | # Convertit 20251203_172811 → "03/12/2025 17:28:11" | |
| 105 | + | local d="$1" | |
| 106 | + | local date_part="${d:0:8}" | |
| 107 | + | local time_part="${d:9:6}" | |
| 108 | + | echo "${date_part:6:2}/${date_part:4:2}/${date_part:0:4} ${time_part:0:2}:${time_part:2:2}:${time_part:4:2}" | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | get_size() { | |
| 112 | + | # Taille lisible | |
| 113 | + | du -sh "$1" 2>/dev/null | awk '{print $1}' | |
| 114 | + | } | |
| 115 | + | ||
| 102 | 116 | ############################# | |
| 103 | 117 | # DÉBUT SCRIPT | |
| 104 | 118 | ############################# | |
| @@ -118,7 +132,7 @@ log_message "Début sauvegarde Docker + configs Portainer & CasaOS..." | |||
| 118 | 132 | ############################################## | |
| 119 | 133 | log_message "Création de l’archive : $BACKUP_FILE" | |
| 120 | 134 | ||
| 121 | - | # Construction des arguments d'exclusion dynamiques | |
| 135 | + | # Construction des arguments d'exclusion dynamiques pour le TAR | |
| 122 | 136 | EXCLUDE_ARGS=( | |
| 123 | 137 | "--exclude=*.log" | |
| 124 | 138 | "--exclude=.composer" | |
| @@ -141,7 +155,6 @@ EXCLUDE_ARGS=( | |||
| 141 | 155 | "--exclude=.rvm" | |
| 142 | 156 | "--exclude=node_modules" | |
| 143 | 157 | "--exclude=lost+found" | |
| 144 | - | "--exclude=casaos_data" | |
| 145 | 158 | ) | |
| 146 | 159 | ||
| 147 | 160 | for d in "${EXCLUDE_DIRS[@]}"; do | |
| @@ -176,14 +189,17 @@ if [ -d "$SOURCE_DIR/casaos_data" ]; then | |||
| 176 | 189 | done | |
| 177 | 190 | fi | |
| 178 | 191 | ||
| 179 | - | log_message "Extraction des docker-compose Docker (hors casaos_data)..." | |
| 180 | - | find "$SOURCE_DIR" -type f -name "docker-compose.y*ml" ! -path "$SOURCE_DIR/casaos_data/*" | while read file; do | |
| 181 | - | container_name=$(basename "$(dirname "$file")") | |
| 182 | - | dest_dir="$CONFIG_DIR/docker/$container_name" | |
| 183 | - | mkdir -p "$dest_dir" | |
| 184 | - | cp "$file" "$dest_dir/" | |
| 185 | - | log_message " [Docker] → Compose trouvé : $file" | |
| 186 | - | done | |
| 192 | + | log_message "Extraction des docker-compose Docker (hors casaos_data & dossiers exclus)..." | |
| 193 | + | find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| 194 | + | ! -path "$SOURCE_DIR/casaos_data/*" \ | |
| 195 | + | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 196 | + | | while read file; do | |
| 197 | + | container_name=$(basename "$(dirname "$file")") | |
| 198 | + | dest_dir="$CONFIG_DIR/docker/$container_name" | |
| 199 | + | mkdir -p "$dest_dir" | |
| 200 | + | cp "$file" "$dest_dir/" | |
| 201 | + | log_message " [Docker] → Compose trouvé : $file" | |
| 202 | + | done | |
| 187 | 203 | ||
| 188 | 204 | ############################################## | |
| 189 | 205 | # 3) Config Portainer (full) | |
| @@ -197,7 +213,7 @@ if docker volume inspect portainer_data >/dev/null 2>&1; then | |||
| 197 | 213 | cp -r /var/lib/docker/volumes/portainer_data/_data/* "$PORTAINER_CONFIG_DIR/" 2>>"$LOG_FILE" | |
| 198 | 214 | PORTAINER_FILES=$(find "$PORTAINER_CONFIG_DIR" -type f 2>/dev/null | wc -l) | |
| 199 | 215 | else | |
| 200 | - | log_message "Portainer non détecté (volume portainer_data absent)." | |
| 216 | + | PORTAINER_CONFIG_DIR="" | |
| 201 | 217 | fi | |
| 202 | 218 | ||
| 203 | 219 | ############################################## | |
| @@ -210,9 +226,6 @@ if [ -d "/var/lib/casaos" ]; then | |||
| 210 | 226 | log_message "Sauvegarde config CasaOS (full)..." | |
| 211 | 227 | mkdir -p "$CASAOS_CONFIG_DIR" | |
| 212 | 228 | cp -r /var/lib/casaos/* "$CASAOS_CONFIG_DIR/" 2>>"$LOG_FILE" | |
| 213 | - | CASAOS_FILES=$(find "$CONFIG_DIR/casaos" -type f -name "docker-compose.y*ml" ! -path "$CONFIG_DIR/casaos/full_config/*" 2>/dev/null | wc -l) | |
| 214 | - | else | |
| 215 | - | log_message "CasaOS non détecté (/var/lib/casaos manquant)." | |
| 216 | 229 | fi | |
| 217 | 230 | ||
| 218 | 231 | ############################################## | |
| @@ -224,8 +237,17 @@ CASAOS_COMPOSE_BACKUP=$(find "$CONFIG_DIR/casaos" -maxdepth 3 -type f -name "doc | |||
| 224 | 237 | DOCKER_COMPOSE_BACKUP=$(find "$CONFIG_DIR/docker" -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l) | |
| 225 | 238 | TOTAL_COMPOSE_BACKUP=$((CASAOS_COMPOSE_BACKUP + DOCKER_COMPOSE_BACKUP)) | |
| 226 | 239 | ||
| 227 | - | # Compose dans le dossier source (hors casaos_data) | |
| 228 | - | SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -type f -name "docker-compose.y*ml" ! -path "$SOURCE_DIR/casaos_data/*" 2>/dev/null | wc -l) | |
| 240 | + | # Compose dans le dossier source (uniquement /home/docker/<container>/docker-compose.*) | |
| 241 | + | SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -mindepth 2 -maxdepth 2 -type f -name "docker-compose.y*ml" \ | |
| 242 | + | ! -path "$SOURCE_DIR/casaos_data/*" \ | |
| 243 | + | ! -path "$SOURCE_DIR/docker_var_lib/*" \ | |
| 244 | + | 2>/dev/null | wc -l) | |
| 245 | + | ||
| 246 | + | # Containers Docker "valides" (dossiers de premier niveau, hors exclusions évidentes) | |
| 247 | + | CONTAINERS_DOCKER=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 248 | + | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 249 | + | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 250 | + | ! -path "$SOURCE_DIR/portainer" 2>/dev/null | wc -l) | |
| 229 | 251 | ||
| 230 | 252 | # Rotation des anciens backups | |
| 231 | 253 | rotate_backups | |
| @@ -239,32 +261,133 @@ NEWEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | tail -n | |||
| 239 | 261 | ||
| 240 | 262 | DURATION="$(format_time $SECONDS)" | |
| 241 | 263 | ||
| 264 | + | # Tailles des backups | |
| 265 | + | TAR_SIZE=$(get_size "$BACKUP_FILE") | |
| 266 | + | CONFIG_SIZE=$(get_size "$CONFIG_DIR") | |
| 267 | + | ||
| 268 | + | # Docker compose directory size | |
| 269 | + | DOCKER_CONFIG_SIZE=$(get_size "$CONFIG_DIR/docker") | |
| 270 | + | ||
| 271 | + | # CasaOS full config size | |
| 272 | + | if [ -d "$CASAOS_CONFIG_DIR" ]; then | |
| 273 | + | CASAOS_CONFIG_SIZE=$(get_size "$CASAOS_CONFIG_DIR") | |
| 274 | + | else | |
| 275 | + | CASAOS_CONFIG_SIZE="" | |
| 276 | + | fi | |
| 277 | + | ||
| 278 | + | # Portainer full config size | |
| 279 | + | if [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ]; then | |
| 280 | + | PORTAINER_CONFIG_SIZE=$(get_size "$PORTAINER_CONFIG_DIR") | |
| 281 | + | else | |
| 282 | + | PORTAINER_CONFIG_SIZE="" | |
| 283 | + | fi | |
| 284 | + | ||
| 285 | + | # Dates humaines | |
| 286 | + | HUMAN_OLDEST=$( [ -n "$OLDEST_BACKUP" ] && human_date "$(basename "$OLDEST_BACKUP" | sed 's/docker_backup_//; s/.tar.gz//')" ) | |
| 287 | + | HUMAN_NEWEST=$( [ -n "$NEWEST_BACKUP" ] && human_date "$(basename "$NEWEST_BACKUP" | sed 's/docker_backup_//; s/.tar.gz//')" ) | |
| 288 | + | ||
| 242 | 289 | ############################################## | |
| 243 | 290 | # 6) RÉSUMÉS | |
| 244 | 291 | ############################################## | |
| 245 | 292 | ||
| 246 | - | ||
| 293 | + | echo -e "${GREEN}===== BACKUP TERMINÉ =====${NC}" | |
| 247 | 294 | ||
| 248 | - | ||
| 295 | + | ############################################## | |
| 296 | + | # LISTE DES DOSSIERS DOCKER PAR TAILLE (ASCII) | |
| 297 | + | ############################################## | |
| 249 | 298 | ||
| 250 | - | echo -e "${GREEN}===== BACKUP TERMINÉ =====${NC}" | |
| 251 | - | echo -e "${CYAN}----- DOCKER -----${NC}" | |
| 252 | - | echo -e "${CYAN}Compose source (hors CasaOS) : ${GREEN}$SOURCE_COMPOSE_COUNT${NC}" | |
| 299 | + | echo -e "\n${CYAN}----- LISTE/TAILLE DES RÉPERTOIRES DOCKER -----${NC}" | |
| 300 | + | ||
| 301 | + | DOCKER_DIRS=$(find "$SOURCE_DIR" -mindepth 1 -maxdepth 1 -type d \ | |
| 302 | + | ! -path "$SOURCE_DIR/casaos_data" \ | |
| 303 | + | ! -path "$SOURCE_DIR/docker_var_lib" \ | |
| 304 | + | ! -path "$SOURCE_DIR/portainer" 2>/dev/null) | |
| 305 | + | ||
| 306 | + | if [ -z "$DOCKER_DIRS" ]; then | |
| 307 | + | echo -e "${YELLOW}(Aucun dossier Docker trouvé)${NC}" | |
| 308 | + | else | |
| 309 | + | echo -e "┌──────────────────────────┬─────────┬────────────────────────────────────────────┐" | |
| 310 | + | printf "│ %-24s │ %-7s │ %-38s │\n" "Container" "Taille" "Chemin" | |
| 311 | + | echo -e "├──────────────────────────┼─────────┼────────────────────────────────────────────┤" | |
| 312 | + | du -sh $DOCKER_DIRS 2>/dev/null | sort -hr | while read -r size path; do | |
| 313 | + | name=$(basename "$path") | |
| 314 | + | printf "│ %-24s │ %-7s │ %-38s │\n" "$name" "$size" "$path" | |
| 315 | + | done | |
| 316 | + | echo -e "└──────────────────────────┴─────────┴────────────────────────────────────────────┘" | |
| 317 | + | fi | |
| 318 | + | ||
| 319 | + | ################################# | |
| 320 | + | # DOCKER | |
| 321 | + | ################################# | |
| 322 | + | echo -e "${CYAN}\n----- DOCKER -----${NC}" | |
| 323 | + | echo -e "${CYAN}Containers Docker détectés : ${GREEN}$CONTAINERS_DOCKER${NC}" | |
| 324 | + | echo -e "${CYAN}Compose source (Docker) : ${GREEN}$SOURCE_COMPOSE_COUNT${NC}" | |
| 253 | 325 | echo -e "${CYAN}Compose backup (Docker) : ${GREEN}$DOCKER_COMPOSE_BACKUP${NC}" | |
| 254 | 326 | echo -e "${CYAN}Dossier compose Docker : ${YELLOW}$CONFIG_DIR/docker${NC}" | |
| 327 | + | echo -e "${CYAN}Taille compose Docker : ${GREEN}$DOCKER_CONFIG_SIZE${NC}" | |
| 328 | + | ||
| 329 | + | ################################# | |
| 330 | + | # CASAOS (si présent) | |
| 331 | + | ################################# | |
| 332 | + | if [ -d "$CASAOS_CONFIG_DIR" ] || [ "$CASAOS_COMPOSE_BACKUP" -gt 0 ]; then | |
| 333 | + | echo -e "${CYAN}\n----- CASAOS -----${NC}" | |
| 334 | + | echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}" | |
| 335 | + | echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}" | |
| 336 | + | [ -n "$CASAOS_CONFIG_SIZE" ] && echo -e "${CYAN}Taille config CasaOS (full) : ${GREEN}$CASAOS_CONFIG_SIZE${NC}" | |
| 337 | + | fi | |
| 255 | 338 | ||
| 256 | - | echo -e "${CYAN}----- CASAOS -----${NC}" | |
| 257 | - | echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}" | |
| 258 | - | echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}" | |
| 259 | - | ||
| 260 | - | echo -e "${CYAN}----- PORTAINER -----${NC}" | |
| 261 | - | echo -e "${CYAN}Fichiers config Portainer : ${GREEN}$PORTAINER_FILES${NC}" | |
| 262 | - | echo -e "${CYAN}Dossier Portainer backup : ${YELLOW}$PORTAINER_CONFIG_DIR${NC}" | |
| 339 | + | ################################# | |
| 340 | + | # PORTAINER (si présent) | |
| 341 | + | ################################# | |
| 342 | + | if [ -n "$PORTAINER_CONFIG_DIR" ] && [ -d "$PORTAINER_CONFIG_DIR" ]; then | |
| 343 | + | echo -e "${CYAN}\n----- PORTAINER -----${NC}" | |
| 344 | + | echo -e "${CYAN}Fichiers config Portainer : ${GREEN}$PORTAINER_FILES${NC}" | |
| 345 | + | echo -e "${CYAN}Dossier Portainer backup : ${YELLOW}$PORTAINER_CONFIG_DIR${NC}" | |
| 346 | + | [ -n "$PORTAINER_CONFIG_SIZE" ] && echo -e "${CYAN}Taille Portainer (full) : ${GREEN}$PORTAINER_CONFIG_SIZE${NC}" | |
| 347 | + | fi | |
| 263 | 348 | ||
| 264 | - | echo -e "${CYAN}----- GLOBAL -----${NC}" | |
| 349 | + | ################################# | |
| 350 | + | # GLOBAL | |
| 351 | + | ################################# | |
| 352 | + | echo -e "${CYAN}\n----- GLOBAL -----${NC}" | |
| 353 | + | echo -e "${CYAN}Taille archive tar.gz : ${GREEN}$TAR_SIZE${NC}" | |
| 354 | + | echo -e "${CYAN}Taille dossier config : ${GREEN}$CONFIG_SIZE${NC}" | |
| 265 | 355 | echo -e "${CYAN}Nombre de .tar.gz : ${GREEN}$TOTAL_TAR${NC}" | |
| 266 | - | echo -e "${CYAN}Oldest backup : ${YELLOW}${OLDEST_BACKUP:-N/A}${NC}" | |
| 267 | - | echo -e "${CYAN}Newest backup : ${YELLOW}${NEWEST_BACKUP:-N/A}${NC}" | |
| 356 | + | echo -e "${CYAN}Oldest backup : ${YELLOW}$OLDEST_BACKUP${NC}" | |
| 357 | + | echo -e "${CYAN}Oldest backup (human) : ${GREEN}${HUMAN_OLDEST:-N/A}${NC}" | |
| 358 | + | echo -e "${CYAN}Newest backup : ${YELLOW}$NEWEST_BACKUP${NC}" | |
| 359 | + | echo -e "${CYAN}Newest backup (human) : ${GREEN}${HUMAN_NEWEST:-N/A}${NC}" | |
| 268 | 360 | echo -e "${CYAN}Archive courante : ${YELLOW}$BACKUP_FILE${NC}" | |
| 269 | 361 | echo -e "${CYAN}Dossier config courant : ${YELLOW}$CONFIG_DIR${NC}" | |
| 270 | 362 | echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}" | |
| 363 | + | ||
| 364 | + | ################################# | |
| 365 | + | # JSON (optionnel : ./script.sh --json) | |
| 366 | + | ################################# | |
| 367 | + | if [ "$1" = "--json" ]; then | |
| 368 | + | echo "" | |
| 369 | + | echo "{" | |
| 370 | + | echo " \"date\": \"$DATE\"," | |
| 371 | + | echo " \"backup_file\": \"$BACKUP_FILE\"," | |
| 372 | + | echo " \"backup_size\": \"$TAR_SIZE\"," | |
| 373 | + | echo " \"config_dir\": \"$CONFIG_DIR\"," | |
| 374 | + | echo " \"config_size\": \"$CONFIG_SIZE\"," | |
| 375 | + | echo " \"docker\": {" | |
| 376 | + | echo " \"containers\": $CONTAINERS_DOCKER," | |
| 377 | + | echo " \"compose_source\": $SOURCE_COMPOSE_COUNT," | |
| 378 | + | echo " \"compose_backup\": $DOCKER_COMPOSE_BACKUP" | |
| 379 | + | echo " }," | |
| 380 | + | echo " \"casaos\": {" | |
| 381 | + | echo " \"compose_backup\": $CASAOS_COMPOSE_BACKUP" | |
| 382 | + | echo " }," | |
| 383 | + | echo " \"portainer\": {" | |
| 384 | + | echo " \"files\": $PORTAINER_FILES" | |
| 385 | + | echo " }," | |
| 386 | + | echo " \"tar_count\": $TOTAL_TAR," | |
| 387 | + | echo " \"oldest_backup\": \"$OLDEST_BACKUP\"," | |
| 388 | + | echo " \"oldest_backup_human\": \"${HUMAN_OLDEST:-N/A}\"," | |
| 389 | + | echo " \"newest_backup\": \"$NEWEST_BACKUP\"," | |
| 390 | + | echo " \"newest_backup_human\": \"${HUMAN_NEWEST:-N/A}\"," | |
| 391 | + | echo " \"duration\": \"$DURATION\"" | |
| 392 | + | echo "}" | |
| 393 | + | fi | |