Files
aiops/backend/model/deploy_tool.go
T
Logan 7e1c8f583c feat: 工具配置增强、站点拨测与日志中心多项改进
- 工具配置:新增卸载 API/UI、Go 工具链、流水线构建自动安装依赖
- 修复 ListTools VerifyTool 递归栈溢出导致获取工具配置失败
- Node.js Alpine 安装改用 unofficial-builds musl 预编译包与 index.json 解析 LTS
- 站点拨测:详情页路由、告警自动恢复、并发拨测与默认可观测频率
- 日志中心:RBAC、查询构建器、ES/Loki 增强与审计 request/response 展示
- 发布配置:构建节点、流水线远程执行、Deploy RBAC 导航拆分
2026-07-02 07:47:33 +08:00

383 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import "time"
// ============================================
// DeployTool 工具配置(懒加载/预装/禁用)
// 按 deploy_ 前缀,与 PipelineRepo/Registry 同属发布配置域
// ============================================
// ToolInstallMethod 安装方式
type ToolInstallMethod string
const (
ToolPreinstall ToolInstallMethod = "preinstall" // 预装在 Dockerfile 中
ToolLazy ToolInstallMethod = "lazy" // 懒加载:首次使用时自动下载
ToolDisabled ToolInstallMethod = "disabled" // 禁用:不安装
)
// ToolStatus 安装状态
type ToolStatus string
const (
ToolNotInstalled ToolStatus = "not_installed" // 未安装
ToolInstalling ToolStatus = "installing" // 安装中
ToolInstalled ToolStatus = "installed" // 已安装
ToolFailed ToolStatus = "failed" // 安装失败
)
// DeployTool 工具配置表
type DeployTool struct {
ID uint `gorm:"primaryKey;autoIncrement;comment:主键ID" json:"id"`
Name string `gorm:"type:varchar(64);uniqueIndex;not null;comment:工具名称(英文标识)" json:"name"`
DisplayName string `gorm:"type:varchar(128);not null;comment:显示名称" json:"display_name"`
Description string `gorm:"type:varchar(256);comment:工具描述" json:"description,omitempty"`
Category string `gorm:"type:varchar(32);default:other;comment:分类: k8s/build/deploy/automation" json:"category"`
InstallMethod ToolInstallMethod `gorm:"type:varchar(16);default:lazy;comment:安装方式: preinstall/lazy/disabled" json:"install_method"`
CheckCommand string `gorm:"type:varchar(256);comment:检测命令(如 kubectl version --client)" json:"check_command,omitempty"`
BinaryName string `gorm:"type:varchar(64);comment:二进制文件名(如 kubectl/mvn/node)" json:"binary_name,omitempty"`
InstallPath string `gorm:"type:varchar(256);comment:安装目标路径(如 /usr/local/bin)" json:"install_path,omitempty"`
DownloadURL string `gorm:"type:varchar(512);comment:下载地址模板(支持 {version})" json:"download_url,omitempty"`
VersionURL string `gorm:"type:varchar(512);comment:版本查询地址(如 stable.txt)" json:"version_url,omitempty"`
InstallScript string `gorm:"type:text;comment:自定义安装脚本(Shell)" json:"install_script,omitempty"`
DefaultVersion string `gorm:"type:varchar(32);comment:默认版本号" json:"default_version,omitempty"`
Status ToolStatus `gorm:"type:varchar(16);default:not_installed;comment:当前安装状态" json:"status"`
InstalledVer string `gorm:"type:varchar(128);comment:已安装版本号" json:"installed_version,omitempty"`
LastCheck *time.Time `gorm:"comment:最后检测时间" json:"last_check,omitempty"`
ErrorMsg string `gorm:"type:varchar(512);comment:安装失败原因" json:"error_msg,omitempty"`
Enabled bool `gorm:"default:true;comment:是否启用" json:"enabled"`
SortOrder int `gorm:"default:0;comment:排序" json:"sort_order"`
CreatedAt time.Time `gorm:"not null;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"not null;comment:更新时间" json:"updated_at"`
}
// TableName 表名
func (DeployTool) TableName() string {
return "deploy_tools"
}
// ============================================
// 预置工具定义(Seeder)— 精简版 v2
// 移除: kubectl(Dockerfile 预装)、helm(非核心)
// 新增: nvm(管理 Node 版本)、jdk(Java 构建)
// ============================================
// PredefinedTools 返回系统预置的工具配置列表
func PredefinedTools() []DeployTool {
return []DeployTool{
// ──── JDK — Java 构建 // Logan.Li ────
{
Name: "jdk",
DisplayName: "JDK (Java)",
Description: "Java 开发工具包,流水线 Java/Maven 构建阶段使用",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "java",
InstallPath: "/usr/local/bin/java",
CheckCommand: "/usr/local/bin/java -version 2>&1 | head -1",
VersionURL: "https://api.adoptium.net/v3/info/release_versions?heap_size=normal&image_type=jdk&page=0&page_size=1&project=jdk&release_type=ga&semver=false&sort_method=DEFAULT&sort_order=DESC&version=%5B17%2C99%5D",
DownloadURL: "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-{version}/OpenJDK17U-jdk_x64_linux_hotspot_{version}.tar.gz",
DefaultVersion: "17.0.13+7",
InstallScript: `#!/bin/sh
# JDK lazy install — Alpine apk 优先,否则 Adoptium API 多镜像 // Logan.Li
JDK_VERSION="${TOOL_VERSION:-17.0.13+7}"
JDK_MAJOR=$(echo "$JDK_VERSION" | cut -d. -f1)
JDK_FILE_VER=$(echo "$JDK_VERSION" | tr '+' '_')
echo "[JDK] Installing ${JDK_VERSION} (major ${JDK_MAJOR})..."
if command -v apk >/dev/null 2>&1; then
case "$JDK_MAJOR" in
11) APK_PKG="openjdk11-jdk" ;;
17) APK_PKG="openjdk17-jdk" ;;
21) APK_PKG="openjdk21-jdk" ;;
*) APK_PKG="" ;;
esac
if [ -n "$APK_PKG" ]; then
echo "[JDK] Trying apk: $APK_PKG"
if apk add --no-cache "$APK_PKG"; then
JAVA_BIN=$(command -v java 2>/dev/null || echo "/usr/lib/jvm/java-${JDK_MAJOR}-openjdk/bin/java")
mkdir -p /usr/local/bin /usr/local/share/jdk/bin
ln -sf "$JAVA_BIN" /usr/local/bin/java
ln -sf "$(dirname "$JAVA_BIN")/javac" /usr/local/bin/javac 2>/dev/null || true
ln -sf "$(dirname "$JAVA_BIN")/jar" /usr/local/bin/jar 2>/dev/null || true
echo "[JDK] Installed via apk: $(java -version 2>&1 | head -1)"
exit 0
fi
fi
fi
cd /tmp && rm -rf jdk.tar.gz jdk-install
mkdir -p jdk-install && cd jdk-install
DOWNLOADED=0
for URL in \
"https://api.adoptium.net/v3/binary/version/${JDK_VERSION}/linux/x64/jdk/hotspot/normal/eclipse?project=jdk" \
"https://mirrors.tuna.tsinghua.edu.cn/Adoptium/${JDK_MAJOR}/jdk/${JDK_VERSION}/OpenJDK${JDK_MAJOR}U-jdk_x64_linux_hotspot_${JDK_FILE_VER}.tar.gz" \
"https://github.com/adoptium/temurin${JDK_MAJOR}-binaries/releases/download/jdk-${JDK_VERSION}/OpenJDK${JDK_MAJOR}U-jdk_x64_linux_hotspot_${JDK_FILE_VER}.tar.gz"
do
echo "[JDK] Trying $URL"
if curl -fsSL -L -o jdk.tar.gz "$URL"; then
DOWNLOADED=1
break
fi
rm -f jdk.tar.gz
done
[ "$DOWNLOADED" -eq 1 ] || { echo "[JDK] all mirrors failed"; exit 1; }
tar xzf jdk.tar.gz
JDK_DIR=$(find . -maxdepth 1 -type d -name 'jdk-*' | head -1)
[ -n "$JDK_DIR" ] || { echo "[JDK] extract dir not found"; exit 1; }
mkdir -p /usr/local/share
rm -rf /usr/local/share/jdk
mv "$JDK_DIR" /usr/local/share/jdk
ln -sf /usr/local/share/jdk/bin/java /usr/local/bin/java
ln -sf /usr/local/share/jdk/bin/javac /usr/local/bin/javac
ln -sf /usr/local/share/jdk/bin/jar /usr/local/bin/jar
cd /tmp && rm -rf jdk-install
echo "[JDK] Installed: $(/usr/local/bin/java -version 2>&1 | head -1)"
`,
SortOrder: 1,
},
// ──── Maven — Java 构建 // Logan.Li ────
{
Name: "maven",
DisplayName: "Maven",
Description: "Java 项目构建工具,流水线 Java 构建阶段使用(依赖 JDK)",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "mvn",
InstallPath: "/usr/local/bin/mvn",
CheckCommand: "/usr/local/bin/mvn --version 2>/dev/null | head -1",
DownloadURL: "https://dlcdn.apache.org/maven/maven-3/{version}/binaries/apache-maven-{version}-bin.tar.gz",
VersionURL: "https://dlcdn.apache.org/maven/maven-3/",
DefaultVersion: "3.9.9",
InstallScript: `#!/bin/sh
# Maven lazy install — 多镜像轮询 // Logan.Li
MAVEN_VERSION="${TOOL_VERSION:-3.9.9}"
echo "[Maven] Downloading ${MAVEN_VERSION}..."
cd /tmp && rm -rf maven.tar.gz maven-install
mkdir -p maven-install && cd maven-install
DOWNLOADED=0
for URL in \
"https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
"https://repo.huaweicloud.com/apache/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
"https://dlcdn.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
"https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz"
do
echo "[Maven] Trying $URL"
if curl -fsSL -o maven.tar.gz "$URL"; then
DOWNLOADED=1
break
fi
rm -f maven.tar.gz
done
[ "$DOWNLOADED" -eq 1 ] || { echo "[Maven] all mirrors failed"; exit 1; }
tar xzf maven.tar.gz
MVN_DIR=$(find . -maxdepth 1 -type d -name 'apache-maven-*' | head -1)
[ -n "$MVN_DIR" ] || { echo "[Maven] extract dir not found"; exit 1; }
mkdir -p /usr/local/share
rm -rf /usr/local/share/maven
mv "$MVN_DIR" /usr/local/share/maven
ln -sf /usr/local/share/maven/bin/mvn /usr/local/bin/mvn
cd /tmp && rm -rf maven-install
echo "[Maven] Installed: $(/usr/local/bin/mvn --version 2>&1 | head -1)"
`,
SortOrder: 2,
},
// ──── Go — 后端构建 // Logan.Li ────
{
Name: "golang",
DisplayName: "Go (Golang)",
Description: "Go 语言工具链,流水线 go build/test 阶段使用",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "go",
InstallPath: "/usr/local/bin/go",
CheckCommand: "/usr/local/bin/go version 2>/dev/null",
DownloadURL: "https://go.dev/dl/go{version}.linux-amd64.tar.gz",
DefaultVersion: "1.24.0",
InstallScript: `#!/bin/sh
# Go lazy install — 国内镜像优先 // Logan.Li
GO_VERSION="${TOOL_VERSION:-1.24.0}"
GO_VERSION="${GO_VERSION#go}"
echo "[Go] Installing go${GO_VERSION}..."
cd /tmp && rm -rf go.tar.gz go-install
mkdir -p go-install && cd go-install
DOWNLOADED=0
for URL in \
"https://golang.google.cn/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
"https://mirrors.aliyun.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" \
"https://mirrors.ustc.edu.cn/golang/go${GO_VERSION}.linux-amd64.tar.gz" \
"https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
do
echo "[Go] Trying $URL"
if curl -fsSL -L -o go.tar.gz "$URL"; then
DOWNLOADED=1
break
fi
rm -f go.tar.gz
done
[ "$DOWNLOADED" -eq 1 ] || { echo "[Go] all mirrors failed"; exit 1; }
tar xzf go.tar.gz
[ -d go ] || { echo "[Go] extract dir not found"; exit 1; }
rm -rf /usr/local/go
mv go /usr/local/go
mkdir -p /usr/local/bin
ln -sf /usr/local/go/bin/go /usr/local/bin/go
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
mkdir -p /etc/profile.d
cat > /etc/profile.d/golang.sh << 'GO_PROFILE'
export GOROOT=/usr/local/go
export PATH=$GOROOT/bin:$PATH
export GOPROXY=https://goproxy.cn,direct
export GOTOOLCHAIN=local
GO_PROFILE
chmod +x /etc/profile.d/golang.sh
export GOROOT=/usr/local/go
export PATH=$GOROOT/bin:$PATH
export GOPROXY=https://goproxy.cn,direct
export GOTOOLCHAIN=local
echo "[Go] Installed: $(/usr/local/bin/go version)"
`,
SortOrder: 3,
},
// ──── NVM — Node Version Manager // Logan.Li ────
{
Name: "nvm",
DisplayName: "NVM (Node 版本管理)",
Description: "Node 版本管理器,流水线 Node.js 构建阶段使用(node 依赖此工具)",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "nvm",
InstallPath: "/usr/local/share/nvm/nvm.sh",
CheckCommand: ". /usr/local/share/nvm/nvm.sh 2>/dev/null && nvm --version 2>/dev/null",
VersionURL: "https://api.github.com/repos/nvm-sh/nvm/releases/latest",
DefaultVersion: "0.40.1",
InstallScript: `#!/bin/sh
# NVM lazy install — 使用 bash 执行官方脚本 // Logan.Li
NVM_VERSION="${TOOL_VERSION:-0.40.1}"
NVM_DIR="/usr/local/share/nvm"
echo "[NVM] Downloading v${NVM_VERSION}..."
mkdir -p "$NVM_DIR"
curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh" -o /tmp/nvm-install.sh
export NVM_DIR
bash /tmp/nvm-install.sh
rm -f /tmp/nvm-install.sh
[ -s "$NVM_DIR/nvm.sh" ] || { echo "[NVM] nvm.sh not found"; exit 1; }
mkdir -p /etc/profile.d
cat > /etc/profile.d/nvm.sh << 'NVM_PROFILE'
export NVM_DIR="/usr/local/share/nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
NVM_PROFILE
chmod +x /etc/profile.d/nvm.sh
. "$NVM_DIR/nvm.sh"
echo "[NVM] Installed: $(nvm --version 2>/dev/null || echo v${NVM_VERSION})"
`,
SortOrder: 4,
},
// ──── Node.js — 通过 NVM 安装 // Logan.Li ────
{
Name: "nodejs",
DisplayName: "Node.js + npm",
Description: "前端构建工具,流水线 npm install/build 阶段使用(通过 NVM 安装)",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "node",
InstallPath: "/usr/local/bin/node",
CheckCommand: "node --version 2>/dev/null",
DefaultVersion: "lts",
InstallScript: `#!/bin/sh
# Node.js 安装 — Alpine 用 unofficial-builds musl 包(官方已停 musl 预编译)// Logan.Li
NODE_VERSION="${TOOL_VERSION:-lts}"
NVM_DIR="/usr/local/share/nvm"
NODE_MIRROR="${NODE_MIRROR:-https://npmmirror.com/mirrors/node}"
echo "[Node.js] Installing (${NODE_VERSION})..."
mkdir -p "$NVM_DIR/versions/node"
export NVM_DIR
resolve_version() {
case "$1" in
lts)
curl -fsSL "https://nodejs.org/dist/index.json" 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(next(x['version'] for x in d if x.get('lts')))" 2>/dev/null || echo "v24.18.0"
;;
latest|node)
curl -fsSL "https://nodejs.org/dist/index.json" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)[0]['version'])" 2>/dev/null || echo "v24.18.0"
;;
*)
echo "v${1#v}"
;;
esac
}
direct_install_binary() {
RESOLVED="$1"
DEST="$NVM_DIR/versions/node/${RESOLVED}"
TMP="/tmp/node-dl-$$"
rm -rf "$TMP" "$DEST"
mkdir -p "$TMP"
if [ -f /etc/alpine-release ]; then
# Node 官方仅 glibc;Alpine musl 走 unofficial-builds // Logan.Li
URLS="https://unofficial-builds.nodejs.org/download/release/${RESOLVED}/node-${RESOLVED}-linux-x64-musl.tar.xz"
else
URLS="${NODE_MIRROR}/${RESOLVED}/node-${RESOLVED}-linux-x64.tar.xz https://nodejs.org/dist/${RESOLVED}/node-${RESOLVED}-linux-x64.tar.xz"
fi
for URL in $URLS; do
echo "[Node.js] Downloading $URL"
rm -rf "$TMP"/* 2>/dev/null || true
if curl -fsSL -L "$URL" | tar -xJ -C "$TMP" 2>/dev/null; then
SUB=$(find "$TMP" -mindepth 1 -maxdepth 1 -type d | head -1)
if [ -n "$SUB" ] && [ -x "$SUB/bin/node" ]; then
mv "$SUB" "$DEST"
rm -rf "$TMP"
echo "[Node.js] Installed $RESOLVED"
return 0
fi
fi
echo "[Node.js] Failed: $URL"
done
rm -rf "$TMP"
return 1
}
RESOLVED=$(resolve_version "$NODE_VERSION")
[ -n "$RESOLVED" ] || { echo "[Node.js] cannot resolve version for $NODE_VERSION"; exit 1; }
echo "[Node.js] Target version: $RESOLVED"
direct_install_binary "$RESOLVED" || { echo "[Node.js] binary install failed"; exit 1; }
INST="$RESOLVED"
mkdir -p /usr/local/bin
ln -sf "$NVM_DIR/versions/node/${INST}/bin/node" /usr/local/bin/node
ln -sf "$NVM_DIR/versions/node/${INST}/bin/npm" /usr/local/bin/npm
ln -sf "$NVM_DIR/versions/node/${INST}/bin/npx" /usr/local/bin/npx
"$NVM_DIR/versions/node/${INST}/bin/npm" config set registry https://registry.npmmirror.com
echo "[Node.js] Installed: $(/usr/local/bin/node --version) / npm $("$NVM_DIR/versions/node/${INST}/bin/npm" --version)"
`,
SortOrder: 5,
},
// ──── Git — 版本控制(懒加载, U4 镜像瘦身)// Logan.Li ────
{
Name: "git",
DisplayName: "Git",
Description: "版本控制工具,流水线代码拉取使用(首次使用自动安装)",
Category: "build",
InstallMethod: ToolLazy,
BinaryName: "git",
InstallPath: "/usr/bin/git",
CheckCommand: "git --version 2>/dev/null",
InstallScript: `apk add --no-cache git`,
SortOrder: 6,
},
// ──── Docker CLI — 容器构建(懒加载, U4 镜像瘦身)// Logan.Li ────
{
Name: "docker-cli",
DisplayName: "Docker CLI",
Description: "Docker 命令行工具,流水线镜像构建/推送使用(首次使用自动安装)",
Category: "deploy",
InstallMethod: ToolLazy,
BinaryName: "docker",
InstallPath: "/usr/bin/docker",
CheckCommand: "docker --version 2>/dev/null",
InstallScript: `apk add --no-cache docker-cli`,
SortOrder: 7,
},
}
}