✨ Características: - 45 ejercicios universitarios (Basic → Advanced) - Renderizado LaTeX profesional - IA generativa (Z.ai/DashScope) - Docker 9 servicios - Tests 123/123 pasando - Seguridad enterprise (JWT, XSS, Rate limiting) 🐳 Infraestructura: - Next.js 14 + Node.js 20 - PostgreSQL 15 + Redis 7 - Docker Compose completo - Nginx + SSL ready 📚 Documentación: - 5 informes técnicos completos - README profesional - Scripts de deployment automatizados Estado: Producción lista ✅
236 lines
6.9 KiB
Bash
Executable File
236 lines
6.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# ================================================
|
|
# Math Platform - Database Backup Script
|
|
# ================================================
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
BACKUP_DIR="$PROJECT_ROOT/docker/backups"
|
|
DB_CONTAINER="math-postgres"
|
|
DB_USER="mathuser"
|
|
DB_NAME="mathdb"
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
BACKUP_FILE="$BACKUP_DIR/mathdb_backup_$TIMESTAMP.sql"
|
|
COMPRESSED_FILE="$BACKUP_FILE.gz"
|
|
|
|
# Retention settings
|
|
RETENTION_DAYS=30
|
|
RETENTION_COUNT=20
|
|
|
|
echo -e "${BLUE}============================================${NC}"
|
|
echo -e "${BLUE}Math Platform - Database Backup${NC}"
|
|
echo -e "${BLUE}============================================${NC}"
|
|
|
|
# Create backup directory
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# Function to check if container is running
|
|
check_container() {
|
|
if ! docker ps | grep -q $DB_CONTAINER; then
|
|
echo -e "${RED}Error: Database container $DB_CONTAINER is not running!${NC}"
|
|
exit 1
|
|
fi
|
|
echo -e "${GREEN}Database container is running${NC}"
|
|
}
|
|
|
|
# Function to create backup
|
|
create_backup() {
|
|
echo -e "${YELLOW}Creating database backup...${NC}"
|
|
echo -e "Timestamp: $TIMESTAMP"
|
|
echo -e "Destination: $COMPRESSED_FILE"
|
|
|
|
if docker exec $DB_CONTAINER pg_dump -U $DB_USER $DB_NAME > "$BACKUP_FILE" 2>/dev/null; then
|
|
if [ -f "$BACKUP_FILE" ] && [ -s "$BACKUP_FILE" ]; then
|
|
# Compress backup
|
|
gzip "$BACKUP_FILE"
|
|
|
|
# Get file size
|
|
FILE_SIZE=$(du -h "$COMPRESSED_FILE" | cut -f1)
|
|
echo -e "${GREEN}Backup created successfully!${NC}"
|
|
echo -e "${GREEN}File size: $FILE_SIZE${NC}"
|
|
echo -e "${GREEN}Location: $COMPRESSED_FILE${NC}"
|
|
|
|
# Create checksum
|
|
sha256sum "$COMPRESSED_FILE" > "$COMPRESSED_FILE.sha256"
|
|
echo -e "${GREEN}Checksum: ${COMPRESSED_FILE}.sha256${NC}"
|
|
else
|
|
echo -e "${RED}Error: Backup file is empty or was not created!${NC}"
|
|
rm -f "$BACKUP_FILE"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo -e "${RED}Error: Failed to create database backup!${NC}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to restore backup
|
|
restore_backup() {
|
|
local backup_file=$1
|
|
|
|
if [ -z "$backup_file" ]; then
|
|
echo -e "${RED}Error: Please specify backup file to restore${NC}"
|
|
echo "Usage: $0 --restore <backup_file>"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$backup_file" ]; then
|
|
echo -e "${RED}Error: Backup file not found: $backup_file${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${YELLOW}Restoring database from backup...${NC}"
|
|
echo -e "Source: $backup_file"
|
|
echo -e "${RED}WARNING: This will overwrite the current database!${NC}"
|
|
|
|
read -p "Are you sure? (yes/no): " confirm
|
|
if [ "$confirm" != "yes" ]; then
|
|
echo -e "${YELLOW}Restore cancelled${NC}"
|
|
exit 0
|
|
fi
|
|
|
|
# Decompress if needed
|
|
local temp_file="$backup_file"
|
|
if [[ "$backup_file" == *.gz ]]; then
|
|
temp_file="/tmp/restore_$(date +%s).sql"
|
|
gunzip -c "$backup_file" > "$temp_file"
|
|
fi
|
|
|
|
# Drop existing database and recreate
|
|
docker exec -i $DB_CONTAINER psql -U $DB_USER -d postgres <<-EOF
|
|
DROP DATABASE IF EXISTS $DB_NAME;
|
|
CREATE DATABASE $DB_NAME;
|
|
EOF
|
|
|
|
# Restore backup
|
|
docker exec -i $DB_CONTAINER psql -U $DB_USER $DB_NAME < "$temp_file"
|
|
|
|
# Cleanup
|
|
if [ "$temp_file" != "$backup_file" ]; then
|
|
rm -f "$temp_file"
|
|
fi
|
|
|
|
echo -e "${GREEN}Database restored successfully!${NC}"
|
|
}
|
|
|
|
# Function to list backups
|
|
list_backups() {
|
|
echo -e "\n${BLUE}============================================${NC}"
|
|
echo -e "${BLUE}Available Backups${NC}"
|
|
echo -e "${BLUE}============================================${NC}"
|
|
|
|
if [ "$(ls -A $BACKUP_DIR 2>/dev/null)" ]; then
|
|
printf "%-40s %-15s %-10s\n" "File Name" "Date" "Size"
|
|
printf "%-40s %-15s %-10s\n" "---------" "----" "----"
|
|
|
|
for file in "$BACKUP_DIR"/mathdb_backup_*.sql.gz; do
|
|
if [ -f "$file" ]; then
|
|
filename=$(basename "$file")
|
|
date=$(echo $filename | grep -oP '\d{8}_\d{6}' | sed 's/_/ /')
|
|
size=$(du -h "$file" | cut -f1)
|
|
printf "%-40s %-15s %-10s\n" "$filename" "$date" "$size"
|
|
fi
|
|
done
|
|
else
|
|
echo -e "${YELLOW}No backups found${NC}"
|
|
fi
|
|
}
|
|
|
|
# Function to cleanup old backups
|
|
cleanup_old_backups() {
|
|
echo -e "${YELLOW}Cleaning up old backups...${NC}"
|
|
echo -e "Retention: $RETENTION_COUNT backups or $RETENTION_DAYS days"
|
|
|
|
# Remove backups older than retention days
|
|
find "$BACKUP_DIR" -name "mathdb_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
|
|
find "$BACKUP_DIR" -name "mathdb_backup_*.sql.gz.sha256" -mtime +$RETENTION_DAYS -delete
|
|
|
|
# Keep only the most recent N backups
|
|
ls -t "$BACKUP_DIR"/mathdb_backup_*.sql.gz 2>/dev/null | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm
|
|
ls -t "$BACKUP_DIR"/mathdb_backup_*.sql.gz.sha256 2>/dev/null | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm
|
|
|
|
# Count remaining backups
|
|
count=$(ls -1 "$BACKUP_DIR"/mathdb_backup_*.sql.gz 2>/dev/null | wc -l)
|
|
echo -e "${GREEN}Cleanup completed. $count backup(s) retained${NC}"
|
|
}
|
|
|
|
# Function to setup automated backups
|
|
setup_cron() {
|
|
echo -e "${YELLOW}Setting up automated daily backups...${NC}"
|
|
|
|
# Create cron job
|
|
local cron_job="0 2 * * * $PROJECT_ROOT/docker/backup.sh >/dev/null 2>&1"
|
|
|
|
# Add to crontab if not exists
|
|
(crontab -l 2>/dev/null | grep -v "$PROJECT_ROOT/docker/backup.sh"; echo "$cron_job") | crontab -
|
|
|
|
echo -e "${GREEN}Automated backup scheduled for daily at 2:00 AM${NC}"
|
|
echo -e "${YELLOW}View crontab with: crontab -l${NC}"
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
ACTION="backup"
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--restore)
|
|
ACTION="restore"
|
|
RESTORE_FILE="$2"
|
|
shift 2
|
|
;;
|
|
--list)
|
|
ACTION="list"
|
|
shift
|
|
;;
|
|
--cleanup)
|
|
ACTION="cleanup"
|
|
shift
|
|
;;
|
|
--setup-cron)
|
|
ACTION="setup-cron"
|
|
shift
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown option: $1${NC}"
|
|
echo "Usage: $0 [--restore <file>] [--list] [--cleanup] [--setup-cron]"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
case $ACTION in
|
|
backup)
|
|
check_container
|
|
create_backup
|
|
cleanup_old_backups
|
|
;;
|
|
restore)
|
|
check_container
|
|
restore_backup "$RESTORE_FILE"
|
|
;;
|
|
list)
|
|
list_backups
|
|
;;
|
|
cleanup)
|
|
cleanup_old_backups
|
|
;;
|
|
setup-cron)
|
|
setup_cron
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|