#!/bin/bash # E-Ticket - Script d'export pour migration de serveur # Genere un bundle complet et autonome pour migrer l'application sur un autre serveur. # # Le bundle contient: # - dump de la base PostgreSQL (db.sql.gz) # - uploads Vich/Flysystem (events, billets, logos) (public_uploads.tar.gz) # - etat applicatif var/ (var_state.tar.gz) # payouts/, billets/, invoices/, unsubscribed.json # - configuration runtime sensible (env.local, cert/) # - manifest avec checksums SHA-256 (manifest.txt) # # Le tout est ensuite empaquete dans une archive .tar.gz transferable par scp/rsync. # # Usage: # ./backup.sh [DOSSIER_DESTINATION] # # Variables d'environnement supportees: # COMPOSE_FILE : fichier docker-compose a utiliser (defaut: docker-compose-prod.yml) # DB_SERVICE : service Docker de la base (defaut: db-master) # DB_USER : utilisateur PostgreSQL (defaut: e-ticket) # DB_NAME : base de donnees a exporter (defaut: e-ticket) # SKIP_SECRETS : '1' pour exclure .env.local + cert (defaut: inclus) set -euo pipefail # --- Configuration --- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEST_DIR="${1:-${SCRIPT_DIR}/var/migration}" COMPOSE_FILE="${COMPOSE_FILE:-${SCRIPT_DIR}/docker-compose-prod.yml}" DB_SERVICE="${DB_SERVICE:-db-master}" DB_USER="${DB_USER:-e-ticket}" DB_NAME="${DB_NAME:-e-ticket}" SKIP_SECRETS="${SKIP_SECRETS:-0}" DATE="$(date +%Y%m%d_%H%M%S)" BUNDLE_NAME="e_ticket_migration_${DATE}" WORK_DIR="${DEST_DIR}/${BUNDLE_NAME}" BUNDLE_FILE="${DEST_DIR}/${BUNDLE_NAME}.tar.gz" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" } err() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERREUR: $*" >&2 } cleanup() { if [ -d "${WORK_DIR}" ]; then rm -rf "${WORK_DIR}" fi } # Cleanup du WORK_DIR meme en cas d'erreur (le BUNDLE_FILE final reste) trap cleanup EXIT # --- Verifications prealables --- if [ ! -f "${COMPOSE_FILE}" ]; then err "Fichier docker-compose introuvable: ${COMPOSE_FILE}" exit 1 fi if ! docker compose -f "${COMPOSE_FILE}" ps --services --status running 2>/dev/null | grep -qx "${DB_SERVICE}"; then err "Le service '${DB_SERVICE}' n'est pas demarre" err "Demarrer la stack avec: make start_prod" exit 1 fi mkdir -p "${WORK_DIR}" log "=== Export de migration E-Ticket ===" log "Bundle: ${BUNDLE_NAME}" log "Destination: ${DEST_DIR}" # --- 1. Dump base de donnees --- log "[1/5] Dump PostgreSQL '${DB_NAME}' depuis ${DB_SERVICE}..." if ! docker compose -f "${COMPOSE_FILE}" exec -T "${DB_SERVICE}" \ pg_dump -U "${DB_USER}" -d "${DB_NAME}" \ --clean --if-exists --no-owner --no-privileges --quote-all-identifiers \ | gzip > "${WORK_DIR}/db.sql.gz"; then err "Echec du dump PostgreSQL" exit 1 fi if [ ! -s "${WORK_DIR}/db.sql.gz" ]; then err "Le dump PostgreSQL est vide" exit 1 fi log " OK ($(du -h "${WORK_DIR}/db.sql.gz" | cut -f1))" # --- 2. Uploads publics (events, billets, logos) --- log "[2/5] Archivage public/uploads (events, billets, logos)..." if [ -d "${SCRIPT_DIR}/public/uploads" ]; then tar -czf "${WORK_DIR}/public_uploads.tar.gz" -C "${SCRIPT_DIR}/public" uploads log " OK ($(du -h "${WORK_DIR}/public_uploads.tar.gz" | cut -f1))" else err "public/uploads introuvable" exit 1 fi # --- 3. Etat applicatif var/ (PDFs generes, desinscrits...) --- log "[3/5] Archivage etat applicatif var/ (payouts, billets, invoices, unsubscribed.json)..." VAR_ITEMS=() for item in payouts billets invoices unsubscribed.json; do if [ -e "${SCRIPT_DIR}/var/${item}" ]; then VAR_ITEMS+=("${item}") fi done if [ ${#VAR_ITEMS[@]} -gt 0 ]; then tar -czf "${WORK_DIR}/var_state.tar.gz" -C "${SCRIPT_DIR}/var" "${VAR_ITEMS[@]}" log " OK - elements inclus: ${VAR_ITEMS[*]} ($(du -h "${WORK_DIR}/var_state.tar.gz" | cut -f1))" else log " Aucun element a archiver dans var/ (saut)" fi # --- 4. Configuration runtime sensible --- if [ "${SKIP_SECRETS}" = "1" ]; then log "[4/5] Secrets exclus (SKIP_SECRETS=1)" log " ATTENTION: vous devrez deployer .env.local et config/cert/ manuellement sur le nouveau serveur" else log "[4/5] Archivage configuration sensible (.env.local + config/cert/)..." SECRET_ITEMS=() if [ -f "${SCRIPT_DIR}/.env.local" ]; then cp -p "${SCRIPT_DIR}/.env.local" "${WORK_DIR}/env.local" chmod 600 "${WORK_DIR}/env.local" SECRET_ITEMS+=(".env.local") fi if [ -d "${SCRIPT_DIR}/config/cert" ]; then mkdir -p "${WORK_DIR}/cert" cp -rp "${SCRIPT_DIR}/config/cert/." "${WORK_DIR}/cert/" chmod -R go-rwx "${WORK_DIR}/cert" SECRET_ITEMS+=("config/cert/") fi if [ ${#SECRET_ITEMS[@]} -gt 0 ]; then log " OK - elements inclus: ${SECRET_ITEMS[*]}" else log " Aucun secret trouve a archiver (saut)" fi fi # --- 5. Manifest avec checksums et metadata --- log "[5/5] Generation du manifest..." { echo "# E-Ticket migration bundle" echo "bundle_name: ${BUNDLE_NAME}" echo "created_at: $(date --iso-8601=seconds)" echo "source_host: $(hostname)" echo "git_commit: $(git -C "${SCRIPT_DIR}" rev-parse HEAD 2>/dev/null || echo 'unknown')" echo "git_branch: $(git -C "${SCRIPT_DIR}" rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')" echo "db_name: ${DB_NAME}" echo "db_user: ${DB_USER}" echo "skip_secrets: ${SKIP_SECRETS}" echo echo "# SHA-256 checksums" (cd "${WORK_DIR}" && find . -type f ! -name 'manifest.txt' -print0 | sort -z | xargs -0 sha256sum) } > "${WORK_DIR}/manifest.txt" log " OK" # --- Empaquetage final --- log "Empaquetage du bundle dans ${BUNDLE_FILE}..." tar -czf "${BUNDLE_FILE}" -C "${DEST_DIR}" "${BUNDLE_NAME}" BUNDLE_SIZE="$(du -h "${BUNDLE_FILE}" | cut -f1)" BUNDLE_SHA="$(sha256sum "${BUNDLE_FILE}" | cut -d' ' -f1)" log "=== Export termine ===" log "Bundle : ${BUNDLE_FILE}" log "Taille : ${BUNDLE_SIZE}" log "SHA-256 : ${BUNDLE_SHA}" log log "Pour transferer vers le nouveau serveur:" log " scp '${BUNDLE_FILE}' user@nouveau-serveur:/var/www/e-ticket/" log "Puis sur le nouveau serveur:" log " ./restore.sh '${BUNDLE_NAME}.tar.gz'"