Add reusable obsutil installer and update flow

This commit is contained in:
Codex
2026-03-16 19:29:41 +08:00
parent f73e401748
commit 7465658ff7
5 changed files with 160 additions and 5 deletions
+8 -2
View File
@@ -4,7 +4,7 @@
# - 打包多目录(支持 pigz),生成 SHA256 校验,obsutil 分片/并发上传 # - 打包多目录(支持 pigz),生成 SHA256 校验,obsutil 分片/并发上传
# - 上传 .tar.gz 以及 .tar.gz.sha256,并下载远端 .sha256 比对确保完整性 # - 上传 .tar.gz 以及 .tar.gz.sha256,并下载远端 .sha256 比对确保完整性
# - 成功/失败写入日志并 Telegram 通知 # - 成功/失败写入日志并 Telegram 通知
# - 支持 --dry-run / --verify / --keep-local / --concurrency / --rate / --label / --sse # - 支持 --dry-run / --self-check / --verify / --keep-local / --concurrency / --rate / --label / --sse
# 退出码:0 成功;2 配置缺失;3 打包失败;4 上传失败;5 校验失败 # 退出码:0 成功;2 配置缺失;3 打包失败;4 上传失败;5 校验失败
set -Eeuo pipefail set -Eeuo pipefail
@@ -81,6 +81,7 @@ BACKUP_PATHS=()
KEEP_LOCAL=false KEEP_LOCAL=false
DRY_RUN=false DRY_RUN=false
SELF_CHECK=false
VERIFY_ONLY=false VERIFY_ONLY=false
CLI_LABEL="" CLI_LABEL=""
CLI_SSE="none" CLI_SSE="none"
@@ -92,7 +93,7 @@ GPG_SYM=false
usage() { usage() {
cat <<'USAGE' cat <<'USAGE'
用法: 用法:
./backup.sh [--dry-run] [--verify] [--keep-local] ./backup.sh [--dry-run] [--self-check] [--verify] [--keep-local]
[--concurrency=N] [--rate=10MB/s] [--concurrency=N] [--rate=10MB/s]
[--label=NAME] [--label=NAME]
[--sse=none|kms|aes256] [--sse=none|kms|aes256]
@@ -103,6 +104,7 @@ USAGE
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--dry-run) DRY_RUN=true; shift;; --dry-run) DRY_RUN=true; shift;;
--self-check) DRY_RUN=true; SELF_CHECK=true; shift;;
--verify) VERIFY_ONLY=true; shift;; --verify) VERIFY_ONLY=true; shift;;
--keep-local) KEEP_LOCAL=true; shift;; --keep-local) KEEP_LOCAL=true; shift;;
--concurrency=*) CLI_CONCURRENCY="${1#*=}"; shift;; --concurrency=*) CLI_CONCURRENCY="${1#*=}"; shift;;
@@ -524,6 +526,10 @@ if $DRY_RUN; then
log "INFO" "Dry-run 模式:不执行上传。归档:${ARCHIVE_BASE} 大小:${BACKUP_SIZE_HUMAN}" log "INFO" "Dry-run 模式:不执行上传。归档:${ARCHIVE_BASE} 大小:${BACKUP_SIZE_HUMAN}"
log "INFO" "本次总用时:${SECONDS}s" log "INFO" "本次总用时:${SECONDS}s"
tg_backup_dryrun "$LABEL" "$(date +'%Y-%m-%d %H:%M:%S')" "$(printf '%s\n' "${BACKUP_PATHS[@]}")" "$(tg_read_user_excludes "$USER_EXCLUDE_FILE")" "$ARCHIVE_BASE" "$BACKUP_SIZE_HUMAN" "${PACK_SECONDS}s" tg_backup_dryrun "$LABEL" "$(date +'%Y-%m-%d %H:%M:%S')" "$(printf '%s\n' "${BACKUP_PATHS[@]}")" "$(tg_read_user_excludes "$USER_EXCLUDE_FILE")" "$ARCHIVE_BASE" "$BACKUP_SIZE_HUMAN" "${PACK_SECONDS}s"
if $SELF_CHECK; then
rm -f "$ARCHIVE_PATH" "$SHA_PATH" || true
log "INFO" "Self-check 模式:已删除本地自检归档与校验文件"
fi
exit 0 exit 0
fi fi
+18
View File
@@ -14,6 +14,7 @@ usage() {
./install.sh [--user=NAME] [--mode=system|user] [--dry-run] ./install.sh [--user=NAME] [--mode=system|user] [--dry-run]
说明: 说明:
- 若未检测到仓库内 obsutil,会自动调用 lib/obsutil.sh 安装
- system 模式会安装到 /etc/systemd/system - system 模式会安装到 /etc/systemd/system
- user 模式会安装到 ~/.config/systemd/user - user 模式会安装到 ~/.config/systemd/user
- 不会覆盖已有 env.conf 和 exclude.user.list - 不会覆盖已有 env.conf 和 exclude.user.list
@@ -61,6 +62,18 @@ if [[ "$INSTALL_MODE" == "user" ]]; then
SYSTEMD_DIR="${HOME_DIR}/.config/systemd/user" SYSTEMD_DIR="${HOME_DIR}/.config/systemd/user"
fi fi
if [[ -f "${SCRIPT_DIR}/obsutil" ]]; then
chmod 755 "${SCRIPT_DIR}/obsutil"
echo "已检测到仓库内 obsutil${SCRIPT_DIR}/obsutil"
else
chmod 755 "${SCRIPT_DIR}/lib/obsutil.sh"
if $DRY_RUN; then
bash "${SCRIPT_DIR}/lib/obsutil.sh" --dry-run
else
bash "${SCRIPT_DIR}/lib/obsutil.sh"
fi
fi
mkdir -p "${SCRIPT_DIR}/systemd" mkdir -p "${SCRIPT_DIR}/systemd"
if [[ ! -f "${SCRIPT_DIR}/env.conf" ]]; then if [[ ! -f "${SCRIPT_DIR}/env.conf" ]]; then
@@ -84,10 +97,15 @@ fi
chmod 755 \ chmod 755 \
"${SCRIPT_DIR}/backup.sh" \ "${SCRIPT_DIR}/backup.sh" \
"${SCRIPT_DIR}/clean_backups.sh" \ "${SCRIPT_DIR}/clean_backups.sh" \
"${SCRIPT_DIR}/lib/obsutil.sh" \
"${SCRIPT_DIR}/lib/telegram.sh" \ "${SCRIPT_DIR}/lib/telegram.sh" \
"${SCRIPT_DIR}/install.sh" \ "${SCRIPT_DIR}/install.sh" \
"${SCRIPT_DIR}/update.sh" "${SCRIPT_DIR}/update.sh"
if [[ -f "${SCRIPT_DIR}/obsutil" ]]; then
chmod 755 "${SCRIPT_DIR}/obsutil"
fi
if $DRY_RUN; then if $DRY_RUN; then
echo "[dry-run] 目标 systemd 目录:$SYSTEMD_DIR" echo "[dry-run] 目标 systemd 目录:$SYSTEMD_DIR"
else else
Executable
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# 下载或更新仓库内的 obsutil 二进制。
# - 默认安装到仓库根目录下的 ./obsutil
# - 若系统已有 obsutil,不会覆盖;只管理仓库内副本
# - install.sh 和手动维护都可复用这个脚本
set -Eeuo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}"
LIB_DIR="$(cd "$(dirname -- "$SCRIPT_PATH")" && pwd -P)"
ROOT_DIR="$(cd "${LIB_DIR}/.." && pwd -P)"
TARGET_BIN="${ROOT_DIR}/obsutil"
DRY_RUN=false
usage() {
cat <<'USAGE'
用法:
./lib/obsutil.sh [--dry-run]
说明:
- 下载并安装或更新仓库内的 ./obsutil
- 默认覆盖仓库里的旧版本
- dry-run 只打印将执行的动作,不实际下载
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "未知参数:$1" >&2; usage; exit 2 ;;
esac
done
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "缺少命令:$1" >&2
exit 2
}
}
download_file() {
local url="$1"
local output="$2"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$url" -o "$output"
return 0
fi
if command -v wget >/dev/null 2>&1; then
wget -qO "$output" "$url"
return 0
fi
echo "缺少下载工具:curl 或 wget" >&2
exit 2
}
resolve_package_name() {
case "$(uname -m)" in
x86_64|amd64) printf '%s\n' "obsutil_linux_amd64.tar.gz" ;;
aarch64|arm64) printf '%s\n' "obsutil_linux_arm64.tar.gz" ;;
*)
echo "不支持的 CPU 架构:$(uname -m)" >&2
echo "请手动安装 obsutil 后再试" >&2
exit 2
;;
esac
}
need_cmd install
need_cmd tar
PACKAGE_NAME="$(resolve_package_name)"
DOWNLOAD_URL="https://obs-community-intl.obs.ap-southeast-1.myhuaweicloud.com/obsutil/current/${PACKAGE_NAME}"
if $DRY_RUN; then
if [[ -x "$TARGET_BIN" ]]; then
echo "[dry-run] 将更新仓库内 obsutil${TARGET_BIN}"
else
echo "[dry-run] 将安装仓库内 obsutil${TARGET_BIN}"
fi
echo "[dry-run] 下载地址:${DOWNLOAD_URL}"
exit 0
fi
TMP_DIR="$(mktemp -d)"
ARCHIVE_PATH="${TMP_DIR}/${PACKAGE_NAME}"
trap 'rm -rf "$TMP_DIR"' EXIT
if [[ -x "$TARGET_BIN" ]]; then
echo "开始更新仓库内 obsutil${TARGET_BIN}"
else
echo "开始安装仓库内 obsutil${TARGET_BIN}"
fi
download_file "$DOWNLOAD_URL" "$ARCHIVE_PATH"
tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR"
BINARY_PATH="$(find "$TMP_DIR" -type f -name obsutil | head -n 1)"
if [[ -z "$BINARY_PATH" ]]; then
echo "下载包中未找到 obsutil 可执行文件" >&2
exit 2
fi
install -m 755 "$BINARY_PATH" "$TARGET_BIN"
VERSION_OUTPUT="$("$TARGET_BIN" version 2>/dev/null || true)"
if [[ -z "$VERSION_OUTPUT" ]]; then
echo "obsutil 已安装,但运行校验失败:${TARGET_BIN}" >&2
exit 2
fi
echo "obsutil 已就绪:${TARGET_BIN}"
echo "$VERSION_OUTPUT" | head -n 1
+17 -1
View File
@@ -4,6 +4,7 @@
- `backup.sh`:打包目录、生成 `sha256`、上传到 OBS、下载远端校验文件做一致性校验 - `backup.sh`:打包目录、生成 `sha256`、上传到 OBS、下载远端校验文件做一致性校验
- `clean_backups.sh`:按文件名日期清理旧备份 - `clean_backups.sh`:按文件名日期清理旧备份
- `lib/obsutil.sh`:下载或更新仓库根目录下的 `./obsutil`
- `lib/telegram.sh`:统一处理 Telegram 通知模板和发送逻辑 - `lib/telegram.sh`:统一处理 Telegram 通知模板和发送逻辑
## 配置 ## 配置
@@ -49,6 +50,12 @@ EOF
./backup.sh --dry-run ./backup.sh --dry-run
``` ```
仅做自检,且不保留本地归档:
```bash
./backup.sh --self-check
```
检查远端前缀是否可访问: 检查远端前缀是否可访问:
```bash ```bash
@@ -73,6 +80,7 @@ cd /root/backup_OBS
`install.sh` 会自动完成: `install.sh` 会自动完成:
- 如果未检测到仓库根目录下的 `./obsutil`,则自动调用 `./lib/obsutil.sh`
- 如果不存在,则创建 `env.conf` - 如果不存在,则创建 `env.conf`
- 如果不存在,则创建 `exclude.user.list` - 如果不存在,则创建 `exclude.user.list`
- 修正脚本执行权限 - 修正脚本执行权限
@@ -93,6 +101,14 @@ cd /root/backup_OBS
- `system` 模式需要 root 权限 - `system` 模式需要 root 权限
- `user` 模式会安装到 `~/.config/systemd/user` - `user` 模式会安装到 `~/.config/systemd/user`
- 安装脚本不会覆盖已有的 `env.conf``exclude.user.list` - 安装脚本不会覆盖已有的 `env.conf``exclude.user.list`
- `install.sh` 和后续脚本都只使用仓库根目录下的 `./obsutil`
- `obsutil` 安装完成后,首次仍需手动执行 `./obsutil config -interactive`
如果你想手动安装或更新仓库根目录下的 `./obsutil`,可以直接执行:
```bash
./lib/obsutil.sh
```
常用查看命令: 常用查看命令:
@@ -114,7 +130,7 @@ journalctl -u backup-obs-update.service -n 100
- `git fetch --tags origin` - `git fetch --tags origin`
- 默认更新 `stable` 分支,或切换到你指定的 tag / 分支 - 默认更新 `stable` 分支,或切换到你指定的 tag / 分支
- 修正脚本执行权限 - 修正脚本执行权限
- 自动执行一次 `./backup.sh --dry-run` 自检 - 自动执行一次 `./backup.sh --self-check` 自检
也可以手动指定版本: 也可以手动指定版本:
+2 -2
View File
@@ -13,7 +13,7 @@ usage() {
说明: 说明:
- 不带参数时,默认更新 stable 分支 - 不带参数时,默认更新 stable 分支
- 带参数时,可以切换到指定分支或 tag - 带参数时,可以切换到指定分支或 tag
- 更新后会自动执行一次 ./backup.sh --dry-run 自检 - 更新后会自动执行一次 ./backup.sh --self-check 自检
USAGE USAGE
} }
@@ -53,4 +53,4 @@ chmod 755 \
"${SCRIPT_DIR}/install.sh" \ "${SCRIPT_DIR}/install.sh" \
"${SCRIPT_DIR}/update.sh" "${SCRIPT_DIR}/update.sh"
bash "${SCRIPT_DIR}/backup.sh" --dry-run bash "${SCRIPT_DIR}/backup.sh" --self-check