#!/bin/bash # ============================================================================= # install_cron.sh — Installe les scripts Docker dans la crontab # ============================================================================= # Usage : # bash install_cron.sh → Installation interactive # bash install_cron.sh --force → Installation sans confirmation # bash install_cron.sh --uninstall → Retire les entrées du cron # bash install_cron.sh --status → Vérifie si les crons sont actifs # bash install_cron.sh --dry-run → Affiche ce qui serait installé # # Paramètres configurables : voir docker-scripts.conf # ============================================================================= set -euo pipefail # ─── Charger la configuration ──────────────────────────────────────────────── # Ordre : 1) config globale (template) → 2) config spécifique à l'app (surcharge) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" GLOBAL_CONFIG="${SCRIPT_DIR}/docker-scripts.conf" if [[ -f "$GLOBAL_CONFIG" ]]; then # shellcheck source=/dev/null source "$GLOBAL_CONFIG" fi # ─── Nom de l'application (défaut si pas dans la config) ───────────────────── DOCKER_APP_NAME="${DOCKER_APP_NAME:-gitea}" # ─── Configuration locale (après chargement global, permet surcharge env) ──── COMPOSE_DIR="${COMPOSE_DIR:-/srv/docker/$DOCKER_APP_NAME}" COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}" # Charger la config spécifique à l'application (surcharge la config globale) APP_CONFIG="${COMPOSE_DIR}/docker-scripts.conf" if [[ -f "$APP_CONFIG" ]] && [[ "$APP_CONFIG" != "$GLOBAL_CONFIG" ]]; then # shellcheck source=/dev/null source "$APP_CONFIG" fi # ─── Configuration locale ──────────────────────────────────────────────────── SCRIPTS_DIR="${SCRIPTS_DIR:-/opt/docker-scripts}" CRON_BACKUP_SCHEDULE="${CRON_BACKUP_SCHEDULE:-0 2 * * *}" CRON_UPDATE_SCHEDULE="${CRON_UPDATE_SCHEDULE:-0 4 * * *}" BACKUP_SCRIPT="${BACKUP_SCRIPT:-docker-backup.sh}" UPDATE_SCRIPT="${UPDATE_SCRIPT:-docker-auto-update.sh}" LOG_DIR="${LOG_DIR:-/var/log}" BACKUP_LOG="${BACKUP_LOG:-$LOG_DIR/${DOCKER_APP_NAME}-backup-cron.log}" UPDATE_LOG="${UPDATE_LOG:-$LOG_DIR/${DOCKER_APP_NAME}-update-cron.log}" CRON_MARKER="${CRON_MARKER:-# >>> ${DOCKER_APP_NAME^^} SCRIPTS (managed by install_cron.sh) <<<}" # Détection de l'utilisateur CRON_USER="${CRON_USER:-$USER}" # ─── Couleurs ─────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' ok() { echo -e " ${GREEN}✅${NC} $1"; } warn() { echo -e " ${YELLOW}⚠️${NC} $1"; } err() { echo -e " ${RED}❌${NC} $1"; } info() { echo -e " ${CYAN}📋${NC} $1"; } # ─── Usage ────────────────────────────────────────────────────────────────── usage() { cat << EOF Usage: $0 [OPTION] Options : --force Installation sans confirmation --dry-run Affiche ce qui serait installé sans rien faire --uninstall Retire les scripts du cron --status Vérifie l'état des crons --help Ce message Configuration (variables d'environnement) : SCRIPTS_DIR Dossier des scripts (défaut: /opt/docker-scripts) CRON_BACKUP_SCHEDULE Horaire backup (défaut: 0 2 * * *) CRON_UPDATE_SCHEDULE Horaire update (défaut: 0 4 * * *) EOF exit 0 } # ─── Vérification des prérequis ───────────────────────────────────────────── check_prerequisites() { local missing=0 if ! command -v crontab &>/dev/null; then err "crontab n'est pas installé" missing=1 fi if [[ ! -f "$SCRIPTS_DIR/$BACKUP_SCRIPT" ]]; then err "Script backup introuvable : $SCRIPTS_DIR/$BACKUP_SCRIPT" missing=1 fi if [[ ! -f "$SCRIPTS_DIR/$UPDATE_SCRIPT" ]]; then err "Script update introuvable : $SCRIPTS_DIR/$UPDATE_SCRIPT" missing=1 fi # Vérifier aussi la présence du fichier de config (optionnel mais recommandé) if [[ ! -f "$SCRIPTS_DIR/docker-scripts.conf" ]]; then warn "Fichier de configuration introuvable : $SCRIPTS_DIR/docker-scripts.conf" info "Les scripts utiliseront leurs valeurs par défaut" fi return $missing } # ─── Construire le bloc cron ──────────────────────────────────────────────── build_cron_block() { cat << CRON_BLOCK $CRON_MARKER # Backup quotidien (DB + volumes) $CRON_BACKUP_SCHEDULE $SCRIPTS_DIR/$BACKUP_SCRIPT >> $BACKUP_LOG 2>&1 # Vérification mise à jour Docker $CRON_UPDATE_SCHEDULE $SCRIPTS_DIR/$UPDATE_SCRIPT >> $UPDATE_LOG 2>&1 # >>> END ${DOCKER_APP_NAME^^} SCRIPTS <<< CRON_BLOCK } # ─── Status ───────────────────────────────────────────────────────────────── show_status() { echo "" echo "════════════════════════════════════════════════════════" echo "📊 ÉTAT DES CRONS" echo "════════════════════════════════════════════════════════" echo "" local current_cron current_cron=$(crontab -l 2>/dev/null || echo "") # Vérifier présence du marqueur if echo "$current_cron" | grep -qF "$CRON_MARKER"; then ok "Bloc de scripts trouvé dans la crontab de $CRON_USER" echo "" echo "Entrées actives :" # Extraire toutes les lignes entre les marqueurs echo "$current_cron" | sed -n "/$CRON_MARKER/,/>>> END ${DOCKER_APP_NAME^^} SCRIPTS </dev/null | cut -f1) log_lines=$(wc -l < "$BACKUP_LOG" 2>/dev/null || echo "0") log_date=$(tail -1 "$BACKUP_LOG" 2>/dev/null | cut -c1-19 || echo "N/A") ok "Log backup : $BACKUP_LOG ($log_size, $log_lines lignes, dernier: $log_date)" else warn "Log backup : $BACKUP_LOG (pas encore créé)" fi if [[ -f "$UPDATE_LOG" ]]; then local log_size2 log_lines2 log_date2 log_size2=$(du -h "$UPDATE_LOG" 2>/dev/null | cut -f1) log_lines2=$(wc -l < "$UPDATE_LOG" 2>/dev/null || echo "0") log_date2=$(tail -1 "$UPDATE_LOG" 2>/dev/null | cut -c1-19 || echo "N/A") ok "Log update : $UPDATE_LOG ($log_size2, $log_lines2 lignes, dernier: $log_date2)" else warn "Log update : $UPDATE_LOG (pas encore créé)" fi echo "" echo "════════════════════════════════════════════════════════" } # ─── Installation ─────────────────────────────────────────────────────────── do_install() { echo "" echo "════════════════════════════════════════════════════════" echo "🔧 INSTALLATION DES CRONS" echo "════════════════════════════════════════════════════════" echo "" info "Utilisateur : $CRON_USER" info "Dossier scripts : $SCRIPTS_DIR" info "Horaire backup : $CRON_BACKUP_SCHEDULE" info "Horaire update : $CRON_UPDATE_SCHEDULE" echo "" # Vérifier prérequis check_prerequisites || { echo "" err "Prérequis manquants. Placez les scripts dans $SCRIPTS_DIR/" echo "" echo " git clone https://git.dracodev.net/Outils/docker-stack-template.git $SCRIPTS_DIR" echo "" exit 1 } # Rendre les scripts exécutables chmod +x "$SCRIPTS_DIR/$BACKUP_SCRIPT" "$SCRIPTS_DIR/$UPDATE_SCRIPT" ok "Scripts rendus exécutables" # Créer les dossiers de logs si nécessaire if [[ ! -d "$LOG_DIR" ]]; then mkdir -p "$LOG_DIR" 2>/dev/null || { warn "Impossible de créer $LOG_DIR — les logs iront dans \$HOME" BACKUP_LOG="$HOME/${DOCKER_APP_NAME}-backup-cron.log" UPDATE_LOG="$HOME/${DOCKER_APP_NAME}-update-cron.log" } elif [[ ! -w "$LOG_DIR" ]]; then warn "Pas de droit d'écriture sur $LOG_DIR — les logs iront dans \$HOME" BACKUP_LOG="$HOME/${DOCKER_APP_NAME}-backup-cron.log" UPDATE_LOG="$HOME/${DOCKER_APP_NAME}-update-cron.log" fi # Lire la crontab actuelle local current_cron current_cron=$(crontab -l 2>/dev/null || echo "") # Vérifier si déjà installé if echo "$current_cron" | grep -qF "$CRON_MARKER"; then warn "Les crons sont déjà installés" info "Utilisez --uninstall pour les retirer d'abord, ou --force pour réinstaller" show_status exit 0 fi # Construire le bloc cron local cron_block cron_block=$(build_cron_block) # Appliquer : gérer le cas où la crontab est vide if [[ -z "$current_cron" ]]; then echo "$cron_block" | crontab - else printf "%s\n%s\n" "$current_cron" "$cron_block" | crontab - fi ok "Crons installés dans la crontab de $CRON_USER" echo "" echo "────────────────────────────────────────────────────────" echo "📋 RÉSUMÉ" echo "────────────────────────────────────────────────────────" echo "" echo " 🕐 $CRON_BACKUP_SCHEDULE → Backup" echo " 🕐 $CRON_UPDATE_SCHEDULE → Vérification màj" echo "" echo " 📊 Logs :" echo " Backup : $BACKUP_LOG" echo " Update : $UPDATE_LOG" echo "" echo " 🔍 Vérifier : $0 --status" echo " 🗑️ Retirer : $0 --uninstall" echo "" echo "════════════════════════════════════════════════════════" } # ─── Dry run ──────────────────────────────────────────────────────────────── do_dry_run() { echo "" echo "════════════════════════════════════════════════════════" echo "🔍 DRY RUN — APERÇU DE L'INSTALLATION" echo "════════════════════════════════════════════════════════" echo "" info "Utilisateur : $CRON_USER" info "Dossier scripts : $SCRIPTS_DIR" info "Horaire backup : $CRON_BACKUP_SCHEDULE" info "Horaire update : $CRON_UPDATE_SCHEDULE" echo "" check_prerequisites || true echo "" echo "Bloc qui serait ajouté à la crontab :" echo "────────────────────────────────────────" build_cron_block echo "────────────────────────────────────────" echo "" echo "⚠️ Aucune modification n'a été effectuée." echo " Utilisez --force pour installer sans confirmation." echo "" } # ─── Désinstallation ──────────────────────────────────────────────────────── do_uninstall() { echo "" echo "════════════════════════════════════════════════════════" echo "🗑️ DÉSINSTALLATION DES CRONS" echo "════════════════════════════════════════════════════════" echo "" local current_cron current_cron=$(crontab -l 2>/dev/null || echo "") if ! echo "$current_cron" | grep -qF "$CRON_MARKER"; then warn "Aucun cron trouvé — rien à désinstaller" exit 0 fi # Retirer le bloc entre les marqueurs local new_cron new_cron=$(echo "$current_cron" | sed "/$CRON_MARKER/,/>>> END ${DOCKER_APP_NAME^^} SCRIPTS </dev/null || true ok "Crontab vidée et crons retirés" else echo "$new_cron" | crontab - ok "Crons retirés de la crontab de $CRON_USER" fi echo "" echo " Les scripts eux-mêmes n'ont PAS été supprimés." echo " Ils restent dans $SCRIPTS_DIR/" echo "" echo "════════════════════════════════════════════════════════" } # ─── Main ─────────────────────────────────────────────────────────────────── FORCE=false UNINSTALL=false STATUS=false DRY_RUN=false for arg in "$@"; do case "$arg" in --force) FORCE=true ;; --uninstall) UNINSTALL=true ;; --status) STATUS=true ;; --dry-run) DRY_RUN=true ;; --help|-h) usage ;; *) echo "Option inconnue : $arg"; usage ;; esac done if [[ "$STATUS" == "true" ]]; then show_status exit 0 fi if [[ "$UNINSTALL" == "true" ]]; then do_uninstall exit 0 fi if [[ "$DRY_RUN" == "true" ]]; then do_dry_run exit 0 fi # Installation if [[ "$FORCE" != "true" ]]; then echo "" echo "Ce script va ajouter les entrées suivantes à la crontab de $CRON_USER :" echo "" echo " $CRON_BACKUP_SCHEDULE → Backup" echo " $CRON_UPDATE_SCHEDULE → Vérification màj" echo "" read -p "Continuer ? [O/n] " -r REPLY if [[ ! "$REPLY" =~ ^[OoYy]?$ ]]; then echo "Annulé." exit 0 fi fi do_install