diff --git a/deploy_prod.sh b/deploy_prod.sh new file mode 100755 index 0000000..f23f1fc --- /dev/null +++ b/deploy_prod.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ========================= +# Deploy PROD webval (Jetson) +# Repo -> /var/www/mathematiques +# Backup + exclusions + rollback +# ========================= + +APP_NAME="webval" +SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DST_DIR="/var/www/mathematiques" + +# Dossier backups (hors web) +BACKUP_ROOT="/var/backups/${APP_NAME}" +TS="$(date +%Y%m%d_%H%M%S)" +BACKUP_DIR="${BACKUP_ROOT}/prev_${TS}" + +# URL de check (adapte si besoin) +HEALTH_URL="http://127.0.0.1/" +HEALTH_TIMEOUT=10 + +# Exclusions: runtime + config sensible + git +RSYNC_EXCLUDES=( + ".git/" + "evaluations/" + "evaluations_transit/" + "uploads/" + "logs/" + "temp/" + "backup/" + "backups/" + "config/database.php" + "config/secrets.php" + "config/db_credentials.txt" +) + +# --- helpers --- +die() { echo "ERREUR: $*" >&2; exit 1; } + +print_excludes() { + for e in "${RSYNC_EXCLUDES[@]}"; do + echo " - $e" + done +} + +rsync_exclude_args() { + for e in "${RSYNC_EXCLUDES[@]}"; do + printf -- "--exclude=%q " "$e" + done +} + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || die "Commande manquante: $1" +} + +healthcheck() { + # Healthcheck simple: HTTP 200/301/302 attendu sur la home + # (Si ton app a une URL spécifique de health, mets-la dans HEALTH_URL) + if curl -fsS -m "${HEALTH_TIMEOUT}" -o /dev/null -I "${HEALTH_URL}"; then + return 0 + fi + return 1 +} + +rollback() { + echo + echo "=== ROLLBACK ===" + echo "Restauration depuis: ${BACKUP_DIR}" + if [[ ! -d "${BACKUP_DIR}" ]]; then + die "Backup introuvable, rollback impossible: ${BACKUP_DIR}" + fi + + sudo rsync -a --delete "${BACKUP_DIR}/" "${DST_DIR}/" + + sudo systemctl reload php8.1-fpm >/dev/null 2>&1 || true + sudo systemctl reload nginx >/dev/null 2>&1 || true + + echo "Rollback terminé." +} + +# --- prérequis --- +need_cmd rsync +need_cmd curl +need_cmd date + +echo "=== Deploy PROD (${APP_NAME}) ===" +echo "Source: ${SRC_DIR}" +echo "Dest : ${DST_DIR}" +echo "Backup: ${BACKUP_DIR}" +echo +echo "Exclusions:" +print_excludes +echo + +[[ -d "${SRC_DIR}/.git" ]] || die "Pas de .git dans ${SRC_DIR} (pas un repo ?)." +[[ -d "${DST_DIR}" ]] || die "Destination inexistante: ${DST_DIR}" + +# Si tu veux empêcher un deploy avec un working tree sale: +if ! git -C "${SRC_DIR}" diff --quiet || ! git -C "${SRC_DIR}" diff --cached --quiet; then + echo "AVERTISSEMENT: ton repo a des modifications non commit." + echo "Tu peux quand même déployer, mais c'est risqué." + read -r -p "Continuer malgré tout ? (oui/non) " ans_dirty + [[ "${ans_dirty}" == "oui" ]] || exit 0 +fi + +# --- aperçu --- +echo "--- Aperçu (dry-run) ---" +# shellcheck disable=SC2046 +sudo rsync -a --delete --dry-run \ + $(rsync_exclude_args) \ + "${SRC_DIR}/" "${DST_DIR}/" | sed -n '1,200p' +echo "(aperçu tronqué à 200 lignes)" +echo + +read -r -p "Lancer le backup + déploiement maintenant ? (oui/non) " ans +[[ "${ans}" == "oui" ]] || { echo "Annulé."; exit 0; } + +# --- backup --- +echo +echo "--- Backup PROD -> ${BACKUP_DIR} ---" +sudo mkdir -p "${BACKUP_ROOT}" +sudo rsync -a --delete "${DST_DIR}/" "${BACKUP_DIR}/" + +# --- deploy --- +echo +echo "--- Déploiement ---" +# shellcheck disable=SC2046 +sudo rsync -a --delete \ + $(rsync_exclude_args) \ + "${SRC_DIR}/" "${DST_DIR}/" + +# --- reload --- +echo +echo "--- Reload services ---" +sudo systemctl reload php8.1-fpm >/dev/null 2>&1 || true +sudo systemctl reload nginx >/dev/null 2>&1 || true + +# --- healthcheck --- +echo +echo "--- Healthcheck: ${HEALTH_URL} ---" +if healthcheck; then + echo "OK: deploy réussi." + echo "Backup conservé: ${BACKUP_DIR}" + exit 0 +fi + +echo "ECHEC: healthcheck KO. On rollback." +rollback + +echo +echo "Après rollback, je te conseille de regarder :" +echo " - sudo tail -n 80 /var/log/nginx/error.log" +echo " - sudo journalctl -u php8.1-fpm -n 80 --no-pager" +exit 2