#!/bin/bash
#====================================================================
# Description: CDN Node Installation Script
#              - System initialization for Debian 12
#              - Install and configure components:
#                * OpenResty
#                * Logstash 7.6.1
#                * Logstash-exporter
#                * Young Agent
#              - Setup firewall, SSH, and system optimizations
#              - Added firewall rule 443/udp
# Author: Liu YanHao
# Updated by: Zhang JinWei
# Create Time: 2024-11-15
# Last Modified: 2025-06-13
# Version: 1.4
# Usage: ./cdninstall.sh
# Example: ./cdninstall.sh
#====================================================================
set -e

# ----------------------------------------Check System Environment / 检查系统环境----------------------------------------
function check_os() {
    # Check OS version / 检查操作系统版本
    if ! grep -q "Debian GNU/Linux 1[12]" /etc/os-release 2>/dev/null; then
        echo -e "\e[31m脚本仅支持 Debian 11 和 Debian 12 / This script only supports Debian 11 and Debian 12\e[0m"
        exit 1
    fi

    # Validate required parameters / 验证必需的参数
    if [[ -z "${1}" ]] || [[ -z "${2}" ]] ; then
        echo -e "\e[31m请提供正确的 IP 地址和 salt_id 前缀参数 / Please provide correct IP address and salt_id prefix\e[0m"
        exit 1
    fi
}

# ----------------------------------------Software Installation / 软件包安装----------------------------------------
function software_install() {
    # Disable swap / 关闭交换分区
    sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab
    swapoff -a

    # Install required packages / 安装必需软件包
    apt-get update &&
        apt-get -y install vim wget curl net-tools bash-completion htop iotop iftop sysstat lsof fping mtr-tiny traceroute tcpdump telnet netcat-openbsd tree zip unzip chrony expect default-jdk-headless git
}

# ----------------------------------------Disk Initialization / 磁盘初始化----------------------------------------
function disk_init() {
    bash /root/cdninstall/pkg/disk_init.sh

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m 磁盘初始化成功 \e[0m"
    else
        echo -e "\e[1;31m 磁盘初始化失败 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Hostname Configuration / 主机名配置----------------------------------------
function hostname_config() {
    # Set hostname based on IP / 根据IP设置主机名
    hostnamectl set-hostname cdn-$(echo ${1} | sed 's/\./-/g')
    grep -lr ${1} /etc/hosts &>/dev/null || echo "${1}  $(hostname)" >>/etc/hosts

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m 主机名配置成功 \e[0m"
    else
        echo -e "\e[1;31m 主机名配置失败 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Firewall Configuration / 防火墙配置----------------------------------------
function firewall_config() {
    # Enable and start firewall / 启用并启动防火墙
    apt-get -y install firewalld
    systemctl disable --now ufw 2>/dev/null || true
    systemctl enable --now firewalld

    # Configure firewall rules / 配置防火墙规则
    (curl -sSL http://deb.aorta.global/ACL/firewall_allow_all.sh | bash) || (wget -qO- http://deb.aorta.global/ACL/firewall_allow_all.sh | bash)
    firewall-cmd --permanent --add-port={80,443,8085,10050}/tcp
    firewall-cmd --permanent --add-port=443/udp
    firewall-cmd --reload

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m 防火墙配置成功 \e[0m"
    else
        echo -e "\e[1;31m 防火墙配置失败 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Network and Time Configuration / 网络和时间配置----------------------------------------
function NetworkYH() {
    # Set timezone and sync time / 设置时区并同步时间
    timedatectl set-timezone Asia/Shanghai
    apt-get -y install chrony
    systemctl enable chronyd && systemctl restart chronyd
    chronyc tracking && chronyc -a makestep

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m 网络和时间配置成功 \e[0m"
    else
        echo -e "\e[1;31m 网络和时间配置失败 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Kernel Optimization / 内核优化----------------------------------------
function kernel_optimize() {
    # Configure history settings / 配置历史记录设置
    cat <<'EOF' >/etc/profile.d/history.sh
    # Enable history append mode / 启用历史记录追加模式
    shopt -s histappend

    # Set history size and file size / 设置历史记录大小和文件大小
    export HISTSIZE=1000000
    export HISTFILESIZE=1000000

    # Set history time format / 设置历史记录时间格式
    export HISTTIMEFORMAT="%F %T "

    # Ignore duplicates and commands starting with space / 忽略重复命令和以空格开头的命令
    export HISTCONTROL=ignoreboth

    # Sync history across multiple terminals / 在多个终端间同步历史记录
    export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
EOF

    # Disable mail check / 禁用邮件检查
    cat <<'EOF' >/etc/profile.d/mailcheck.sh
    unset MAILCHECK
EOF

    # Reload profile settings / 重新加载 profile 配置
    source /etc/profile

    # 以下内容重启生效
    [ ! -f /etc/security/limits.conf.bak ] && cp /etc/security/limits.conf{,.bak}
    cat >/etc/security/limits.conf <<'EOF'
root     soft   nofile    1048576
root     hard   nofile    1048576
root     soft   nproc     1048576
root     hard   nproc     1048576
root     soft   core      unlimited
root     hard   core      unlimited
root     hard   memlock   unlimited
root     soft   memlock   unlimited

*     soft   nofile    1048576
*     hard   nofile    1048576
*     soft   nproc     1048576
*     hard   nproc     1048576
*     soft   core      unlimited
*     hard   core      unlimited
*     hard   memlock   unlimited
*     soft   memlock   unlimited
EOF
    sysctl -p
    
}

# ----------------------------------------Salt Installation / Salt 安装----------------------------------------
function salt_install() {
    bash /root/cdninstall/pkg/salt/salt_install.sh "${1}" "${2}"

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m salt 部署成功 \e[0m"
    else
        echo -e "\e[1;31m salt 部署失败，检查/root/cdninstall/pkg/salt_install.sh \e[0m"
        exit 1
    fi
}

# ----------------------------------------Young Agent Installation / Young Agent 安装----------------------------------------
function young_agent_install() {
    # 修改young_agent配置文件中的id和ip为传入的IP参数
    if grep -q "^ *id:" /root/cdninstall/pkg/young_agent/conf/config.yml; then
        sed -i "s/^ *id:.*$/  id: ${1}/" /root/cdninstall/pkg/young_agent/conf/config.yml
    else
        # 如果id字段不存在，则在workdir部分前添加
        sed -i "/workdir:/i\\  id: ${1}" /root/cdninstall/pkg/young_agent/conf/config.yml
    fi

    if grep -q "^ *ip:" /root/cdninstall/pkg/young_agent/conf/config.yml; then
        sed -i "s/^ *ip:.*$/  ip: ${1}/" /root/cdninstall/pkg/young_agent/conf/config.yml
    else
        # 如果ip字段不存在，则在id字段后添加
        sed -i "/^ *id:/a\\  ip: ${1}" /root/cdninstall/pkg/young_agent/conf/config.yml
    fi
    
    bash /root/cdninstall/pkg/young_agent/install/install.sh

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m young_agent 部署成功 \e[0m"
    else
        echo -e "\e[1;31m young_agent 部署失败，检查/root/cdninstall/pkg/young_agent/install/install.sh \e[0m"
        exit 1
    fi
}

# ----------------------------------------OpenResty Installation / OpenResty 安装----------------------------------------
function openresty_install() {
    bash /root/cdninstall/pkg/openresty/openresty_install.sh

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m openresty 部署成功 \e[0m"
    else
        echo -e "\e[1;31m openresty 部署失败，检查/root/cdninstall/pkg/openresty_install.sh \e[0m"
        exit 1
    fi
}

# ----------------------------------------Redis Configuration / Redis 配置----------------------------------------
function redis_config() {
    # 获取本机 IP 地址
    local ip=$(ip -4 addr show $(ip -o -4 route show to default | awk '{print $5}') | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
    echo "检测到本机ip：$ip"

    # 判断函数：是否在允许的网段
    is_allowed_ip() {
        [[ "$ip" == 38.123.160.* ]] || \
        [[ "$ip" == 206.238.225.* ]] || \
        [[ "$ip" == 206.238.229.* ]] || \
        [[ "$ip" == 38.83.16.* ]]
    }

    # 配置文件路径
    local config_file="/usr/local/openresty/lualib/sm/config.lua"
    if [ ! -f "$config_file" ]; then
        echo -e "\e[1;31m redis 配置文件不存在，检查/usr/local/openresty/lualib/sm/config.lua \e[0m"
        exit 1
    fi

    # 根据 IP 选择 Redis 节点
    local redis_host
    local redis_port="6379"
    local redis_password="ybxFXKIQC8vSoece"

    if is_allowed_ip; then
        redis_host="206.238.225.170"
        echo "IP $ip 走美国 redis 节点，正在修改 config.lua 指向 206.238.225.170"
    else
        redis_host="154.89.0.188"
        echo "IP $ip 走香港 redis 节点，正在修改 config.lua 指向 154.89.0.188"
    fi

    # 备份原始配置文件
    cp "$config_file" "${config_file}.bak"

    sed -i "s/host[[:space:]]*=[[:space:]]*\"[^\"]*\"/host = \"$redis_host\"/g" "$config_file"
    sed -i "s/port[[:space:]]*=[[:space:]]*[0-9]\+/port = $redis_port/g" "$config_file"
    sed -i "s/password[[:space:]]*=[[:space:]]*\"[^\"]*\"/password = \"$redis_password\"/g" "$config_file"

    if [[ $? -eq 0 ]]; then
        nginx -s reload
        echo -e "\e[1;32m redis 配置成功 \e[0m"
    else
        mv "${config_file}.bak" "$config_file"
        echo -e "\e[1;31m redis 配置失败，已恢复原始配置 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Logstash Installation / Logstash 安装----------------------------------------
function logstash_install() {
    # Calculate workers based on CPU cores / 根据CPU核心数计算workers数
    CPUs=$(lscpu | grep "^CPU(s)" | awk '{print $2}')
    workers=$((CPUs / 2))

    # Install and configure logstash / 安装并配置logstash
    tar -xf /root/cdninstall/pkg/logstash/logstash-7.10.2.tgz -C /usr/local/
    cp -f /root/cdninstall/pkg/logstash/nginx.conf /usr/local/logstash/config/conf.d/nginx.conf

    # Configure pipelines / 配置管道
    cat >/usr/local/logstash/config/pipelines.yml <<EOF
# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
#   https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html

- pipeline.id: main
  path.config: "/usr/local/logstash/config/conf.d/*.conf"
  pipeline.workers: ${workers}
  pipeline.batch.size: 2000
  pipeline.batch.delay: 500
EOF

    local mem_total=$(awk '/MemTotal/ {printf "%.0f", $2/1024/1024}' /proc/meminfo)
    local heap_size=$((mem_total / 2 < 31 ? mem_total / 2 : 31))
    [[ ${heap_size} -lt 1 ]] && heap_size=1
    sed -i -e "s/^-Xms[0-9]*g/-Xms${heap_size}g/g" \
        -e "s/^-Xmx[0-9]*g/-Xmx${heap_size}g/g" \
        /usr/local/logstash/config/jvm.options

    # 定义 Logstash 的路径和用户
    LOGSTASH_HOME="/usr/local/logstash"
    LOGSTASH_USER="root" # 假设您有一个专门的 logstash 用户，如果没有，可以先用 root

    # 使用 cat 命令创建 systemd 服务文件
    cat > /etc/systemd/system/logstash.service <<EOF
[Unit]
Description=Logstash
Documentation=https://www.elastic.co/guide/en/logstash/current/index.html
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=${LOGSTASH_USER}
Group=${LOGSTASH_USER}

Environment=LS_HOME=${LOGSTASH_HOME}
Environment=LS_SETTINGS_DIR=${LOGSTASH_HOME}/config
RuntimeDirectory=logstash
PIDFile=/var/run/logstash.pid
WorkingDirectory=${LOGSTASH_HOME}
ExecStart=${LOGSTASH_HOME}/bin/logstash --path.settings \${LS_SETTINGS_DIR}
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
LimitMEMLOCK=infinity
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable --now logstash

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m logstash 部署成功 \e[0m"
    else
        echo -e "\e[1;31m logstash 部署失败，检查/etc/logstash/conf.d/nginx.conf配置文件 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Logstash-exporter Installation / Logstash-exporter 安装----------------------------------------
function logstash_exporter_install() {
    # Download and setup logstash-exporter / 下载并设置logstash-exporter
    if [ ! -f /usr/bin/logstash-exporter ]; then
        wget -O /usr/bin/logstash-exporter https://github.com/kuskoman/logstash-exporter/releases/download/v1.7.0/logstash-exporter-linux
        chmod a+x /usr/bin/logstash-exporter
    fi

    # 使用systemd托管
    cat >/usr/lib/systemd/system/logstash-exporter.service <<EOF
[Unit]
Description=logstash-exporter.service
After=syslog.target
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/logstash-exporter
Restart=always
RestartSec=10
StartLimitInterval=100

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now logstash-exporter.service

    if [[ $? -eq 0 ]]; then
        echo -e "\e[1;32m logstash-exporter 部署成功 \e[0m"
    else
        echo -e "\e[1;31m logstash-exporter 部署失败，检查/usr/lib/systemd/system/logstash-exporter.service配置文件 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Log Cleanup Configuration / 日志清理配置----------------------------------------
function log_rotate() {
    # 使用logrotate设置日志轮转
    cat > /etc/logrotate.d/nginxlog <<EOF
/usr/local/openresty/nginx/logs/access.log /usr/local/openresty/nginx/logs/error.log {
    size 500M
    rotate 7
    missingok
    notifempty
    compress
    delaycompress
    create 0640 root root
    sharedscripts
    postrotate
        [ -f /usr/local/openresty/nginx/logs/nginx.pid ] && kill -USR1 \`cat /usr/local/openresty/nginx/logs/nginx.pid\`
    endscript
}
EOF

    # 添加crontab计划任务，每小时执行logrotate
    echo '0 * * * * /usr/sbin/logrotate /etc/logrotate.d/nginxlog' >/var/spool/cron/crontabs/root

    # 确保logrotate已安装并启用
    apt-get -y install logrotate
    systemctl enable --now cron

    if [[ -f /etc/logrotate.d/nginxlog ]]; then
        echo -e "\e[1;32m 日志轮转配置成功 \e[0m"
    else
        echo -e "\e[1;31m 日志轮转配置失败 \e[0m"
        exit 1
    fi
}

# ----------------------------------------Lua Compilation / Lua 编译----------------------------------------
function compile_lua() {
    # 编译Lua文件为LuaJIT字节码
    bash /root/cdninstall/pkg/compile_lua.sh

    if [[ $? -eq 0 ]]; then
        cp -f /root/cdninstall/pkg/compile_lua.sh /usr/local/openresty/compile_lua.sh
        echo -e "\e[1;32m Lua文件编译成功 \e[0m"
    else
        echo -e "\e[1;31m Lua文件编译失败，检查/root/cdninstall/pkg/compile_lua.sh \e[0m"
        exit 1
    fi
}

# ----------------------------------------Check Service/ 检查节点是否能够正常使用----------------------------------------
function check_service() {
    curl -sSL http://deb.aorta.global/SuperCDN/check_node.sh | bash
}

# ----------------------------------------Main Function / 主函数----------------------------------------
function main() {
    check_os "${1}" "${2}"     # System check / 系统检查
    software_install           # Install required software / 安装必需软件
    disk_init                  # Initialize disk / 初始化磁盘
    hostname_config "${1}"     # Configure hostname / 配置主机名
    firewall_config            # Configure firewall / 配置防火墙
    NetworkYH                  # Configure network and time / 配置网络和时间
    kernel_optimize            # Optimize kernel parameters / 优化内核参数
    salt_install "${1}" "${2}" # Install salt / 安装salt
    young_agent_install "${1}" # Young Agent Installation / Young Agent 安装
    openresty_install          # OpenResty Installation / OpenResty 安装
    redis_config               # Redis Configuration / Redis 配置
    logstash_install           # Logstash Installation / Logstash 安装
    logstash_exporter_install  # Logstash-exporter Installation / Logstash-exporter 安装
    log_rotate                 # Log Cleanup Configuration / 日志清理配置
#    compile_lua                # Compile Lua files to LuaJIT bytecode / 编译Lua文件为LuaJIT字节码
    check_service              # Check Service / 检查节点各项服务是否达标
}

main "${1}" "${2}"
echo ""
[[ $? -eq 0 ]] && echo -e "\e[1;32m cdninstall 组件全部部署成功 \e[0m"
