diff --git a/update.sh b/update.sh index c4b54ad..6d7a7b3 100644 --- a/update.sh +++ b/update.sh @@ -1,57 +1,101 @@ #!/usr/bin/env bash set -euo pipefail -METHOD="${1:-unknown}" +MODE="${1:-unknown}" -LOG_DIR="/var/log/lxc-updater-TM" +# 📁 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_FILE" + echo "$1" >>"$LOG_ARCHIVE" } run_cmd() { - local msg="$1" - shift + local title="$1"; shift + # console courte + log complet + printf "⏳ %s..." "$title" + { + echo "----- ${title} -----" + echo "CMD: $*" + "$@" + echo "----- FIN ${title} -----" + echo + } >>"$LOG_FILE" 2>&1 + echo " ✅" +} - echo "⏳ $msg..." - "$@" >>"$LOG_FILE" 2>&1 - echo "✅ $msg terminé" +# 🔎 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 Debian / Ubuntu (APT)" + log "📦 Mise à jour système (APT)" export DEBIAN_FRONTEND=noninteractive - run_cmd "Mise à jour des dépôts" apt-get update -y - run_cmd "Installation des mises à jour" apt-get upgrade -y + run_cmd "Mise à jour de la liste des paquets" apt-get update -y - systemctl daemon-reload >>"$LOG_FILE" 2>&1 || true + 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 Alpine (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 < <( @@ -61,64 +105,97 @@ update_docker() { ) 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 "⚠️ Dossier Compose ignoré : $d" + log "⚠️ Compose ignoré (chemin invalide ou sans compose.yml) : $d" fi done - if (( ${#valid_dirs[@]} > 0 )); then - + 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 - - log "📂 Projet : $d" - - if docker compose version >>"$LOG_FILE" 2>&1; then - run_cmd "Téléchargement des images" bash -c "cd '$d' && docker compose pull" - run_cmd "Redéploiement des services" bash -c "cd '$d' && docker compose up -d" - elif command -v docker-compose >>"$LOG_FILE" 2>&1; then - run_cmd "Téléchargement des images" bash -c "cd '$d' && docker-compose pull" - run_cmd "Redéploiement des services" bash -c "cd '$d' && docker-compose up -d" - else - log "❌ Docker Compose n'est pas installé" - return 2 - fi - + 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 "⚠️ Aucun projet Compose détecté" - log "⬇️ Mise à jour des images Docker utilisées" - - while read -r img; do - [[ -n "$img" ]] || continue - run_cmd "Téléchargement $img" docker pull "$img" - done < <(docker ps --format '{{.Image}}' | sort -u) - + log "✅ Images Docker mises à jour : ${updated}" + log "⚠️ Note : sans Compose, les conteneurs ne sont pas recréés automatiquement." fi } -case "$METHOD" in - apt) - update_apt - ;; - apk) - update_apk - ;; - docker) - update_docker - ;; +# --- 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 "❌ Méthode inconnue : $METHOD" - exit 1 + log "⚠️ Système de base non détecté (apt/apk). On saute la mise à jour OS." ;; esac -log "🧾 Log update : $LOG_FILE" +# 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" \ No newline at end of file