diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/src/metric/.gitignore b/src/metric/.gitignore new file mode 100644 index 0000000..09d33d4 --- /dev/null +++ b/src/metric/.gitignore @@ -0,0 +1,7 @@ +/prometheus/data/ +/client-plugins/dcgm-exporter-installer/ +/client-plugins/node-exporter-installer/ +/client-plugins/demo-all-in-one/artifact/ +/client-plugins/demo-all-in-one/publish/ +/client-plugins/demo-all-in-one/checklist +/client-plugins/demo-all-in-one/VERSION diff --git a/src/metric/client-plugins/demo-all-in-one/.VERSION.example b/src/metric/client-plugins/demo-all-in-one/.VERSION.example new file mode 100644 index 0000000..5e57fb8 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/.VERSION.example @@ -0,0 +1 @@ +1.29.0 diff --git a/src/metric/client-plugins/demo-all-in-one/.checklist.example b/src/metric/client-plugins/demo-all-in-one/.checklist.example new file mode 100644 index 0000000..89cf322 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/.checklist.example @@ -0,0 +1,3 @@ +# 组件名称 目录路径 版本号 [依赖组件] [安装顺序] +dcgm-exporter-installer /Users/sundapeng/Project/nlp/aiops/client-plugins/dcgm-exporter-installer 1.1.0 +node-exporter-installer /Users/sundapeng/Project/nlp/aiops/client-plugins/node-exporter-installer 1.1.0 diff --git a/src/metric/client-plugins/demo-all-in-one/README.md b/src/metric/client-plugins/demo-all-in-one/README.md new file mode 100644 index 0000000..67808a8 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/README.md @@ -0,0 +1,57 @@ +# 客户侧组件安装包构建、发布流程 + +## 第一步:配置版本和组件 + +首先搞定配置文件: + +1. 把 `.checklist.example` 重命名成 `checklist` +2. 把 `.VERSION.example` 重命名成 `VERSION` + +### checklist 文件格式 +``` +# 组件名称 目录路径 版本号 [依赖组件] [安装顺序] +dcgm-exporter-installer /path/to/dcgm-exporter-installer 1.1.0 +node-exporter-installer /path/to/node-exporter-installer 1.1.0 +``` + +### VERSION 文件 +设置需要发布的版本号,比如 `1.29.0` + +> 建议用 `version-manager.sh` 来管理版本 + +## 第二步:构建安装包 + +直接跑脚本: +```bash +./package_artifact.sh +``` + +构建完的东西会放在 `artifact/` 目录下,按版本分文件夹。 + +如果版本已经存在了,想要覆盖重新构建: +```bash +./package_artifact.sh --force +``` + +构建完可以手工测试安装包。 + +## 第三步:发布安装包 + +用这个脚本发布: +```bash +./publish_artifact.sh +``` + +发布后的内容在 `publish/` 目录里,包含: +- 压缩版本的安装包 +- 一键安装的bash脚本 + +## 第四步:部署到FTP服务器 + +把发布的内容上传到FTP服务器,客户端就可以通过一键命令安装: + +```bash +curl -fsSL http://your-ftp-server/install.sh | sh - +``` + +这样客户就能直接从FTP服务器下载并安装组件了。 \ No newline at end of file diff --git a/src/metric/client-plugins/demo-all-in-one/check_health.sh b/src/metric/client-plugins/demo-all-in-one/check_health.sh new file mode 100755 index 0000000..527b2a0 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/check_health.sh @@ -0,0 +1,204 @@ +#!/bin/bash + +# 整体健康检查脚本,调用各个组件的健康检查并将结果写入 .health_log 文件 + +set -e + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HEALTH_LOG_FILE="$SCRIPT_DIR/.health_log" +INSTALL_RECORD_FILE="$SCRIPT_DIR/.install_record" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 - 输出到 stderr 避免影响 JSON 结果 +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 +} + +# 检查单个组件健康状态 +check_component() { + local component_name="$1" + local check_script_path="$2" + + log_info "检查 $component_name 健康状态..." + + if [[ ! -f "$check_script_path" ]]; then + log_error "健康检查脚本不存在: $check_script_path" + echo "{\"name\": \"$component_name\", \"status\": \"unhealth\", \"reason\": \"健康检查脚本不存在: $check_script_path\"}" + return 1 + fi + + if [[ ! -x "$check_script_path" ]]; then + log_error "健康检查脚本无执行权限: $check_script_path" + echo "{\"name\": \"$component_name\", \"status\": \"unhealth\", \"reason\": \"健康检查脚本无执行权限: $check_script_path\"}" + return 1 + fi + + # 执行健康检查脚本,只捕获 stdout,stderr 输出到终端 + local result + if result=$("$check_script_path" 2>/dev/null); then + log_success "$component_name 健康检查通过" + echo "$result" + return 0 + else + log_warning "$component_name 健康检查失败" + echo "$result" + return 1 + fi +} + +# 生成时间戳 +get_timestamp() { + date '+%Y-%m-%d %H:%M:%S' +} + +# 从安装记录文件中读取组件安装目录 +read_install_record() { + local install_record_file="$1" + + if [[ ! -f "$install_record_file" ]]; then + log_error "安装记录文件不存在: $install_record_file" + return 1 + fi + + # 检查是否有 jq 命令来解析 JSON + if command -v jq &> /dev/null; then + # 使用 jq 解析 JSON + local components_json + if components_json=$(jq -r '.components | to_entries[] | "\(.key):\(.value.install_dir)"' "$install_record_file" 2>/dev/null); then + echo "$components_json" + return 0 + else + log_error "无法解析安装记录文件 JSON 格式: $install_record_file" + return 1 + fi + else + # 如果没有 jq,尝试简单的文本解析 + log_warning "jq 命令不可用,尝试简单文本解析" + + # 查找所有 install_dir 行 + local components=() + while IFS= read -r line; do + if [[ "$line" =~ \"install_dir\":[[:space:]]*\"([^\"]+)\" ]]; then + local install_dir="${BASH_REMATCH[1]}" + # 从路径中提取组件名称 + local component_name=$(basename "$install_dir") + components+=("$component_name:$install_dir") + fi + done < "$install_record_file" + + if [[ ${#components[@]} -gt 0 ]]; then + printf '%s\n' "${components[@]}" + return 0 + else + log_error "无法从安装记录文件中提取组件信息" + return 1 + fi + fi +} + +# 主函数 +main() { + echo "==========================================" >&2 + echo " 整体健康检查脚本" >&2 + echo "==========================================" >&2 + echo >&2 + + # 记录健康检查开始时间 + local start_time=$(get_timestamp) + log_info "健康检查开始时间: $start_time" + + # 从安装记录文件中读取组件信息 + log_info "从安装记录文件读取组件信息: $INSTALL_RECORD_FILE" + local components_info + if ! components_info=$(read_install_record "$INSTALL_RECORD_FILE"); then + log_error "无法读取安装记录文件,健康检查终止" + exit 1 + fi + + # 存储所有检查结果 + local all_results=() + local overall_status="health" + + # 逐个检查组件 + while IFS= read -r component_info; do + if [[ -n "$component_info" ]]; then + IFS=':' read -r component_name install_dir <<< "$component_info" + local check_script_path="$install_dir/check_health.sh" + + local result + if result=$(check_component "$component_name" "$check_script_path"); then + all_results+=("$result") + else + all_results+=("$result") + overall_status="unhealth" + fi + fi + done <<< "$components_info" + + # 记录健康检查结束时间 + local end_time=$(get_timestamp) + log_info "健康检查结束时间: $end_time" + + # 构建完整的健康检查结果 JSON + local health_check_result=$(cat << EOF +{ + "start_time": "$start_time", + "end_time": "$end_time", + "overall_status": "$overall_status", + "components": [ +$(printf '%s,\n' "${all_results[@]}" | sed '$s/,$//') + ] +} +EOF +) + + # 写入健康日志文件 + log_info "将健康检查结果写入日志文件: $HEALTH_LOG_FILE" + echo "$health_check_result" >> "$HEALTH_LOG_FILE" + + # 输出 JSON 结果到 stdout + echo "$health_check_result" + + # 显示总结到 stderr + echo >&2 + echo "==========================================" >&2 + echo " 健康检查总结" >&2 + echo "==========================================" >&2 + echo "开始时间: $start_time" >&2 + echo "结束时间: $end_time" >&2 + echo "整体状态: $overall_status" >&2 + echo "日志文件: $HEALTH_LOG_FILE" >&2 + echo >&2 + + if [[ "$overall_status" == "health" ]]; then + log_success "所有组件健康检查通过!" + exit 0 + else + log_error "部分组件健康检查失败,请查看上述详细信息" + exit 1 + fi +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/demo-all-in-one/deps/cron-offline.tar.gz b/src/metric/client-plugins/demo-all-in-one/deps/cron-offline.tar.gz new file mode 100644 index 0000000..77104f7 Binary files /dev/null and b/src/metric/client-plugins/demo-all-in-one/deps/cron-offline.tar.gz differ diff --git a/src/metric/client-plugins/demo-all-in-one/install-argus-metric.sh b/src/metric/client-plugins/demo-all-in-one/install-argus-metric.sh new file mode 100644 index 0000000..0e40d9f --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/install-argus-metric.sh @@ -0,0 +1,221 @@ +#!/bin/bash + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 配置变量 +DEFAULT_VERSION="1.20.0" +BASE_URL="https://releases.yourdomain.com/argus-metric" +TEMP_DIR="/tmp/argus-metric-install-$$" + +# 解析参数 +VERSION="$DEFAULT_VERSION" +ACTION="install" + +while [[ $# -gt 0 ]]; do + case $1 in + --version) + VERSION="$2" + shift 2 + ;; + --uninstall) + ACTION="uninstall" + shift + ;; + --help) + echo "Argus Metric 在线安装脚本" + echo + echo "用法: curl -sfL https://install-argus-metric.yourdomain.com | sh -s -- [选项]" + echo + echo "选项:" + echo " --version VERSION 指定版本 (默认: $DEFAULT_VERSION)" + echo " --uninstall 卸载" + echo " --help 显示帮助" + echo + echo "示例:" + echo " curl -sfL https://install-argus-metric.yourdomain.com | sh -" + echo " curl -sfL https://install-argus-metric.yourdomain.com | sh -s -- --version 1.20.0" + echo " curl -sfL https://install-argus-metric.yourdomain.com | sh -s -- --uninstall" + exit 0 + ;; + *) + log_error "未知参数: $1" + echo "使用 --help 查看帮助信息" + exit 1 + ;; + esac +done + +# 清理函数 +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + fi +} + +trap cleanup EXIT + +# 检查是否为 root 用户 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + log_info "请使用: sudo curl -sfL https://install-argus-metric.yourdomain.com | sh -" + exit 1 + fi +} + +# 检查系统要求 +check_system() { + log_info "检查系统要求..." + + # 检查操作系统 + if [[ ! -f /etc/os-release ]]; then + log_error "无法检测操作系统版本" + exit 1 + fi + + source /etc/os-release + log_info "检测到操作系统: $NAME $VERSION" + + # 检查系统架构 + arch=$(uname -m) + log_info "系统架构: $arch" + + # 检查磁盘空间 + available_space=$(df / | awk 'NR==2 {print $4}') + if [[ $available_space -lt 10485760 ]]; then # 10GB in KB + log_warning "可用磁盘空间不足 10GB,当前可用: $(($available_space / 1024 / 1024))GB" + fi +} + +# 下载并安装 +install_argus_metric() { + log_info "开始安装 Argus Metric v$VERSION..." + + # 创建临时目录 + mkdir -p "$TEMP_DIR" + cd "$TEMP_DIR" + + # 下载发布包 + TAR_NAME="argus-metric-$VERSION.tar.gz" + log_info "下载发布包: $TAR_NAME" + if ! curl -sfL "$BASE_URL/$TAR_NAME" -o "$TAR_NAME"; then + log_error "下载发布包失败: $BASE_URL/$TAR_NAME" + exit 1 + fi + + # 解压发布包 + log_info "解压发布包..." + if ! tar -xzf "$TAR_NAME"; then + log_error "解压发布包失败" + exit 1 + fi + + # 进入解压目录 + cd "argus-metric-$VERSION" + + # 执行安装 + log_info "执行安装..." + if [[ -f "install_artifact.sh" ]]; then + chmod +x install_artifact.sh + if ./install_artifact.sh; then + log_success "Argus Metric v$VERSION 安装完成!" + else + log_error "安装失败" + exit 1 + fi + else + log_error "未找到安装脚本 install_artifact.sh" + exit 1 + fi +} + +# 卸载 +uninstall_argus_metric() { + log_info "开始卸载 Argus Metric..." + + # 创建临时目录 + mkdir -p "$TEMP_DIR" + cd "$TEMP_DIR" + + # 下载发布包 + TAR_NAME="argus-metric-$VERSION.tar.gz" + log_info "下载发布包: $TAR_NAME" + if ! curl -sfL "$BASE_URL/$TAR_NAME" -o "$TAR_NAME"; then + log_error "下载发布包失败: $BASE_URL/$TAR_NAME" + exit 1 + fi + + # 解压发布包 + log_info "解压发布包..." + if ! tar -xzf "$TAR_NAME"; then + log_error "解压发布包失败" + exit 1 + fi + + # 进入解压目录 + cd "argus-metric-$VERSION" + + # 执行卸载 + log_info "执行卸载..." + if [[ -f "uninstall_artifact.sh" ]]; then + chmod +x uninstall_artifact.sh + if ./uninstall_artifact.sh; then + log_success "Argus Metric 卸载完成!" + else + log_error "卸载失败" + exit 1 + fi + else + log_error "未找到卸载脚本 uninstall_artifact.sh" + exit 1 + fi +} + +# 主函数 +main() { + echo "==========================================" + echo " Argus Metric 在线安装脚本 v1.0" + echo "==========================================" + echo + + check_root + check_system + + if [[ "$ACTION" == "uninstall" ]]; then + uninstall_argus_metric + else + install_argus_metric + fi + + echo + log_info "操作完成!" +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/demo-all-in-one/install_artifact.sh b/src/metric/client-plugins/demo-all-in-one/install_artifact.sh new file mode 100755 index 0000000..d868bb1 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/install_artifact.sh @@ -0,0 +1,643 @@ +#!/bin/bash + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 配置变量 +INSTALL_DIR="${1:-$(pwd)}" # 使用第一个参数作为安装目录,如果没有参数则使用当前目录 +TEMP_DIR="/tmp/metrics-install-$$" +VERSION_FILE="version.json" + +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + log_info "请使用: sudo $0 [安装目录]" + log_info "如果不指定安装目录,将使用当前目录: $(pwd)" + exit 1 + fi +} + +# 检查系统要求 +check_system() { + log_info "检查系统要求..." + + # 检查操作系统 + if [[ ! -f /etc/os-release ]]; then + log_error "无法检测操作系统版本" + exit 1 + fi + + source /etc/os-release + log_info "检测到操作系统: $NAME $VERSION" + + # 检查系统架构 + arch=$(uname -m) + log_info "系统架构: $arch" + + # 检查磁盘空间 + available_space=$(df / | awk 'NR==2 {print $4}') + if [[ $available_space -lt 10485760 ]]; then # 10GB in KB + log_warning "可用磁盘空间不足 10GB,当前可用: $(($available_space / 1024 / 1024))GB" + fi + + # 检查内存 + total_mem=$(free -m | awk 'NR==2{print $2}') + if [[ $total_mem -lt 4096 ]]; then # 4GB + log_warning "系统内存不足 4GB,当前: ${total_mem}MB" + fi +} + +# 查找版本文件 +find_version_file() { + log_info "查找版本信息文件..." + + # 在当前目录查找 + if [[ -f "$VERSION_FILE" ]]; then + VERSION_FILE_PATH="$VERSION_FILE" + log_success "找到版本文件: $VERSION_FILE" + return 0 + fi + + # 在 artifact 目录查找 + for version_dir in artifact/*/; do + if [[ -f "${version_dir}${VERSION_FILE}" ]]; then + VERSION_FILE_PATH="${version_dir}${VERSION_FILE}" + log_success "找到版本文件: $VERSION_FILE_PATH" + return 0 + fi + done + + log_error "未找到版本信息文件 $VERSION_FILE" + exit 1 +} + +# 解析版本信息 +parse_version_info() { + log_info "解析版本信息..." + + if [[ ! -f "$VERSION_FILE_PATH" ]]; then + log_error "版本文件不存在: $VERSION_FILE_PATH" + exit 1 + fi + + # 使用 jq 解析 JSON(如果可用) + if command -v jq &> /dev/null; then + # 验证JSON文件格式 + if ! jq empty "$VERSION_FILE_PATH" 2>/dev/null; then + log_error "JSON文件格式错误,请检查 $VERSION_FILE_PATH" + exit 1 + fi + + VERSION=$(jq -r '.version' "$VERSION_FILE_PATH") + BUILD_TIME=$(jq -r '.build_time' "$VERSION_FILE_PATH") + + # 解析 artifact_list + if jq -e '.artifact_list' "$VERSION_FILE_PATH" > /dev/null 2>&1; then + jq -r '.artifact_list | to_entries[] | "\(.key):\(.value)"' "$VERSION_FILE_PATH" > "$TEMP_DIR/components.txt" + else + log_error "version.json 中缺少 artifact_list 字段" + exit 1 + fi + + # 解析 checksums + if jq -e '.checksums' "$VERSION_FILE_PATH" > /dev/null 2>&1; then + jq -r '.checksums | to_entries[] | "\(.key):\(.value)"' "$VERSION_FILE_PATH" > "$TEMP_DIR/checksums.txt" + else + log_error "version.json 中缺少 checksums 字段" + exit 1 + fi + + # 解析 install_order(现在包含完整的文件名) + if jq -e '.install_order' "$VERSION_FILE_PATH" > /dev/null 2>&1; then + jq -r '.install_order[]' "$VERSION_FILE_PATH" > "$TEMP_DIR/install_order.txt" + else + log_error "version.json 中缺少 install_order 字段" + exit 1 + fi + + else + log_warning "jq 未安装,使用简单的 JSON 解析" + # 简单的 JSON 解析 + VERSION=$(grep '"version"' "$VERSION_FILE_PATH" | sed 's/.*"version": *"\([^"]*\)".*/\1/') + BUILD_TIME=$(grep '"build_time"' "$VERSION_FILE_PATH" | sed 's/.*"build_time": *"\([^"]*\)".*/\1/') + + # 解析 artifact_list + grep -A 100 '"artifact_list"' "$VERSION_FILE_PATH" | grep -E '^\s*"[^"]+":\s*"[^"]+"' | while read line; do + component=$(echo "$line" | sed 's/.*"\([^"]*\)":\s*"[^"]*".*/\1/') + version=$(echo "$line" | sed 's/.*"[^"]*":\s*"\([^"]*\)".*/\1/') + echo "$component:$version" >> "$TEMP_DIR/components.txt" + done + + # 解析 checksums + grep -A 100 '"checksums"' "$VERSION_FILE_PATH" | grep -E '^\s*"[^"]+":\s*"[^"]+"' | while read line; do + component=$(echo "$line" | sed 's/.*"\([^"]*\)":\s*"[^"]*".*/\1/') + checksum=$(echo "$line" | sed 's/.*"[^"]*":\s*"\([^"]*\)".*/\1/') + echo "$component:$checksum" >> "$TEMP_DIR/checksums.txt" + done + + # 解析 install_order + grep -A 100 '"install_order"' "$VERSION_FILE_PATH" | grep -E '^\s*"[^"]+"' | while read line; do + component=$(echo "$line" | sed 's/.*"\([^"]*\)".*/\1/') + echo "$component" >> "$TEMP_DIR/install_order.txt" + done + + # 验证解析结果 + if [[ ! -f "$TEMP_DIR/components.txt" || ! -s "$TEMP_DIR/components.txt" ]]; then + log_error "无法解析 artifact_list,请检查 version.json 格式" + exit 1 + fi + + if [[ ! -f "$TEMP_DIR/checksums.txt" || ! -s "$TEMP_DIR/checksums.txt" ]]; then + log_error "无法解析 checksums,请检查 version.json 格式" + exit 1 + fi + + if [[ ! -f "$TEMP_DIR/install_order.txt" || ! -s "$TEMP_DIR/install_order.txt" ]]; then + log_error "无法解析 install_order,请检查 version.json 格式" + exit 1 + fi + fi + + log_success "版本信息解析完成" + log_info " 版本: $VERSION" + log_info " 构建时间: $BUILD_TIME" + + component_count=0 + if [[ -f "$TEMP_DIR/components.txt" ]]; then + component_count=$(wc -l < "$TEMP_DIR/components.txt") + log_info " 组件数量: $component_count" + log_info " 组件列表:" + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + version=$(echo "$line" | cut -d':' -f2) + log_info " - $component v$version" + done < "$TEMP_DIR/components.txt" + else + log_error "components.txt 文件不存在" + exit 1 + fi +} + +# 验证文件完整性 +verify_checksums() { + log_info "验证文件完整性..." + + artifact_dir=$(dirname "$VERSION_FILE_PATH") + failed_verification=0 + + if [[ -f "$TEMP_DIR/checksums.txt" ]]; then + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + expected_checksum=$(echo "$line" | cut -d':' -f2-) + + # 查找匹配的 tar 文件 + actual_file="" + for file in "$artifact_dir/${component}-"*.tar.gz; do + if [[ -f "$file" ]]; then + actual_file="$file" + break + fi + done + + if [[ -z "$actual_file" ]]; then + log_error "找不到组件文件: $component" + failed_verification=1 + continue + fi + + # 计算实际校验和 + actual_checksum="sha256:$(sha256sum "$actual_file" | cut -d' ' -f1)" + + if [[ "$actual_checksum" == "$expected_checksum" ]]; then + log_success " $component: 校验通过" + else + log_error " $component: 校验失败" + log_error " 期望: $expected_checksum" + log_error " 实际: $actual_checksum" + failed_verification=1 + fi + done < "$TEMP_DIR/checksums.txt" + fi + + if [[ $failed_verification -eq 1 ]]; then + log_error "文件完整性验证失败" + exit 1 + fi + + log_success "所有文件校验通过" +} + +# 创建安装目录 +create_install_dirs() { + log_info "创建安装目录..." + + mkdir -p "$INSTALL_DIR" + mkdir -p "$TEMP_DIR" + + log_success "安装目录创建完成: $INSTALL_DIR" +} + +# 安装系统依赖包 +install_system_deps() { + log_info "检查系统依赖包..." + + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local deps_dir="$script_dir/deps" + + # 检查deps目录是否存在 + if [[ ! -d "$deps_dir" ]]; then + log_info "deps 目录不存在,跳过系统依赖包安装" + return 0 + fi + + # 检查是否有tar.gz文件 + local deps_count=$(find "$deps_dir" -name "*.tar.gz" | wc -l) + if [[ $deps_count -eq 0 ]]; then + log_info "deps 目录中没有 tar.gz 文件,跳过系统依赖包安装" + return 0 + fi + + log_info "找到 $deps_count 个系统依赖包,开始安装..." + + # 创建临时目录用于解压依赖包 + local deps_temp_dir="$TEMP_DIR/deps" + mkdir -p "$deps_temp_dir" + + # 处理每个tar.gz文件 + find "$deps_dir" -name "*.tar.gz" | while read tar_file; do + local tar_basename=$(basename "$tar_file") + local extract_name="${tar_basename%.tar.gz}" + + log_info "处理依赖包: $tar_basename" + + # 解压到临时目录 + local extract_dir="$deps_temp_dir/$extract_name" + mkdir -p "$extract_dir" + + if tar -xzf "$tar_file" -C "$extract_dir"; then + log_success " $tar_basename 解压完成" + else + log_error " $tar_basename 解压失败" + continue + fi + + # 进入解压目录,查找deb包 + cd "$extract_dir" + local deb_count=$(find . -name "*.deb" | wc -l) + + if [[ $deb_count -gt 0 ]]; then + log_info " 找到 $deb_count 个 deb 包,开始安装..." + + # 1. 先尝试安装所有deb包 + log_info " 第1步:批量安装deb包..." + if dpkg -i *.deb 2>/dev/null; then + log_success " 所有deb包安装成功" + else + log_warning " 部分deb包安装失败,可能存在依赖问题" + + # 2. 使用apt-get修复依赖 + log_info " 第2步:修复依赖关系..." + if apt-get install -f -y; then + log_success " 依赖关系修复完成" + else + log_error " 依赖关系修复失败" + # 继续处理其他包,不退出 + fi + fi + else + log_info " $tar_basename 中没有找到deb包,跳过" + fi + + # 返回到依赖临时目录 + cd "$deps_temp_dir" + done + + log_success "系统依赖包安装完成" +} + +# 安装组件 +install_components() { + log_info "开始安装组件..." + + artifact_dir=$(dirname "$VERSION_FILE_PATH") + install_count=0 + total_count=0 + + if [[ -f "$TEMP_DIR/install_order.txt" ]]; then + total_count=$(wc -l < "$TEMP_DIR/install_order.txt") + fi + + if [[ -f "$TEMP_DIR/install_order.txt" ]]; then + while IFS= read -r filename; do + install_count=$((install_count + 1)) + + # 从文件名中提取组件名(去掉时间戳后缀) + component=$(echo "$filename" | sed 's/-[0-9]\{8\}-[0-9]\{6\}\.tar\.gz$//') + + log_info "[$install_count/$total_count] 安装 $component..." + log_info " 文件名: $filename" + + # 直接使用完整的文件名 + tar_file="$artifact_dir/$filename" + + if [[ ! -f "$tar_file" ]]; then + log_error "找不到组件文件: $filename" + log_info " 期望路径: $tar_file" + log_info " 当前目录: $(pwd)" + log_info " 目录内容:" + ls -la "$artifact_dir" | while read line; do + log_info " $line" + done + exit 1 + fi + + log_info " 找到文件: $tar_file" + + # 解压到临时目录 + component_temp_dir="$TEMP_DIR/$component" + mkdir -p "$component_temp_dir" + + if tar -xzf "$tar_file" -C "$component_temp_dir"; then + log_success " $component 解压完成" + else + log_error " $component 解压失败" + exit 1 + fi + + # 查找解压后的目录 + extracted_dir="" + for dir in "$component_temp_dir"/*; do + if [[ -d "$dir" ]]; then + extracted_dir="$dir" + break + fi + done + + if [[ -z "$extracted_dir" ]]; then + log_error " $component 解压后未找到目录" + exit 1 + fi + + # 执行安装脚本 + if [[ -f "$extracted_dir/install.sh" ]]; then + log_info " 执行 $component 安装脚本..." + if (cd "$extracted_dir" && ./install.sh); then + log_success " $component 安装完成" + else + log_error " $component 安装失败" + exit 1 + fi + else + log_error " $component 缺少 install.sh 文件" + exit 1 + fi + + # 将解压后的目录移动到安装目录,保留组件目录 + component_install_dir="$INSTALL_DIR/$component" + if [[ -d "$component_install_dir" ]]; then + log_info " 组件目录已存在,备份后更新: $component_install_dir" + mv "$component_install_dir" "${component_install_dir}.backup.$(date +%Y%m%d_%H%M%S)" + fi + mv "$extracted_dir" "$component_install_dir" + log_success " 组件目录已保存: $component_install_dir" + + # 清理临时文件 + rm -rf "$component_temp_dir" + done < "$TEMP_DIR/install_order.txt" + fi + + log_success "所有组件安装完成" +} + +# 创建安装记录 +create_install_record() { + log_info "创建安装记录..." + + # 等待一段时间确保所有进程都已启动 + log_info "等待进程启动..." + sleep 3 + + local install_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + local install_record_file=".install_record" + + # 创建 JSON 格式的安装记录 + cat > "$install_record_file" << EOF +{ + "version": "$VERSION", + "build_time": "$BUILD_TIME", + "install_time": "$install_time", + "install_dir": "$INSTALL_DIR", + "install_pid": $$, + "components": { +EOF + + # 添加组件信息 + local first_component=true + if [[ -f "$TEMP_DIR/components.txt" ]]; then + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + version=$(echo "$line" | cut -d':' -f2) + + # 获取组件的进程信息 + local component_pid="" + + # 根据组件名查找进程,使用多种方法确保能找到PID + case "$component" in + "node-exporter-installer") + # 尝试多种方式查找node_exporter进程 + component_pid=$(pgrep -f "node_exporter" | head -1) + if [[ -z "$component_pid" ]]; then + component_pid=$(pgrep -f "node-exporter" | head -1) + fi + if [[ -z "$component_pid" ]]; then + component_pid=$(ps aux | grep -v grep | grep "node_exporter" | awk '{print $2}' | head -1) + fi + ;; + "dcgm-exporter-installer") + # 尝试多种方式查找dcgm-exporter进程 + component_pid=$(pgrep -f "dcgm-exporter" | head -1) + if [[ -z "$component_pid" ]]; then + component_pid=$(pgrep -f "dcgm_exporter" | head -1) + fi + if [[ -z "$component_pid" ]]; then + component_pid=$(ps aux | grep -v grep | grep "dcgm-exporter" | awk '{print $2}' | head -1) + fi + ;; + esac + + # 记录找到的PID信息 + if [[ -n "$component_pid" ]]; then + log_info " 找到 $component 进程 PID: $component_pid" + else + log_warning " 未找到 $component 进程" + fi + + # 添加逗号分隔符 + if [[ "$first_component" == "true" ]]; then + first_component=false + else + echo "," >> "$install_record_file" + fi + + # 添加组件信息 + cat >> "$install_record_file" << EOF + "$component": { + "version": "$version", + "pid": "$component_pid", + "install_dir": "$INSTALL_DIR/$component" + } +EOF + done < "$TEMP_DIR/components.txt" + fi + + # 结束 JSON + cat >> "$install_record_file" << EOF + } +} +EOF + + log_success "安装记录已创建: $install_record_file" +} + +# 设置健康检查定时任务 +setup_health_check_cron() { + log_info "设置健康检查定时任务..." + + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local check_health_script="$script_dir/check_health.sh" + + # 检查健康检查脚本是否存在 + if [[ ! -f "$check_health_script" ]]; then + log_error "健康检查脚本不存在: $check_health_script" + return 1 + fi + + # 确保脚本有执行权限 + chmod +x "$check_health_script" + + # 创建临时crontab文件 + local temp_cron="/tmp/crontab_$$" + + # 获取当前用户的crontab(如果存在) + crontab -l 2>/dev/null > "$temp_cron" || touch "$temp_cron" + + # 检查是否已经存在健康检查任务 + if grep -q "check_health.sh" "$temp_cron"; then + log_warning "健康检查定时任务已存在,跳过设置" + rm -f "$temp_cron" + return 0 + fi + + # 添加新的定时任务(每5分钟执行一次) + echo "# Argus-Metrics 健康检查定时任务" >> "$temp_cron" + echo "*/5 * * * * $check_health_script >> $script_dir/.health_cron.log 2>&1" >> "$temp_cron" + + # 安装新的crontab + if crontab "$temp_cron"; then + log_success "健康检查定时任务设置成功" + log_info " 执行频率: 每5分钟" + log_info " 日志文件: $script_dir/.health_cron.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 "执行首次健康检查..." + if "$check_health_script"; then + log_success "首次健康检查完成" + else + log_warning "首次健康检查失败,但定时任务已设置" + fi +} + +# 显示安装信息 +show_install_info() { + log_success "Argus-Metrics All-in-One 安装完成!" + echo + echo "安装信息:" + echo " 版本: $VERSION" + echo " 构建时间: $BUILD_TIME" + echo " 安装目录: $INSTALL_DIR" + echo + echo "已安装组件:" + if [[ -f "$TEMP_DIR/components.txt" ]]; then + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + version=$(echo "$line" | cut -d':' -f2) + echo " - $component v$version" + done < "$TEMP_DIR/components.txt" + fi + echo + echo "访问地址:" + echo " Node Exporter: http://localhost:9100" + echo " DCGM Exporter: http://localhost:9400" + echo + echo "健康检查:" + echo " 安装记录: .install_record" + echo " 健康日志: .health_log" + echo " 定时任务日志: .health_cron.log" + echo " 查看定时任务: crontab -l" + echo +} + +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + fi +} + +trap cleanup EXIT + +# 主函数 +main() { + echo "==========================================" + echo " Argus-Metrics All-in-One 安装脚本 v1.0" + echo "==========================================" + echo + log_info "安装目录: $INSTALL_DIR" + echo + + check_root + check_system + find_version_file + create_install_dirs + parse_version_info + verify_checksums + install_system_deps + install_components + create_install_record + setup_health_check_cron + show_install_info +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/demo-all-in-one/package_artifact.sh b/src/metric/client-plugins/demo-all-in-one/package_artifact.sh new file mode 100755 index 0000000..4cb7dc8 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/package_artifact.sh @@ -0,0 +1,433 @@ +#!/bin/bash + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 显示帮助信息 +show_help() { + echo "AIOps All-in-One 打包脚本" + echo + echo "用法: $0 [选项]" + echo + echo "选项:" + echo " --force 强制重新打包,即使版本已存在" + echo " --help 显示此帮助信息" + echo + echo "示例:" + echo " $0 # 正常打包,跳过已存在的版本" + echo " $0 --force # 强制重新打包" + echo +} + +# 解析命令行参数 +FORCE_PACKAGE=false +if [[ "$1" == "--force" ]]; then + FORCE_PACKAGE=true + log_info "强制重新打包模式" +elif [[ "$1" == "--help" || "$1" == "-h" ]]; then + show_help + exit 0 +fi + +# 获取当前目录和版本 +CURRENT_DIR=$(pwd) +VERSION=$(cat VERSION 2>/dev/null || echo "1.0.0") +ARTIFACT_DIR="artifact/$VERSION" + +log_info "开始打包 AIOps All-in-One 安装包 v$VERSION" + +# 检查必要文件 +log_info "检查必要文件..." +if [[ ! -f "VERSION" ]]; then + log_error "VERSION 文件不存在" + exit 1 +fi + +if [[ ! -f "checklist" ]]; then + log_error "checklist 文件不存在" + exit 1 +fi + +# 检查是否已存在该版本 +if [[ -d "$ARTIFACT_DIR" && "$FORCE_PACKAGE" == "false" ]]; then + log_info "检查版本 $VERSION 是否已存在..." + + # 检查 version.json 是否存在 + if [[ -f "$ARTIFACT_DIR/version.json" ]]; then + log_info "找到已存在的版本信息文件" + + # 检查是否所有组件文件都存在 + missing_files=0 + existing_components=0 + + # 解析已存在的 version.json 来检查文件 + if command -v jq &> /dev/null; then + # 使用 jq 解析 + while IFS= read -r component; do + existing_components=$((existing_components + 1)) + # 查找对应的 tar 文件 + found_file=false + for file in "$ARTIFACT_DIR/${component}-"*.tar.gz; do + if [[ -f "$file" ]]; then + found_file=true + break + fi + done + if [[ "$found_file" == "false" ]]; then + missing_files=$((missing_files + 1)) + log_warning " 缺少文件: $component" + fi + done < <(jq -r '.artifact_list | keys[]' "$ARTIFACT_DIR/version.json" 2>/dev/null) + else + # 简单的文件检查 + for file in "$ARTIFACT_DIR"/*.tar.gz; do + if [[ -f "$file" ]]; then + existing_components=$((existing_components + 1)) + fi + done + fi + + # 如果所有文件都存在,则跳过打包 + if [[ $missing_files -eq 0 && $existing_components -gt 0 ]]; then + log_success "版本 $VERSION 已完整打包,跳过重复打包" + echo + echo "现有文件:" + ls -la "$ARTIFACT_DIR" + echo + echo "如需强制重新打包,请删除目录: rm -rf $ARTIFACT_DIR" + echo "或使用: ./package.sh --force" + exit 0 + else + log_warning "版本 $VERSION 存在但不完整,将重新打包" + log_info " 现有组件: $existing_components" + log_info " 缺少文件: $missing_files" + fi + else + log_warning "版本目录存在但缺少 version.json,将重新打包" + fi +fi + +# 创建 artifact 目录 +mkdir -p "$ARTIFACT_DIR" +log_info "创建输出目录: $ARTIFACT_DIR" + +# 创建临时文件存储数据 +TEMP_DIR=$(mktemp -d) +COMPONENTS_FILE="$TEMP_DIR/components.txt" +VERSIONS_FILE="$TEMP_DIR/versions.txt" +DEPENDENCIES_FILE="$TEMP_DIR/dependencies.txt" +INSTALL_ORDER_FILE="$TEMP_DIR/install_order.txt" +CHECKSUMS_FILE="$TEMP_DIR/checksums.txt" +ARTIFACT_LIST_FILE="$TEMP_DIR/artifact_list.txt" + +# 解析 checklist 文件 +log_info "解析组件清单..." +line_num=0 +component_count=0 + +while IFS= read -r line; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + line_num=$((line_num + 1)) + + # 解析行: 组件名 目录路径 版本 [依赖组件] [安装顺序] + read -r component component_path version dep_component order <<< "$line" + + if [[ -z "$component" || -z "$component_path" || -z "$version" ]]; then + log_warning "跳过无效行 $line_num: $line" + continue + fi + + # 存储组件信息 + echo "$component" >> "$COMPONENTS_FILE" + echo "$component:$version" >> "$VERSIONS_FILE" + echo "$component:$component_path" >> "$TEMP_DIR/component_paths.txt" + + if [[ -n "$dep_component" && "$dep_component" != "$component" ]]; then + echo "$component:$dep_component" >> "$DEPENDENCIES_FILE" + fi + + if [[ -n "$order" && "$order" =~ ^[0-9]+$ ]]; then + echo "$order:$component" >> "$INSTALL_ORDER_FILE" + else + # 如果没有指定顺序,按解析顺序分配 + echo "$line_num:$component" >> "$INSTALL_ORDER_FILE" + fi + + component_count=$((component_count + 1)) + log_info " - $component v$version" +done < checklist + +if [[ $component_count -eq 0 ]]; then + log_error "没有找到有效的组件" + rm -rf "$TEMP_DIR" + exit 1 +fi + +log_success "找到 $component_count 个组件" + +# 检查组件目录是否存在 +log_info "检查组件目录..." +missing_components=() + +while IFS= read -r component; do + # 获取组件路径 + component_path=$(grep "^$component:" "$TEMP_DIR/component_paths.txt" | cut -d':' -f2-) + if [[ -z "$component_path" ]]; then + log_error "未找到组件 $component 的路径配置" + log_info "请检查 component_paths.txt 文件或添加路径配置" + exit 1 + fi + + if [[ ! -d "$component_path" ]]; then + missing_components+=("$component:$component_path") + fi +done < "$COMPONENTS_FILE" + +if [[ ${#missing_components[@]} -gt 0 ]]; then + log_error "以下组件目录不存在:" + for component_path in "${missing_components[@]}"; do + echo " - $component_path" + done + rm -rf "$TEMP_DIR" + exit 1 +fi + +# 打包各个组件 +log_info "开始打包组件..." + +while IFS= read -r component; do + # 获取组件版本和路径 + version=$(grep "^$component:" "$VERSIONS_FILE" | cut -d':' -f2) + component_path=$(grep "^$component:" "$TEMP_DIR/component_paths.txt" | cut -d':' -f2-) + if [[ -z "$component_path" ]]; then + log_error "未找到组件 $component 的路径配置" + log_info "请检查 component_paths.txt 文件或添加路径配置" + exit 1 + fi + + log_info "打包 $component v$version..." + log_info " 组件路径: $component_path" + + # 进入组件目录 + cd "$component_path" + + # 检查组件是否有 package.sh + if [[ ! -f "package.sh" ]]; then + log_error "$component 缺少 package.sh 文件" + cd "$CURRENT_DIR" + rm -rf "$TEMP_DIR" + exit 1 + fi + + # 执行组件的打包脚本 + if ./package.sh; then + # 查找生成的 tar 包 + tar_file=$(find . -name "*.tar.gz" -type f | head -1) + if [[ -n "$tar_file" ]]; then + # 移动到 artifact 目录 + mv "$tar_file" "$CURRENT_DIR/$ARTIFACT_DIR/" + tar_filename=$(basename "$tar_file") + + # 计算校验和 + checksum=$(sha256sum "$CURRENT_DIR/$ARTIFACT_DIR/$tar_filename" | cut -d' ' -f1) + echo "$component:sha256:$checksum" >> "$CHECKSUMS_FILE" + echo "$component:$version" >> "$ARTIFACT_LIST_FILE" + + # 将完整的文件名存储到安装顺序文件中 + echo "$tar_filename" >> "$TEMP_DIR/install_order_files.txt" + + log_success " $component 打包完成: $tar_filename" + else + log_error "$component 打包失败,未找到生成的 tar 包" + cd "$CURRENT_DIR" + rm -rf "$TEMP_DIR" + exit 1 + fi + else + log_error "$component 打包失败" + cd "$CURRENT_DIR" + rm -rf "$TEMP_DIR" + exit 1 + fi + + # 返回主目录 + cd "$CURRENT_DIR" +done < "$COMPONENTS_FILE" + +# 生成 version.json +log_info "生成版本信息文件..." +version_json="$ARTIFACT_DIR/version.json" + +# 构建依赖关系 JSON +deps_json="" +if [[ -f "$DEPENDENCIES_FILE" ]]; then + first=true + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + dep=$(echo "$line" | cut -d':' -f2) + if [[ "$first" == "true" ]]; then + deps_json="\"$component\":[\"$dep\"]" + first=false + else + deps_json="$deps_json,\"$component\":[\"$dep\"]" + fi + done < "$DEPENDENCIES_FILE" +fi + +# 构建安装顺序数组 +order_array="" +if [[ -f "$TEMP_DIR/install_order_files.txt" ]]; then + first=true + while IFS= read -r filename; do + if [[ "$first" == "true" ]]; then + order_array="\"$filename\"" + first=false + else + order_array="$order_array,\"$filename\"" + fi + done < "$TEMP_DIR/install_order_files.txt" +fi + +# 构建 artifact_list JSON +artifact_json="" +if [[ -f "$ARTIFACT_LIST_FILE" ]]; then + first=true + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + version=$(echo "$line" | cut -d':' -f2) + if [[ "$first" == "true" ]]; then + artifact_json="\"$component\":\"$version\"" + first=false + else + artifact_json="$artifact_json,\"$component\":\"$version\"" + fi + done < "$ARTIFACT_LIST_FILE" +fi + +# 构建 checksums JSON +checksums_json="" +if [[ -f "$CHECKSUMS_FILE" ]]; then + first=true + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + checksum=$(echo "$line" | cut -d':' -f2-) + if [[ "$first" == "true" ]]; then + checksums_json="\"$component\":\"$checksum\"" + first=false + else + checksums_json="$checksums_json,\"$component\":\"$checksum\"" + fi + done < "$CHECKSUMS_FILE" +fi + +# 生成完整的 version.json +cat > "$version_json" << EOF +{ + "version": "$VERSION", + "build_time": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", + "artifact_list": { + $artifact_json + }, + "checksums": { + $checksums_json + }, + "dependencies": { + $deps_json + }, + "install_order": [ + $order_array + ] +} +EOF + +log_success "版本信息文件生成完成: $version_json" + +# 复制`安装`脚本到 artifact 目录 +log_info "复制安装脚本..." +if [[ -f "install_artifact.sh" ]]; then + cp "install_artifact.sh" "$ARTIFACT_DIR/install.sh" + chmod +x "$ARTIFACT_DIR/install.sh" + log_success "安装脚本复制完成: $ARTIFACT_DIR/install.sh" +else + log_warning "install_artifact.sh 文件不存在" +fi + +# 复制`卸载`脚本到 artifact 目录 +log_info "复制卸载脚本..." +if [[ -f "uninstall_artifact.sh" ]]; then + cp "uninstall_artifact.sh" "$ARTIFACT_DIR/uninstall.sh" + chmod +x "$ARTIFACT_DIR/uninstall.sh" + log_success "卸载脚本复制完成: $ARTIFACT_DIR/uninstall.sh" +else + log_warning "uninstall_artifact.sh 文件不存在" +fi + +# 复制`健康检查`脚本到 artifact 目录 +log_info "复制健康检查脚本..." +if [[ -f "check_health.sh" ]]; then + cp "check_health.sh" "$ARTIFACT_DIR/check_health.sh" + chmod +x "$ARTIFACT_DIR/check_health.sh" + log_success "健康检查脚本复制完成: $ARTIFACT_DIR/check_health.sh" +else + log_warning "check_health.sh 文件不存在" +fi + +# 复制 deps 目录到 artifact 目录 +log_info "复制系统依赖包..." +if [[ -d "deps" ]]; then + cp -r "deps" "$ARTIFACT_DIR/" + log_success "系统依赖包复制完成: $ARTIFACT_DIR/deps" + + # 显示deps目录内容 + log_info " 依赖包列表:" + find "$ARTIFACT_DIR/deps" -name "*.tar.gz" -exec basename {} \; | while read dep_file; do + log_info " - $dep_file" + done +else + log_warning "deps 目录不存在,跳过依赖包复制" +fi + +# 显示打包结果 +log_success "打包完成!" +echo +echo "版本: $VERSION" +echo "输出目录: $ARTIFACT_DIR" +echo "包含组件:" +if [[ -f "$ARTIFACT_LIST_FILE" ]]; then + while IFS= read -r line; do + component=$(echo "$line" | cut -d':' -f1) + version=$(echo "$line" | cut -d':' -f2) + echo " - $component v$version" + done < "$ARTIFACT_LIST_FILE" +fi +echo +echo "文件列表:" +ls -la "$ARTIFACT_DIR" +echo + +# 清理临时文件 +rm -rf "$TEMP_DIR" diff --git a/src/metric/client-plugins/demo-all-in-one/publish_artifact.sh b/src/metric/client-plugins/demo-all-in-one/publish_artifact.sh new file mode 100755 index 0000000..16c17f2 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/publish_artifact.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +set -e + +# 颜色定义 +GREEN='\033[0;32m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 显示帮助信息 +show_help() { + echo "AIOps Artifact 发布脚本" + echo + echo "用法: $0 <版本号>" + echo + echo "参数:" + echo " <版本号> 要发布的版本号,对应 artifact 目录中的版本" + echo + echo "示例:" + echo " $0 1.20.0 # 发布 1.20.0 版本" + echo +} + +# 检查参数 +if [[ $# -ne 1 ]]; then + log_error "请提供版本号参数" + show_help + exit 1 +fi + +VERSION="$1" +ARTIFACT_DIR="artifact/$VERSION" +PUBLISH_DIR="publish/$VERSION" + +# 检查版本目录是否存在 +if [[ ! -d "$ARTIFACT_DIR" ]]; then + log_error "版本目录不存在: $ARTIFACT_DIR" + exit 1 +fi + +log_info "开始发布版本: $VERSION" + +# 创建发布目录 +log_info "创建发布目录: $PUBLISH_DIR" +mkdir -p "$PUBLISH_DIR" + +# 复制所有 tar.gz 文件到发布目录 +log_info "复制 artifact 文件..." +tar_files=$(find "$ARTIFACT_DIR" -name "*.tar.gz" -type f) + +if [[ -z "$tar_files" ]]; then + log_error "在 $ARTIFACT_DIR 中未找到 tar.gz 文件" + exit 1 +fi + +for file in $tar_files; do + filename=$(basename "$file") + log_info " 复制: $filename" + cp "$file" "$PUBLISH_DIR/" +done + +# 复制版本信息文件 +if [[ -f "$ARTIFACT_DIR/version.json" ]]; then + log_info "复制版本信息文件..." + cp "$ARTIFACT_DIR/version.json" "$PUBLISH_DIR/" +fi + +# 复制安装脚本 +if [[ -f "install_artifact.sh" ]]; then + log_info "复制安装脚本..." + cp "install_artifact.sh" "$PUBLISH_DIR/" +fi + +if [[ -f "uninstall_artifact.sh" ]]; then + log_info "复制卸载脚本..." + cp "uninstall_artifact.sh" "$PUBLISH_DIR/" +fi + +# 创建tar包 +TAR_NAME="argus-metric-$VERSION.tar.gz" +log_info "创建发布包: $TAR_NAME" +cd publish +tar -czf "$TAR_NAME" "$VERSION" +cd .. + +# 显示发布结果 +log_success "版本 $VERSION 发布完成!" +echo +echo "发布目录: $PUBLISH_DIR" +echo "发布包: publish/$TAR_NAME" +echo "包大小: $(du -h "publish/$TAR_NAME" | cut -f1)" +echo +echo "包含文件:" +ls -la "$PUBLISH_DIR" | while read line; do + echo " $line" +done +echo +echo "使用方法:" +echo " 1. 将 publish/$TAR_NAME 部署到 Web 服务器" +echo " 2. 用户可以通过以下命令安装:" +echo " curl -sfL https://yourdomain.com/$TAR_NAME | tar -xz && cd argus-metric-$VERSION && sudo ./install_artifact.sh" diff --git a/src/metric/client-plugins/demo-all-in-one/uninstall_artifact.sh b/src/metric/client-plugins/demo-all-in-one/uninstall_artifact.sh new file mode 100644 index 0000000..fce9087 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/uninstall_artifact.sh @@ -0,0 +1,274 @@ +#!/bin/bash + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 配置变量 +INSTALL_DIR="/opt/aiops" +TEMP_DIR="/tmp/aiops-uninstall-$$" +VERSION_FILE="version.json" + +# 检查是否为 root 用户 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + log_info "请使用: sudo $0" + exit 1 + fi +} + +# 查找版本文件 +find_version_file() { + log_info "查找版本信息文件..." + + # 在当前目录查找 + if [[ -f "$VERSION_FILE" ]]; then + VERSION_FILE_PATH="$VERSION_FILE" + log_success "找到版本文件: $VERSION_FILE" + return 0 + fi + + # 在 artifact 目录查找 + for version_dir in artifact/*/; do + if [[ -f "${version_dir}${VERSION_FILE}" ]]; then + VERSION_FILE_PATH="${version_dir}${VERSION_FILE}" + log_success "找到版本文件: $VERSION_FILE_PATH" + return 0 + fi + done + + log_error "未找到版本信息文件 $VERSION_FILE" + log_info "请确保在正确的目录下运行此脚本" + exit 1 +} + +# 解析版本信息 +parse_version_info() { + log_info "解析版本信息..." + + if [[ ! -f "$VERSION_FILE_PATH" ]]; then + log_error "版本文件不存在: $VERSION_FILE_PATH" + exit 1 + fi + + # 使用 jq 解析 JSON(如果可用) + if command -v jq &> /dev/null; then + VERSION=$(jq -r '.version' "$VERSION_FILE_PATH") + BUILD_TIME=$(jq -r '.build_time' "$VERSION_FILE_PATH") + + # 解析 install_order(现在包含完整的文件名) + if jq -e '.install_order' "$VERSION_FILE_PATH" > /dev/null 2>&1; then + jq -r '.install_order[]' "$VERSION_FILE_PATH" > "$TEMP_DIR/install_order.txt" + else + log_error "version.json 中缺少 install_order 字段" + exit 1 + fi + else + log_warning "jq 未安装,使用简单的 JSON 解析" + VERSION=$(grep '"version"' "$VERSION_FILE_PATH" | sed 's/.*"version": *"\([^"]*\)".*/\1/') + BUILD_TIME=$(grep '"build_time"' "$VERSION_FILE_PATH" | sed 's/.*"build_time": *"\([^"]*\)".*/\1/') + + # 解析 install_order + grep -A 100 '"install_order"' "$VERSION_FILE_PATH" | grep -E '^\s*"[^"]+"' | while read line; do + component=$(echo "$line" | sed 's/.*"\([^"]*\)".*/\1/') + echo "$component" >> "$TEMP_DIR/install_order.txt" + done + fi + + log_success "版本信息解析完成" + log_info " 版本: $VERSION" + log_info " 构建时间: $BUILD_TIME" +} + +# 创建临时目录 +create_temp_dirs() { + log_info "创建临时目录..." + mkdir -p "$TEMP_DIR" + log_success "临时目录创建完成: $TEMP_DIR" +} + +# 卸载组件 +uninstall_components() { + log_info "开始卸载组件..." + + artifact_dir=$(dirname "$VERSION_FILE_PATH") + uninstall_count=0 + total_count=0 + + if [[ -f "$TEMP_DIR/install_order.txt" ]]; then + total_count=$(wc -l < "$TEMP_DIR/install_order.txt") + fi + + if [[ -f "$TEMP_DIR/install_order.txt" ]]; then + while IFS= read -r filename; do + uninstall_count=$((uninstall_count + 1)) + + # 从文件名中提取组件名(去掉时间戳后缀) + component=$(echo "$filename" | sed 's/-[0-9]\{8\}-[0-9]\{6\}\.tar\.gz$//') + + log_info "[$uninstall_count/$total_count] 卸载 $component..." + + # 直接使用完整的文件名 + tar_file="$artifact_dir/$filename" + + if [[ ! -f "$tar_file" ]]; then + log_error "找不到组件文件: $filename" + exit 1 + fi + + # 解压到临时目录 + component_temp_dir="$TEMP_DIR/$component" + mkdir -p "$component_temp_dir" + + if tar -xzf "$tar_file" -C "$component_temp_dir"; then + log_success " $component 解压完成" + else + log_error " $component 解压失败" + exit 1 + fi + + # 查找解压后的目录 + extracted_dir="" + for dir in "$component_temp_dir"/*; do + if [[ -d "$dir" ]]; then + extracted_dir="$dir" + break + fi + done + + if [[ -z "$extracted_dir" ]]; then + log_error " $component 解压后未找到目录" + exit 1 + fi + + # 执行卸载脚本 + if [[ -f "$extracted_dir/uninstall.sh" ]]; then + log_info " 执行 $component 卸载脚本..." + # 所有组件都只需要一个确认 + if (cd "$extracted_dir" && echo "y" | ./uninstall.sh); then + log_success " $component 卸载完成" + else + log_error " $component 卸载失败" + exit 1 + fi + else + log_warning " $component 缺少 uninstall.sh 文件,跳过卸载" + fi + + # 清理临时文件 + rm -rf "$component_temp_dir" + done < "$TEMP_DIR/install_order.txt" + fi + + log_success "所有组件卸载完成" +} + +# 清理全局文件 +cleanup_global_files() { + log_info "清理全局文件..." + + # 清理安装目录 + if [[ -d "$INSTALL_DIR" ]]; then + rm -rf "$INSTALL_DIR" + log_success "安装目录已清理: $INSTALL_DIR" + else + log_info "安装目录不存在: $INSTALL_DIR" + fi + + # 清理可能的全局配置文件 + local global_configs=( + "/etc/aiops" + "/var/log/aiops" + ) + + for config in "${global_configs[@]}"; do + if [[ -d "$config" ]]; then + rm -rf "$config" + log_success "全局配置已清理: $config" + fi + done +} + +# 显示卸载信息 +show_uninstall_info() { + log_success "AIOps All-in-One 卸载完成!" + echo + echo "卸载信息:" + echo " 版本: $VERSION" + echo " 构建时间: $BUILD_TIME" + echo + echo "清理内容:" + echo " - 二进制文件" + echo " - 配置文件" + echo " - 数据目录" + echo " - 进程和服务" + echo " - 全局安装目录" + echo + echo "注意:" + echo " - 系统依赖包可能仍然存在" + echo " - 如需完全清理,请手动检查并删除相关文件" + echo +} + +# 清理函数 +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + fi +} + +# 设置清理陷阱 +trap cleanup EXIT + +# 主函数 +main() { + echo "==========================================" + echo " AIOps All-in-One 卸载脚本" + echo "==========================================" + echo + + check_root + find_version_file + create_temp_dirs + parse_version_info + + log_warning "此操作将完全卸载 AIOps All-in-One" + read -p "确认继续?(y/N): " confirm + + if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then + log_info "取消卸载操作" + exit 0 + fi + + uninstall_components + cleanup_global_files + show_uninstall_info +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi \ No newline at end of file diff --git a/src/metric/client-plugins/demo-all-in-one/version-manager.sh b/src/metric/client-plugins/demo-all-in-one/version-manager.sh new file mode 100755 index 0000000..28b3497 --- /dev/null +++ b/src/metric/client-plugins/demo-all-in-one/version-manager.sh @@ -0,0 +1,350 @@ +#!/bin/bash + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 显示帮助信息 +show_help() { + echo "AIOps 版本管理工具" + echo + echo "用法: $0 [options]" + echo + echo "命令:" + echo " bump - 升级版本号 (major|minor|patch)" + echo " set - 设置指定版本号" + echo " show - 显示当前版本信息" + echo " list - 列出所有版本" + echo " clean - 清理旧版本" + echo " validate - 验证版本配置" + echo + echo "示例:" + echo " $0 bump minor # 升级次版本号 1.0.0 -> 1.1.0" + echo " $0 set 2.0.0 # 设置版本为 2.0.0" + echo " $0 show # 显示当前版本" + echo " $0 list # 列出所有版本" +} + +# 获取当前版本 +get_current_version() { + if [[ -f "VERSION" ]]; then + cat VERSION + else + echo "0.0.0" + fi +} + +# 设置版本号 +set_version() { + local new_version="$1" + + # 验证版本号格式 + if [[ ! "$new_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + log_error "无效的版本号格式: $new_version" + log_info "版本号格式应为: major.minor.patch (如: 1.2.3)" + exit 1 + fi + + echo "$new_version" > VERSION + log_success "版本号已设置为: $new_version" +} + +# 升级版本号 +bump_version() { + local bump_type="$1" + local current_version=$(get_current_version) + + # 解析当前版本号 + IFS='.' read -r major minor patch <<< "$current_version" + + case "$bump_type" in + "major") + major=$((major + 1)) + minor=0 + patch=0 + ;; + "minor") + minor=$((minor + 1)) + patch=0 + ;; + "patch") + patch=$((patch + 1)) + ;; + *) + log_error "无效的升级类型: $bump_type" + log_info "支持的类型: major, minor, patch" + exit 1 + ;; + esac + + local new_version="$major.$minor.$patch" + set_version "$new_version" + log_success "版本号已从 $current_version 升级到 $new_version" +} + +# 显示当前版本信息 +show_version() { + local current_version=$(get_current_version) + log_info "当前版本: $current_version" + + if [[ -f "checklist" ]]; then + echo + echo "组件清单:" + while IFS= read -r line; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + read -r component version dep order <<< "$line" + if [[ -n "$component" && -n "$version" ]]; then + echo " - $component v$version" + fi + done < checklist + fi + + # 检查是否有对应的 artifact + local artifact_dir="artifact/$current_version" + if [[ -d "$artifact_dir" ]]; then + echo + echo "已构建的组件:" + for file in "$artifact_dir"/*.tar.gz; do + if [[ -f "$file" ]]; then + local filename=$(basename "$file") + local size=$(du -h "$file" | cut -f1) + echo " - $filename ($size)" + fi + done + + if [[ -f "$artifact_dir/version.json" ]]; then + echo + echo "版本信息文件: $artifact_dir/version.json" + fi + else + echo + log_warning "未找到对应的构建目录: $artifact_dir" + log_info "运行 ./package.sh 进行构建" + fi +} + +# 列出所有版本 +list_versions() { + log_info "所有版本列表:" + echo + + if [[ ! -d "artifact" ]]; then + log_warning "artifact 目录不存在" + return + fi + + for version_dir in artifact/*/; do + if [[ -d "$version_dir" ]]; then + local version=$(basename "$version_dir") + local current_version=$(get_current_version) + + if [[ "$version" == "$current_version" ]]; then + echo " * $version (当前版本)" + else + echo " $version" + fi + + # 显示该版本的组件 + local component_count=0 + for file in "$version_dir"/*.tar.gz; do + if [[ -f "$file" ]]; then + component_count=$((component_count + 1)) + fi + done + + if [[ $component_count -gt 0 ]]; then + echo " 包含 $component_count 个组件" + fi + fi + done +} + +# 清理旧版本 +clean_versions() { + local current_version=$(get_current_version) + local keep_versions=5 # 保留最近5个版本 + + log_info "清理旧版本 (保留最近 $keep_versions 个版本)..." + + if [[ ! -d "artifact" ]]; then + log_warning "artifact 目录不存在" + return + fi + + # 获取所有版本目录,按修改时间排序 + local versions=() + while IFS= read -r -d '' version_dir; do + versions+=("$(basename "$version_dir")") + done < <(find artifact -maxdepth 1 -type d -name "[0-9]*" -print0 | sort -z) + + local total_versions=${#versions[@]} + local versions_to_remove=$((total_versions - keep_versions)) + + if [[ $versions_to_remove -le 0 ]]; then + log_info "无需清理,当前只有 $total_versions 个版本" + return + fi + + log_info "将删除 $versions_to_remove 个旧版本..." + + for ((i=0; i