mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-09-08 08:57:01 +08:00
功能: 新增 installscript 包,渲染 systemd/docker/foreground 安装脚本
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
# BackupX Agent docker-compose 片段
|
||||||
|
# 生成于 {{.MasterURL}} · 节点 ID {{.NodeID}}
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
backupx-agent:
|
||||||
|
image: awuqing/backupx:{{.AgentVersion}}
|
||||||
|
command: ["agent"]
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
BACKUPX_AGENT_MASTER: "{{.MasterURL}}"
|
||||||
|
BACKUPX_AGENT_TOKEN: "{{.AgentToken}}"
|
||||||
|
volumes:
|
||||||
|
- /var/lib/backupx-agent:/tmp/backupx-agent
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# BackupX Agent 一键安装脚本(由 Master 动态渲染)
|
||||||
|
# 模式: {{.Mode}} | 架构: {{.Arch}} | 版本: {{.AgentVersion}}
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
MASTER_URL="{{.MasterURL}}"
|
||||||
|
AGENT_TOKEN="{{.AgentToken}}"
|
||||||
|
AGENT_VERSION="{{.AgentVersion}}"
|
||||||
|
DOWNLOAD_BASE="{{.DownloadBase}}"
|
||||||
|
INSTALL_PREFIX="{{.InstallPrefix}}"
|
||||||
|
ARCH="{{.Arch}}"
|
||||||
|
|
||||||
|
# 1. 前置检查
|
||||||
|
[ "$(id -u)" -eq 0 ] || { echo "请使用 root 或 sudo 执行" >&2; exit 1; }
|
||||||
|
command -v curl >/dev/null || command -v wget >/dev/null \
|
||||||
|
|| { echo "需要 curl 或 wget" >&2; exit 1; }
|
||||||
|
{{if eq .Mode "systemd"}}command -v systemctl >/dev/null || { echo "不支持非 systemd 系统" >&2; exit 1; }
|
||||||
|
{{end}}{{if eq .Mode "docker"}}command -v docker >/dev/null || { echo "需要先安装 docker" >&2; exit 1; }
|
||||||
|
{{end}}
|
||||||
|
# 2. 架构检测
|
||||||
|
if [ "$ARCH" = "auto" ]; then
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) ARCH=amd64 ;;
|
||||||
|
aarch64|arm64) ARCH=arm64 ;;
|
||||||
|
*) echo "不支持的架构: $(uname -m)" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
{{if ne .Mode "docker"}}
|
||||||
|
# 3. 下载二进制(systemd / foreground 模式)
|
||||||
|
ARCHIVE="backupx-${AGENT_VERSION}-linux-${ARCH}.tar.gz"
|
||||||
|
URL="${DOWNLOAD_BASE}/${AGENT_VERSION}/${ARCHIVE}"
|
||||||
|
TMPDIR="$(mktemp -d)"; trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
echo "[1/4] 下载 ${URL}"
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
curl -fsSL "$URL" -o "$TMPDIR/pkg.tar.gz"
|
||||||
|
else
|
||||||
|
wget -qO "$TMPDIR/pkg.tar.gz" "$URL"
|
||||||
|
fi
|
||||||
|
tar xzf "$TMPDIR/pkg.tar.gz" -C "$TMPDIR"
|
||||||
|
|
||||||
|
# 4. 安装二进制 + 用户
|
||||||
|
echo "[2/4] 安装到 ${INSTALL_PREFIX}"
|
||||||
|
id backupx >/dev/null 2>&1 || useradd --system --home-dir "$INSTALL_PREFIX" --shell /usr/sbin/nologin backupx
|
||||||
|
install -d -o backupx -g backupx "$INSTALL_PREFIX" /var/lib/backupx-agent
|
||||||
|
install -m 0755 "$TMPDIR/backupx-${AGENT_VERSION}-linux-${ARCH}/backupx" "$INSTALL_PREFIX/backupx"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "systemd"}}
|
||||||
|
# 5. systemd unit
|
||||||
|
echo "[3/4] 配置 systemd"
|
||||||
|
cat > /etc/systemd/system/backupx-agent.service <<UNIT
|
||||||
|
[Unit]
|
||||||
|
Description=BackupX Agent
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=backupx
|
||||||
|
Environment="BACKUPX_AGENT_MASTER=${MASTER_URL}"
|
||||||
|
Environment="BACKUPX_AGENT_TOKEN=${AGENT_TOKEN}"
|
||||||
|
ExecStart=${INSTALL_PREFIX}/backupx agent --temp-dir /var/lib/backupx-agent
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
UNIT
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now backupx-agent
|
||||||
|
|
||||||
|
# 6. 等待上线
|
||||||
|
echo "[4/4] 等待节点上线"
|
||||||
|
for i in $(seq 1 15); do
|
||||||
|
sleep 2
|
||||||
|
if curl -fsSL -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null \
|
||||||
|
| grep -q '"status":"online"'; then
|
||||||
|
echo "✓ 节点已上线"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "⚠ 30s 内未收到上线心跳,请检查防火墙或 journalctl -u backupx-agent"
|
||||||
|
exit 2
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "foreground"}}
|
||||||
|
# 5. 前台运行
|
||||||
|
echo "[3/3] 前台启动 agent(Ctrl+C 退出)"
|
||||||
|
export BACKUPX_AGENT_MASTER="${MASTER_URL}"
|
||||||
|
export BACKUPX_AGENT_TOKEN="${AGENT_TOKEN}"
|
||||||
|
exec "${INSTALL_PREFIX}/backupx" agent --temp-dir /var/lib/backupx-agent
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "docker"}}
|
||||||
|
# Docker 模式:直接用镜像启动容器
|
||||||
|
echo "[1/2] 拉取镜像 awuqing/backupx:${AGENT_VERSION}"
|
||||||
|
docker pull "awuqing/backupx:${AGENT_VERSION}"
|
||||||
|
echo "[2/2] 启动容器 backupx-agent"
|
||||||
|
docker rm -f backupx-agent >/dev/null 2>&1 || true
|
||||||
|
docker run -d --name backupx-agent --restart=unless-stopped \
|
||||||
|
-e "BACKUPX_AGENT_MASTER=${MASTER_URL}" \
|
||||||
|
-e "BACKUPX_AGENT_TOKEN=${AGENT_TOKEN}" \
|
||||||
|
-v /var/lib/backupx-agent:/tmp/backupx-agent \
|
||||||
|
"awuqing/backupx:${AGENT_VERSION}" agent
|
||||||
|
echo "✓ 容器已启动"
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// Package installscript 负责把一次性安装令牌 + 节点配置渲染为可执行 shell 脚本或 docker-compose YAML。
|
||||||
|
//
|
||||||
|
// 模板文件通过 go:embed 嵌入二进制,避免运行时依赖外部资源。
|
||||||
|
package installscript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"backupx/server/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed templates/agent-install.sh.tmpl
|
||||||
|
var installScriptTmpl string
|
||||||
|
|
||||||
|
//go:embed templates/agent-compose.yml.tmpl
|
||||||
|
var composeYamlTmpl string
|
||||||
|
|
||||||
|
// Context 是模板渲染输入。
|
||||||
|
type Context struct {
|
||||||
|
MasterURL string
|
||||||
|
AgentToken string
|
||||||
|
AgentVersion string
|
||||||
|
Mode string // systemd|docker|foreground
|
||||||
|
Arch string // amd64|arm64|auto
|
||||||
|
DownloadBase string
|
||||||
|
InstallPrefix string
|
||||||
|
NodeID uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadBaseFor 将下载源枚举转换为具体 URL 前缀。
|
||||||
|
func DownloadBaseFor(src string) string {
|
||||||
|
switch src {
|
||||||
|
case model.InstallSourceGhproxy:
|
||||||
|
return "https://ghproxy.com/https://github.com/Awuqing/BackupX/releases/download"
|
||||||
|
default:
|
||||||
|
return "https://github.com/Awuqing/BackupX/releases/download"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderScript 渲染目标机安装脚本。
|
||||||
|
func RenderScript(ctx Context) (string, error) {
|
||||||
|
ctx = withDefaults(ctx)
|
||||||
|
tmpl, err := template.New("install").Parse(installScriptTmpl)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("parse template: %w", err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, ctx); err != nil {
|
||||||
|
return "", fmt.Errorf("execute template: %w", err)
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderComposeYaml 渲染 docker-compose.yml 片段。
|
||||||
|
func RenderComposeYaml(ctx Context) (string, error) {
|
||||||
|
ctx = withDefaults(ctx)
|
||||||
|
tmpl, err := template.New("compose").Parse(composeYamlTmpl)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("parse template: %w", err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, ctx); err != nil {
|
||||||
|
return "", fmt.Errorf("execute template: %w", err)
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withDefaults(ctx Context) Context {
|
||||||
|
if ctx.InstallPrefix == "" {
|
||||||
|
ctx.InstallPrefix = "/opt/backupx-agent"
|
||||||
|
}
|
||||||
|
if ctx.DownloadBase == "" {
|
||||||
|
ctx.DownloadBase = DownloadBaseFor(model.InstallSourceGitHub)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package installscript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"backupx/server/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testCtx = Context{
|
||||||
|
MasterURL: "https://master.example.com",
|
||||||
|
AgentToken: "test-token-hex",
|
||||||
|
AgentVersion: "v1.7.0",
|
||||||
|
Mode: model.InstallModeSystemd,
|
||||||
|
Arch: model.InstallArchAuto,
|
||||||
|
DownloadBase: "https://github.com/Awuqing/BackupX/releases/download",
|
||||||
|
InstallPrefix: "/opt/backupx-agent",
|
||||||
|
NodeID: 42,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderScriptSystemd(t *testing.T) {
|
||||||
|
got, err := RenderScript(testCtx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render err: %v", err)
|
||||||
|
}
|
||||||
|
mustContain := []string{
|
||||||
|
"BACKUPX_AGENT_MASTER=${MASTER_URL}",
|
||||||
|
`Environment="BACKUPX_AGENT_TOKEN=${AGENT_TOKEN}"`,
|
||||||
|
"systemctl daemon-reload",
|
||||||
|
"systemctl enable --now backupx-agent",
|
||||||
|
"X-Agent-Token: ${AGENT_TOKEN}",
|
||||||
|
"MASTER_URL=\"https://master.example.com\"",
|
||||||
|
"AGENT_TOKEN=\"test-token-hex\"",
|
||||||
|
}
|
||||||
|
for _, s := range mustContain {
|
||||||
|
if !strings.Contains(got, s) {
|
||||||
|
t.Errorf("systemd script missing %q", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mustNotContain := []string{"docker run", `exec "${INSTALL_PREFIX}/backupx" agent --temp-dir`}
|
||||||
|
for _, s := range mustNotContain {
|
||||||
|
if strings.Contains(got, s) {
|
||||||
|
t.Errorf("systemd script unexpectedly contains %q", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderScriptForeground(t *testing.T) {
|
||||||
|
ctx := testCtx
|
||||||
|
ctx.Mode = model.InstallModeForeground
|
||||||
|
got, err := RenderScript(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render err: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, `exec "${INSTALL_PREFIX}/backupx" agent`) {
|
||||||
|
t.Errorf("foreground script missing exec line:\n%s", got)
|
||||||
|
}
|
||||||
|
if strings.Contains(got, "systemctl daemon-reload") {
|
||||||
|
t.Errorf("foreground script should not reference systemctl:\n%s", got)
|
||||||
|
}
|
||||||
|
if strings.Contains(got, "docker run") {
|
||||||
|
t.Errorf("foreground script should not reference docker:\n%s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderScriptDocker(t *testing.T) {
|
||||||
|
ctx := testCtx
|
||||||
|
ctx.Mode = model.InstallModeDocker
|
||||||
|
got, err := RenderScript(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render err: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, "docker run") {
|
||||||
|
t.Errorf("docker script missing `docker run`:\n%s", got)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, "awuqing/backupx:${AGENT_VERSION}") {
|
||||||
|
t.Errorf("docker script missing image tag reference:\n%s", got)
|
||||||
|
}
|
||||||
|
if strings.Contains(got, "systemctl daemon-reload") {
|
||||||
|
t.Errorf("docker script should not reference systemctl:\n%s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderComposeYaml(t *testing.T) {
|
||||||
|
ctx := testCtx
|
||||||
|
ctx.Mode = model.InstallModeDocker
|
||||||
|
got, err := RenderComposeYaml(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render err: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, "image: awuqing/backupx:v1.7.0") {
|
||||||
|
t.Errorf("compose missing image:\n%s", got)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, `BACKUPX_AGENT_TOKEN: "test-token-hex"`) {
|
||||||
|
t.Errorf("compose missing token env:\n%s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDownloadBaseMapping(t *testing.T) {
|
||||||
|
cases := map[string]string{
|
||||||
|
model.InstallSourceGitHub: "https://github.com/Awuqing/BackupX/releases/download",
|
||||||
|
model.InstallSourceGhproxy: "https://ghproxy.com/https://github.com/Awuqing/BackupX/releases/download",
|
||||||
|
}
|
||||||
|
for src, want := range cases {
|
||||||
|
got := DownloadBaseFor(src)
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("src=%s want=%s got=%s", src, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderScriptDefaultsApplied(t *testing.T) {
|
||||||
|
ctx := testCtx
|
||||||
|
ctx.InstallPrefix = "" // 应被默认为 /opt/backupx-agent
|
||||||
|
ctx.DownloadBase = "" // 应被默认为 github
|
||||||
|
got, err := RenderScript(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render err: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, "INSTALL_PREFIX=\"/opt/backupx-agent\"") {
|
||||||
|
t.Errorf("default InstallPrefix not applied:\n%s", got)
|
||||||
|
}
|
||||||
|
if !strings.Contains(got, "DOWNLOAD_BASE=\"https://github.com/Awuqing/BackupX/releases/download\"") {
|
||||||
|
t.Errorf("default DownloadBase not applied:\n%s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# BackupX Agent docker-compose 片段
|
||||||
|
# 生成于 {{.MasterURL}} · 节点 ID {{.NodeID}}
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
backupx-agent:
|
||||||
|
image: awuqing/backupx:{{.AgentVersion}}
|
||||||
|
command: ["agent"]
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
BACKUPX_AGENT_MASTER: "{{.MasterURL}}"
|
||||||
|
BACKUPX_AGENT_TOKEN: "{{.AgentToken}}"
|
||||||
|
volumes:
|
||||||
|
- /var/lib/backupx-agent:/tmp/backupx-agent
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# BackupX Agent 一键安装脚本(由 Master 动态渲染)
|
||||||
|
# 模式: {{.Mode}} | 架构: {{.Arch}} | 版本: {{.AgentVersion}}
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
MASTER_URL="{{.MasterURL}}"
|
||||||
|
AGENT_TOKEN="{{.AgentToken}}"
|
||||||
|
AGENT_VERSION="{{.AgentVersion}}"
|
||||||
|
DOWNLOAD_BASE="{{.DownloadBase}}"
|
||||||
|
INSTALL_PREFIX="{{.InstallPrefix}}"
|
||||||
|
ARCH="{{.Arch}}"
|
||||||
|
|
||||||
|
# 1. 前置检查
|
||||||
|
[ "$(id -u)" -eq 0 ] || { echo "请使用 root 或 sudo 执行" >&2; exit 1; }
|
||||||
|
command -v curl >/dev/null || command -v wget >/dev/null \
|
||||||
|
|| { echo "需要 curl 或 wget" >&2; exit 1; }
|
||||||
|
{{if eq .Mode "systemd"}}command -v systemctl >/dev/null || { echo "不支持非 systemd 系统" >&2; exit 1; }
|
||||||
|
{{end}}{{if eq .Mode "docker"}}command -v docker >/dev/null || { echo "需要先安装 docker" >&2; exit 1; }
|
||||||
|
{{end}}
|
||||||
|
# 2. 架构检测
|
||||||
|
if [ "$ARCH" = "auto" ]; then
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) ARCH=amd64 ;;
|
||||||
|
aarch64|arm64) ARCH=arm64 ;;
|
||||||
|
*) echo "不支持的架构: $(uname -m)" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
{{if ne .Mode "docker"}}
|
||||||
|
# 3. 下载二进制(systemd / foreground 模式)
|
||||||
|
ARCHIVE="backupx-${AGENT_VERSION}-linux-${ARCH}.tar.gz"
|
||||||
|
URL="${DOWNLOAD_BASE}/${AGENT_VERSION}/${ARCHIVE}"
|
||||||
|
TMPDIR="$(mktemp -d)"; trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
echo "[1/4] 下载 ${URL}"
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
curl -fsSL "$URL" -o "$TMPDIR/pkg.tar.gz"
|
||||||
|
else
|
||||||
|
wget -qO "$TMPDIR/pkg.tar.gz" "$URL"
|
||||||
|
fi
|
||||||
|
tar xzf "$TMPDIR/pkg.tar.gz" -C "$TMPDIR"
|
||||||
|
|
||||||
|
# 4. 安装二进制 + 用户
|
||||||
|
echo "[2/4] 安装到 ${INSTALL_PREFIX}"
|
||||||
|
id backupx >/dev/null 2>&1 || useradd --system --home-dir "$INSTALL_PREFIX" --shell /usr/sbin/nologin backupx
|
||||||
|
install -d -o backupx -g backupx "$INSTALL_PREFIX" /var/lib/backupx-agent
|
||||||
|
install -m 0755 "$TMPDIR/backupx-${AGENT_VERSION}-linux-${ARCH}/backupx" "$INSTALL_PREFIX/backupx"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "systemd"}}
|
||||||
|
# 5. systemd unit
|
||||||
|
echo "[3/4] 配置 systemd"
|
||||||
|
cat > /etc/systemd/system/backupx-agent.service <<UNIT
|
||||||
|
[Unit]
|
||||||
|
Description=BackupX Agent
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=backupx
|
||||||
|
Environment="BACKUPX_AGENT_MASTER=${MASTER_URL}"
|
||||||
|
Environment="BACKUPX_AGENT_TOKEN=${AGENT_TOKEN}"
|
||||||
|
ExecStart=${INSTALL_PREFIX}/backupx agent --temp-dir /var/lib/backupx-agent
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
UNIT
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now backupx-agent
|
||||||
|
|
||||||
|
# 6. 等待上线
|
||||||
|
echo "[4/4] 等待节点上线"
|
||||||
|
for i in $(seq 1 15); do
|
||||||
|
sleep 2
|
||||||
|
if curl -fsSL -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null \
|
||||||
|
| grep -q '"status":"online"'; then
|
||||||
|
echo "✓ 节点已上线"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "⚠ 30s 内未收到上线心跳,请检查防火墙或 journalctl -u backupx-agent"
|
||||||
|
exit 2
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "foreground"}}
|
||||||
|
# 5. 前台运行
|
||||||
|
echo "[3/3] 前台启动 agent(Ctrl+C 退出)"
|
||||||
|
export BACKUPX_AGENT_MASTER="${MASTER_URL}"
|
||||||
|
export BACKUPX_AGENT_TOKEN="${AGENT_TOKEN}"
|
||||||
|
exec "${INSTALL_PREFIX}/backupx" agent --temp-dir /var/lib/backupx-agent
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Mode "docker"}}
|
||||||
|
# Docker 模式:直接用镜像启动容器
|
||||||
|
echo "[1/2] 拉取镜像 awuqing/backupx:${AGENT_VERSION}"
|
||||||
|
docker pull "awuqing/backupx:${AGENT_VERSION}"
|
||||||
|
echo "[2/2] 启动容器 backupx-agent"
|
||||||
|
docker rm -f backupx-agent >/dev/null 2>&1 || true
|
||||||
|
docker run -d --name backupx-agent --restart=unless-stopped \
|
||||||
|
-e "BACKUPX_AGENT_MASTER=${MASTER_URL}" \
|
||||||
|
-e "BACKUPX_AGENT_TOKEN=${AGENT_TOKEN}" \
|
||||||
|
-v /var/lib/backupx-agent:/tmp/backupx-agent \
|
||||||
|
"awuqing/backupx:${AGENT_VERSION}" agent
|
||||||
|
echo "✓ 容器已启动"
|
||||||
|
{{end}}
|
||||||
Reference in New Issue
Block a user