- 文件上传验证: ModelUploader组件增强、上传API错误处理 - GLTF解析器: 增强节点提取和元数据 - 板材编辑: PanelEditor客户端验证 + panels API服务端验证 - 装配步骤编辑: 修复未使用代码,添加预览按钮 - 装配动画播放: AssemblyPlayer步骤导航边界检查优化 - 分享链接: 完整CRUD API(创建、获取、删除),含验证和过期检查 跳过可选测试任务以加快MVP开发
237 lines
5.5 KiB
Bash
237 lines
5.5 KiB
Bash
#!/bin/bash
|
||
|
||
# ============================================
|
||
# 文件存储备份脚本
|
||
# ============================================
|
||
# 功能:备份 MinIO 文件存储
|
||
# 使用:./backup-files.sh [备份目录]
|
||
# ============================================
|
||
|
||
set -e
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
# 配置
|
||
BACKUP_DIR="${1:-./backups/files}"
|
||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||
BACKUP_FILE="files-backup-${TIMESTAMP}.tar.gz"
|
||
LOG_FILE="backup-files-${TIMESTAMP}.log"
|
||
|
||
# MinIO 数据目录(Docker 容器内的挂载路径)
|
||
MINIO_DATA_DIR="${MINIO_DATA_DIR:-./minio-data}"
|
||
|
||
# 日志函数
|
||
log() {
|
||
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "${BACKUP_DIR}/${LOG_FILE}"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "${BACKUP_DIR}/${LOG_FILE}"
|
||
}
|
||
|
||
warn() {
|
||
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "${BACKUP_DIR}/${LOG_FILE}"
|
||
}
|
||
|
||
# 检查依赖
|
||
check_dependencies() {
|
||
log "检查依赖..."
|
||
|
||
if ! command -v tar &> /dev/null; then
|
||
error "tar 未安装"
|
||
exit 1
|
||
fi
|
||
|
||
if ! command -v gzip &> /dev/null; then
|
||
error "gzip 未安装"
|
||
exit 1
|
||
fi
|
||
|
||
log "✅ 依赖检查通过"
|
||
}
|
||
|
||
# 验证 MinIO 数据目录
|
||
check_minio_directory() {
|
||
log "验证 MinIO 数据目录..."
|
||
|
||
if [ ! -d "$MINIO_DATA_DIR" ]; then
|
||
error "MinIO 数据目录不存在: $MINIO_DATA_DIR"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查目录是否为空
|
||
if [ -z "$(ls -A $MINIO_DATA_DIR 2>/dev/null)" ]; then
|
||
warn "MinIO 数据目录为空"
|
||
fi
|
||
|
||
log "✅ MinIO 数据目录验证通过"
|
||
}
|
||
|
||
# 创建备份目录
|
||
create_backup_directory() {
|
||
log "创建备份目录: ${BACKUP_DIR}"
|
||
|
||
mkdir -p "${BACKUP_DIR}"
|
||
|
||
if [ ! -d "${BACKUP_DIR}" ]; then
|
||
error "无法创建备份目录"
|
||
exit 1
|
||
fi
|
||
|
||
log "✅ 备份目录已创建"
|
||
}
|
||
|
||
# 检查磁盘空间
|
||
check_disk_space() {
|
||
log "检查磁盘空间..."
|
||
|
||
# 获取可用空间(MB)
|
||
AVAILABLE_SPACE=$(df -m "${BACKUP_DIR}" | awk 'NR==2 {print $4}')
|
||
|
||
# 计算 MinIO 数据大小(MB)
|
||
MINIO_SIZE=$(du -sm "$MINIO_DATA_DIR" | cut -f1)
|
||
|
||
# 需要至少 1.5 倍的数据大小空间(考虑压缩)
|
||
REQUIRED_SPACE=$((MINIO_SIZE * 3 / 2))
|
||
|
||
log "MinIO 数据大小: ${MINIO_SIZE} MB"
|
||
log "可用空间: ${AVAILABLE_SPACE} MB"
|
||
log "需要空间: ${REQUIRED_SPACE} MB"
|
||
|
||
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_SPACE" ]; then
|
||
error "磁盘空间不足"
|
||
exit 1
|
||
fi
|
||
|
||
log "✅ 磁盘空间充足"
|
||
}
|
||
|
||
# 执行备份
|
||
perform_backup() {
|
||
log "开始备份文件存储..."
|
||
log "备份文件: ${BACKUP_FILE}"
|
||
|
||
START_TIME=$(date +%s)
|
||
|
||
# 执行备份并压缩
|
||
if tar -czf "${BACKUP_DIR}/${BACKUP_FILE}" \
|
||
-C "$(dirname "$MINIO_DATA_DIR")" \
|
||
"$(basename "$MINIO_DATA_DIR")" \
|
||
2>&1 | tee -a "${BACKUP_DIR}/${LOG_FILE}"; then
|
||
|
||
END_TIME=$(date +%s)
|
||
DURATION=$((END_TIME - START_TIME))
|
||
|
||
log "✅ 备份完成,耗时: ${DURATION} 秒"
|
||
else
|
||
error "备份失败"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 验证备份文件
|
||
verify_backup() {
|
||
log "验证备份文件..."
|
||
|
||
if [ ! -f "${BACKUP_DIR}/${BACKUP_FILE}" ]; then
|
||
error "备份文件不存在"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查文件大小
|
||
FILE_SIZE=$(du -h "${BACKUP_DIR}/${BACKUP_FILE}" | cut -f1)
|
||
log "备份文件大小: ${FILE_SIZE}"
|
||
|
||
# 验证 tar.gz 文件完整性
|
||
if tar -tzf "${BACKUP_DIR}/${BACKUP_FILE}" > /dev/null 2>&1; then
|
||
log "✅ 备份文件完整性验证通过"
|
||
else
|
||
error "备份文件损坏"
|
||
exit 1
|
||
fi
|
||
|
||
# 生成 checksum
|
||
CHECKSUM=$(sha256sum "${BACKUP_DIR}/${BACKUP_FILE}" | cut -d' ' -f1)
|
||
echo "$CHECKSUM" > "${BACKUP_DIR}/${BACKUP_FILE}.sha256"
|
||
log "✅ Checksum: ${CHECKSUM}"
|
||
}
|
||
|
||
# 清理旧备份
|
||
cleanup_old_backups() {
|
||
log "清理旧备份..."
|
||
|
||
# 保留最近 7 个备份
|
||
KEEP_COUNT=7
|
||
|
||
# 获取备份文件列表(按时间排序)
|
||
BACKUP_FILES=($(ls -t "${BACKUP_DIR}"/files-backup-*.tar.gz 2>/dev/null || true))
|
||
BACKUP_COUNT=${#BACKUP_FILES[@]}
|
||
|
||
if [ "$BACKUP_COUNT" -gt "$KEEP_COUNT" ]; then
|
||
DELETE_COUNT=$((BACKUP_COUNT - KEEP_COUNT))
|
||
log "发现 ${BACKUP_COUNT} 个备份,删除最旧的 ${DELETE_COUNT} 个"
|
||
|
||
for ((i=KEEP_COUNT; i<BACKUP_COUNT; i++)); do
|
||
OLD_BACKUP="${BACKUP_FILES[$i]}"
|
||
log "删除: $(basename $OLD_BACKUP)"
|
||
rm -f "$OLD_BACKUP"
|
||
rm -f "${OLD_BACKUP}.sha256"
|
||
done
|
||
|
||
log "✅ 清理完成"
|
||
else
|
||
log "当前有 ${BACKUP_COUNT} 个备份,无需清理"
|
||
fi
|
||
}
|
||
|
||
# 生成备份摘要
|
||
generate_summary() {
|
||
log "生成备份摘要..."
|
||
|
||
cat > "${BACKUP_DIR}/backup-summary-${TIMESTAMP}.json" << EOF
|
||
{
|
||
"timestamp": "$(date -Iseconds)",
|
||
"backup_file": "${BACKUP_FILE}",
|
||
"source_directory": "${MINIO_DATA_DIR}",
|
||
"size": "$(du -b "${BACKUP_DIR}/${BACKUP_FILE}" | cut -f1)",
|
||
"checksum": "$(cat "${BACKUP_DIR}/${BACKUP_FILE}.sha256")",
|
||
"status": "success"
|
||
}
|
||
EOF
|
||
|
||
log "✅ 备份摘要已生成"
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
echo "========================================"
|
||
echo " 文件存储备份脚本"
|
||
echo "========================================"
|
||
echo ""
|
||
|
||
check_dependencies
|
||
check_minio_directory
|
||
create_backup_directory
|
||
check_disk_space
|
||
perform_backup
|
||
verify_backup
|
||
cleanup_old_backups
|
||
generate_summary
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
log "🎉 备份成功完成!"
|
||
echo "========================================"
|
||
echo ""
|
||
echo "备份文件: ${BACKUP_DIR}/${BACKUP_FILE}"
|
||
echo "日志文件: ${BACKUP_DIR}/${LOG_FILE}"
|
||
echo ""
|
||
}
|
||
|
||
# 执行主函数
|
||
main
|