切換選單
切換偏好設定選單
切換個人選單
尚未登入
若您做出任何編輯,會公開您的 IP 位址。

使用搬瓦工api自動周期性創建快照並telegrambot通知

出自md5.pw
這是此頁面最近一次修訂;沒有已批准修訂。

注意: 創建快照的過程中,虛擬機會自動重啟!

請先閱讀關於 快照、備份與恢復 了解 此項功能

快照、備份與恢復

使用前

獲取telegramBot bot token和chat_id

請參考 使用搬瓦工api監控網絡流量的使用並telegrambot通知

再次提醒:

務必保管好bot token 和 chat_id

務必保管好bot token 和 chat_id

務必保管好bot token 和 chat_id

獲取搬瓦工api_key和veid(伺服器id)

請參考: 搬瓦工api使用

再次提醒:

務必保管好api_key 和 veid 不要洩漏給任何人知道

務必保管好api_key 和 veid 不要洩漏給任何人知道

務必保管好api_key 和 veid 不要洩漏給任何人知道

開始配置

切換root帳戶

  • 輸入命令:su -(注意:su 後面有個空格和減號,這很重要,代表同時切換環境變量)
  • 輸入 Root 密碼(輸入時看不見)。
  • 此時你的提示符會變成 #,代表你又是 Root 了。

先檢查是否安裝了jq

輸入 jq --version

如果輸出

-bash: jq: command not found

說明沒有安裝

安裝jq

用於解析api返回的複雜內容

1. Debian / Ubuntu

sudo apt update sudo apt install jq -y

2. CentOS / RHEL

# 如果是 CentOS 7,可能需要先安裝 epel-release

sudo yum install epel-release -y

sudo yum install jq -y

如果是 RHEL 8/9 或 AlmaLinux

sudo dnf install jq -y

驗證是否安裝成功

安裝完成後,你可以輸入

jq --version

腳本

需要修改的地方

VEID="你的VEID"

API_KEY="你的API_KEY"

TG_BOT_TOKEN="你的BOT_TOKEN"

TG_CHAT_ID="你的CHAT_ID"


TAG_PREFIX="bwgApiAutoSnapShot" #快照描述的前綴 作為判斷快照是否創建、刪除、鎖定的重要依據


MAX_LOG_LINES=500 # 設置日誌最大保留行數,超過則清空


LOG_FILE="/var/log/bwg_snapshot.log" # 日誌文件路徑


檢查 /root/autosnapshot.sh 是否存在

輸入 ls /root/autosnapshot.sh

上面 藍色框框就是文件不存在 就可以不修改文件名

下面的紅色框框 就是文件存在 需要修改文件名字 /root/這裡是文件名字.sh 比如修改成/root/autosnapshot11.sh


把下面內容修改後 就可以複製粘貼到ssh裡面 然後按回車 就可以創建腳本文件了

cat << 'EOF' > /root/autosnapshot.sh
#!/bin/bash

# ================= 配置区域 =================
VEID="你的VEID"
API_KEY="你的API_KEY"
TG_BOT_TOKEN="你的BOT_TOKEN"
TG_CHAT_ID="你的CHAT_ID"

MAX_LOG_LINES=500  # 设置日志最大保留行数,超过则清空


LOG_FILE="/var/log/bwg_snapshot.log"
TAG_PREFIX="bwgApiAutoSnapShot"
# ===========================================

API_URL="https://api.64clouds.com/v1"
DATE_TODAY=$(date +"%Y_%m_%d")
CURRENT_SNAPSHOT_NAME="${TAG_PREFIX}_${DATE_TODAY}"

log() {
    # 检查日志文件是否存在
    if [ -f "$LOG_FILE" ]; then
        # 获取当前行数
        local current_lines=$(grep -c "" "$LOG_FILE")
        if [ "$current_lines" -gt "$MAX_LOG_LINES" ]; then
            # 超过行数,保留最后 10 行并标记清空,或者直接清空
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] 日志达到上限,执行自动清理。" > "$LOG_FILE"
        fi
    fi
    # 正常写入日志
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

send_tg() {
    local msg="$1"
    # 发送 TG 消息并根据 curl 状态码记录日志
    curl -s -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
        -d "chat_id=${TG_CHAT_ID}" \
        -d "text=${msg}" \
        -d "disable_notification=true" > /dev/null
    
    if [ $? -eq 0 ]; then
        log "Telegram 通知发送成功: $msg"
    else
        log "Telegram 通知发送失败,请检查网络或 Token。"
    fi
}

call_api() {
    local endpoint="$1"
    local extra_params="$2"
    # --max-time 30: 设置最大超时时间为30秒
    # --retry 3: 如果失败自动重试3次
    curl -s --max-time 30 --retry 3 -X POST "${API_URL}/${endpoint}" \
         -d "veid=${VEID}" \
         -d "api_key=${API_KEY}" \
         ${extra_params}
}

# 【新增函数】提取快照数据的公共逻辑
get_snapshot_map() {
    echo "$SNAPSHOT_LIST" | jq -r --arg tag "$TAG_PREFIX" '
        .snapshots[] | 
        select(try (.description | @base64d) catch "" | contains($tag)) | 
        "\(.sticky)|\((.description | @base64d))|\(.fileName)"
    '
}

# 预检
if ! command -v jq &> /dev/null; then
    log "错误: 未安装 jq,请安装jq"
    exit 1
fi

log "--- 脚本启动 ---"
SNAPSHOT_LIST=$(call_api "snapshot/list" "")

# ================= 模式 1: 开机补刀/清理逻辑 (默认) =================
if [[ "$1" != "-c" ]]; then
    log "进入开机自检模式..."
    
    # 调用函数获取数据
    MAP_DATA=$(get_snapshot_map)

    # 使用 grep -c 直接统计行数,不再使用 wc -l
    count_a=$(echo "$MAP_DATA" | grep -c "^true")
    count_b=$(echo "$MAP_DATA" | grep -c "^false")

    log "开机自检状态: 符合前缀的置顶数 $count_a, 符合前缀的未置顶数 $count_b"

    if [ "$count_a" -eq 0 ] && [ "$count_b" -eq 0 ]; then
        log "状态 [0,0]:未发现任何相关快照,无需操作。"
        exit 0

    elif [ "$count_b" -eq 1 ]; then
        NEW_FILENAME=$(echo "$MAP_DATA" | grep "^false" | cut -d "|" -f 3)
        NEW_DESC=$(echo "$MAP_DATA" | grep "^false" | cut -d "|" -f 2)
        
        if [ "$count_a" -eq 1 ]; then
            OLD_FILENAME=$(echo "$MAP_DATA" | grep "^true" | cut -d "|" -f 3)
            OLD_DESC=$(echo "$MAP_DATA" | grep "^true" | cut -d "|" -f 2)
            
            log "发现新快照,正在删除旧的已置顶快照: $OLD_DESC"
            
            DEL_RES=$(call_api "snapshot/delete" "--data-urlencode snapshot=${OLD_FILENAME}")
            
            # 【替换 1】使用 jq 判断删除结果
            API_ERR_DEL=$(echo "$DEL_RES" | jq -r '.error' 2>/dev/null)
            if [ "$API_ERR_DEL" = "0" ]; then
                log "旧快照删除成功。"
                DEL_MSG="已成功删除旧快照: ${OLD_DESC}。"
            else
                log "旧快照删除失败: $DEL_RES"
                DEL_MSG="删除旧快照发生错误。"
            fi
        fi
        # 锁定新快照(b)
        log "正在锁定新快照: $NEW_DESC ..."
        LOCK_RES=$(call_api "snapshot/toggleSticky" "--data-urlencode snapshot=${NEW_FILENAME} -d sticky=1")
        
        # 使用 jq 解析 error 字段的值是否等于 0
        API_ERROR=$(echo "$LOCK_RES" | jq -r '.error' 2>/dev/null)

        if [ "$API_ERROR" = "0" ]; then
            log "新快照锁定成功。"
            send_tg "✅ 快照更替完成!${DEL_MSG}新快照 ${NEW_DESC} 已成功锁定。"
            exit 0
        else
            log "新快照锁定失败,API返回: $LOCK_RES"
            send_tg "❌ ${DEL_MSG}但新快照 ${NEW_DESC} 锁定失败,解析出的错误码为: ${API_ERROR}"
            exit 1
        fi

    else
        log "自检状态 [$count_a,$count_b]:不满足自动更替条件。"
        send_tg "ℹ️ 搬瓦工自检报告:当前状态为 [$count_a,$count_b],未达到快照更迭条件,脚本未执行操作。请手动查看.."
        exit 1
    fi
fi

# ================= 模式 2: 创建逻辑 (-c 参数) =================
log "进入快照创建模式 (-c)..."

# 调用函数获取数据
MAP_DATA=$(get_snapshot_map)

count_a=$(echo "$MAP_DATA" | grep -c "^true")
count_b=$(echo "$MAP_DATA" | grep -c "^false")

log "状态检查: 符合前缀的已置顶快照数 $count_a, 符合前缀的未置顶的快照数 $count_b"

DO_CREATE=false

if [ "$count_a" -eq 0 ] && [ "$count_b" -eq 0 ]; then
    log "状态 [0,0]:准备发起首次创建。"
    DO_CREATE=true
elif [ "$count_a" -eq 1 ] && [ "$count_b" -eq 0 ]; then
    log "状态 [1,0]:准备创建新的备份。"
    DO_CREATE=true
elif [ "$count_a" -eq 0 ] && [ "$count_b" -eq 1 ]; then
    log "状态 [0,1]:存在未锁定的快照,无法判断未锁定的快照目的,停止自动化创建快照,请锁定或删除旧快照或更改description"
    send_tg "⚠️ 存在未锁定的快照,无法判断未锁定的快照目的,停止自动化创建快照,请锁定或删除旧快照或更改description"
elif [ "$count_a" -eq 2 ]; then
    log "状态 [$count_a,$count_b]:置顶名额满。"
    send_tg "🚫 快照置顶名额已满 (2/2),请手动删除旧备份。"
else
    log "状态 [$count_a,$count_b]:未知状态,停止操作。"
    send_tg "❌ 未创建快照:不清楚的快照数量 (a=$count_a, b=$count_b)。"
fi

if [ "$DO_CREATE" = true ]; then
    # 再次检查日期防止重复
    if echo "$MAP_DATA" | grep -q "$DATE_TODAY"; then
        log "今日快照已存在,跳过。今日: $DATE_TODAY"
    else
        log "发起创建快照请求: $CURRENT_SNAPSHOT_NAME"
        CREATE_RESULT=$(call_api "snapshot/create" "--data-urlencode description=${CURRENT_SNAPSHOT_NAME}")
        
        # 【替换 2】使用 jq 判断创建请求结果
        API_ERR_CREATE=$(echo "$CREATE_RESULT" | jq -r '.error' 2>/dev/null)
        if [ "$API_ERR_CREATE" = "0" ]; then
            log "创建快照请求成功发送。"
        else
            log "创建快照请求失败: $CREATE_RESULT"
            send_tg "⚠️ 搬瓦工 API 创建快照请求返回异常。"
        fi
    fi
fi
EOF

授予運行權限

輸入

chmod +x /root/autosnapshot.sh


查看是否成功 輸入 ls -l /root/autosnapshot.sh

像藍色的有x就是成功了 像上面後紅色的- 沒有x 就是失敗了...

配置開機置頂快照 和定期創建快照

0 3 * * 1

這是一個cron的表達式 用來設定 運行時間的

0 代表 第 0 分鐘的時候

3 代表 第3小時的時候 就是凌晨3點

第一個 * 代表 哪一天 *代表所有天

第二個 * 代表 哪一月 *代表所有月

1 代表 星期一

合起來就是

每周一的凌晨3:00運行 創建快照的指令

可以按照自己的時間自行修改

0 3 * * 1 root /usr/local/bin/bwg_snap.sh -c >> /var/log/bwg_snapshot.log 2>&1


開機啟動檢查是否有未鎖定的快照(認為是上一次的快照)

如果文件名 改了的話 這裡也要修改 其他的地方不需要

@reboot root /usr/local/bin/bwg_snap.sh >> /var/log/bwg_snapshot.log 2>&1


檢查定時文件是否存在

輸入 ls /etc/cron.d/bwg_snap

上面紅色框框 就是 文件不存在 不需要修改名字

下面藍色框框 就是 文件存在 需要文件名字../etc/cron.d/你需要修改的名字 比如/etc/cron.d/bwg_snap1

修改後 複製粘貼到ssh裡面 回車就行了

cat <<EOF > /etc/cron.d/bwg_snap
# 每周一凌晨 3 点创建快照
0 3 * * 1 root /usr/local/bin/bwg_snap.sh -c >> /var/log/bwg_snapshot.log 2>&1
# 开机自启
@reboot root /usr/local/bin/bwg_snap.sh >> /var/log/bwg_snapshot.log 2>&1
EOF

# 修改文件權限

chmod 644 /etc/cron.d/bwg_snap


如果你想測試 可以輸入

/root/autosnapshot.sh -c

根據時間 一天只能創建一個快照....腳本設定 非api設置的...

創建快照 系統會重啟 請注意為保存的數據會丟失...

開機後應該會自動置頂這個快照 或 手動輸入 /root/autosnapshot.sh

檢查是否存在 有前綴名但未置頂的快照 或 有前綴 或 有一個 有前綴的並且置頂的快照 和 一個 有前綴未置頂的快照

都會執行 刪除置頂的快照(如果有)然後置頂那個 未置頂的快照

查看日誌 cat /var/log/bwg_snapshot.log