| 
                        123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 | 
                        - #!/bin/bash
 - 
 - # RAGFlow Data Migration Script
 - # Usage: ./migration.sh [backup|restore] [backup_folder]
 - # 
 - # This script helps you backup and restore RAGFlow Docker volumes
 - # including MySQL, MinIO, Redis, and Elasticsearch data.
 - 
 - set -e  # Exit on any error
 - # Instead, we'll handle errors manually for better debugging experience
 - 
 - # Default values
 - DEFAULT_BACKUP_FOLDER="backup"
 - VOLUMES=("docker_mysql_data" "docker_minio_data" "docker_redis_data" "docker_esdata01")
 - BACKUP_FILES=("mysql_backup.tar.gz" "minio_backup.tar.gz" "redis_backup.tar.gz" "es_backup.tar.gz")
 - 
 - # Function to display help information
 - show_help() {
 -     echo "RAGFlow Data Migration Tool"
 -     echo ""
 -     echo "USAGE:"
 -     echo "  $0 <operation> [backup_folder]"
 -     echo ""
 -     echo "OPERATIONS:"
 -     echo "  backup   - Create backup of all RAGFlow data volumes"
 -     echo "  restore  - Restore RAGFlow data volumes from backup"
 -     echo "  help     - Show this help message"
 -     echo ""
 -     echo "PARAMETERS:"
 -     echo "  backup_folder  - Name of backup folder (default: '$DEFAULT_BACKUP_FOLDER')"
 -     echo ""
 -     echo "EXAMPLES:"
 -     echo "  $0 backup                    # Backup to './backup' folder"
 -     echo "  $0 backup my_backup          # Backup to './my_backup' folder"
 -     echo "  $0 restore                   # Restore from './backup' folder"
 -     echo "  $0 restore my_backup         # Restore from './my_backup' folder"
 -     echo ""
 -     echo "DOCKER VOLUMES:"
 -     echo "  - docker_mysql_data     (MySQL database)"
 -     echo "  - docker_minio_data     (MinIO object storage)"
 -     echo "  - docker_redis_data     (Redis cache)"
 -     echo "  - docker_esdata01       (Elasticsearch indices)"
 - }
 - 
 - # Function to check if Docker is running
 - check_docker() {
 -     if ! docker info >/dev/null 2>&1; then
 -         echo "❌ Error: Docker is not running or not accessible"
 -         echo "Please start Docker and try again"
 -         exit 1
 -     fi
 - }
 - 
 - # Function to check if volume exists
 - volume_exists() {
 -     local volume_name=$1
 -     docker volume inspect "$volume_name" >/dev/null 2>&1
 - }
 - 
 - # Function to check if any containers are using the target volumes
 - check_containers_using_volumes() {
 -     echo "🔍 Checking for running containers that might be using target volumes..."
 -     
 -     # Get all running containers
 -     local running_containers=$(docker ps --format "{{.Names}}")
 -     
 -     if [ -z "$running_containers" ]; then
 -         echo "✅ No running containers found"
 -         return 0
 -     fi
 -     
 -     # Check each running container for volume usage
 -     local containers_using_volumes=()
 -     local volume_usage_details=()
 -     
 -     for container in $running_containers; do
 -         # Get container's mount information
 -         local mounts=$(docker inspect "$container" --format '{{range .Mounts}}{{.Source}}{{"|"}}{{end}}' 2>/dev/null || echo "")
 -         
 -         # Check if any of our target volumes are used by this container
 -         for volume in "${VOLUMES[@]}"; do
 -             if echo "$mounts" | grep -q "$volume"; then
 -                 containers_using_volumes+=("$container")
 -                 volume_usage_details+=("$container -> $volume")
 -                 break
 -             fi
 -         done
 -     done
 -     
 -     # If any containers are using our volumes, show error and exit
 -     if [ ${#containers_using_volumes[@]} -gt 0 ]; then
 -         echo ""
 -         echo "❌ ERROR: Found running containers using target volumes!"
 -         echo ""
 -         echo "📋 Running containers status:"
 -         docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
 -         echo ""
 -         echo "🔗 Volume usage details:"
 -         for detail in "${volume_usage_details[@]}"; do
 -             echo "  - $detail"
 -         done
 -         echo ""
 -         echo "🛑 SOLUTION: Stop the containers before performing backup/restore operations:"
 -         echo "   docker-compose -f docker/<your-docker-compose-file>.yml down"
 -         echo ""
 -         echo "💡 After backup/restore, you can restart with:"
 -         echo "   docker-compose -f docker/<your-docker-compose-file>.yml up -d"
 -         echo ""
 -         exit 1
 -     fi
 -     
 -     echo "✅ No containers are using target volumes, safe to proceed"
 -     return 0
 - }
 - 
 - # Function to confirm user action
 - confirm_action() {
 -     local message=$1
 -     echo -n "$message (y/N): "
 -     read -r response
 -     case "$response" in
 -         [yY]|[yY][eE][sS]) return 0 ;;
 -         *) return 1 ;;
 -     esac
 - }
 - 
 - # Function to perform backup
 - perform_backup() {
 -     local backup_folder=$1
 -     
 -     echo "🚀 Starting RAGFlow data backup..."
 -     echo "📁 Backup folder: $backup_folder"
 -     echo ""
 -     
 -     # Check if any containers are using the volumes
 -     check_containers_using_volumes
 -     
 -     # Create backup folder if it doesn't exist
 -     mkdir -p "$backup_folder"
 -     
 -     # Backup each volume
 -     for i in "${!VOLUMES[@]}"; do
 -         local volume="${VOLUMES[$i]}"
 -         local backup_file="${BACKUP_FILES[$i]}"
 -         local step=$((i + 1))
 -         
 -         echo "📦 Step $step/4: Backing up $volume..."
 -         
 -         if volume_exists "$volume"; then
 -             docker run --rm \
 -                 -v "$volume":/source \
 -                 -v "$(pwd)/$backup_folder":/backup \
 -                 alpine tar czf "/backup/$backup_file" -C /source .
 -             echo "✅ Successfully backed up $volume to $backup_folder/$backup_file"
 -         else
 -             echo "⚠️  Warning: Volume $volume does not exist, skipping..."
 -         fi
 -         echo ""
 -     done
 -     
 -     echo "🎉 Backup completed successfully!"
 -     echo "📍 Backup location: $(pwd)/$backup_folder"
 -     
 -     # List backup files with sizes
 -     echo ""
 -     echo "📋 Backup files created:"
 -     for backup_file in "${BACKUP_FILES[@]}"; do
 -         if [ -f "$backup_folder/$backup_file" ]; then
 -             local size=$(ls -lh "$backup_folder/$backup_file" | awk '{print $5}')
 -             echo "  - $backup_file ($size)"
 -         fi
 -     done
 - }
 - 
 - # Function to perform restore
 - perform_restore() {
 -     local backup_folder=$1
 -     
 -     echo "🔄 Starting RAGFlow data restore..."
 -     echo "📁 Backup folder: $backup_folder"
 -     echo ""
 -     
 -     # Check if any containers are using the volumes
 -     check_containers_using_volumes
 -     
 -     # Check if backup folder exists
 -     if [ ! -d "$backup_folder" ]; then
 -         echo "❌ Error: Backup folder '$backup_folder' does not exist"
 -         exit 1
 -     fi
 -     
 -     # Check if all backup files exist
 -     local missing_files=()
 -     for backup_file in "${BACKUP_FILES[@]}"; do
 -         if [ ! -f "$backup_folder/$backup_file" ]; then
 -             missing_files+=("$backup_file")
 -         fi
 -     done
 -     
 -     if [ ${#missing_files[@]} -gt 0 ]; then
 -         echo "❌ Error: Missing backup files:"
 -         for file in "${missing_files[@]}"; do
 -             echo "  - $file"
 -         done
 -         echo "Please ensure all backup files are present in '$backup_folder'"
 -         exit 1
 -     fi
 -     
 -     # Check for existing volumes and warn user
 -     local existing_volumes=()
 -     for volume in "${VOLUMES[@]}"; do
 -         if volume_exists "$volume"; then
 -             existing_volumes+=("$volume")
 -         fi
 -     done
 -     
 -     if [ ${#existing_volumes[@]} -gt 0 ]; then
 -         echo "⚠️  WARNING: The following Docker volumes already exist:"
 -         for volume in "${existing_volumes[@]}"; do
 -             echo "  - $volume"
 -         done
 -         echo ""
 -         echo "🔴 IMPORTANT: Restoring will OVERWRITE existing data!"
 -         echo "💡 Recommendation: Create a backup of your current data first:"
 -         echo "   $0 backup current_backup_$(date +%Y%m%d_%H%M%S)"
 -         echo ""
 -         
 -         if ! confirm_action "Do you want to continue with the restore operation?"; then
 -             echo "❌ Restore operation cancelled by user"
 -             exit 0
 -         fi
 -     fi
 -     
 -     # Create volumes and restore data
 -     for i in "${!VOLUMES[@]}"; do
 -         local volume="${VOLUMES[$i]}"
 -         local backup_file="${BACKUP_FILES[$i]}"
 -         local step=$((i + 1))
 -         
 -         echo "🔧 Step $step/4: Restoring $volume..."
 -         
 -         # Create volume if it doesn't exist
 -         if ! volume_exists "$volume"; then
 -             echo "  📋 Creating Docker volume: $volume"
 -             docker volume create "$volume"
 -         else
 -             echo "  📋 Using existing Docker volume: $volume"
 -         fi
 -         
 -         # Restore data
 -         echo "  📥 Restoring data from $backup_file..."
 -         docker run --rm \
 -             -v "$volume":/target \
 -             -v "$(pwd)/$backup_folder":/backup \
 -             alpine tar xzf "/backup/$backup_file" -C /target
 -         
 -         echo "✅ Successfully restored $volume"
 -         echo ""
 -     done
 -     
 -     echo "🎉 Restore completed successfully!"
 -     echo "💡 You can now start your RAGFlow services"
 - }
 - 
 - # Main script logic
 - main() {
 -     # Check if Docker is available
 -     check_docker
 -     
 -     # Parse command line arguments
 -     local operation=${1:-}
 -     local backup_folder=${2:-$DEFAULT_BACKUP_FOLDER}
 -     
 -     # Handle help or no arguments
 -     if [ -z "$operation" ] || [ "$operation" = "help" ] || [ "$operation" = "-h" ] || [ "$operation" = "--help" ]; then
 -         show_help
 -         exit 0
 -     fi
 -     
 -     # Validate operation
 -     case "$operation" in
 -         backup)
 -             perform_backup "$backup_folder"
 -             ;;
 -         restore)
 -             perform_restore "$backup_folder"
 -             ;;
 -         *)
 -             echo "❌ Error: Invalid operation '$operation'"
 -             echo ""
 -             show_help
 -             exit 1
 -             ;;
 -     esac
 - }
 - 
 - # Run main function with all arguments
 - main "$@"
 
 
  |