- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
383 lines
14 KiB
Bash
Executable File
383 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Script de déploiement unifié pour GEOSECTOR API
|
|
# Version: 4.0 (Janvier 2025)
|
|
# Auteur: Pierre (avec l'aide de Claude)
|
|
#
|
|
# Usage:
|
|
# ./deploy-api.sh # Déploiement local DEV (code → container geo)
|
|
# ./deploy-api.sh rca # Livraison RECETTE (container geo → rca-geo)
|
|
# ./deploy-api.sh pra # Livraison PRODUCTION (rca-geo → pra-geo)
|
|
|
|
set -euo pipefail
|
|
|
|
# =====================================
|
|
# Configuration générale
|
|
# =====================================
|
|
|
|
# Paramètre optionnel pour l'environnement cible
|
|
TARGET_ENV=${1:-dev}
|
|
|
|
# Configuration SSH
|
|
HOST_KEY="/home/pierre/.ssh/id_rsa_mbpi"
|
|
HOST_PORT="22"
|
|
HOST_USER="root"
|
|
|
|
# Configuration des serveurs
|
|
RCA_HOST="195.154.80.116" # IN3 - Serveur de recette
|
|
PRA_HOST="51.159.7.190" # IN4 - Serveur de production
|
|
|
|
# Configuration Incus
|
|
INCUS_PROJECT="default"
|
|
API_PATH="/var/www/geosector/api"
|
|
FINAL_OWNER="nginx"
|
|
FINAL_GROUP="nginx"
|
|
FINAL_OWNER_LOGS="nobody"
|
|
FINAL_GROUP_LOGS="nginx"
|
|
|
|
# Configuration de sauvegarde
|
|
BACKUP_DIR="/data/backup/geosector/api"
|
|
|
|
# Couleurs pour les messages
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[0;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# =====================================
|
|
# Fonctions utilitaires
|
|
# =====================================
|
|
|
|
echo_step() {
|
|
echo -e "${GREEN}==>${NC} $1"
|
|
}
|
|
|
|
echo_info() {
|
|
echo -e "${BLUE}Info:${NC} $1"
|
|
}
|
|
|
|
echo_warning() {
|
|
echo -e "${YELLOW}Warning:${NC} $1"
|
|
}
|
|
|
|
echo_error() {
|
|
echo -e "${RED}Error:${NC} $1"
|
|
exit 1
|
|
}
|
|
|
|
# Fonction pour nettoyer les anciens backups
|
|
cleanup_old_backups() {
|
|
local prefix=""
|
|
case $TARGET_ENV in
|
|
"dev") prefix="api-dev-" ;;
|
|
"rca") prefix="api-rca-" ;;
|
|
"pra") prefix="api-pra-" ;;
|
|
esac
|
|
|
|
echo_info "Cleaning old backups (keeping last 5)..."
|
|
ls -t "${BACKUP_DIR}"/${prefix}*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f && {
|
|
REMAINING_BACKUPS=$(ls "${BACKUP_DIR}"/${prefix}*.tar.gz 2>/dev/null | wc -l)
|
|
echo_info "Kept ${REMAINING_BACKUPS} backup(s) for ${TARGET_ENV}"
|
|
}
|
|
}
|
|
|
|
# =====================================
|
|
# Détermination de la configuration selon l'environnement
|
|
# =====================================
|
|
|
|
case $TARGET_ENV in
|
|
"dev")
|
|
echo_step "Configuring for DEV deployment on IN3"
|
|
SOURCE_TYPE="local_code"
|
|
DEST_CONTAINER="dva-geo"
|
|
DEST_HOST="${RCA_HOST}" # IN3 pour le DEV aussi
|
|
ENV_NAME="DEVELOPMENT"
|
|
;;
|
|
"rca")
|
|
echo_step "Configuring for RECETTE delivery"
|
|
SOURCE_TYPE="remote_container"
|
|
SOURCE_CONTAINER="dva-geo"
|
|
SOURCE_HOST="${RCA_HOST}"
|
|
DEST_CONTAINER="rca-geo"
|
|
DEST_HOST="${RCA_HOST}"
|
|
ENV_NAME="RECETTE"
|
|
;;
|
|
"pra")
|
|
echo_step "Configuring for PRODUCTION delivery"
|
|
SOURCE_TYPE="remote_container"
|
|
SOURCE_HOST="${RCA_HOST}"
|
|
SOURCE_CONTAINER="rca-geo"
|
|
DEST_CONTAINER="pra-geo"
|
|
DEST_HOST="${PRA_HOST}"
|
|
ENV_NAME="PRODUCTION"
|
|
;;
|
|
*)
|
|
echo_error "Unknown environment: $TARGET_ENV. Use 'dev', 'rca' or 'pra'"
|
|
;;
|
|
esac
|
|
|
|
echo_info "Deployment flow: ${ENV_NAME}"
|
|
|
|
# =====================================
|
|
# Création de l'archive selon la source
|
|
# =====================================
|
|
|
|
# Créer le dossier de backup s'il n'existe pas
|
|
if [ ! -d "${BACKUP_DIR}" ]; then
|
|
echo_info "Creating backup directory ${BACKUP_DIR}..."
|
|
mkdir -p "${BACKUP_DIR}" || echo_error "Failed to create backup directory"
|
|
fi
|
|
|
|
# Horodatage format YYYYMMDDHH
|
|
TIMESTAMP=$(date +%Y%m%d%H)
|
|
|
|
# Nom de l'archive selon l'environnement
|
|
case $TARGET_ENV in
|
|
"dev")
|
|
ARCHIVE_NAME="api-dev-${TIMESTAMP}.tar.gz"
|
|
;;
|
|
"rca")
|
|
ARCHIVE_NAME="api-rca-${TIMESTAMP}.tar.gz"
|
|
;;
|
|
"pra")
|
|
ARCHIVE_NAME="api-pra-${TIMESTAMP}.tar.gz"
|
|
;;
|
|
esac
|
|
|
|
ARCHIVE_PATH="${BACKUP_DIR}/${ARCHIVE_NAME}"
|
|
|
|
if [ "$SOURCE_TYPE" = "local_code" ]; then
|
|
# DEV: Créer une archive depuis le code local
|
|
echo_step "Creating archive from local code..."
|
|
|
|
# Vérification des fichiers requis
|
|
if [ ! -f "src/Config/AppConfig.php" ]; then
|
|
echo_error "Configuration file missing"
|
|
fi
|
|
|
|
if [ ! -f "composer.json" ] || [ ! -f "composer.lock" ]; then
|
|
echo_error "Composer files missing"
|
|
fi
|
|
|
|
tar --exclude='.git' \
|
|
--exclude='.gitignore' \
|
|
--exclude='.vscode' \
|
|
--exclude='logs' \
|
|
--exclude='sessions' \
|
|
--exclude='opendata' \
|
|
--exclude='*.template' \
|
|
--exclude='*.sh' \
|
|
--exclude='.env' \
|
|
--exclude='.env_marker' \
|
|
--exclude='*.log' \
|
|
--exclude='.DS_Store' \
|
|
--exclude='README.md' \
|
|
--exclude="*.tar.gz" \
|
|
--exclude='node_modules' \
|
|
--exclude='vendor' \
|
|
--exclude='*.swp' \
|
|
--exclude='*.swo' \
|
|
--exclude='*~' \
|
|
-czf "${ARCHIVE_PATH}" . 2>/dev/null || echo_error "Failed to create archive"
|
|
|
|
echo_info "Archive created: ${ARCHIVE_PATH}"
|
|
echo_info "Archive size: $(du -h "${ARCHIVE_PATH}" | cut -f1)"
|
|
|
|
# Cette section n'est plus utilisée car RCA utilise maintenant remote_container
|
|
|
|
elif [ "$SOURCE_TYPE" = "remote_container" ]; then
|
|
# RCA et PRA: Créer une archive depuis un container distant
|
|
echo_step "Creating archive from remote container ${SOURCE_CONTAINER} on ${SOURCE_HOST}..."
|
|
|
|
# Créer l'archive sur le serveur source
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "
|
|
incus project switch ${INCUS_PROJECT} &&
|
|
incus exec ${SOURCE_CONTAINER} -- tar \
|
|
--exclude='logs' \
|
|
--exclude='uploads' \
|
|
--exclude='sessions' \
|
|
--exclude='opendata' \
|
|
-czf /tmp/${ARCHIVE_NAME} -C ${API_PATH} .
|
|
" || echo_error "Failed to create archive on remote"
|
|
|
|
# Extraire l'archive du container vers l'hôte
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "
|
|
incus file pull ${SOURCE_CONTAINER}/tmp/${ARCHIVE_NAME} /tmp/${ARCHIVE_NAME} &&
|
|
incus exec ${SOURCE_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME}
|
|
" || echo_error "Failed to extract archive from remote container"
|
|
|
|
# Copier l'archive vers la machine locale
|
|
scp -i ${HOST_KEY} -P ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST}:/tmp/${ARCHIVE_NAME} ${ARCHIVE_PATH} || echo_error "Failed to copy archive locally"
|
|
|
|
echo_info "Archive saved: ${ARCHIVE_PATH}"
|
|
echo_info "Archive size: $(du -h "${ARCHIVE_PATH}" | cut -f1)"
|
|
fi
|
|
|
|
# Nettoyer les anciens backups
|
|
cleanup_old_backups
|
|
|
|
# =====================================
|
|
# Déploiement selon la destination
|
|
# =====================================
|
|
|
|
# Tous les déploiements se font maintenant sur des containers distants
|
|
if [ "$DEST_HOST" != "local" ]; then
|
|
# Déploiement sur container distant (DEV, RCA ou PRA)
|
|
echo_step "Deploying to remote container ${DEST_CONTAINER} on ${DEST_HOST}..."
|
|
|
|
# Créer une sauvegarde sur le serveur de destination
|
|
BACKUP_TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
REMOTE_BACKUP_DIR="${API_PATH}_backup_${BACKUP_TIMESTAMP}"
|
|
|
|
echo_info "Creating backup on destination..."
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${DEST_HOST} "
|
|
incus project switch ${INCUS_PROJECT} &&
|
|
incus exec ${DEST_CONTAINER} -- test -d ${API_PATH} &&
|
|
incus exec ${DEST_CONTAINER} -- cp -r ${API_PATH} ${REMOTE_BACKUP_DIR} &&
|
|
echo 'Backup created: ${REMOTE_BACKUP_DIR}'
|
|
" || echo_warning "No existing installation to backup"
|
|
|
|
# Transférer l'archive vers le serveur de destination
|
|
echo_info "Transferring archive to ${DEST_HOST}..."
|
|
|
|
if [ "$SOURCE_TYPE" = "local_code" ]; then
|
|
# Pour DEV: copier depuis local vers IN3
|
|
scp -i ${HOST_KEY} -P ${HOST_PORT} ${ARCHIVE_PATH} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} || echo_error "Failed to copy archive to destination"
|
|
elif [ "$SOURCE_TYPE" = "remote_container" ] && [ "$SOURCE_HOST" = "$DEST_HOST" ]; then
|
|
# Pour RCA: même serveur (IN3), pas de transfert nécessaire, l'archive est déjà là
|
|
echo_info "Archive already on destination server (same host)"
|
|
else
|
|
# Pour PRA: l'archive est déjà sur la machine locale (copiée depuis IN3)
|
|
# On la transfère maintenant vers IN4
|
|
echo_info "Transferring archive from local to IN4..."
|
|
scp -i ${HOST_KEY} -P ${HOST_PORT} ${ARCHIVE_PATH} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} || echo_error "Failed to copy archive to IN4"
|
|
|
|
# Nettoyer sur le serveur source IN3
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "rm -f /tmp/${ARCHIVE_NAME}" || echo_warning "Could not clean source server"
|
|
fi
|
|
|
|
# Déployer sur le container de destination
|
|
echo_info "Extracting on destination container..."
|
|
|
|
# Déterminer le nom de l'environnement pour le marqueur
|
|
case $TARGET_ENV in
|
|
"dev") ENV_MARKER="development" ;;
|
|
"rca") ENV_MARKER="recette" ;;
|
|
"pra") ENV_MARKER="production" ;;
|
|
esac
|
|
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${DEST_HOST} "
|
|
set -euo pipefail
|
|
|
|
# Pousser l'archive dans le container
|
|
incus project switch ${INCUS_PROJECT} &&
|
|
incus file push /tmp/${ARCHIVE_NAME} ${DEST_CONTAINER}/tmp/${ARCHIVE_NAME} &&
|
|
|
|
# Nettoyer sélectivement (préserver logs, uploads et sessions)
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH} -mindepth 1 -maxdepth 1 ! -name 'uploads' ! -name 'logs' ! -name 'sessions' -exec rm -rf {} \; 2>/dev/null || true &&
|
|
|
|
# Extraire l'archive
|
|
incus exec ${DEST_CONTAINER} -- tar -xzf /tmp/${ARCHIVE_NAME} -C ${API_PATH}/ &&
|
|
|
|
# Créer le marqueur d'environnement pour la détection CLI
|
|
incus exec ${DEST_CONTAINER} -- bash -c 'echo \"${ENV_MARKER}\" > ${API_PATH}/.env_marker' &&
|
|
|
|
# Permissions
|
|
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER}:${FINAL_GROUP} ${API_PATH} &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH} -type d -exec chmod 755 {} \; &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH} -type f -exec chmod 644 {} \; &&
|
|
|
|
# Permissions spéciales pour logs
|
|
incus exec ${DEST_CONTAINER} -- mkdir -p ${API_PATH}/logs/events &&
|
|
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER_LOGS}:${FINAL_GROUP} ${API_PATH}/logs &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH}/logs -type d -exec chmod 750 {} \; &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH}/logs -type f -exec chmod 640 {} \; &&
|
|
|
|
# Permissions spéciales pour uploads
|
|
incus exec ${DEST_CONTAINER} -- mkdir -p ${API_PATH}/uploads &&
|
|
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER_LOGS}:${FINAL_GROUP} ${API_PATH}/uploads &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH}/uploads -type d -exec chmod 750 {} \; &&
|
|
incus exec ${DEST_CONTAINER} -- find ${API_PATH}/uploads -type f -exec chmod 640 {} \; &&
|
|
|
|
# Permissions spéciales pour sessions
|
|
incus exec ${DEST_CONTAINER} -- mkdir -p ${API_PATH}/sessions &&
|
|
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER_LOGS}:${FINAL_GROUP} ${API_PATH}/sessions &&
|
|
incus exec ${DEST_CONTAINER} -- chmod 700 ${API_PATH}/sessions &&
|
|
|
|
# Composer (installation stricte - échec bloquant)
|
|
incus exec ${DEST_CONTAINER} -- bash -c 'cd ${API_PATH} && composer install --no-dev --optimize-autoloader' || { echo 'ERROR: Composer install failed'; exit 1; } &&
|
|
|
|
# Nettoyage
|
|
incus exec ${DEST_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME} &&
|
|
rm -f /tmp/${ARCHIVE_NAME}
|
|
" || echo_error "Deployment failed on destination"
|
|
|
|
echo_info "Remote backup saved: ${REMOTE_BACKUP_DIR} on ${DEST_CONTAINER}"
|
|
|
|
# Nettoyage des anciens backups sur le container distant
|
|
echo_info "Cleaning old backup directories on ${DEST_CONTAINER}..."
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${DEST_HOST} "
|
|
incus exec ${DEST_CONTAINER} -- bash -c 'rm -rf ${API_PATH}_backup_*'
|
|
" && echo_info "Old backups cleaned" || echo_warning "Could not clean old backups"
|
|
|
|
# =====================================
|
|
# Configuration des tâches CRON
|
|
# =====================================
|
|
|
|
echo_step "Configuring CRON tasks..."
|
|
|
|
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${DEST_HOST} "
|
|
incus exec ${DEST_CONTAINER} -- bash <<'EOFCRON'
|
|
# Sauvegarder les crons existants (hors geosector)
|
|
crontab -l 2>/dev/null | grep -v 'geosector/api/scripts/cron' > /tmp/crontab_backup || true
|
|
|
|
# Créer le nouveau crontab avec les tâches CRON pour l'API
|
|
cat /tmp/crontab_backup > /tmp/new_crontab
|
|
cat >> /tmp/new_crontab <<'EOF'
|
|
|
|
# GEOSECTOR API - Email queue processing (every 5 minutes)
|
|
*/5 * * * * /usr/bin/php /var/www/geosector/api/scripts/cron/process_email_queue.php >> /var/www/geosector/api/logs/email_queue.log 2>&1
|
|
|
|
# GEOSECTOR API - Security data cleanup (daily at 2am)
|
|
0 2 * * * /usr/bin/php /var/www/geosector/api/scripts/cron/cleanup_security_data.php >> /var/www/geosector/api/logs/cleanup_security.log 2>&1
|
|
|
|
# GEOSECTOR API - Stripe devices update (weekly Sunday at 3am)
|
|
0 3 * * 0 /usr/bin/php /var/www/geosector/api/scripts/cron/update_stripe_devices.php >> /var/www/geosector/api/logs/stripe_devices.log 2>&1
|
|
EOF
|
|
|
|
# Installer le nouveau crontab
|
|
crontab /tmp/new_crontab
|
|
|
|
# Nettoyer
|
|
rm -f /tmp/crontab_backup /tmp/new_crontab
|
|
|
|
# Afficher les crons installés
|
|
echo 'CRON tasks installed:'
|
|
crontab -l | grep geosector
|
|
EOFCRON
|
|
" && echo_info "CRON tasks configured successfully" || echo_warning "CRON configuration failed"
|
|
fi
|
|
|
|
# L'archive reste dans le dossier de backup, pas de nettoyage nécessaire
|
|
echo_info "Archive preserved in backup directory: ${ARCHIVE_PATH}"
|
|
|
|
# =====================================
|
|
# Résumé final
|
|
# =====================================
|
|
|
|
echo_step "Deployment completed successfully!"
|
|
echo_info "Environment: ${ENV_NAME}"
|
|
|
|
if [ "$TARGET_ENV" = "dev" ]; then
|
|
echo_info "Deployed from local code to container ${DEST_CONTAINER} on IN3 (${DEST_HOST})"
|
|
elif [ "$TARGET_ENV" = "rca" ]; then
|
|
echo_info "Delivered from ${SOURCE_CONTAINER} to ${DEST_CONTAINER} on ${DEST_HOST}"
|
|
elif [ "$TARGET_ENV" = "pra" ]; then
|
|
echo_info "Delivered from ${SOURCE_CONTAINER} on ${SOURCE_HOST} to ${DEST_CONTAINER} on ${DEST_HOST}"
|
|
fi
|
|
|
|
echo_info "Deployment completed at: $(date)"
|
|
|
|
# Journaliser le déploiement
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - API deployed to ${ENV_NAME} (${DEST_CONTAINER}) - Archive: ${ARCHIVE_NAME}" >> ~/.geo_deploy_history |