273 lines
8.6 KiB
Bash
Executable File
273 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
||
# 灾难恢复脚本 - 从完整备份恢复站点
|
||
# 用法:bash restore-full.sh [备份文件名]
|
||
# 无参数则自动检测当前目录下的最新备份
|
||
|
||
set -e
|
||
|
||
BACKUP_DIR="/Users/niuniu/programs/docker/db-backups"
|
||
REMOTE_BASE="/root/docker"
|
||
|
||
log() { echo "[$(date '+%H:%M:%S')] $1"; }
|
||
warn() { echo "[$(date '+%H:%M:%S')] [警告] $1"; }
|
||
error() { echo "[$(date '+%H:%M:%S')] [错误] $1"; exit 1; }
|
||
|
||
# ============================================================
|
||
# 1. 选择备份文件
|
||
# ============================================================
|
||
if [[ -n "$1" ]]; then
|
||
BACKUP_FILE="$1"
|
||
else
|
||
echo ""
|
||
echo "=========================================="
|
||
echo " 可用的完整备份文件"
|
||
echo "=========================================="
|
||
echo ""
|
||
|
||
# 列出本地备份
|
||
if [[ -d "$BACKUP_DIR" ]]; then
|
||
local_files=$(ls -t ${BACKUP_DIR}/full-backup-*.tar.gz 2>/dev/null | head -10)
|
||
if [[ -n "$local_files" ]]; then
|
||
echo "本地备份:"
|
||
index=1
|
||
while IFS= read -r file; do
|
||
filename=$(basename "$file")
|
||
filesize=$(du -h "$file" | cut -f1)
|
||
echo " $index) $filename ($filesize)"
|
||
files[$index]="$file"
|
||
((index++))
|
||
done <<< "$local_files"
|
||
echo ""
|
||
fi
|
||
fi
|
||
|
||
# 列出云端备份
|
||
echo "云端备份:"
|
||
cloud_files=$(ssh txjp "ls -t /root/docker/db-backups/full-backup-*.tar.gz 2>/dev/null | head -10" 2>/dev/null || true)
|
||
if [[ -n "$cloud_files" ]]; then
|
||
while IFS= read -r file; do
|
||
filename=$(basename "$file")
|
||
echo " $index) [云端] $filename"
|
||
files[$index]="cloud:$file"
|
||
((index++))
|
||
done <<< "$cloud_files"
|
||
echo ""
|
||
fi
|
||
|
||
if [[ ${#files[@]} -eq 0 ]]; then
|
||
error "未找到任何备份文件"
|
||
fi
|
||
|
||
printf "请选择备份文件 (1-$((index-1))): "
|
||
read choice
|
||
|
||
if [[ -z "${files[$choice]}" ]]; then
|
||
error "无效选择"
|
||
fi
|
||
|
||
BACKUP_FILE="${files[$choice]}"
|
||
fi
|
||
|
||
# ============================================================
|
||
# 2. 下载云端备份到临时目录
|
||
# ============================================================
|
||
RESTORE_DIR="/tmp/restore-$$"
|
||
mkdir -p "$RESTORE_DIR"
|
||
|
||
if [[ "$BACKUP_FILE" == cloud:* ]]; then
|
||
cloud_path="${BACKUP_FILE#cloud:}"
|
||
log "从云端下载备份..."
|
||
scp "txjp:$cloud_path" "$RESTORE_DIR/"
|
||
BACKUP_FILE="$RESTORE_DIR/$(basename $cloud_path)"
|
||
fi
|
||
|
||
# ============================================================
|
||
# 3. 解压备份
|
||
# ============================================================
|
||
log "解压备份文件..."
|
||
cd "$RESTORE_DIR"
|
||
tar xzf "$BACKUP_FILE"
|
||
|
||
# 检测备份内容
|
||
BACKUP_CONTENT="$RESTORE_DIR/full-backup"
|
||
if [[ ! -d "$BACKUP_CONTENT" ]]; then
|
||
error "备份文件格式错误"
|
||
fi
|
||
|
||
log "备份内容:"
|
||
ls -la "$BACKUP_CONTENT/"
|
||
|
||
# ============================================================
|
||
# 4. 选择要恢复的站点
|
||
# ============================================================
|
||
echo ""
|
||
echo "=========================================="
|
||
echo " 选择要恢复的内容"
|
||
echo "=========================================="
|
||
echo ""
|
||
echo " 1) assets - 资产管理系统"
|
||
echo " 2) issue - 工单系统"
|
||
echo " 3) ldap - 用户目录服务"
|
||
echo " 4) gitea - 代码仓库"
|
||
echo " 5) nginx - 反向代理配置"
|
||
echo " 6) 全部恢复"
|
||
echo ""
|
||
printf "请选择 (1-6): "
|
||
read site_choice
|
||
|
||
# ============================================================
|
||
# 5. 执行恢复
|
||
# ============================================================
|
||
restore_assets() {
|
||
log "恢复 assets 站点..."
|
||
|
||
# 恢复数据库
|
||
if [[ -f "$BACKUP_CONTENT/databases/assets.db" ]]; then
|
||
log "恢复 assets 数据库..."
|
||
scp "$BACKUP_CONTENT/databases/assets.db" txjp:/tmp/assets.db
|
||
ssh txjp "docker cp /tmp/assets.db assets-ai:/app/data/assets.db && rm /tmp/assets.db"
|
||
ssh txjp "docker restart assets-ai"
|
||
log "assets 数据库恢复完成"
|
||
fi
|
||
|
||
# 恢复配置
|
||
if [[ -d "$BACKUP_CONTENT/configs/assets-ai" ]]; then
|
||
log "恢复 assets 配置..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/assets-ai"
|
||
scp "$BACKUP_CONTENT/configs/assets-ai/"* txjp:$REMOTE_BASE/assets-ai/ 2>/dev/null || true
|
||
fi
|
||
|
||
# 恢复上传文件
|
||
if [[ -d "$BACKUP_CONTENT/uploads/assets-uploads" ]]; then
|
||
log "恢复 assets 上传文件..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/assets-ai/data"
|
||
scp -r "$BACKUP_CONTENT/uploads/assets-uploads/"* txjp:$REMOTE_BASE/assets-ai/data/uploads/ 2>/dev/null || true
|
||
fi
|
||
}
|
||
|
||
restore_issue() {
|
||
log "恢复 issue 站点..."
|
||
|
||
# 恢复数据库
|
||
if [[ -f "$BACKUP_CONTENT/databases/issue.db" ]]; then
|
||
log "恢复 issue 数据库..."
|
||
scp "$BACKUP_CONTENT/databases/issue.db" txjp:/tmp/issue.db
|
||
ssh txjp "docker cp /tmp/issue.db issue-ai:/app/data/issue.db && rm /tmp/issue.db"
|
||
ssh txjp "docker restart issue-ai"
|
||
log "issue 数据库恢复完成"
|
||
fi
|
||
|
||
# 恢复配置
|
||
if [[ -d "$BACKUP_CONTENT/configs/issue-ai" ]]; then
|
||
log "恢复 issue 配置..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/issue-ai"
|
||
scp "$BACKUP_CONTENT/configs/issue-ai/"* txjp:$REMOTE_BASE/issue-ai/ 2>/dev/null || true
|
||
fi
|
||
|
||
# 恢复上传文件
|
||
if [[ -d "$BACKUP_CONTENT/uploads/issue-uploads" ]]; then
|
||
log "恢复 issue 上传文件..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/issue-ai/data"
|
||
scp -r "$BACKUP_CONTENT/uploads/issue-uploads/"* txjp:$REMOTE_BASE/issue-ai/data/uploads/ 2>/dev/null || true
|
||
fi
|
||
|
||
# 恢复报告文件
|
||
if [[ -d "$BACKUP_CONTENT/uploads/issue-reports" ]]; then
|
||
log "恢复 issue 报告文件..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/issue-ai/data"
|
||
scp -r "$BACKUP_CONTENT/uploads/issue-reports/"* txjp:$REMOTE_BASE/issue-ai/data/reports/ 2>/dev/null || true
|
||
fi
|
||
}
|
||
|
||
restore_ldap() {
|
||
log "恢复 ldap 站点..."
|
||
|
||
# 恢复数据库
|
||
if [[ -f "$BACKUP_CONTENT/databases/ldap.db" ]]; then
|
||
log "恢复 ldap 数据库..."
|
||
scp "$BACKUP_CONTENT/databases/ldap.db" txjp:/tmp/ldap.db
|
||
ssh txjp "docker cp /tmp/ldap.db lldap:/data/users.db && rm /tmp/ldap.db"
|
||
ssh txjp "docker restart lldap"
|
||
log "ldap 数据库恢复完成"
|
||
fi
|
||
|
||
# 恢复配置
|
||
if [[ -d "$BACKUP_CONTENT/configs/ldap-ai" ]]; then
|
||
log "恢复 ldap 配置..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/ldap-ai"
|
||
scp "$BACKUP_CONTENT/configs/ldap-ai/"* txjp:$REMOTE_BASE/ldap-ai/ 2>/dev/null || true
|
||
fi
|
||
}
|
||
|
||
restore_gitea() {
|
||
log "恢复 gitea 站点..."
|
||
|
||
# 恢复数据库
|
||
if [[ -f "$BACKUP_CONTENT/databases/gitea.db" ]]; then
|
||
log "恢复 gitea 数据库..."
|
||
scp "$BACKUP_CONTENT/databases/gitea.db" txjp:/tmp/gitea.db
|
||
ssh txjp "docker cp /tmp/gitea.db gitea-ai:/data/gitea.db && rm /tmp/gitea.db"
|
||
fi
|
||
|
||
# 恢复代码仓库
|
||
if [[ -d "$BACKUP_CONTENT/gitea/git" ]]; then
|
||
log "恢复 gitea 代码仓库..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/gitea-ai/data"
|
||
scp -r "$BACKUP_CONTENT/gitea/git" txjp:$REMOTE_BASE/gitea-ai/data/
|
||
fi
|
||
|
||
# 恢复配置
|
||
if [[ -d "$BACKUP_CONTENT/gitea/conf" ]]; then
|
||
log "恢复 gitea 配置..."
|
||
ssh txjp "mkdir -p $REMOTE_BASE/gitea-ai/data/gitea"
|
||
scp -r "$BACKUP_CONTENT/gitea/conf" txjp:$REMOTE_BASE/gitea-ai/data/gitea/
|
||
fi
|
||
|
||
# 恢复 docker-compose
|
||
if [[ -d "$BACKUP_CONTENT/configs/gitea-ai" ]]; then
|
||
log "恢复 gitea docker-compose..."
|
||
scp "$BACKUP_CONTENT/configs/gitea-ai/"* txjp:$REMOTE_BASE/gitea-ai/ 2>/dev/null || true
|
||
fi
|
||
|
||
# 重启容器
|
||
ssh txjp "cd $REMOTE_BASE/gitea-ai && docker compose down && docker compose up -d"
|
||
log "gitea 恢复完成"
|
||
}
|
||
|
||
restore_nginx() {
|
||
log "恢复 nginx 配置..."
|
||
|
||
if [[ -d "$BACKUP_CONTENT/nginx" ]]; then
|
||
ssh txjp "mkdir -p $REMOTE_BASE/nginx-proxy-ai/conf.d"
|
||
scp "$BACKUP_CONTENT/nginx/"* txjp:$REMOTE_BASE/nginx-proxy-ai/conf.d/
|
||
ssh txjp "docker exec nginx-ai nginx -t && docker exec nginx-ai nginx -s reload"
|
||
log "nginx 配置恢复完成"
|
||
fi
|
||
}
|
||
|
||
# 执行恢复
|
||
case "$site_choice" in
|
||
1) restore_assets ;;
|
||
2) restore_issue ;;
|
||
3) restore_ldap ;;
|
||
4) restore_gitea ;;
|
||
5) restore_nginx ;;
|
||
6)
|
||
restore_assets
|
||
restore_issue
|
||
restore_ldap
|
||
restore_gitea
|
||
restore_nginx
|
||
;;
|
||
*) error "无效选择" ;;
|
||
esac
|
||
|
||
# ============================================================
|
||
# 6. 清理临时文件
|
||
# ============================================================
|
||
log "清理临时文件..."
|
||
rm -rf "$RESTORE_DIR"
|
||
|
||
echo ""
|
||
log "恢复完成!"
|