2025-12-31 18:24:15 +03:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
|
|
# Скрипт для восстановления базы данных из дампа
|
|
|
|
|
|
# Использование:
|
2025-12-31 19:11:28 +03:00
|
|
|
|
# ./restore-db.sh [имя_дампа.sql.gz] # Восстановление в .env
|
2025-12-31 18:24:15 +03:00
|
|
|
|
# ./restore-db.sh --env-file .env.prod [имя_дампа] # Восстановление в указанный файл
|
2025-12-31 19:11:28 +03:00
|
|
|
|
# ./restore-db.sh production-backup.sql.gz # Восстановление в .env
|
2025-12-31 18:24:15 +03:00
|
|
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
|
|
# Значения по умолчанию
|
2025-12-31 19:11:28 +03:00
|
|
|
|
DEFAULT_ENV_FILE=".env"
|
2025-12-31 18:24:15 +03:00
|
|
|
|
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}
|
|
|
|
|
|
|
|
|
|
|
|
# Проверяем наличие дампа
|
|
|
|
|
|
if [ -z "$DUMP_FILE" ]; then
|
|
|
|
|
|
echo "❌ Ошибка: Укажите имя дампа"
|
|
|
|
|
|
echo "Использование: ./restore-db.sh [--env-file FILE] [имя_дампа.sql.gz]"
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo "Доступные дампы:"
|
|
|
|
|
|
ls -lh database-dumps/*.sql.gz 2>/dev/null | awk '{print " " $9}' | sed "s|database-dumps/||g" || echo " (нет дампов)"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
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!"
|
|
|
|
|
|
echo " Хост: $DB_HOST:$DB_PORT"
|
|
|
|
|
|
echo " Пользователь: $DB_USER"
|
|
|
|
|
|
read -p " Продолжить? (yes/no): " confirm
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$confirm" != "yes" ]; then
|
|
|
|
|
|
echo "❌ Отменено."
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo "🔄 Восстановление базы данных из дампа..."
|
|
|
|
|
|
echo " База: $DB_NAME"
|
|
|
|
|
|
echo " Хост: $DB_HOST:$DB_PORT"
|
|
|
|
|
|
echo " Файл: $FULL_DUMP_PATH"
|
|
|
|
|
|
|
2026-01-01 18:21:18 +03:00
|
|
|
|
# Распаковываем и модифицируем дамп
|
2025-12-31 18:24:15 +03:00
|
|
|
|
TEMP_DUMP="/tmp/restore_$$.sql"
|
|
|
|
|
|
if [[ "$FULL_DUMP_PATH" == *.gz ]]; then
|
2026-01-01 18:21:18 +03:00
|
|
|
|
echo " Распаковка и модификация дампа..."
|
|
|
|
|
|
gunzip -c "$FULL_DUMP_PATH" | \
|
|
|
|
|
|
sed 's/n8n_user/'"$DB_USER"'/g' | \
|
|
|
|
|
|
sed '/^\\restrict/d' | \
|
|
|
|
|
|
sed '/^\\unrestrict/d' > "$TEMP_DUMP"
|
2025-12-31 18:24:15 +03:00
|
|
|
|
else
|
2026-01-01 18:21:18 +03:00
|
|
|
|
echo " Модификация дампа..."
|
|
|
|
|
|
cat "$FULL_DUMP_PATH" | \
|
|
|
|
|
|
sed 's/n8n_user/'"$DB_USER"'/g' | \
|
|
|
|
|
|
sed '/^\\restrict/d' | \
|
|
|
|
|
|
sed '/^\\unrestrict/d' > "$TEMP_DUMP"
|
2025-12-31 18:24:15 +03:00
|
|
|
|
fi
|
|
|
|
|
|
|
2026-01-01 18:21:18 +03:00
|
|
|
|
echo " Владелец таблиц в дампе заменён на: $DB_USER"
|
|
|
|
|
|
|
2025-12-31 18:24:15 +03:00
|
|
|
|
# Восстанавливаем через docker-compose, если контейнер запущен
|
|
|
|
|
|
if docker-compose ps db 2>/dev/null | grep -q "Up"; then
|
|
|
|
|
|
echo " Используется docker-compose..."
|
|
|
|
|
|
# Очищаем базу и восстанавливаем
|
|
|
|
|
|
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..."
|
|
|
|
|
|
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"
|
|
|
|
|
|
|
2026-01-01 18:21:18 +03:00
|
|
|
|
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 ""
|
2025-12-31 18:24:15 +03:00
|
|
|
|
echo "✅ База данных успешно восстановлена из дампа!"
|
2026-01-01 18:21:18 +03:00
|
|
|
|
echo ""
|
|
|
|
|
|
echo "📌 ВАЖНО: После первой регистрации/входа пользователя все данные"
|
|
|
|
|
|
echo " будут автоматически привязаны к этому пользователю."
|
2025-12-31 18:24:15 +03:00
|
|
|
|
|