|
#!/usr/bin/env bash |
|
|
|
set -Eeuo pipefail |
|
|
|
readonly DEFAULT_INSTALL_DIR="/data/komari-agent" |
|
readonly DEFAULT_SERVICE_NAME="komari-agent" |
|
readonly DOWNLOAD_BASE_URL="https://github.com/komari-monitor/komari-agent/releases/latest/download" |
|
|
|
install_dir="${KOMARI_AGENT_DIR:-$DEFAULT_INSTALL_DIR}" |
|
service_name="${KOMARI_AGENT_SERVICE:-$DEFAULT_SERVICE_NAME}" |
|
arch_input="${KOMARI_AGENT_ARCH:-auto}" |
|
dry_run=0 |
|
no_restart=0 |
|
tmp_file="" |
|
backup_file="" |
|
binary_file="" |
|
|
|
log() { |
|
printf '[komari-agent] %s\n' "$*" |
|
} |
|
|
|
warn() { |
|
printf '[komari-agent] warning: %s\n' "$*" >&2 |
|
} |
|
|
|
die() { |
|
printf '[komari-agent] error: %s\n' "$*" >&2 |
|
exit 1 |
|
} |
|
|
|
usage() { |
|
cat <<'EOF' |
|
更新 Komari Agent 二进制文件,并按需重启 systemd 服务。 |
|
|
|
用法: |
|
update-komari-agent.sh [选项] |
|
|
|
选项: |
|
-d, --dir, --install-dir DIR |
|
Agent 所在目录(默认: /data/komari-agent) |
|
-s, --service NAME systemd 服务名(默认: komari-agent) |
|
-a, --arch ARCH 发布包架构;默认根据 uname -m 自动探测 |
|
可用值: amd64, arm64, arm, 386 |
|
--no-restart 只更新文件,不重启 systemd 服务 |
|
--dry-run 只显示解析结果,不下载、不修改文件、不操作服务 |
|
-h, --help 显示帮助 |
|
|
|
也可以使用环境变量: |
|
KOMARI_AGENT_DIR, KOMARI_AGENT_SERVICE, KOMARI_AGENT_ARCH |
|
|
|
示例: |
|
sudo ./update-komari-agent.sh |
|
sudo ./update-komari-agent.sh --dir /opt/komari-agent --service komari-agent |
|
sudo ./update-komari-agent.sh --arch amd64 --no-restart |
|
EOF |
|
} |
|
|
|
parse_args() { |
|
while (($# > 0)); do |
|
case "$1" in |
|
-d|--dir|--install-dir) |
|
(($# >= 2)) || die "选项 $1 缺少参数" |
|
install_dir="$2" |
|
shift 2 |
|
;; |
|
--dir=*|--install-dir=*) |
|
install_dir="${1#*=}" |
|
shift |
|
;; |
|
-s|--service|--service-name) |
|
(($# >= 2)) || die "选项 $1 缺少参数" |
|
service_name="$2" |
|
shift 2 |
|
;; |
|
--service=*|--service-name=*) |
|
service_name="${1#*=}" |
|
shift |
|
;; |
|
-a|--arch|--architecture) |
|
(($# >= 2)) || die "选项 $1 缺少参数" |
|
arch_input="$2" |
|
shift 2 |
|
;; |
|
--arch=*|--architecture=*) |
|
arch_input="${1#*=}" |
|
shift |
|
;; |
|
--no-restart) |
|
no_restart=1 |
|
shift |
|
;; |
|
--dry-run) |
|
dry_run=1 |
|
shift |
|
;; |
|
-h|--help) |
|
usage |
|
exit 0 |
|
;; |
|
--) |
|
shift |
|
(($# == 0)) || die "不支持位置参数: $*" |
|
;; |
|
*) |
|
die "未知选项或位置参数: $1(使用 --help 查看用法)" |
|
;; |
|
esac |
|
done |
|
} |
|
|
|
detect_arch() { |
|
local machine_arch="$1" |
|
|
|
case "$machine_arch" in |
|
x86_64|amd64) |
|
printf 'amd64\n' |
|
;; |
|
aarch64|arm64) |
|
printf 'arm64\n' |
|
;; |
|
armv7l|armv7|armhf|armv6l|armv6) |
|
printf 'arm\n' |
|
;; |
|
i386|i686|x86|386) |
|
printf '386\n' |
|
;; |
|
*) |
|
die "无法为本机架构 '$machine_arch' 找到 Komari Agent 发布包,请使用 --arch 指定" |
|
;; |
|
esac |
|
} |
|
|
|
normalize_arch() { |
|
local requested_arch="$1" |
|
|
|
case "$requested_arch" in |
|
""|auto) |
|
detect_arch "$(uname -m)" |
|
;; |
|
amd64|x86_64) |
|
printf 'amd64\n' |
|
;; |
|
arm64|aarch64) |
|
printf 'arm64\n' |
|
;; |
|
arm|armv7|armv7l|armhf|armv6|armv6l) |
|
printf 'arm\n' |
|
;; |
|
386|i386|i686|x86) |
|
printf '386\n' |
|
;; |
|
*) |
|
die "不支持的架构 '$requested_arch',可用值: amd64, arm64, arm, 386" |
|
;; |
|
esac |
|
} |
|
|
|
cleanup() { |
|
if [[ -n "$tmp_file" && -e "$tmp_file" ]]; then |
|
rm -f -- "$tmp_file" |
|
fi |
|
} |
|
|
|
rollback_binary() { |
|
local failed_file="${binary_file}.failed.$(date +%Y%m%d%H%M%S)-$$" |
|
|
|
if [[ -e "$binary_file" ]]; then |
|
mv -- "$binary_file" "$failed_file" |
|
warn "保留未能启动的新文件: $failed_file" |
|
fi |
|
|
|
if [[ -n "$backup_file" && -e "$backup_file" ]]; then |
|
mv -- "$backup_file" "$binary_file" |
|
log "已恢复旧版 Agent: $binary_file" |
|
fi |
|
} |
|
|
|
download_binary() { |
|
local download_url="$1" |
|
|
|
if command -v curl >/dev/null 2>&1; then |
|
curl \ |
|
--fail \ |
|
--location \ |
|
--show-error \ |
|
--silent \ |
|
--retry 3 \ |
|
--retry-delay 1 \ |
|
--connect-timeout 15 \ |
|
--output "$tmp_file" \ |
|
"$download_url" |
|
elif command -v wget >/dev/null 2>&1; then |
|
wget \ |
|
--tries=3 \ |
|
--timeout=15 \ |
|
--output-document="$tmp_file" \ |
|
"$download_url" |
|
else |
|
die "找不到 curl 或 wget,无法下载 Agent" |
|
fi |
|
} |
|
|
|
parse_args "$@" |
|
|
|
if [[ "$install_dir" == "" ]]; then |
|
die "安装目录不能为空" |
|
fi |
|
|
|
if [[ ! "$service_name" =~ ^[A-Za-z0-9_.@:-]+$ ]]; then |
|
die "非法的 systemd 服务名: $service_name" |
|
fi |
|
|
|
machine_arch="$(uname -m)" |
|
release_arch="$(normalize_arch "$arch_input")" |
|
download_url="${DOWNLOAD_BASE_URL}/komari-agent-linux-${release_arch}" |
|
|
|
if (( dry_run )); then |
|
printf 'install_dir=%s\n' "$install_dir" |
|
printf 'service_name=%s\n' "$service_name" |
|
printf 'machine_arch=%s\n' "$machine_arch" |
|
printf 'release_arch=%s\n' "$release_arch" |
|
printf 'download_url=%s\n' "$download_url" |
|
printf 'restart=%s\n' "$([[ $no_restart -eq 1 ]] && printf no || printf yes)" |
|
exit 0 |
|
fi |
|
|
|
if [[ "$(uname -s)" != "Linux" ]]; then |
|
die "该脚本只支持 Linux" |
|
fi |
|
|
|
if (( ! no_restart )) && (( EUID != 0 )); then |
|
die "需要重启 systemd 服务,请使用 root 运行(例如: sudo $0)" |
|
fi |
|
|
|
if ! command -v uname >/dev/null 2>&1 || ! command -v mktemp >/dev/null 2>&1; then |
|
die "缺少必要命令: uname 或 mktemp" |
|
fi |
|
|
|
mkdir -p -- "$install_dir" |
|
install_dir="$(cd -- "$install_dir" && pwd -P)" |
|
binary_file="${install_dir}/agent" |
|
tmp_file="$(mktemp "${install_dir}/.agent.download.XXXXXX")" |
|
trap cleanup EXIT |
|
|
|
log "本机架构: $machine_arch;下载架构: $release_arch" |
|
log "安装目录: $install_dir;systemd 服务: $service_name" |
|
log "下载: $download_url" |
|
download_binary "$download_url" |
|
|
|
if [[ ! -s "$tmp_file" ]]; then |
|
die "下载结果为空" |
|
fi |
|
|
|
if command -v file >/dev/null 2>&1 && ! file --brief "$tmp_file" | grep -q 'ELF'; then |
|
die "下载结果不是 ELF 可执行文件,已保留现有 Agent" |
|
fi |
|
|
|
chmod 0755 -- "$tmp_file" |
|
|
|
if [[ -e "$binary_file" ]]; then |
|
backup_file="${binary_file}.old.$(date +%Y%m%d%H%M%S)-$$" |
|
mv -- "$binary_file" "$backup_file" |
|
log "旧版 Agent 已备份到: $backup_file" |
|
fi |
|
|
|
mv -- "$tmp_file" "$binary_file" |
|
tmp_file="" |
|
log "新版 Agent 已安装到: $binary_file" |
|
|
|
if (( no_restart )); then |
|
log "按参数跳过 systemd 重启" |
|
exit 0 |
|
fi |
|
|
|
if ! command -v systemctl >/dev/null 2>&1; then |
|
rollback_binary |
|
die "找不到 systemctl,已恢复旧版 Agent" |
|
fi |
|
|
|
if ! systemctl restart "$service_name"; then |
|
warn "systemd 服务重启失败: $service_name" |
|
rollback_binary |
|
systemctl restart "$service_name" || true |
|
die "更新失败,已尝试恢复旧版 Agent" |
|
fi |
|
|
|
if ! systemctl is-active --quiet "$service_name"; then |
|
warn "systemd 服务重启后未处于 active 状态: $service_name" |
|
rollback_binary |
|
systemctl restart "$service_name" || true |
|
die "更新失败,已尝试恢复旧版 Agent" |
|
fi |
|
|
|
log "systemd 服务已重启并处于 active 状态: $service_name" |
|
systemctl --no-pager --full status "$service_name" || true |