ocngx / migrate.sh
tanbushi's picture
update
7f2e1a6
#!/bin/bash
# OCNGX 迁移工具
# 用于在不同 HuggingFace Spaces 之间快速迁移系统
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MIGRATION_LOG="/tmp/ocngx_migration_$(date +%s).log"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$MIGRATION_LOG"
}
log_info() {
echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$MIGRATION_LOG"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$MIGRATION_LOG"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$MIGRATION_LOG"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$MIGRATION_LOG"
}
# 显示帮助信息
usage() {
echo "OCNGX 迁移工具 - 在不同 HuggingFace Spaces 之间迁移系统"
echo ""
echo "用法: $0 [选项] <源Space> <目标Space>"
echo ""
echo "参数:"
echo " <源Space> 源 HuggingFace Space 名称"
echo " <目标Space> 目标 HuggingFace Space 名称"
echo ""
echo "选项:"
echo " -b, --backup-only 仅创建备份,不执行迁移"
echo " -r, --restore-only 仅恢复备份,不创建新备份"
echo " -k, --keep-backup 保留本地备份文件"
echo " -f, --force 强制覆盖目标配置"
echo " -d, --dry-run 模拟运行,不执行实际操作"
echo " -h, --help 显示帮助信息"
echo ""
echo "示例:"
echo " $0 source-space target-space"
echo " $0 --backup-only source-space"
echo " $0 --restore-only --force target-space backup.tar.gz"
echo ""
exit 1
}
# 解析命令行参数
SOURCE_SPACE=""
TARGET_SPACE=""
BACKUP_ONLY=false
RESTORE_ONLY=false
KEEP_BACKUP=false
FORCE_MODE=false
DRY_RUN=false
BACKUP_FILE=""
while [[ $# -gt 0 ]]; do
case $1 in
-b|--backup-only)
BACKUP_ONLY=true
shift
;;
-r|--restore-only)
RESTORE_ONLY=true
shift
;;
-k|--keep-backup)
KEEP_BACKUP=true
shift
;;
-f|--force)
FORCE_MODE=true
shift
;;
-d|--dry-run)
DRY_RUN=true
shift
;;
-h|--help)
usage
;;
-*)
log_error "未知选项: $1"
usage
;;
*)
if [[ -z "$SOURCE_SPACE" ]]; then
SOURCE_SPACE="$1"
elif [[ -z "$TARGET_SPACE" ]]; then
TARGET_SPACE="$1"
elif [[ -z "$BACKUP_FILE" ]]; then
BACKUP_FILE="$1"
else
log_error "参数过多"
usage
fi
shift
;;
esac
done
# 验证参数
validate_parameters() {
log_info "验证参数..."
if [[ "$RESTORE_ONLY" == true ]]; then
if [[ -z "$TARGET_SPACE" && -z "$BACKUP_FILE" ]]; then
log_error "恢复模式需要指定目标Space或备份文件"
usage
fi
else
if [[ -z "$SOURCE_SPACE" || -z "$TARGET_SPACE" ]]; then
log_error "必须指定源Space和目标Space"
usage
fi
fi
log_success "参数验证通过"
}
# 检测当前环境
detect_current_environment() {
log_info "检测当前环境..."
if [[ -n "${SPACE_ID:-}" ]]; then
CURRENT_ENV="huggingface"
CURRENT_SPACE="$SPACE_ID"
log_info "当前环境: HuggingFace Space ($CURRENT_SPACE)"
elif [[ -f /.dockerenv ]]; then
CURRENT_ENV="docker"
CURRENT_SPACE="docker-container"
log_info "当前环境: Docker 容器"
else
CURRENT_ENV="local"
CURRENT_SPACE="local-machine"
log_info "当前环境: 本地机器"
fi
}
# 检查网络连接
check_network_connectivity() {
log_info "检查网络连接..."
# 检查 HuggingFace 连通性
if curl -s --connect-timeout 10 https://huggingface.co >/dev/null 2>&1; then
log_success "HuggingFace 连接正常"
else
log_error "无法连接到 HuggingFace"
exit 1
fi
}
# 创建源Space备份
create_source_backup() {
log_info "在源Space创建备份: $SOURCE_SPACE"
if [[ "$DRY_RUN" == true ]]; then
log_warning "[DRY-RUN] 模拟在 $SOURCE_SPACE 创建备份"
return
fi
# 这里需要SSH或API方式连接到源Space
# 实际实现取决于具体的访问方式
local source_url="https://$SOURCE_SPACE.hf.space"
log_info "源Space URL: $source_url"
# 方案1: 通过SSH访问(如果支持)
# ssh user@$SOURCE_SPACE.hf.space "./backup-scripts/backup.sh"
# 方案2: 通过API触发备份
# curl -X POST "$source_url/api/backup"
# 方案3: 通过HuggingFace CLI
# huggingface-cli space create-backup $SOURCE_SPACE
# 临时方案: 假设可以SSH访问
log_warning "需要手动在源Space执行: ./backup-scripts/backup.sh"
log_info "等待用户确认备份已完成..."
read -p "确认备份已完成? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_success "源Space备份已确认"
else
log_error "备份未完成,终止迁移"
exit 1
fi
}
# 下载备份文件
download_backup() {
log_info "下载备份文件..."
if [[ "$DRY_RUN" == true ]]; then
log_warning "[DRY-RUN] 模拟下载备份文件"
return
fi
# 这里需要实现从源Space下载备份的逻辑
# 可能的实现方式:
# 1. 通过SCP下载
# scp user@$SOURCE_SPACE.hf.space:/var/backups/ocngx/latest.tar.gz ./
# 2. 通过HTTP下载
# wget "$source_url/download/backup/latest.tar.gz"
# 3. 通过HuggingFace API下载
# huggingface-cli space download-backup $SOURCE_SPACE
# 临时方案: 假设用户已手动下载
log_warning "需要手动从源Space下载备份文件到当前目录"
log_info "备份文件通常位于: /var/backups/ocngx/ocngx_backup_*.tar.gz"
read -p "请输入备份文件路径: " backup_path
if [[ -f "$backup_path" ]]; then
BACKUP_FILE="$backup_path"
log_success "备份文件已找到: $BACKUP_FILE"
else
log_error "备份文件不存在: $backup_path"
exit 1
fi
}
# 准备目标Space
prepare_target_space() {
log_info "准备目标Space: $TARGET_SPACE"
if [[ "$DRY_RUN" == true ]]; then
log_warning "[DRY-RUN] 模拟准备目标Space"
return
fi
# 1. 检查目标Space是否存在
local target_url="https://$TARGET_SPACE.hf.space"
log_info "目标Space URL: $target_url"
# 2. 部署基础代码到目标Space
log_info "部署基础代码到目标Space..."
# 这里需要实现部署逻辑
# 可能的实现方式:
# 1. 通过Git部署
# git clone <项目仓库> target-deploy
# cd target-deploy
# git remote set-url origin git@hf.co:spaces/$TARGET_SPACE
# git push origin main
# 2. 通过HuggingFace CLI部署
# huggingface-cli space create $TARGET_SPACE --space-type docker
# 临时方案: 假设用户已手动部署
log_warning "需要手动将项目代码部署到目标Space: $TARGET_SPACE"
log_info "步骤:"
log_info "1. 创建新的Space: https://huggingface.co/new-space"
log_info "2. 克隆当前项目代码"
log_info "3. 推送到新Space"
read -p "确认目标Space已准备完成? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_success "目标Space准备已确认"
else
log_error "目标Space未准备完成,终止迁移"
exit 1
fi
}
# 配置目标环境
configure_target_environment() {
log_info "配置目标环境..."
if [[ "$DRY_RUN" == true ]]; then
log_warning "[DRY-RUN] 模拟配置目标环境"
return
fi
# 这里需要在目标Space上执行环境配置
# 类似于 prepare_target_space 的逻辑
log_warning "需要手动在目标Space配置环境:"
log_info "1. SSH连接到目标Space"
log_info "2. 设置环境变量: export SPACE_ID=$TARGET_SPACE"
log_info "3. 运行: source deploy-config.sh && configure_for_deployment"
read -p "确认环境配置已完成? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_success "目标环境配置已确认"
else
log_error "环境配置未完成,终止迁移"
exit 1
fi
}
# 恢复数据到目标Space
restore_to_target() {
log_info "恢复数据到目标Space..."
if [[ "$DRY_RUN" == true ]]; then
log_warning "[DRY-RUN] 模拟恢复数据到目标Space"
return
fi
# 上传备份文件到目标Space
log_info "上传备份文件到目标Space..."
# 实现上传逻辑
# scp backup.tar.gz user@$TARGET_SPACE.hf.space:/tmp/
# 在目标Space执行恢复
log_info "在目标Space执行数据恢复..."
# 实现恢复逻辑
# ssh user@$TARGET_SPACE.hf.space "./backup-scripts/restore.sh --force /tmp/backup.tar.gz"
log_warning "需要手动在目标Space执行:"
log_info "1. 上传备份文件: scp $BACKUP_FILE user@$TARGET_SPACE.hf.space:/tmp/"
log_info "2. SSH连接到目标Space"
log_info "3. 运行: ./backup-scripts/restore.sh --force /tmp/$(basename $BACKUP_FILE)"
read -p "确认数据恢复已完成? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_success "数据恢复已确认"
else
log_error "数据恢复未完成,终止迁移"
exit 1
fi
}
# 验证迁移结果
verify_migration() {
log_info "验证迁移结果..."
local target_url="https://$TARGET_SPACE.hf.space"
# 检查目标Space健康状态
if curl -s --connect-timeout 10 "$target_url/health" >/dev/null 2>&1; then
log_success "目标Space健康检查通过"
else
log_warning "目标Space健康检查失败,请手动验证"
fi
# 检查OpenCode状态
if curl -s --connect-timeout 10 "$target_url/global/health" >/dev/null 2>&1; then
log_success "OpenCode服务状态正常"
else
log_warning "OpenCode服务状态异常,请手动检查"
fi
}
# 清理临时文件
cleanup() {
log_info "清理临时文件..."
if [[ "$KEEP_BACKUP" != true ]] && [[ -n "$BACKUP_FILE" ]] && [[ -f "$BACKUP_FILE" ]]; then
if [[ "$DRY_RUN" != true ]]; then
rm -f "$BACKUP_FILE"
log_success "已清理备份文件: $BACKUP_FILE"
fi
fi
# 清理日志文件
# rm -f "$MIGRATION_LOG"
}
# 生成迁移报告
generate_report() {
log_info "生成迁移报告..."
local report_file="migration_report_$(date +%Y%m%d_%H%M%S).txt"
cat > "$report_file" << EOF
OCNGX 迁移报告
===============
迁移时间: $(date '+%Y-%m-%d %H:%M:%S')
源Space: $SOURCE_SPACE
目标Space: $TARGET_SPACE
备份文件: $BACKUP_FILE
当前环境: $CURRENT_ENV ($CURRENT_SPACE)
迁移参数:
- 强制模式: $FORCE_MODE
- 仅备份: $BACKUP_ONLY
- 仅恢复: $RESTORE_ONLY
- 保留备份: $KEEP_BACKUP
- 模拟运行: $DRY_RUN
迁移日志:
$(cat "$MIGRATION_LOG")
后续步骤:
1. 访问目标Space: https://$TARGET_SPACE.hf.space
2. 验证所有功能正常
3. 更新DNS或代理配置(如需要)
4. 通知用户迁移完成
注意事项:
- 请保留此报告用于记录
- 建议在迁移后24小时内监控系统状态
- 如有问题,请检查迁移日志
EOF
log_success "迁移报告已生成: $report_file"
}
# 主迁移流程
execute_migration() {
log_info "开始迁移流程..."
log_info "源Space: $SOURCE_SPACE -> 目标Space: $TARGET_SPACE"
if [[ "$BACKUP_ONLY" == true ]]; then
create_source_backup
download_backup
log_success "备份完成"
return
fi
if [[ "$RESTORE_ONLY" == true ]]; then
if [[ -z "$TARGET_SPACE" ]]; then
# 本地恢复模式
log_info "本地恢复模式"
if [[ -z "$BACKUP_FILE" ]]; then
log_error "本地恢复需要指定备份文件"
exit 1
fi
./backup-scripts/restore.sh ${FORCE_MODE:+--force} "$BACKUP_FILE"
else
prepare_target_space
configure_target_environment
restore_to_target
fi
verify_migration
log_success "恢复完成"
return
fi
# 完整迁移流程
create_source_backup
download_backup
prepare_target_space
configure_target_environment
restore_to_target
verify_migration
log_success "迁移完成!"
}
# 错误处理
handle_error() {
log_error "迁移过程中发生错误"
cleanup
exit 1
}
# 主函数
main() {
echo "🚀 OCNGX 迁移工具"
echo "=================="
validate_parameters
detect_current_environment
check_network_connectivity
trap handle_error ERR
execute_migration
generate_report
cleanup
echo ""
log_success "迁移流程执行完成!"
echo "📊 迁移日志: $MIGRATION_LOG"
echo "📋 如有疑问,请查看迁移报告"
}
# 执行主函数
main "$@"