#!/bin/bash
# Redis哨兵集群部署与卸载脚本

# 颜色配置
GREEN="\033[32m"
YELLOW="\033[33m"
BLUE="\033[34m"
RED="\033[31m"
RESET="\033[0m"

# 提示函数
info() { echo -e "[ ${BLUE}INFO ${RESET}] $1"; }
success() { echo -e "[ ${GREEN}SUCCESS ${RESET}] $1"; }
warning() { echo -e "[ ${YELLOW}WARNING ${RESET}] $1"; }
error() { echo -e "[ ${RED}ERROR ${RESET}] $1"; exit 1; }

# 基础配置
REDIS_PORT=6379
SENTINEL_PORT=26379
SENTINEL_NAME="mymaster"
LOG_DIR="/var/log/redis"
CONFIG_DIR="/etc/redis"
SSH_OPTS="-T -o StrictHostKeyChecking=no -o LogLevel=ERROR"

# 全局变量
ACTION=""
NODES=()
NODE_COUNT=0
MASTER=""
SLAVES=()
QUORUM=1
PASSWORD=""  

# 参数解析（支持--install/--uninstall、--ip、--passwd参数）
parse_args() {
    # 初始化参数变量
    local ip_provided=0
    local passwd_provided=0

    # 遍历解析参数
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --install|--uninstall)
                ACTION="$1"
                shift
                ;;
            --ip=*)
                IP_LIST="${1#*=}"
                ip_provided=1
                shift
                ;;
            --passwd=*)
                PASSWORD="${1#*=}"
                passwd_provided=1
                shift
                ;;
            *)
                error "无效参数: $1 （使用帮助：--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码）"
                ;;
        esac
    done

    # 验证必要参数
    if [[ -z "$ACTION" ]]; then
        error "必须指定参数：--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
    fi
    if [[ $ip_provided -eq 0 ]]; then
        error "必须指定参数：--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
    fi
    if [[ $passwd_provided -eq 0 ]]; then
        error "必须指定参数：--install/--uninstall --ip=IP1,IP2,IP3... --passwd=redis密码"
    fi

    # 解析节点列表
    IFS=',' read -ra NODES <<< "$IP_LIST"
    NODE_COUNT=${#NODES[@]}
    if [[ $NODE_COUNT -lt 1 ]]; then
        error "IP列表不能为空，至少需要1个节点"
    fi
    
    # 配置主从节点和投票阈值
    MASTER="${NODES[0]}"
    SLAVES=("${NODES[@]:1}")
    QUORUM=$((NODE_COUNT / 2 + 1))  # 自动计算投票阈值
}

# 安装流程核心函数
install() {
    echo -e "=========================================="
    echo -e "=== ${GREEN}Redis哨兵集群安装部署${RESET} ==="
    echo -e "=========================================="
    info "部署节点总数：$NODE_COUNT 个（${NODES[*]}）"
    info "主节点：$MASTER | 从节点：${SLAVES[*]}（共${#SLAVES[@]}个）"
    info "哨兵投票阈值（QUORUM）：$QUORUM（自动计算：$NODE_COUNT/2 +1）"
    info "Redis密码：******（已通过命令行传入）"
    info "预估总耗时：9-14 分钟（视节点数和网络）"
    echo -e "==========================================\n"

    # 步骤1：初始化环境
    info "步骤1/5：初始化所有节点环境 [${YELLOW}预估：5-9 分钟${RESET}]"
    info "正在安装依赖、配置日志目录和防火墙..."
    for node in "${NODES[@]}"; do
        ssh $SSH_OPTS $node "
            apt-get update -y >/dev/null 2>&1;
            apt-get install -y redis-server redis-sentinel net-tools >/dev/null 2>&1;
            mkdir -p $CONFIG_DIR $LOG_DIR;
            chown -R redis:redis $CONFIG_DIR $LOG_DIR;
            ufw disable >/dev/null 2>&1;
            iptables -F INPUT >/dev/null 2>&1;
        " >/dev/null 2>&1 || error "节点 $node 环境初始化失败"
    done
    success "步骤1完成：所有节点环境初始化完毕\n"

    # 步骤2：配置主节点
    info "步骤2/5：配置主节点 $MASTER [${YELLOW}预估：30秒${RESET}]"
    ssh $SSH_OPTS $MASTER "
        cat > $CONFIG_DIR/redis.conf <<EOF
bind 0.0.0.0
protected-mode no
port $REDIS_PORT
requirepass $PASSWORD
masterauth $PASSWORD
daemonize no
logfile "$LOG_DIR/redis.log"
dir /tmp
replica-serve-stale-data yes
replica-read-only yes
EOF
        chown redis:redis $CONFIG_DIR/redis.conf;
        cat > /etc/systemd/system/redis.service <<EOF
[Unit]
Description=Redis Master Node
After=network.target
[Service]
User=redis
ExecStart=/usr/bin/redis-server $CONFIG_DIR/redis.conf
ExecStop=/usr/bin/redis-cli -p $REDIS_PORT -a $PASSWORD shutdown
Restart=always
[Install]
WantedBy=multi-user.target
EOF
        systemctl daemon-reload;
        systemctl restart redis;
        systemctl enable redis;
    " >/dev/null 2>&1 || error "主节点 $MASTER 配置失败"
    success "步骤2完成：主节点配置完毕\n"

    # 步骤3：配置从节点
    info "步骤3/5：配置从节点 [${YELLOW}预估：${#SLAVES[@]}*30秒${RESET}]"
    info "从节点列表：${SLAVES[*]}"
    for slave in "${SLAVES[@]}"; do
        info "正在配置从节点：$slave"
        ssh $SSH_OPTS $slave "
            cat > $CONFIG_DIR/redis.conf <<EOF
bind 0.0.0.0
protected-mode no
port $REDIS_PORT
requirepass $PASSWORD
masterauth $PASSWORD
daemonize no
logfile "$LOG_DIR/redis.log"
dir /tmp
replica-serve-stale-data yes
replica-read-only yes
replicaof $MASTER $REDIS_PORT
EOF
            chown redis:redis $CONFIG_DIR/redis.conf;
            cat > /etc/systemd/system/redis.service <<EOF
[Unit]
Description=Redis Slave Node
After=network.target
[Service]
User=redis
ExecStart=/usr/bin/redis-server $CONFIG_DIR/redis.conf
ExecStop=/usr/bin/redis-cli -p $REDIS_PORT -a $PASSWORD shutdown
Restart=always
[Install]
WantedBy=multi-user.target
EOF
            systemctl daemon-reload;
            systemctl restart redis;
            systemctl enable redis;
        " >/dev/null 2>&1 || error "从节点 $slave 配置失败"
    done
    success "步骤3完成：所有从节点配置完毕\n"

    # 步骤4：配置哨兵集群
    info "步骤4/5：配置哨兵集群 [${YELLOW}预估：$NODE_COUNT*30秒${RESET}]"
    info "哨兵投票阈值：$QUORUM（需$QUORUM个哨兵确认主节点下线才触发转移）"
    for node in "${NODES[@]}"; do
        info "正在配置哨兵节点：$node"
        ssh $SSH_OPTS $node "
            cat > $CONFIG_DIR/sentinel.conf <<EOF
port $SENTINEL_PORT
daemonize no
logfile "$LOG_DIR/sentinel.log"
sentinel monitor $SENTINEL_NAME $MASTER $REDIS_PORT $QUORUM
sentinel down-after-milliseconds $SENTINEL_NAME 5000
sentinel auth-pass $SENTINEL_NAME $PASSWORD
sentinel config-epoch $SENTINEL_NAME 0
EOF
            chown redis:redis $CONFIG_DIR/sentinel.conf;
            cat > /etc/systemd/system/redis-sentinel.service <<EOF
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
User=redis
ExecStart=/usr/bin/redis-sentinel $CONFIG_DIR/sentinel.conf
ExecStop=/usr/bin/redis-cli -p $SENTINEL_PORT shutdown
Restart=always
[Install]
WantedBy=multi-user.target
EOF
            systemctl daemon-reload;
            systemctl restart redis-sentinel;
            systemctl enable redis-sentinel;
        " >/dev/null 2>&1 || error "哨兵节点 $node 配置失败"
    done
    success "步骤4完成：哨兵集群配置完毕\n"

    # 步骤5：验证集群
    info "步骤5/5：验证集群状态 [${YELLOW}预估：1分钟${RESET}]"
    info "验证主节点 $MASTER..."
    master_info=$(ssh $SSH_OPTS $MASTER "redis-cli -p $REDIS_PORT -a $PASSWORD info replication | grep -E 'role:|connected_slaves'" 2>/dev/null)
    echo "  $master_info"

    for slave in "${SLAVES[@]}"; do
        info "验证从节点 $slave..."
        slave_info=$(ssh $SSH_OPTS $slave "redis-cli -p $REDIS_PORT -a $PASSWORD info replication | grep -E 'role:|master_host|master_link_status'" 2>/dev/null)
        echo "  $slave_info"
    done

    info "验证哨兵集群..."
    sentinel_info=$(ssh $SSH_OPTS $MASTER "redis-cli -p $SENTINEL_PORT info sentinel | grep 'master0:'" 2>/dev/null)
    echo "  $sentinel_info"

    success "步骤5完成：集群验证完毕\n"

    # 部署总结
    echo -e "=========================================="
    echo -e "=== ${GREEN}部署成功！${RESET} ==="
    echo -e "☆ 集群架构：$NODE_COUNT节点（1主${#SLAVES[@]}从$NODE_COUNT哨兵）"
    echo -e "☆ 核心配置：Redis端口$REDIS_PORT | 哨兵端口$SENTINEL_PORT | 投票阈值$QUORUM"
    echo -e "☆ 功能状态：主从同步正常 | 哨兵监控正常 | 故障转移就绪"
    echo -e "=========================================="
}

# 卸载流程核心函数
uninstall() {
    echo -e "=========================================="
    echo -e "=== ${RED}Redis哨兵集群彻底卸载${RESET} ==="
    echo -e "=========================================="
    info "卸载节点列表：${NODES[*]}（共$NODE_COUNT个节点）"
    info "Redis密码：******（已通过命令行传入）"
    info "预估耗时：3-6 分钟（清理所有资源）"
    echo -e "==========================================\n"

    # 逐节点卸载
    for i in "${!NODES[@]}"; do
        node="${NODES[$i]}"
        idx=$((i + 1))
        info "正在卸载节点（$idx/$NODE_COUNT）：$node"
        ssh $SSH_OPTS $node "
            # 停止服务（使用传入的密码）
            systemctl stop redis-sentinel >/dev/null 2>&1;
            redis-cli -p $REDIS_PORT -a '$PASSWORD' shutdown >/dev/null 2>&1;
            # 禁用服务
            systemctl disable redis redis-sentinel >/dev/null 2>&1;
            # 清理文件
            rm -rf $CONFIG_DIR $LOG_DIR /etc/systemd/system/redis* >/dev/null 2>&1;
            # 卸载依赖
            apt-get remove -y redis-server redis-sentinel >/dev/null 2>&1;
            apt-get autoremove -y >/dev/null 2>&1;
        " >/dev/null 2>&1 || error "节点 $node 卸载失败"
        success "节点 $node 卸载完成"
    done

    # 卸载总结
    echo -e "\n=========================================="
    echo -e "=== ${GREEN}卸载成功！${RESET} ==="
    echo -e "✓ 已彻底清理所有Redis相关资源："
    echo -e "  - 服务：redis-server、redis-sentinel（停止+禁用）"
    echo -e "  - 文件：配置目录、日志目录、systemd服务文件"
    echo -e "  - 依赖：redis相关安装包及依赖组件"
    echo -e "=========================================="
}

# 执行入口
parse_args "$@"
if [ "$ACTION" = "--install" ]; then
    install
elif [ "$ACTION" = "--uninstall" ]; then
    uninstall
fi
