#!/bin/bash


MYSQL_USER=repl
MYSQL_PASSWD=Xjb0^DDy
HOST='127.0.0.1'
USE_MEM="1024m"
IOPS=60

recovery_backup_log="/tmp/recovery_backup.log"
>$recovery_backup_log

log() {
    local text;local logtype
    logtype=$1
    text=$2
    case $logtype in 
        error)
            echo -e "\033[31m`date +'%F %H:%M:%S'`[$1]\t$2\033[0m" | tee -a $recovery_backup_log;;
        info)
            echo -e "\033[32m`date +'%F %H:%M:%S'`[$1]\t$2\033[0m" | tee -a $recovery_backup_log;;
        warn)
            echo -e "\033[33m`date +'%F %H:%M:%S'`[$1]\t$2\033[0m" | tee -a $recovery_backup_log;;
    esac
}

# 在 MySQL 容器中执行命令
exec_on_container() {
    container_id=$(docker ps |grep -E "mysql:v8|mysql:prod" |awk '{print $1}')
    exec_sql="mysql -urepl -pXjb0^DDy -N -e"

    if [ "$1" == "sql" ];then
        docker exec  $container_id $exec_sql "$2"
    else
        docker exec  $container_id bash -c "$*"
    fi
}

# 检查 MGR 状态
check_mgr() {
    res=$(exec_on_container sql "select * from performance_schema.replication_group_members")
    health_num=$(echo $res | grep -o ONLINE |wc -l)
    if [ "$health_num" != "3" ];then
        # echo "MGR 集群异常，当前节点数量为: $health_num."
        log info "MGR cluster is unhealthy. Number of current nodes:$health_num. Start backup..."
    else
        if [ "$ISFORCE" != "true" ];then
            # echo "MGR 集群节点状态正常，当前节点数量为: $health_num. 无需进行数据备份及恢复，如需要强制执行，使用 -f/--force 参数."
            log error "MGR cluster is healthy. Number of current nodes:$health_num. No need for data recovery, if you need to enforce it, use the -f/--force parameter."
            exit 1;
        else
            # echo "MGR 集群节点状态正常，当前节点数量为: $health_num. 强制进行数据备份."
            log warn "MGR cluster is healthy. Number of current nodes:$health_num. Force backup..."
        fi
    fi
}


# 备份磁盘空间检查
check_disk() {
    mysql_usage=$(exec_on_container "du -shk /var/lib/mysql" | awk '{print $1}')
    # local_available=$(exec_on_container "df -T " | grep -w '/' |awk '{print $5}')
    local_available=$(df -T $local_disk_name |awk '{print $5}'|grep -o [0-9].*[0-9])

    if [ $local_available -gt $[mysql_usage*2] ];then
        # echo "磁盘空间正常，开始备份.备份存放在 $local_disk_name 下."
        log info "Disk space is ok. Backup disk is $local_disk_name."
    else
        # 是否有指定其他备份路径。是，继续；否，退出
        if [ -z $backup_disk ];then
            # echo "磁盘空间不足够存放备份，请使用 -b/--back-dir 参数指定数据存放磁盘."
            log error "Not enough disk space. Please use the -b/--back-dir parameter to specify the data storage disk."
            exit 1;
        else
            # echo "备份磁盘为 $backup_disk."
            log info "Backup disk is $local_disk_name."
        fi
    fi
}


ARGS=`getopt -a -o f:c: --long slave-host: -- "$@"`

if [ $? != 0 ];then
  echo "Terminating..."
  exit 1
fi

eval set -- "${ARGS}"

while :
do
  case $1 in
    -f|--force)
      ISFORCE=true
      shift
      ;;
    -c|--slave-host)
      slave_host=$2
      shift 2
      ;;
    --)
      shift
      break
      ;;
    *)
      log error "Parameter error!"
      exit 1
      ;;
  esac
done

#处理剩余的参数
for arg in $@
do
    log error "无效的参数: $arg"
done

stop_recovery_host() {
  if [ "$(docker service ls 2>/dev/null |wc -l )" -ne 0 ];then
    service_name=$(docker service ls |grep "${slave_host}" | awk {'print $2'})
    docker service scale ${service_name}=0
    log info "停止 ${slave_host} 节点数据库，请已经手动登录此节点备份数据库目录"
  else
    log error "此节点不是 swarm 管理节点,需要配置为管理节点才能继续"
    exit 1
  fi
}

confirm_input() {
  echo "执行此脚本前,需要手动备份 ${slave_host} 节点数据目录!否则此脚本会清空并覆盖 ${slave_host} 节点数据目录!"
  read -r -p "确定已经手动备份 ${slave_host} 节点数据库目录? [Y/n] " input
  
  case $input in
    [yY][eE][sS]|[yY])
       log info "开始恢复 ${slave_host} "
       ;;
    [nN][oO]|[nN])
       echo "No"
       exit 1	       	
       ;;
    *)
      echo "无效输入..."
      exit 1
      ;;
  esac
}

recovery_slave_host() {
  docker service scale ${service_name}=1
  sleep 10
  log info "开始恢复 ${slave_host} 节点"
  exec_on_container "ssh -o  StrictHostKeyChecking=no root@${slave_host} 'rm -rf /var/lib/mysql/*'"
  exec_on_container "xtrabackup --throttle=$IOPS --use-memory=$USE_MEM  --host=$HOST  --user=$MYSQL_USER --password=$MYSQL_PASSWD --backup --stream=xbstream | ssh root@${slave_host} 'cat - | xbstream -x -C /var/lib/mysql'"
  exec_on_container "ssh -o StrictHostKeyChecking=no root@${slave_host} 'xtrabackup --prepare --apply-log-only --target-dir=/var/lib/mysql'" 
  if [ $? -eq 0 ];then
    log info "${slave_host} 节点恢复完成,将自动重启节点数据库服务."
  else
    log error "${slave_host} 节点恢复失败,请手动检查！现在退出恢复程序."
    exit 1
  fi

  if [ "$slave_host" == "mysql0" ];then
    exec_on_container "ssh -o StrictHostKeyChecking=no root@${slave_host} echo 0>/var/lib/mysql/last_time"
  fi
  docker service scale ${service_name}=0 && docker service scale ${service_name}=1
  log info "${slave_host} 数据库服务重启完成."
  exec_on_container "mysql -u${MYSQL_USER} -p${MYSQL_PASSWD} -h${slave_host} -e 'reset slave'"
  exec_on_container "mysql -u${MYSQL_USER} -p${MYSQL_PASSWD} -h${slave_host} -e 'start group_replication'"
  exec_on_container sql "select * from performance_schema.replication_group_members"
}

LOCAL_HOSTNAME=$(exec_on_container hostname)
log info "选择恢复的节点是 ${slave_host} 节点."

case $slave_host in
  mysql0)
    [ ${LOCAL_HOSTNAME} == "mysql0" ] && log error "-c 参数指定恢复节点不能是本机！" && exit 1
    check_mgr
    stop_recovery_host
    confirm_input
    recovery_slave_host
    ;;
  mysql1)
    [ ${LOCAL_HOSTNAME} == "mysql1" ] && log error "-c 参数指定恢复节点不能是本机！" && exit 1
    check_mgr
    stop_recovery_host
    confirm_input
    recovery_slave_host
    ;;
  mysql2)
    [ ${LOCAL_HOSTNAME} == "mysql2" ] && log error "-c 参数指定恢复节点不能是本机！" && exit 1
    check_mgr
    stop_recovery_host
    confirm_input
    recovery_slave_host
    ;;
  *)
    log error "输入错误！请通过 -c 参数输入要恢复的数据库集群节点名.(mysql0,mysql1,mysql2)"
    exit 1
    ;;
esac

