#!/bin/bash # Скрипт для восстановления базы данных из дампа # Использование: # ./restore-db.sh [имя_дампа.sql.gz] # Восстановление в .env # ./restore-db.sh --env-file .env.prod [имя_дампа] # Восстановление в указанный файл # ./restore-db.sh production-backup.sql.gz # Восстановление в .env set -e # Значения по умолчанию DEFAULT_ENV_FILE=".env" ENV_FILE="$DEFAULT_ENV_FILE" DUMP_FILE="" # Парсим аргументы while [[ $# -gt 0 ]]; do case $1 in --env-file) ENV_FILE="$2" shift 2 ;; *) if [ -z "$DUMP_FILE" ]; then DUMP_FILE="$1" else echo "❌ Ошибка: Неизвестный аргумент: $1" echo "Использование: ./restore-db.sh [--env-file FILE] [имя_дампа.sql.gz]" exit 1 fi shift ;; esac done # Загружаем переменные окружения из указанного файла if [ -f "$ENV_FILE" ]; then export $(cat "$ENV_FILE" | grep -v '^#' | grep -v '^$' | xargs) echo "📋 Используется файл окружения: $ENV_FILE" else echo "⚠️ Файл $ENV_FILE не найден, используются значения по умолчанию" fi DB_HOST=${DB_HOST:-localhost} DB_PORT=${DB_PORT:-5432} DB_USER=${DB_USER:-playeng} DB_PASSWORD=${DB_PASSWORD:-playeng} DB_NAME=${DB_NAME:-playeng} # Если используется .env (по умолчанию), всегда восстанавливаем в локальную базу # Переопределяем DB_HOST для локального подключения if [ "$ENV_FILE" = "$DEFAULT_ENV_FILE" ] || [ "$ENV_FILE" = ".env" ]; then DB_HOST=localhost echo "📋 Восстановление в локальную базу (DB_HOST=localhost, DB_PORT=$DB_PORT)" fi # Если дамп не указан, выбираем самый свежий if [ -z "$DUMP_FILE" ]; then DUMP_DIR="database-dumps" if [ ! -d "$DUMP_DIR" ]; then echo "❌ Ошибка: Директория дампов не найдена: $DUMP_DIR" exit 1 fi # Ищем самый свежий дамп LATEST_DUMP=$(ls -t "$DUMP_DIR"/*.{sql.gz,sql} 2>/dev/null | head -n 1) if [ -z "$LATEST_DUMP" ]; then echo "❌ Ошибка: Дампы не найдены в директории $DUMP_DIR" exit 1 fi DUMP_FILE=$(basename "$LATEST_DUMP") echo "📦 Автоматически выбран самый свежий дамп: $DUMP_FILE" echo "" fi # Определяем полный путь к файлу if [[ "$DUMP_FILE" =~ ^/ ]]; then # Абсолютный путь FULL_DUMP_PATH="$DUMP_FILE" else # Относительный путь if [[ "$DUMP_FILE" == *.sql.gz ]] || [[ "$DUMP_FILE" == *.sql ]]; then FULL_DUMP_PATH="database-dumps/$DUMP_FILE" else # Пробуем с расширениями if [ -f "database-dumps/$DUMP_FILE.sql.gz" ]; then FULL_DUMP_PATH="database-dumps/$DUMP_FILE.sql.gz" elif [ -f "database-dumps/$DUMP_FILE.sql" ]; then FULL_DUMP_PATH="database-dumps/$DUMP_FILE.sql" else FULL_DUMP_PATH="database-dumps/$DUMP_FILE" fi fi fi if [ ! -f "$FULL_DUMP_PATH" ]; then echo "❌ Ошибка: Файл дампа не найден: $FULL_DUMP_PATH" echo "" echo "Доступные дампы:" ls -lh database-dumps/*.sql.gz 2>/dev/null | awk '{print " " $9}' | sed "s|database-dumps/||g" || echo " (нет дампов)" exit 1 fi echo "⚠️ ВНИМАНИЕ: Это действие удалит все данные в базе $DB_NAME!" if [ "$ENV_FILE" = "$DEFAULT_ENV_FILE" ] || [ "$ENV_FILE" = ".env" ]; then echo " Восстановление в локальную базу: $DB_HOST:$DB_PORT" else echo " Хост: $DB_HOST:$DB_PORT" fi echo " Пользователь: $DB_USER" read -p " Продолжить? (yes/no): " confirm if [ "$confirm" != "yes" ]; then echo "❌ Отменено." exit 0 fi echo "🔄 Восстановление базы данных из дампа..." echo " База: $DB_NAME" if [ "$ENV_FILE" = "$DEFAULT_ENV_FILE" ] || [ "$ENV_FILE" = ".env" ]; then echo " Восстановление в локальную базу: $DB_HOST:$DB_PORT" else echo " Хост: $DB_HOST:$DB_PORT" fi echo " Файл: $FULL_DUMP_PATH" # Распаковываем и модифицируем дамп TEMP_DUMP="/tmp/restore_$$.sql" if [[ "$FULL_DUMP_PATH" == *.gz ]]; then echo " Распаковка и модификация дампа..." gunzip -c "$FULL_DUMP_PATH" | \ sed 's/n8n_user/'"$DB_USER"'/g' | \ sed '/^\\restrict/d' | \ sed '/^\\unrestrict/d' > "$TEMP_DUMP" else echo " Модификация дампа..." cat "$FULL_DUMP_PATH" | \ sed 's/n8n_user/'"$DB_USER"'/g' | \ sed '/^\\restrict/d' | \ sed '/^\\unrestrict/d' > "$TEMP_DUMP" fi echo " Владелец таблиц в дампе заменён на: $DB_USER" # Восстанавливаем через docker-compose, если контейнер запущен if docker-compose ps db 2>/dev/null | grep -q "Up"; then echo " Используется docker-compose..." # Завершаем все активные подключения к базе данных echo " Завершение активных подключений к базе $DB_NAME..." docker-compose exec -T db psql -U "$DB_USER" -d postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$DB_NAME' AND pid <> pg_backend_pid();" 2>/dev/null || true # Очищаем базу и восстанавливаем docker-compose exec -T db psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" docker-compose exec -T db psql -U "$DB_USER" -d postgres -c "CREATE DATABASE $DB_NAME;" docker-compose exec -T db psql -U "$DB_USER" -d "$DB_NAME" < "$TEMP_DUMP" elif command -v psql &> /dev/null; then # Или напрямую через psql echo " Используется локальный psql..." # Завершаем все активные подключения к базе данных echo " Завершение активных подключений к базе $DB_NAME..." PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$DB_NAME' AND pid <> pg_backend_pid();" 2>/dev/null || true # Очищаем базу и восстанавливаем PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "CREATE DATABASE $DB_NAME;" PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" < "$TEMP_DUMP" else echo "❌ Ошибка: psql не найден и docker-compose не запущен" echo " Запустите docker-compose или установите PostgreSQL клиент" rm -f "$TEMP_DUMP" exit 1 fi # Удаляем временный файл rm -f "$TEMP_DUMP" echo "" echo "📦 Применение миграций для добавления user_id..." # Определяем путь к миграциям SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MIGRATIONS_DIR="$SCRIPT_DIR/play-life-backend/migrations" if [ -d "$MIGRATIONS_DIR" ]; then # Применяем миграцию 009 для добавления user_id MIGRATION_FILE="$MIGRATIONS_DIR/009_add_users_and_multitenancy.sql" if [ -f "$MIGRATION_FILE" ]; then echo " Применяем миграцию: 009_add_users_and_multitenancy.sql" if docker-compose ps db 2>/dev/null | grep -q "Up"; then docker-compose exec -T db psql -U "$DB_USER" -d "$DB_NAME" < "$MIGRATION_FILE" 2>/dev/null || true elif command -v psql &> /dev/null; then PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" < "$MIGRATION_FILE" 2>/dev/null || true fi echo " ✅ Миграция применена" fi else echo " ⚠️ Директория миграций не найдена: $MIGRATIONS_DIR" echo " Миграции будут применены при запуске бэкенда" fi echo "" echo "✅ База данных успешно восстановлена из дампа!" echo "" echo "📌 ВАЖНО: После первой регистрации/входа пользователя все данные" echo " будут автоматически привязаны к этому пользователю."