diff --git a/src/metric/client-plugins/all-in-one/config/dns.conf.example b/src/metric/client-plugins/all-in-one/config/dns.conf.example new file mode 100644 index 0000000..73b77bb --- /dev/null +++ b/src/metric/client-plugins/all-in-one/config/dns.conf.example @@ -0,0 +1 @@ +177.177.17.106 diff --git a/src/metric/client-plugins/all-in-one/scripts/check_version.sh b/src/metric/client-plugins/all-in-one/scripts/check_version.sh new file mode 100755 index 0000000..fce49f3 --- /dev/null +++ b/src/metric/client-plugins/all-in-one/scripts/check_version.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +# 版本校验脚本 +# 比较本地 LATEST_VERSION 与 FTP 的 VERSION 版本,如果不一致则更新对应版本 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 - 输出到 stderr 避免影响函数返回值 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" >&2 +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" >&2 +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" >&2 +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 动态获取当前版本目录 +get_current_version_dir() { + # 查找 /opt/argus-metric/versions/ 下的最新版本目录 + local versions_dir="/opt/argus-metric/versions" + if [[ -d "$versions_dir" ]]; then + # 按版本号排序,获取最新的版本目录 + local latest_version_dir=$(ls -1 "$versions_dir" 2>/dev/null | sort -V | tail -1) + if [[ -n "$latest_version_dir" ]]; then + echo "$versions_dir/$latest_version_dir" + else + echo "/opt/argus-metric" + fi + else + echo "/opt/argus-metric" + fi +} + +# 获取当前版本目录 +CURRENT_VERSION_DIR=$(get_current_version_dir) +# LATEST_VERSION 文件在根目录 +LOCAL_VERSION_FILE="/opt/argus-metric/LATEST_VERSION" +REMOTE_VERSION_URL="" +LOG_FILE="$CURRENT_VERSION_DIR/.version_check.log" + +# 从环境变量或配置文件获取 FTP 服务器信息 +get_ftp_config() { + # 优先从环境变量获取配置 + log_info "获取 FTP 配置信息..." + + # 如果环境变量中没有设置,则尝试从配置文件读取 + if [[ -z "$FTP_SERVER" || -z "$FTP_USER" || -z "$FTP_PASSWORD" ]]; then + local config_file="$SCRIPT_DIR/../config/config.env" + if [[ -f "$config_file" ]]; then + log_info "从配置文件读取 FTP 配置: $config_file" + source "$config_file" + fi + else + log_info "使用环境变量中的 FTP 配置" + fi + + # 设置默认值(如果环境变量和配置文件都没有设置) + FTP_SERVER="${FTP_SERVER:-localhost}" + FTP_USER="${FTP_USER:-ftpuser}" + FTP_PASSWORD="${FTP_PASSWORD:-ZGClab1234!}" + + # 构建远程版本文件 URL + REMOTE_VERSION_URL="ftp://${FTP_USER}:${FTP_PASSWORD}@${FTP_SERVER}/LATEST_VERSION" + + log_info "FTP 配置来源: ${FTP_CONFIG_SOURCE:-环境变量/配置文件}" +} + +# 获取远程版本号 +get_remote_version() { + log_info "从 FTP 服务器获取远程版本号..." + log_info "远程地址: $REMOTE_VERSION_URL" + + # 先测试 FTP 连接 + log_info "测试 FTP 连接..." + if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/" >/dev/null 2>&1; then + log_success "FTP 服务器连接成功" + else + log_error "无法连接到 FTP 服务器: $FTP_SERVER" + return 1 + fi + + # 测试 LATEST_VERSION 文件是否存在 + log_info "检查远程 LATEST_VERSION 文件是否存在..." + if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/LATEST_VERSION" >/dev/null 2>&1; then + log_success "远程 LATEST_VERSION 文件存在" + else + log_error "远程 LATEST_VERSION 文件不存在或无法访问" + return 1 + fi + + # 获取远程版本号 + local remote_version + if remote_version=$(curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfL "ftp://${FTP_SERVER}/LATEST_VERSION" 2>/dev/null | tr -d '[:space:]'); then + if [[ -n "$remote_version" ]]; then + log_success "获取到远程版本号: $remote_version" + echo "$remote_version" + else + log_error "远程版本号为空" + return 1 + fi + else + log_error "获取远程版本号失败" + return 1 + fi +} + +# 获取本地版本号 +get_local_version() { + if [[ -f "$LOCAL_VERSION_FILE" ]]; then + local local_version=$(cat "$LOCAL_VERSION_FILE" 2>/dev/null | tr -d '[:space:]') + if [[ -n "$local_version" ]]; then + log_info "本地版本号: $local_version" + echo "$local_version" + else + log_warning "本地版本文件为空" + echo "" + fi + else + log_warning "本地版本文件不存在: $LOCAL_VERSION_FILE" + echo "" + fi +} + +# 更新到新版本 +update_to_version() { + local new_version="$1" + local temp_dir="/tmp/argus-update-$$" + local setup_script="$temp_dir/setup.sh" + + log_info "开始更新到版本: $new_version" + + # 创建临时目录 + mkdir -p "$temp_dir" + + # 下载最新的 setup.sh + log_info "从 FTP 服务器下载最新的安装脚本..." + local setup_url="ftp://${FTP_USER}:${FTP_PASSWORD}@${FTP_SERVER}/setup.sh" + + if curl -fsS "$setup_url" -o "$setup_script"; then + log_success "安装脚本下载完成" + else + log_error "下载安装脚本失败: $setup_url" + rm -rf "$temp_dir" + return 1 + fi + + # 添加执行权限 + chmod +x "$setup_script" + + # 执行安装脚本 + log_info "执行安装脚本进行版本更新..." + if "$setup_script" --server "$FTP_SERVER" --user "$FTP_USER" --password "$FTP_PASSWORD" --version "$new_version"; then + log_success "版本更新完成: $new_version" + rm -rf "$temp_dir" + return 0 + else + log_error "版本更新失败: $new_version" + rm -rf "$temp_dir" + return 1 + fi +} + +# 记录检查日志 +log_check() { + local message="$1" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] $message" >> "$LOG_FILE" +} + +# 主函数 +main() { + log_info "开始版本校验检查..." + log_check "版本校验检查开始" + + # 确保系统目录存在 + mkdir -p "/opt/argus-metric" + mkdir -p "$CURRENT_VERSION_DIR" + + log_info "当前版本目录: $CURRENT_VERSION_DIR" + + # 获取 FTP 配置 + get_ftp_config + + # 获取本地版本号 + local local_version + local_version=$(get_local_version) + + # 获取远程版本号 + local remote_version + if ! remote_version=$(get_remote_version); then + log_error "无法获取远程版本号,跳过本次检查" + log_check "版本校验失败:无法获取远程版本号" + exit 1 + fi + + # 比较版本号 + if [[ "$local_version" == "$remote_version" ]]; then + log_info "版本一致,无需更新 (本地: $local_version, 远程: $remote_version)" + log_check "版本校验完成:版本一致 ($local_version)" + else + log_info "检测到版本不一致 (本地: $local_version, 远程: $remote_version)" + log_check "检测到版本不一致:本地($local_version) -> 远程($remote_version)" + + # 更新到新版本 + if update_to_version "$remote_version"; then + log_success "版本更新成功: $local_version -> $remote_version" + log_check "版本更新成功:$local_version -> $remote_version" + else + log_error "版本更新失败" + log_check "版本更新失败:$local_version -> $remote_version" + exit 1 + fi + fi + + log_success "版本校验检查完成" + log_check "版本校验检查完成" +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/all-in-one/scripts/install_artifact.sh b/src/metric/client-plugins/all-in-one/scripts/install_artifact.sh index b1acd59..acd6757 100755 --- a/src/metric/client-plugins/all-in-one/scripts/install_artifact.sh +++ b/src/metric/client-plugins/all-in-one/scripts/install_artifact.sh @@ -29,6 +29,7 @@ INSTALL_DIR="${1:-$(pwd)}" # 使用第一个参数作为安装目录,如果 TEMP_DIR="/tmp/metrics-install-$$" VERSION_FILE="version.json" + # 加载配置文件 load_config() { local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -51,7 +52,7 @@ copy_config_files() { log_info "复制配置文件到安装目录..." local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - local source_config="$script_dir/config.env" + local source_config="$script_dir/../config/config.env" local target_config="$INSTALL_DIR/config.env" if [[ -f "$source_config" ]]; then @@ -70,6 +71,20 @@ copy_config_files() { else log_warning "源配置文件不存在: $source_config" fi + + # 复制版本校验脚本 + log_info "复制版本校验脚本到安装目录..." + local target_check_version="$INSTALL_DIR/check_version.sh" + + # 检查目标文件是否已存在(从 artifact 包中解压出来的) + if [[ -f "$target_check_version" ]]; then + log_info "版本校验脚本已存在,设置执行权限..." + chmod +x "$target_check_version" + log_success "版本校验脚本权限设置完成: $target_check_version" + else + log_warning "版本校验脚本不存在: $target_check_version" + log_info "请确保 check_version.sh 已包含在 artifact 包中" + fi } check_root() { @@ -482,7 +497,7 @@ install_components() { # 执行安装脚本 if [[ -f "$extracted_dir/install.sh" ]]; then log_info " 执行 $component 安装脚本..." - if (cd "$extracted_dir" && ./install.sh); then + if (cd "$extracted_dir" && ./install.sh "$INSTALL_DIR"); then log_success " $component 安装完成" else log_error " $component 安装失败" @@ -545,7 +560,7 @@ EOF # 根据组件名查找进程,使用多种方法确保能找到PID case "$component" in "node-exporter") - # 查找node_exporter进程 + # 尝试多种方式查找node_exporter进程 component_pid=$(pgrep -f "node_exporter" | head -1) if [[ -z "$component_pid" ]]; then component_pid=$(pgrep -f "node-exporter" | head -1) @@ -574,6 +589,13 @@ EOF component_pid=$(ps aux | grep -v grep | grep "fluent-bit" | awk '{print $2}' | head -1) fi ;; + "argus-agent") + # 查找argus-agent进程 + component_pid=$(pgrep -f "argus-agent" | head -1) + if [[ -z "$component_pid" ]]; then + component_pid=$(ps aux | grep -v grep | grep "argus-agent" | awk '{print $2}' | head -1) + fi + ;; esac # 记录找到的PID信息 @@ -665,6 +687,116 @@ setup_health_check_cron() { log_info "健康检查通过crontab自动执行" } +# 设置 DNS 同步定时任务 +setup_dns_sync_cron() { + log_info "设置 DNS 同步定时任务..." + + # 使用当前版本目录中的 DNS 同步脚本 + local sync_dns_script="$INSTALL_DIR/sync_dns.sh" + + # 检查 DNS 同步脚本是否存在 + if [[ ! -f "$sync_dns_script" ]]; then + log_warning "DNS 同步脚本不存在: $sync_dns_script" + log_warning "跳过 DNS 同步定时任务设置" + return 0 + fi + + # 确保脚本有执行权限 + chmod +x "$sync_dns_script" + + # 创建临时crontab文件 + local temp_cron="/tmp/crontab_$$" + + # 获取当前用户的crontab(如果存在) + crontab -l 2>/dev/null > "$temp_cron" || touch "$temp_cron" + + # 检查并删除旧的 DNS 同步任务 + if grep -q "sync_dns.sh" "$temp_cron"; then + log_info "发现旧的 DNS 同步定时任务,正在更新..." + # 删除所有包含sync_dns.sh的行 + grep -v "sync_dns.sh" "$temp_cron" > "$temp_cron.new" + mv "$temp_cron.new" "$temp_cron" + log_info "旧的 DNS 同步定时任务已删除" + fi + + # 添加新的定时任务(每30秒执行一次) + # 直接使用版本目录中的 DNS 同步脚本 + echo "# Argus-Metrics DNS 同步定时任务" >> "$temp_cron" + echo "* * * * * $sync_dns_script >> $INSTALL_DIR/.dns_sync.log 2>&1" >> "$temp_cron" + echo "* * * * * sleep 30; $sync_dns_script >> $INSTALL_DIR/.dns_sync.log 2>&1" >> "$temp_cron" + + # 安装新的crontab + if crontab "$temp_cron"; then + log_success "DNS 同步定时任务设置成功" + log_info " 执行频率: 每30秒" + log_info " 日志文件: $INSTALL_DIR/.dns_sync.log" + log_info " 查看定时任务: crontab -l" + log_info " 删除定时任务: crontab -e" + else + log_error "DNS 同步定时任务设置失败" + rm -f "$temp_cron" + return 1 + fi + + # 清理临时文件 + rm -f "$temp_cron" + + log_info "DNS 同步通过crontab自动执行" +} + +# 设置版本校验定时任务 +setup_version_check_cron() { + log_info "设置版本校验定时任务..." + + # 使用当前版本目录中的版本校验脚本 + local check_version_script="$INSTALL_DIR/check_version.sh" + + # 检查脚本是否存在 + if [[ ! -f "$check_version_script" ]]; then + log_warning "版本校验脚本不存在: $check_version_script" + log_info "跳过版本校验定时任务设置" + return 0 + fi + + # 确保脚本可执行 + chmod +x "$check_version_script" + + # 创建临时crontab文件 + local temp_cron="/tmp/crontab_$$" + crontab -l > "$temp_cron" 2>/dev/null || touch "$temp_cron" + + # 检查是否已存在版本校验定时任务 + if grep -q "check_version.sh" "$temp_cron"; then + log_info "发现旧的版本校验定时任务,正在更新..." + # 删除所有包含check_version.sh的行 + grep -v "check_version.sh" "$temp_cron" > "$temp_cron.new" + mv "$temp_cron.new" "$temp_cron" + log_info "旧的版本校验定时任务已删除" + fi + + # 添加新的定时任务(每30分钟执行一次) + echo "# Argus-Metrics 版本校验定时任务" >> "$temp_cron" + echo "*/1 * * * * $check_version_script >> $INSTALL_DIR/.version_check.log 2>&1" >> "$temp_cron" + + # 安装新的crontab + if crontab "$temp_cron"; then + log_success "版本校验定时任务设置成功" + log_info " 执行频率: 每1分钟" + log_info " 日志文件: $INSTALL_DIR/.version_check.log" + log_info " 查看定时任务: crontab -l" + log_info " 删除定时任务: crontab -e" + else + log_error "版本校验定时任务设置失败" + rm -f "$temp_cron" + return 1 + fi + + # 清理临时文件 + rm -f "$temp_cron" + + log_info "版本校验通过crontab自动执行" +} + # 显示安装信息 show_install_info() { log_success "Argus-Metrics All-in-One 安装完成!" @@ -702,6 +834,8 @@ main() { copy_config_files create_install_record setup_health_check_cron + setup_dns_sync_cron + setup_version_check_cron show_install_info } diff --git a/src/metric/client-plugins/all-in-one/scripts/package_artifact.sh b/src/metric/client-plugins/all-in-one/scripts/package_artifact.sh index 6783b8e..bf25a82 100755 --- a/src/metric/client-plugins/all-in-one/scripts/package_artifact.sh +++ b/src/metric/client-plugins/all-in-one/scripts/package_artifact.sh @@ -396,6 +396,26 @@ else log_warning "scripts/check_health.sh 文件不存在" fi +# 复制`DNS 同步`脚本到 artifact 目录 +log_info "复制 DNS 同步脚本..." +if [[ -f "scripts/sync_dns.sh" ]]; then + cp "scripts/sync_dns.sh" "$ARTIFACT_DIR/sync_dns.sh" + chmod +x "$ARTIFACT_DIR/sync_dns.sh" + log_success "DNS 同步脚本复制完成: $ARTIFACT_DIR/sync_dns.sh" +else + log_warning "scripts/sync_dns.sh 文件不存在" +fi + +# 复制`版本校验`脚本到 artifact 目录 +log_info "复制版本校验脚本..." +if [[ -f "scripts/check_version.sh" ]]; then + cp "scripts/check_version.sh" "$ARTIFACT_DIR/check_version.sh" + chmod +x "$ARTIFACT_DIR/check_version.sh" + log_success "版本校验脚本复制完成: $ARTIFACT_DIR/check_version.sh" +else + log_warning "scripts/check_version.sh 文件不存在" +fi + # 复制配置文件到 artifact 目录 log_info "复制配置文件..." if [[ -f "config/config.env" ]]; then @@ -405,6 +425,8 @@ else log_warning "config 目录不存在,跳过配置文件复制" fi +# DNS 配置文件不需要复制到版本目录,直接从 FTP 服务器根目录获取 + # 复制 deps 目录到 artifact 目录 log_info "复制系统依赖包..." if [[ -d "deps" ]]; then diff --git a/src/metric/client-plugins/all-in-one/scripts/publish_artifact.sh b/src/metric/client-plugins/all-in-one/scripts/publish_artifact.sh index 0a36cd6..95a92aa 100755 --- a/src/metric/client-plugins/all-in-one/scripts/publish_artifact.sh +++ b/src/metric/client-plugins/all-in-one/scripts/publish_artifact.sh @@ -6,6 +6,7 @@ set -e GREEN='\033[0;32m' BLUE='\033[0;34m' RED='\033[0;31m' +YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { @@ -16,6 +17,10 @@ log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + log_error() { echo -e "${RED}[ERROR]${NC} $1" } @@ -93,6 +98,28 @@ else log_warning "未找到 check_health.sh 文件" fi +# 复制 DNS 同步脚本 +if [[ -f "$ARTIFACT_DIR/sync_dns.sh" ]]; then + log_info "复制 DNS 同步脚本..." + cp "$ARTIFACT_DIR/sync_dns.sh" "$TEMP_PACKAGE_DIR/" +elif [[ -f "scripts/sync_dns.sh" ]]; then + log_info "复制 DNS 同步脚本 (从当前目录)..." + cp "scripts/sync_dns.sh" "$TEMP_PACKAGE_DIR/" +else + log_warning "未找到 sync_dns.sh 文件" +fi + +# 复制版本校验脚本 +if [[ -f "$ARTIFACT_DIR/check_version.sh" ]]; then + log_info "复制版本校验脚本..." + cp "$ARTIFACT_DIR/check_version.sh" "$TEMP_PACKAGE_DIR/" +elif [[ -f "scripts/check_version.sh" ]]; then + log_info "复制版本校验脚本 (从当前目录)..." + cp "scripts/check_version.sh" "$TEMP_PACKAGE_DIR/" +else + log_warning "未找到 check_version.sh 文件" +fi + # 复制安装脚本并重命名为 install.sh if [[ -f "scripts/install_artifact.sh" ]]; then log_info "复制安装脚本..." @@ -113,6 +140,8 @@ else log_warning "未找到 config.env 文件" fi +# DNS 配置文件将在后面直接复制到发布目录根目录,不包含在 tar.gz 中 + # 复制 deps 目录 if [[ -d "$ARTIFACT_DIR/deps" ]]; then log_info "复制系统依赖包..." @@ -134,6 +163,15 @@ rm -rf "$TEMP_PACKAGE_DIR" log_info "更新 LATEST_VERSION 文件..." echo "$VERSION" > "$PUBLISH_DIR/LATEST_VERSION" +# 复制 DNS 配置文件到发布目录根目录(直接从 config 目录复制) +if [[ -f "config/dns.conf" ]]; then + log_info "复制 DNS 配置文件到发布目录根目录..." + cp "config/dns.conf" "$PUBLISH_DIR/" + log_success "DNS 配置文件复制完成: $PUBLISH_DIR/dns.conf" +else + log_warning "未找到 config/dns.conf 文件,跳过 DNS 配置文件复制" +fi + # 复制 setup.sh 到发布目录 if [[ -f "scripts/setup.sh" ]]; then log_info "复制 setup.sh 到发布目录..." diff --git a/src/metric/client-plugins/all-in-one/scripts/setup.sh b/src/metric/client-plugins/all-in-one/scripts/setup.sh index dc95d7d..ad7e0d2 100755 --- a/src/metric/client-plugins/all-in-one/scripts/setup.sh +++ b/src/metric/client-plugins/all-in-one/scripts/setup.sh @@ -296,6 +296,24 @@ update_latest_version_file() { fi } +# 初始化 DNS 配置文件到系统目录 +init_dns_config_to_system() { + log_info "初始化 DNS 配置文件到系统目录..." + + # 系统 DNS 配置文件 + local system_dns_conf="$INSTALL_DIR/dns.conf" + + # 如果系统目录中还没有 dns.conf,创建一个空的占位文件 + if [[ ! -f "$system_dns_conf" ]]; then + touch "$system_dns_conf" + chmod 644 "$system_dns_conf" + log_success "DNS 配置文件占位文件已创建: $system_dns_conf" + log_info "DNS 同步脚本将从 FTP 服务器下载实际的 DNS 配置" + else + log_info "DNS 配置文件已存在: $system_dns_conf" + fi +} + # 备份当前版本 backup_current_version() { local current_version=$(get_current_version) @@ -347,12 +365,23 @@ rollback_to_backup() { # 停止当前服务 stop_services - # 恢复软链接(备份目录应该包含版本内容) - if ln -sfn "$backup_path" "$CURRENT_LINK"; then + # 检查是否存在对应的版本目录 + local version_dir="$VERSIONS_DIR/$backup_name" + + if [[ ! -d "$version_dir" ]]; then + log_info "版本目录不存在,从备份恢复版本目录: $version_dir" + # 从备份目录恢复到版本目录 + mkdir -p "$VERSIONS_DIR" + cp -r "$backup_path" "$version_dir" + fi + + # 恢复软链接指向版本目录 + if ln -sfn "$version_dir" "$CURRENT_LINK"; then log_success "版本回滚完成: $backup_name" - # 启动服务 - # start_services + # 更新LATEST_VERSION文件 + update_latest_version_file "$backup_name" + return 0 else log_error "版本回滚失败" @@ -509,7 +538,8 @@ install_argus_metric() { log_info "开始安装 Argus Metric v$ARGUS_VERSION..." log_info "安装目录: $INSTALL_DIR" - + + # 创建安装目录结构(必须先创建,以便备份时目录存在) create_install_directories # 检查是否已安装 @@ -518,7 +548,7 @@ install_argus_metric() { local current_version=$(get_current_version) if [[ "$current_version" == "$ARGUS_VERSION" ]]; then if [[ "$FORCE_INSTALL" == true ]]; then - log_info "检测到相同版本 v$ARGUS_VERSION,使用了 --force 参数,可强制重新安装" + log_info "检测到相同版本 v$ARGUS_VERSION,但使用了 --force 参数,将强制重新安装" is_upgrade=true # 备份当前版本 backup_current_version @@ -661,6 +691,9 @@ install_argus_metric() { # 更新LATEST_VERSION文件 update_latest_version_file "$ARGUS_VERSION" + # 初始化 DNS 配置文件到系统目录 + init_dns_config_to_system + # 启动服务 # start_services diff --git a/src/metric/client-plugins/all-in-one/scripts/sync_dns.sh b/src/metric/client-plugins/all-in-one/scripts/sync_dns.sh new file mode 100755 index 0000000..9e05f24 --- /dev/null +++ b/src/metric/client-plugins/all-in-one/scripts/sync_dns.sh @@ -0,0 +1,244 @@ +#!/bin/bash + +# DNS 同步脚本 +# 比较 FTP 根目录的 dns.conf 和本地的 dns.conf,如果有变化则同步到 /etc/resolv.conf + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 - 输出到 stderr 避免影响函数返回值 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" >&2 +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" >&2 +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" >&2 +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOCAL_DNS_CONF="/opt/argus-metric/dns.conf" +REMOTE_DNS_CONF_URL="" +RESOLV_CONF="/etc/resolv.conf" +LOG_FILE="/opt/argus-metric/.dns_sync.log" + +# 从环境变量或配置文件获取 FTP 服务器信息 +get_ftp_config() { + # 优先从环境变量获取配置 + log_info "获取 FTP 配置信息..." + + # 如果环境变量中没有设置,则尝试从配置文件读取 + if [[ -z "$FTP_SERVER" || -z "$FTP_USER" || -z "$FTP_PASSWORD" ]]; then + local config_file="$SCRIPT_DIR/config.env" + if [[ -f "$config_file" ]]; then + log_info "从配置文件读取 FTP 配置: $config_file" + source "$config_file" + fi + else + log_info "使用环境变量中的 FTP 配置" + fi + + # 设置默认值(如果环境变量和配置文件都没有设置) + FTP_SERVER="${FTP_SERVER:-localhost}" + FTP_USER="${FTP_USER:-ftpuser}" + FTP_PASSWORD="${FTP_PASSWORD:-ZGClab1234!}" + + # 构建远程 DNS 配置文件 URL + REMOTE_DNS_CONF_URL="ftp://${FTP_USER}:${FTP_PASSWORD}@${FTP_SERVER}/dns.conf" + + log_info "FTP 配置来源: ${FTP_CONFIG_SOURCE:-环境变量/配置文件}" +} + +# 下载远程 DNS 配置文件 +download_remote_dns_conf() { + local temp_file="/tmp/dns.conf.remote.$$" + + log_info "从 FTP 服务器下载 DNS 配置文件..." + log_info "远程地址: $REMOTE_DNS_CONF_URL" + log_info "FTP 服务器: $FTP_SERVER" + log_info "FTP 用户: $FTP_USER" + + # 先测试 FTP 连接 + log_info "测试 FTP 连接..." + if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/" >/dev/null 2>&1; then + log_success "FTP 服务器连接成功" + else + log_error "无法连接到 FTP 服务器: $FTP_SERVER" + log_error "请检查:" + log_error " 1. FTP 服务器是否运行" + log_error " 2. 网络连接是否正常" + log_error " 3. 服务器地址是否正确" + return 1 + fi + + # 测试 dns.conf 文件是否存在 + log_info "检查远程 dns.conf 文件是否存在..." + if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/dns.conf" >/dev/null 2>&1; then + log_success "远程 dns.conf 文件存在" + else + log_error "远程 dns.conf 文件不存在或无法访问" + log_error "请检查 FTP 服务器根目录下是否有 dns.conf 文件" + return 1 + fi + + # 尝试下载文件 + log_info "开始下载 dns.conf 文件..." + if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sf "ftp://${FTP_SERVER}/dns.conf" -o "$temp_file" 2>/dev/null; then + log_success "远程 DNS 配置文件下载成功" + echo "$temp_file" + else + log_error "下载 dns.conf 文件失败" + log_error "尝试手动测试命令:" + log_error " curl -u ${FTP_USER}:${FTP_PASSWORD} ftp://${FTP_SERVER}/dns.conf" + rm -f "$temp_file" + return 1 + fi +} + +# 比较两个文件是否相同 +compare_files() { + local file1="$1" + local file2="$2" + + if [[ ! -f "$file1" || ! -f "$file2" ]]; then + return 1 + fi + + # 使用 diff 比较文件内容 + if diff -q "$file1" "$file2" >/dev/null 2>&1; then + return 0 # 文件相同 + else + return 1 # 文件不同 + fi +} + +# 将 DNS 配置追加到 /etc/resolv.conf +update_resolv_conf() { + local dns_conf_file="$1" + + log_info "更新 /etc/resolv.conf 文件..." + + # 备份原始文件 + if [[ -f "$RESOLV_CONF" ]]; then + cp "$RESOLV_CONF" "${RESOLV_CONF}.backup.$(date +%Y%m%d_%H%M%S)" + log_info "已备份原始 resolv.conf 文件" + fi + + # 读取 DNS 配置文件并追加到 resolv.conf + while IFS= read -r line; do + # 跳过空行和注释行 + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + # 验证是否为有效的 IP 地址 + if [[ "$line" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + # 检查是否已存在相同的 nameserver 行 + if ! grep -q "nameserver $line" "$RESOLV_CONF" 2>/dev/null; then + echo "nameserver $line" >> "$RESOLV_CONF" + log_info "添加 DNS 服务器: $line" + else + log_info "DNS 服务器已存在,跳过: $line" + fi + else + log_warning "跳过无效的 DNS 地址: $line" + fi + done < "$dns_conf_file" + + # 设置文件权限 + chmod 644 "$RESOLV_CONF" + + log_success "/etc/resolv.conf 文件更新完成" +} + +# 记录同步日志 +log_sync() { + local message="$1" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] $message" >> "$LOG_FILE" +} + +# 主函数 +main() { + log_info "开始 DNS 同步检查..." + log_sync "DNS 同步检查开始" + + # 确保系统目录存在 + mkdir -p "/opt/argus-metric" + + # 获取 FTP 配置 + get_ftp_config + + # 检查本地 DNS 配置文件是否存在 + if [[ ! -f "$LOCAL_DNS_CONF" ]]; then + log_warning "本地 DNS 配置文件不存在: $LOCAL_DNS_CONF" + log_warning "将下载远程配置文件并更新系统 DNS 设置" + + # 下载远程配置文件 + if remote_file=$(download_remote_dns_conf); then + # 复制到本地 + cp "$remote_file" "$LOCAL_DNS_CONF" + log_success "远程 DNS 配置文件已保存到本地" + + # 更新 resolv.conf + update_resolv_conf "$LOCAL_DNS_CONF" + log_sync "首次同步完成,DNS 配置已更新" + + # 清理临时文件 + rm -f "$remote_file" + else + log_error "无法下载远程 DNS 配置文件,同步失败" + log_sync "同步失败:无法下载远程配置文件" + exit 1 + fi + else + log_info "本地 DNS 配置文件存在: $LOCAL_DNS_CONF" + + # 下载远程配置文件进行比较 + if remote_file=$(download_remote_dns_conf); then + # 比较文件 + if compare_files "$LOCAL_DNS_CONF" "$remote_file"; then + log_info "DNS 配置文件无变化,无需更新" + log_sync "DNS 配置文件无变化" + else + log_info "检测到 DNS 配置文件有变化,开始同步..." + log_sync "检测到 DNS 配置文件变化,开始同步" + + # 更新本地配置文件 + cp "$remote_file" "$LOCAL_DNS_CONF" + log_success "本地 DNS 配置文件已更新" + + # 更新 resolv.conf + update_resolv_conf "$LOCAL_DNS_CONF" + log_sync "DNS 配置同步完成" + fi + + # 清理临时文件 + rm -f "$remote_file" + else + log_error "无法下载远程 DNS 配置文件,跳过本次同步" + log_sync "同步失败:无法下载远程配置文件" + exit 1 + fi + fi + + log_success "DNS 同步检查完成" + log_sync "DNS 同步检查完成" +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi