Remplace 'cp -p' par 'cp -rp' lors de la copie de config/cert/. Sans l'option -r, cp omet le repertoire avec l'erreur: cp: -r non specifie ; omission du repertoire 'config/cert/.' Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
174 lines
6.2 KiB
Bash
Executable File
174 lines
6.2 KiB
Bash
Executable File
#!/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'"
|