Add server migration scripts: backup.sh (export) and restore.sh (import)
backup.sh genere un bundle de migration tar.gz autonome contenant: - dump PostgreSQL gzippe (pg_dump --clean --if-exists --no-owner) - archive public/uploads (events, billets, logos) repere via flysystem.yaml - archive var/ (payouts, billets, invoices, unsubscribed.json) - .env.local et config/cert/ (clef S/MIME), exclus si SKIP_SECRETS=1 - manifest.txt avec metadata (host, git commit/branche, date) et checksums SHA-256 restore.sh restaure un bundle sur un nouveau serveur: - verifie les checksums SHA-256 avant toute action - affiche un plan de restauration et demande confirmation (sauf --yes) - options --skip-db, --skip-uploads, --skip-var, --skip-secrets - cree des sauvegardes de securite avant ecrasement (.env.local, public/uploads, var/) - verifie que le service db-master tourne avant restore PostgreSQL - rappelle les etapes post-migration (migrate_prod, clear_prod) Les deux scripts utilisent des variables d'env override (COMPOSE_FILE, DB_SERVICE, DB_USER, DB_NAME) et s'appuient sur docker-compose-prod.yml par defaut. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
173
backup.sh
Executable file
173
backup.sh
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/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 -p "${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'"
|
||||
Reference in New Issue
Block a user