#!/usr/bin/env bash # 在"目标库所在主机"上安装/更新**整库逻辑备份**的定时计划(幂等)。 # 平台的「系统设置 → 存储与备份」通过 SSH 下发时会调用它;也可在主机上手工执行。 # # 用法(在目标主机上,需要 root): # bash install_backup_schedule.sh --show # 只打印当前计划 # bash install_backup_schedule.sh --time 03:30 --days 7 --months 3 # bash install_backup_schedule.sh --disable # 关闭定时(保留已生成的备份) # # 落盘: # /etc/knowledge-governance/backup-schedule.env 计划参数(0600) # /etc/cron.d/kb-logical-backup cron 条目(0644,root:root) # $KB_BACKUP_ROOT/logs/logical-backup.log 运行日志 # # 输出最后一行固定为 SCHEDULE_APPLIED …,供平台解析核对。 set -euo pipefail if [ -f /etc/knowledge-governance/backup.env ]; then # shellcheck disable=SC1091 . /etc/knowledge-governance/backup.env fi KB_BACKUP_ROOT="${KB_BACKUP_ROOT:-/srv/kb-backups}" BACKUP_SCRIPT="${BACKUP_SCRIPT:-/opt/weknora-test/logical-backup.sh}" SCHEDULE_ENV="/etc/knowledge-governance/backup-schedule.env" CRON_FILE="/etc/cron.d/kb-logical-backup" LOG_FILE="$KB_BACKUP_ROOT/logs/logical-backup.log" TIME=""; DAYS=""; MONTHS=""; MODE="apply" while [ $# -gt 0 ]; do case "$1" in --time) TIME="${2:-}"; shift 2 ;; --days) DAYS="${2:-}"; shift 2 ;; --months) MONTHS="${2:-}"; shift 2 ;; --disable) MODE="disable"; shift ;; --show) MODE="show"; shift ;; *) echo "未知参数: $1" >&2; exit 2 ;; esac done show_state() { echo "备份脚本: $BACKUP_SCRIPT $([ -x "$BACKUP_SCRIPT" ] || [ -f "$BACKUP_SCRIPT" ] && echo '(存在)' || echo '(缺失)')" if [ -f "$SCHEDULE_ENV" ]; then echo "计划参数: $(grep -v '^#' "$SCHEDULE_ENV" | paste -sd' ' -)" else echo "计划参数: 未配置" fi if [ -f "$CRON_FILE" ]; then echo "cron 条目:" # 只列计划行(去掉 SHELL=/PATH= 这类环境行),否则平台会把环境变量当计划回显 grep -E '^[0-9*@]' "$CRON_FILE" | sed 's/^/ /' else echo "cron 条目: 未安装(定时关闭)" fi if command -v systemctl >/dev/null 2>&1; then echo "cron 服务: $(systemctl is-active cron 2>/dev/null || systemctl is-active crond 2>/dev/null || echo unknown)" fi echo "备份根目录: $KB_BACKUP_ROOT($(du -sh "$KB_BACKUP_ROOT/rds-logical" 2>/dev/null | cut -f1 || echo 0) 已用)" } if [ "$MODE" = "show" ]; then show_state exit 0 fi if [ "$MODE" = "disable" ]; then rm -f "$CRON_FILE" if [ -f "$SCHEDULE_ENV" ]; then sed -i 's/^KB_BACKUP_SCHEDULE_ENABLED=.*/KB_BACKUP_SCHEDULE_ENABLED=0/' "$SCHEDULE_ENV" || true fi echo "已关闭定时备份(已生成的备份保留)。" echo "SCHEDULE_APPLIED enabled=0" exit 0 fi # ---- 参数校验(错就拒绝,不落半成品)---- case "$TIME" in [0-2][0-9]:[0-5][0-9]) ;; *) echo "--time 必须是 HH:MM(00:00~23:59),收到 '$TIME'" >&2; exit 2 ;; esac case "$DAYS" in ''|*[!0-9]*) echo "--days 必须是整数" >&2; exit 2 ;; esac case "$MONTHS" in ''|*[!0-9]*) echo "--months 必须是整数" >&2; exit 2 ;; esac [ "$DAYS" -ge 1 ] && [ "$DAYS" -le 365 ] || { echo "--days 需在 1~365" >&2; exit 2; } [ "$MONTHS" -ge 0 ] && [ "$MONTHS" -le 24 ] || { echo "--months 需在 0~24" >&2; exit 2; } [ -f "$BACKUP_SCRIPT" ] || { echo "备份脚本不存在: $BACKUP_SCRIPT" >&2; exit 2; } HOUR="${TIME%%:*}"; MINUTE="${TIME##*:}" # cron 里不能出现未转义的 %;这里全程不使用 % 以免歧义。 CRON_LINE="$MINUTE $HOUR * * * root /bin/bash $BACKUP_SCRIPT >> $LOG_FILE 2>&1" mkdir -p "$KB_BACKUP_ROOT/logs" "$(dirname "$SCHEDULE_ENV")" cat >"$SCHEDULE_ENV" <"$CRON_FILE" </dev/null || true NEXT_RUN="$(date -d "today $TIME" '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null || echo unknown)" if [ "$NEXT_RUN" != "unknown" ] && [ "$(date -d "today $TIME" +%s)" -le "$(date +%s)" ]; then NEXT_RUN="$(date -d "tomorrow $TIME" '+%Y-%m-%dT%H:%M:%S%z')" fi echo "计划已下发:每天 $TIME(保留 $DAYS 天,另按自然月保留 $MONTHS 份)" echo "cron 文件:$CRON_FILE" echo "下次执行:$NEXT_RUN" echo "SCHEDULE_APPLIED enabled=1 time=$TIME days=$DAYS months=$MONTHS next=$NEXT_RUN cron=$CRON_FILE"