From 9bda2bcaebddad2e1cdc3bdd1202be79bc52a99d Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 1 Jun 2026 15:22:22 +0800 Subject: [PATCH] bugfix --- bin/backup_api.sh | 196 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100755 bin/backup_api.sh diff --git a/bin/backup_api.sh b/bin/backup_api.sh new file mode 100755 index 0000000..5303dfb --- /dev/null +++ b/bin/backup_api.sh @@ -0,0 +1,196 @@ +#!/bin/bash +# ============================================================ +# backup_api.sh +# 导出 pricing, llmage, uapi 三个模块的表数据为 SQL 文件 +# +# 用法: +# ./backup_api.sh [options] +# +# 选项: +# -h HOST MySQL 主机 (默认: localhost) +# -P PORT MySQL 端口 (默认: 3306) +# -u USER MySQL 用户名 (默认: root) +# -p PASSWORD MySQL 密码 +# -d DATABASE 数据库名 (默认: sage) +# -o OUTPUT_DIR 输出目录 (默认: ./sql_dumps) +# --no-data 只导出表结构,不导出数据 +# --help 显示帮助 +# ============================================================ + +set -euo pipefail + +# 默认参数 +HOST="localhost" +PORT="3306" +USER="root" +PASSWORD="" +DATABASE="sage" +OUTPUT_DIR="./sql_dumps" +NO_DATA="" +REPOS_DIR="$(cd "$(dirname "$0")/../.." 2>/dev/null && pwd || echo "/home/hermesai/repos")" + +# 各模块排除的表 +declare -A MODULE_EXCLUDES +MODULE_EXCLUDES["llmage"]="llmusage llmusage_accounting_failed llmusage_history" +MODULE_EXCLUDES["uapi"]="uapiset uptask" + +usage() { + sed -n '2,/^# ===/p' "$0" | grep '^#' | sed 's/^# \?//' + exit 0 +} + +# 解析参数 +while [[ $# -gt 0 ]]; do + case "$1" in + -h) HOST="$2"; shift 2 ;; + -P) PORT="$2"; shift 2 ;; + -u) USER="$2"; shift 2 ;; + -p) PASSWORD="$2"; shift 2 ;; + -d) DATABASE="$2"; shift 2 ;; + -o) OUTPUT_DIR="$2"; shift 2 ;; + --no-data) NO_DATA="--no-data"; shift ;; + --help) usage ;; + *) echo "未知参数: $1"; exit 1 ;; + esac +done + +# 构建 mysqldump 基础命令 +MYSQLDUMP_BASE="mysqldump -h${HOST} -P${PORT} -u${USER}" +if [[ -n "$PASSWORD" ]]; then + MYSQLDUMP_BASE="${MYSQLDUMP_BASE} -p${PASSWORD}" +fi + +# 从 models/*.json 提取表名 +get_tables() { + local module_dir="$1" + shift + local excludes=("$@") + local tables=() + + if [[ ! -d "$module_dir/models" ]]; then + echo "警告: 目录不存在 $module_dir/models" >&2 + return + fi + + for f in "$module_dir/models"/*.json; do + [[ -f "$f" ]] || continue + # 从 summary[0].name 提取表名 + local tbl + tbl=$(python3 -c " +import json, sys +try: + d = json.load(open('$f')) + s = d.get('summary', []) + if isinstance(s, list) and len(s) > 0: + print(s[0].get('name', '')) + elif isinstance(s, dict): + print(s.get('name', '')) +except: + pass +" 2>/dev/null) + if [[ -z "$tbl" ]]; then + continue + fi + # 检查是否在排除列表中 + local excluded=false + for ex in "${excludes[@]}"; do + if [[ "$tbl" == "$ex" ]]; then + excluded=true + break + fi + done + if [[ "$excluded" == "false" ]]; then + tables+=("$tbl") + fi + done + echo "${tables[@]}" +} + +# 创建输出目录 +mkdir -p "$OUTPUT_DIR" + +TIMESTAMP=$(date +%Y%m%d_%H%M%S) + +echo "============================================================" +echo " Sage 模块表数据导出" +echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')" +echo " 数据库: ${DATABASE}@${HOST}:${PORT}" +echo " 输出目录: ${OUTPUT_DIR}" +echo "============================================================" + +# 定义模块 +declare -A MODULES +MODULES=( + ["pricing"]="$REPOS_DIR/pricing" + ["llmage"]="$REPOS_DIR/llmage" + ["uapi"]="$REPOS_DIR/uapi" +) + +TOTAL_TABLES=0 +TOTAL_FILES=0 + +for module in pricing llmage uapi; do + module_dir="${MODULES[$module]}" + echo "" + echo "--- 模块: $module ---" + + if [[ ! -d "$module_dir" ]]; then + echo " 跳过: 模块目录不存在 $module_dir" + continue + fi + + # 获取表名(按模块排除指定表) + excludes_str="${MODULE_EXCLUDES[$module]:-}" + excludes_arr=() + if [[ -n "$excludes_str" ]]; then + read -ra excludes_arr <<< "$excludes_str" + fi + tables=$(get_tables "$module_dir" "${excludes_arr[@]+"${excludes_arr[@]}"}") + + if [[ -z "$tables" ]]; then + echo " 跳过: 未找到表定义" + continue + fi + + echo " 表: $tables" + + # 生成 SQL 文件 + outfile="${OUTPUT_DIR}/${module}_${TIMESTAMP}.sql" + table_count=0 + + for tbl in $tables; do + echo -n " 导出 $tbl ... " + if ${MYSQLDUMP_BASE} \ + --single-transaction \ + --routines \ + --triggers \ + --set-gtid-purged=OFF \ + --column-names \ + --complete-insert \ + $NO_DATA \ + "$DATABASE" "$tbl" >> "$outfile" 2>/dev/null; then + echo "OK" + ((table_count++)) + else + # 如果表不存在,跳过 + echo "跳过(表不存在或无权限)" + fi + done + + if [[ $table_count -gt 0 ]]; then + echo " => $outfile ($table_count 个表)" + ((TOTAL_TABLES += table_count)) + ((TOTAL_FILES++)) + else + rm -f "$outfile" + echo " => 无有效表数据" + fi +done + +echo "" +echo "============================================================" +echo " 导出完成" +echo " 文件数: $TOTAL_FILES" +echo " 表总数: $TOTAL_TABLES" +echo " 输出目录: $(cd "$OUTPUT_DIR" && pwd)" +echo "============================================================"