
# 配置rollback_hosts_linux.sh脚本
根据提供的脚本示例，结合实际情况，修改示例中的相关配置。
#### 前提条件
已完成[准备工作](https://support.huaweicloud.com/bestpractice-mgc/mgc_05_0060.html)。
#### 操作步骤
1. 在执行脚本的主机上创建一个名为"**rollback_hosts_linux.sh** "的文件，然后将以下脚本示例的内容复制到文件中。如果您已经通过SSH连接到源端Linux主机，可以直接使用vim创建和编辑脚本文件，步骤如下：
   
   1. 在Vim编辑器中按 i 进入插入模式。
   
   2. 复制并粘贴脚本代码，完成后按 Esc。
   
   3. 输入 :wq 保存并退出。
   
   
   ```
   #!/bin/bash
    
   # Configuration
    
   # Log directory path: Used to store run logs, error logs, and summary logs.
   # If the directory doesn't exist, the script will create it automatically.
   LOG_DIR="/var/log/update_hosts"
    
   # Run log file path: Records detailed information about the script's execution.
   RUN_LOG="$LOG_DIR/run.log"
    
   # Error log file path: Records any errors that occur during the script's execution.
   ERROR_LOG="$LOG_DIR/error.log"
    
   # Summary log file path: Records a summary of the script's execution, including the number of successful and failed servers.
   SUMMARY_LOG="$LOG_DIR/summary.log"
    
   # CSV file path: Contains information about the target hosts (must be manually created and configured).
   CSV_FILE="target_servers.csv"
   DEFAULT_PORT=22
   SSH_TIMEOUT=10
    
   # Initialize log directory and files
   initialize_logs() {
       mkdir -p "$LOG_DIR"
       echo "========================================" >> "$RUN_LOG"
       echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - Starting new rollback execution" >> "$RUN_LOG"
       echo "========================================" >> "$RUN_LOG"
    
       echo "========================================" >> "$ERROR_LOG"
       echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - Starting new rollback execution" >> "$ERROR_LOG"
       echo "========================================" >> "$ERROR_LOG"
    
       echo "========================================" > "$SUMMARY_LOG"
       echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - Starting new rollback execution" >> "$SUMMARY_LOG"
       echo "========================================" >> "$SUMMARY_LOG"
   }
    
   # Log info function
   log_info() {
       echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$RUN_LOG"
   }
    
   # Log error function
   log_error() {
       echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$RUN_LOG" "$ERROR_LOG"
   }
    
   # Read server information from CSV file
   read_servers_from_csv() {
       local csv_file="$1"
       local servers=()
       local header_skipped=false
    
       if [ ! -f "$csv_file" ]; then
           log_error "CSV file '$csv_file' not found."
           exit 1
       fi
    
       # Ensure file ends with a newline character
       sed -i -e '$a\' "$csv_file"
    
       while IFS=, read -r username ip port password; do
           # Skip header row
           if [ "$header_skipped" = false ]; then
               header_skipped=true
               continue
           fi
           # Skip empty and invalid rows
           if [[ -z "$username" || -z "$ip" ]]; then
               continue
           fi
           port=${port:-$DEFAULT_PORT} # Use default port 22
           # Ensure port is numeric
           if ! [[ "$port" =~ ^[0-9]+$ ]]; then
               log_error "Invalid port '$port' for $username@$ip. Skipping this server."
               continue
           fi
           servers+=("$username@$ip:$port:$password")
       done < "$csv_file"
    
       echo "${servers[@]}"
   }
    
   # Initialize log files
   initialize_logs
    
   # Read server information from CSV file
   servers=($(read_servers_from_csv "$CSV_FILE"))
    
   # Counters for success and failure
   success_count=0
   failure_count=0
   failed_servers=()
    
   # Iterate over each server and execute rollback
   for server in "${servers[@]}"; do
     # Extract user, IP, port, and password information
     IFS=':' read -r user_host port pass <<< "$server"
     IFS='@' read -r user ip <<< "$user_host"
     
     log_info "Starting rollback for $user@$ip:$port"
    
     # Create temporary script and SSH_ASKPASS script
     tmp_script=$(mktemp)
     askpass_script=$(mktemp)
    
     cat <<EOF > "$tmp_script"
   #!/bin/bash
   # Backup hosts file
   if [ ! -f /etc/hosts.bak ]; then
     cp /etc/hosts /etc/hosts.bak
   fi
    
   # Remove old Migration-proxy section
   sed -i '/#Migration-proxy-start/,/#Migration-proxy-end/d' /etc/hosts
   EOF
    
     cat <<EOF > "$askpass_script"
   #!/bin/bash
   echo "$pass"
   EOF
    
     chmod +x "$tmp_script" "$askpass_script"
    
     # Set SSH_ASKPASS environment variable and use ssh to connect to the target machine and execute the temporary script
     export SSH_ASKPASS="$askpass_script"
     export DISPLAY=:0
    
     ssh_output=$(mktemp)
     setsid ssh -o BatchMode=no -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no -p "$port" "$user@$ip" 'bash -s' < "$tmp_script" 2> "$ssh_output"
     ssh_status=$?
    
     if [ $ssh_status -eq 0 ]; then
       log_info "Rolled back hosts on $ip:$port successfully"
       ((success_count++))
     else
       ssh_error=$(cat "$ssh_output")
       case $ssh_status in
         1)
           log_error "General error occurred while rolling back hosts on $ip:$port: $ssh_error"
           ;;
         2)
           log_error "Misuse of shell builtins while rolling back hosts on $ip:$port: $ssh_error"
           ;;
         255)
           if [[ "$ssh_error" == *"Permission denied"* ]]; then
             log_error "SSH login failed for $user@$ip:$port: Permission denied (password may be incorrect or username is wrong)"
           elif [[ "$ssh_error" == *"Connection refused"* ]]; then
             log_error "SSH login failed for $user@$ip:$port: Connection refused (port may be incorrect or SSH service not running on target)"
           elif [[ "$ssh_error" == *"No route to host"* ]]; then
             log_error "SSH login failed for $user@$ip:$port: No route to host (network unreachable)"
           elif [[ "$ssh_error" == *"Host key verification failed"* ]]; then
             log_error "SSH login failed for $user@$ip:$port: Host key verification failed"
           elif [[ "$ssh_error" == *"Connection timed out"* ]]; then
             log_error "SSH login failed for $user@$ip:$port: Connection timed out"
           else
             log_error "SSH login failed for $user@$ip:$port: $ssh_error"
           fi
           ;;
         *)
           log_error "An unknown error occurred while rolling back hosts on $ip:$port: $ssh_error"
           ;;
       esac
       failed_servers+=("$user@$ip:$port")
       ((failure_count++))
     fi
    
     # Remove temporary scripts and SSH output file
     rm -f "$tmp_script" "$askpass_script" "$ssh_output"
   done
    
   # Calculate failure and success percentages
   total_count=$
   failure_percentage=$(echo "scale=2; ($failure_count / $total_count) * 100" | bc)
   success_percentage=$(echo "scale=2; ($success_count / $total_count) * 100" | bc)
    
   # Output summary result and log to file
   summary_content=$(cat <<EOF
   ========================================
   [SUMMARY] $(date '+%Y-%m-%d %H:%M:%S') - Execution Rollback Summary
   ========================================
   Total number of servers: $total_count
   Number of successful rollbacks: $success_count
   Number of failed rollbacks: $failure_count
   Success rate: $success_percentage%
   Failure rate: $failure_percentage%
   ----------------------------------------
   EOF
   )
    
   if [ $failure_count -gt 0 ]; then
       summary_content+="Failed servers:\n"
       for server in "${failed_servers[@]}"; do
           summary_content+="  - $server\n"
       done
   fi
   summary_content+="========================================"
    
   # Output summary result to log file and terminal
   echo -e "$summary_content" | tee -a "$SUMMARY_LOG"
    
   log_info "Script execution completed. Check $SUMMARY_LOG for summary."
   ```
   
   
2. 根据实际情况，修改脚本中的以下配置项参数： 
   - **LOG_DIR="/var/log/rollback_hosts"**
     - **描述**：日志目录路径。
     
     - **参数默认值**：/var/log/rollback_hosts
     
     - **修改建议**：修改为当前用户具有写入权限的目录路径。
     
     
     
     - **修改示例**：LOG_DIR="/home/username/rollback_hosts_logs"
      
   
   - **CSV_FILE="target_servers.csv"**
     - **描述**：CSV 文件路径，包含源端主机信息。
     
     - **参数默认值**：target_servers.csv
     
     - **修改建议**：使用绝对路径，或确保相对路径是正确的。
     
     - **修改示例**：CSV_FILE="/home/username/configs/servers.csv"
      
   
   
   
   
3. 配置项参数修改完成并保存后，在终端窗口（如果有图形化界面可以按Ctrl+Alt+T打开终端）执行脚本： 
   ```
   ./rollback_hosts_linux.sh
   ```
   脚本会在终端窗口中输出日志信息，并在执行完毕后生成一个执行结果报告，可以在LOG_DIR 指定目录中的 summary.log 文件中查看。
   
   
 
