Files
Docker/update.sh
2026-03-05 15:44:21 +01:00

209 lines
5.3 KiB
Bash

#!/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"
}
log_file_only() {
echo "[$(date -Is)] $*" >>"$LOG_FILE"
echo "[$(date -Is)] $*" >>"$LOG_ARCHIVE"
}
# ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ spinner
spinner_start() {
local msg="$1"
local -a frames=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏")
local i=0
printf "%s %s" "${frames[0]}" "$msg"
(
while true; do
i=$(( (i + 1) % ${#frames[@]} ))
printf "\r%s %s" "${frames[$i]}" "$msg"
sleep 0.12
done
) &
SPINNER_PID=$!
}
spinner_stop() {
local rc="${1:-0}"
local msg="$2"
if [[ -n "${SPINNER_PID:-}" ]]; then
kill "$SPINNER_PID" >/dev/null 2>&1 || true
wait "$SPINNER_PID" 2>/dev/null || true
unset SPINNER_PID
fi
if [[ "$rc" -eq 0 ]]; then
printf "\r✅ %s\n" "$msg"
else
printf "\r❌ %s\n" "$msg"
fi
}
run_cmd() {
local title="$1"; shift
spinner_start "$title"
log_file_only "----- ${title} -----"
log_file_only "CMD: $*"
set +e
"$@" >>"$LOG_FILE" 2>&1
local rc=$?
set -e
spinner_stop "$rc" "$title"
if [[ $rc -ne 0 ]]; then
log_file_only "ERREUR (code=$rc) sur: $title"
return $rc
fi
return 0
}
# 🔎 APT : nombre de paquets upgradables
apt_upgradable_count() {
LC_ALL=C apt-get -s upgrade 2>/dev/null | grep -c '^Inst ' || true
}
update_apt() {
log "📦 Mise à jour Debian / Ubuntu (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"
return 0
fi
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"
}
update_apk() {
log "📦 Mise à jour Alpine (APK)"
run_cmd "Mise à jour des dépôts" apk update
run_cmd "Installation des mises à jour" apk upgrade
log "✅ Mise à jour APK terminée"
}
# Compose: détecter dirs via labels + vérifier compose file
compose_dirs_from_labels() {
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 '/^<no value>$/d;/^$/d' | sort -u
}
is_compose_dir_valid() {
local d="$1"
[[ -d "$d" ]] && { [[ -f "$d/docker-compose.yml" ]] || [[ -f "$d/compose.yml" ]]; }
}
update_compose_dir() {
local dir="$1"
log "📂 Projet : $dir"
if docker compose version >/dev/null 2>&1; then
run_cmd "Téléchargement des images (Compose)" bash -c "cd '$dir' && docker compose pull"
# 🔁 Recréation SAFE (volumes conservés)
run_cmd "Redéploiement des services (Compose)" bash -c "cd '$dir' && docker compose up -d --remove-orphans"
return 0
fi
if command -v docker-compose >/dev/null 2>&1; then
run_cmd "Téléchargement des images (Compose v1)" bash -c "cd '$dir' && docker-compose pull"
run_cmd "Redéploiement des services (Compose v1)" bash -c "cd '$dir' && docker-compose up -d --remove-orphans"
return 0
fi
log "❌ Docker Compose n'est pas installé"
return 2
}
update_docker_compose() {
log "🐳 Mise à jour Docker (Compose)"
run_cmd "Vérification Docker" docker ps
log "🔍 Recherche de projets Docker Compose"
mapfile -t dirs < <(compose_dirs_from_labels)
valid=()
for d in "${dirs[@]}"; do
if is_compose_dir_valid "$d"; then
valid+=("$d")
else
log "⚠️ Projet ignoré (chemin invalide ou sans compose.yml) : $d"
fi
done
if (( ${#valid[@]} == 0 )); then
log "⚠️ Aucun projet Compose détecté"
return 0
fi
log "📁 Projet(s) Compose détecté(s) : ${#valid[@]}"
for d in "${valid[@]}"; do
update_compose_dir "$d"
done
log "✅ Mise à jour Docker terminée"
}
# --- Parsing MODE (apt/apk + docker) ---
BASE_MODE="${MODE%%+docker}"
HAS_DOCKER="0"
[[ "$MODE" == *"+docker" ]] && HAS_DOCKER="1"
# ─────────────── Sortie lisible ───────────────
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log "📦 Mise à jour du système"
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
case "$BASE_MODE" in
apt) update_apt ;;
apk) update_apk ;;
*) log "⚠️ Impossible de détecter le gestionnaire de paquets (apt/apk)" ;;
esac
if [[ "$HAS_DOCKER" == "1" ]]; then
log ""
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log "🐳 Mise à jour du ou des conteneurs"
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
update_docker_compose
else
log ""
log "🐳 Aucun conteneur Docker détecté"
fi
log ""
log "🧾 Log update : ${LOG_FILE}"
log "🗃️ Archive update : ${LOG_ARCHIVE}"
log "🎉 Mise à jour terminée"