#!/usr/bin/env bash set -euo pipefail MODE="${1:-unknown}" # 📁 Logs par date LOG_ROOT="/var/log/lxc-updater-TM" DATE="$(date +%F)" TS="$(date +%H%M%S)" LOG_DIR="${LOG_ROOT}/${DATE}" LOG_FILE="${LOG_DIR}/lxc-updater-update.log" LOG_ARCHIVE="${LOG_DIR}/lxc-updater-update-${TS}.log" mkdir -p "$LOG_DIR" : > "$LOG_FILE" : > "$LOG_ARCHIVE" log() { echo "$1" echo "$1" >>"$LOG_FILE" echo "$1" >>"$LOG_ARCHIVE" } run_cmd() { local title="$1"; shift # console courte + log complet printf "⏳ %s..." "$title" { echo "----- ${title} -----" echo "CMD: $*" "$@" echo "----- FIN ${title} -----" echo } >>"$LOG_FILE" 2>&1 echo " ✅" } # 🔎 APT : nombre de paquets upgradables apt_upgradable_count() { # On force l’anglais pour un parsing plus stable LC_ALL=C apt-get -s upgrade 2>/dev/null | grep -c '^Inst ' || true } update_apt() { log "📦 Mise à jour système (APT)" export DEBIAN_FRONTEND=noninteractive run_cmd "Mise à jour de la liste des paquets" apt-get update -y local n n="$(apt_upgradable_count)" log "🔎 Paquets disponibles : ${n}" if [[ "$n" -eq 0 ]]; then log "✅ Aucun paquet à mettre à jour" else run_cmd "Installation des mises à jour (${n} paquet(s))" apt-get upgrade -y run_cmd "Rechargement systemd (si nécessaire)" systemctl daemon-reload log "✅ Mise à jour APT terminée" fi } update_apk() { log "📦 Mise à jour système (APK)" run_cmd "Mise à jour des dépôts" apk update # apk ne donne pas un compteur simple “upgradable” comme apt, # donc on fait l’upgrade et tout est loggué. run_cmd "Installation des mises à jour" apk upgrade log "✅ Mise à jour APK terminée" } # 🔎 Docker : ID image docker_image_id() { docker image inspect -f '{{.Id}}' "$1" 2>/dev/null || true } update_docker_compose_dir() { local dir="$1" log "📂 Projet Compose : ${dir}" # pull run_cmd "Docker Compose pull (${dir})" bash -c "cd '$dir' && docker compose pull" # up run_cmd "Docker Compose up -d (${dir})" bash -c "cd '$dir' && docker compose up -d" } update_docker() { log "🐳 Mise à jour Docker" # Vérif docker if ! docker ps >>"$LOG_FILE" 2>&1; then log "❌ Docker n'est pas accessible" return 1 fi # 1) Essayer compose via labels (mais seulement si le dossier existe ET contient un compose) log "🔍 Recherche de projets Docker Compose" mapfile -t dirs < <( docker ps -q | while read -r cid; do docker inspect -f '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}' "$cid" 2>/dev/null || true done | sed '/^$/d;/^$/d' | sort -u ) valid_dirs=() for d in "${dirs[@]}"; do if [[ -d "$d" ]] && { [[ -f "$d/docker-compose.yml" ]] || [[ -f "$d/compose.yml" ]]; }; then valid_dirs+=("$d") else log "⚠️ Compose ignoré (chemin invalide ou sans compose.yml) : $d" fi done if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 && (( ${#valid_dirs[@]} > 0 )); then log "📁 Projet(s) Compose détecté(s) : ${#valid_dirs[@]}" for d in "${valid_dirs[@]}"; do update_docker_compose_dir "$d" done log "✅ Mise à jour Docker (Compose) terminée" return 0 fi # 2) Fallback : pull image par image et afficher si ça change log "⚠️ Aucun Compose utilisable → mise à jour image par image (pull seulement)" mapfile -t images < <(docker ps --format '{{.Image}}' | sort -u) if (( ${#images[@]} == 0 )); then log "✅ Aucun conteneur Docker en cours" return 0 fi local updated=0 for img in "${images[@]}"; do [[ -n "$img" ]] || continue old_id="$(docker_image_id "$img")" # pull (tout dans le log) { echo "----- PULL ${img} -----" docker pull "$img" echo } >>"$LOG_FILE" 2>&1 || true new_id="$(docker_image_id "$img")" # Affichage propre if [[ -n "$old_id" && -n "$new_id" && "$old_id" != "$new_id" ]]; then updated=$((updated+1)) log "⬆️ Image mise à jour : ${img}" log " 🔁 ${old_id:0:20} ➜ ${new_id:0:20}" else # soit déjà à jour, soit pas d’ID exploitable log "✅ Image déjà à jour : ${img}" if [[ -n "$new_id" ]]; then log " 🏷️ ID : ${new_id:0:20}" fi fi done if [[ "$updated" -eq 0 ]]; then log "✅ Aucune mise à jour Docker à appliquer" log "💡 (Si tu veux une MAJ complète des conteneurs, privilégie Docker Compose)" else log "✅ Images Docker mises à jour : ${updated}" log "⚠️ Note : sans Compose, les conteneurs ne sont pas recréés automatiquement." fi } # --- Parsing MODE --- # Exemples : # - apt # - apk # - apt+docker # - apk+docker BASE_MODE="${MODE%%+docker}" HAS_DOCKER="0" if [[ "$MODE" == *"+docker" ]]; then HAS_DOCKER="1" fi log "🧭 Mode de mise à jour : ${MODE}" # 1) Toujours mettre à jour le système de base (si possible) case "$BASE_MODE" in apt) update_apt ;; apk) update_apk ;; *) log "⚠️ Système de base non détecté (apt/apk). On saute la mise à jour OS." ;; esac # 2) Puis Docker si présent if [[ "$HAS_DOCKER" == "1" ]]; then update_docker fi log "🧾 Log update : ${LOG_FILE}" log "🗃️ Archive update : ${LOG_ARCHIVE}" log "🎉 Mise à jour terminée"