Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture Tech Stack: - Backend: FastAPI + python-oracledb (Oracle DB integration) - Frontend: Vue.js 3 + PrimeVue + Vite - Telegram Bot: python-telegram-bot + SQLite - Infrastructure: Shared database pool, JWT authentication, SSH tunnel Features: - FastAPI backend with async Oracle connection pool - Vue.js 3 responsive frontend with PrimeVue components - Telegram bot alternative interface - Microservices architecture with shared components - Complete deployment support (Linux Docker + Windows IIS) - Comprehensive testing (Playwright E2E + pytest) Repository Structure: - reports-app/ - Main application (backend, frontend, telegram-bot) - shared/ - Shared components (database pool, auth, utils) - deployment/ - Deployment scripts (Linux & Windows) - docs/ - Project documentation - security/ - Security scanning and git hooks
This commit is contained in:
342
scripts/rollback.sh
Normal file
342
scripts/rollback.sh
Normal file
@@ -0,0 +1,342 @@
|
||||
#!/bin/bash
|
||||
# ROA2WEB Quick Rollback Script
|
||||
# Fast rollback to previous deployment state
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
BACKUP_DIR="$PROJECT_DIR/backups"
|
||||
LOG_FILE="$PROJECT_DIR/rollback.log"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
local level=$1
|
||||
shift
|
||||
local message="$*"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo -e "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Error handling
|
||||
error_exit() {
|
||||
log "ERROR" "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success message
|
||||
success() {
|
||||
log "SUCCESS" "$1"
|
||||
}
|
||||
|
||||
# Warning message
|
||||
warning() {
|
||||
log "WARNING" "$1"
|
||||
}
|
||||
|
||||
# Info message
|
||||
info() {
|
||||
log "INFO" "$1"
|
||||
}
|
||||
|
||||
# Get last backup
|
||||
get_last_backup() {
|
||||
if [[ -f "$PROJECT_DIR/.last_backup" ]]; then
|
||||
cat "$PROJECT_DIR/.last_backup"
|
||||
else
|
||||
# Find the most recent backup
|
||||
find "$BACKUP_DIR" -name "backup_*" -type d -printf '%T+ %p\n' 2>/dev/null | sort -r | head -n1 | cut -d' ' -f2- | xargs basename 2>/dev/null || echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# List available deployments to rollback to
|
||||
list_rollback_targets() {
|
||||
info "Available rollback targets:"
|
||||
echo ""
|
||||
|
||||
if [[ ! -d "$BACKUP_DIR" ]] || [[ -z "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]]; then
|
||||
warning "No backups found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local current_backup=$(get_last_backup)
|
||||
|
||||
find "$BACKUP_DIR" -name "backup_*" -type d -printf '%T+ %p\n' | sort -r | head -n5 | while read -r line; do
|
||||
local date_part=$(echo "$line" | cut -d' ' -f1 | cut -d+ -f1)
|
||||
local backup_name=$(basename "$(echo "$line" | cut -d' ' -f2)")
|
||||
local backup_path="$(echo "$line" | cut -d' ' -f2)"
|
||||
|
||||
local marker=""
|
||||
if [[ "$backup_name" == "$current_backup" ]]; then
|
||||
marker=" ${GREEN}(current)${NC}"
|
||||
fi
|
||||
|
||||
echo -e "📦 ${BLUE}$backup_name${NC} ($date_part)$marker"
|
||||
|
||||
if [[ -f "$backup_path/backup_info.txt" ]]; then
|
||||
grep -E "(Environment|Git)" "$backup_path/backup_info.txt" | sed 's/^/ /' | head -2
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
# Health check function
|
||||
health_check() {
|
||||
local service=$1
|
||||
local url=$2
|
||||
local timeout=${3:-30}
|
||||
|
||||
info "Performing health check for $service..."
|
||||
|
||||
local count=0
|
||||
while [[ $count -lt $timeout ]]; do
|
||||
if curl -f -s "$url" > /dev/null 2>&1; then
|
||||
success "$service health check passed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
((count++))
|
||||
done
|
||||
|
||||
warning "$service health check failed after ${timeout}s"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check service health
|
||||
check_services_health() {
|
||||
info "Checking services health..."
|
||||
|
||||
local healthy=true
|
||||
|
||||
# Check backend health
|
||||
if ! health_check "Backend API" "http://localhost/api/health" 30; then
|
||||
healthy=false
|
||||
fi
|
||||
|
||||
# Check frontend health
|
||||
if ! health_check "Frontend" "http://localhost/health" 30; then
|
||||
healthy=false
|
||||
fi
|
||||
|
||||
# Check gateway health
|
||||
if ! health_check "Gateway" "http://localhost/health" 30; then
|
||||
healthy=false
|
||||
fi
|
||||
|
||||
if [[ "$healthy" == "true" ]]; then
|
||||
success "All services are healthy"
|
||||
return 0
|
||||
else
|
||||
error_exit "Some services are not healthy"
|
||||
fi
|
||||
}
|
||||
|
||||
# Quick rollback without backup restore
|
||||
quick_rollback() {
|
||||
info "Performing quick rollback (restart with previous images)..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Stop current services
|
||||
info "Stopping current services..."
|
||||
docker-compose -f docker-compose.yml -f docker-compose.production.yml down
|
||||
|
||||
# Get previous image versions
|
||||
local backend_image=$(docker images roa2web/backend --format "{{.ID}}" | sed -n '2p')
|
||||
local frontend_image=$(docker images roa2web/frontend --format "{{.ID}}" | sed -n '2p')
|
||||
local gateway_image=$(docker images roa2web/nginx-gateway --format "{{.ID}}" | sed -n '2p')
|
||||
|
||||
if [[ -n "$backend_image" ]]; then
|
||||
info "Rolling back to previous backend image: $backend_image"
|
||||
docker tag "$backend_image" roa2web/backend:rollback
|
||||
fi
|
||||
|
||||
if [[ -n "$frontend_image" ]]; then
|
||||
info "Rolling back to previous frontend image: $frontend_image"
|
||||
docker tag "$frontend_image" roa2web/frontend:rollback
|
||||
fi
|
||||
|
||||
if [[ -n "$gateway_image" ]]; then
|
||||
info "Rolling back to previous gateway image: $gateway_image"
|
||||
docker tag "$gateway_image" roa2web/nginx-gateway:rollback
|
||||
fi
|
||||
|
||||
# Start services with rollback images
|
||||
info "Starting services with previous images..."
|
||||
docker-compose -f docker-compose.yml -f docker-compose.production.yml up -d
|
||||
|
||||
# Wait for services to start
|
||||
sleep 15
|
||||
|
||||
# Check health
|
||||
if check_services_health; then
|
||||
success "Quick rollback completed successfully!"
|
||||
else
|
||||
warning "Quick rollback completed but some services may not be healthy"
|
||||
fi
|
||||
}
|
||||
|
||||
# Full rollback using backup
|
||||
full_rollback() {
|
||||
local backup_name=$1
|
||||
|
||||
if [[ -z "$backup_name" ]]; then
|
||||
backup_name=$(get_last_backup)
|
||||
fi
|
||||
|
||||
if [[ -z "$backup_name" ]]; then
|
||||
error_exit "No backup found for rollback"
|
||||
fi
|
||||
|
||||
local backup_path="$BACKUP_DIR/$backup_name"
|
||||
|
||||
if [[ ! -d "$backup_path" ]]; then
|
||||
error_exit "Backup not found: $backup_name"
|
||||
fi
|
||||
|
||||
warning "Performing full rollback to backup: $backup_name"
|
||||
warning "This will restore configuration and Docker volumes"
|
||||
warning "Press Ctrl+C to cancel or wait 10 seconds to continue..."
|
||||
sleep 10
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Stop current services
|
||||
info "Stopping current services..."
|
||||
docker-compose -f docker-compose.yml -f docker-compose.production.yml down
|
||||
|
||||
# Restore Docker images
|
||||
if [[ -f "$backup_path/images.tar" ]]; then
|
||||
info "Restoring Docker images..."
|
||||
docker load -i "$backup_path/images.tar"
|
||||
fi
|
||||
|
||||
# Restore configuration files
|
||||
if [[ -d "$backup_path/config" ]]; then
|
||||
info "Restoring configuration files..."
|
||||
|
||||
# Backup current config before restore
|
||||
local config_backup="config_backup_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR/$config_backup"
|
||||
cp -r .env* "$BACKUP_DIR/$config_backup/" 2>/dev/null || true
|
||||
cp docker-compose*.yml "$BACKUP_DIR/$config_backup/"
|
||||
|
||||
# Restore from backup
|
||||
cp "$backup_path"/.env* . 2>/dev/null || true
|
||||
cp "$backup_path"/docker-compose*.yml .
|
||||
|
||||
if [[ -d "$backup_path/config/conf" && -d "nginx" ]]; then
|
||||
cp -r "$backup_path/config/conf" nginx/
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restore Docker volumes
|
||||
if [[ -d "$backup_path/volumes" ]]; then
|
||||
info "Restoring Docker volumes..."
|
||||
|
||||
for volume_backup in "$backup_path/volumes"/*.tar.gz; do
|
||||
if [[ -f "$volume_backup" ]]; then
|
||||
local volume_name=$(basename "$volume_backup" .tar.gz)
|
||||
local full_volume_name="roa2web_$volume_name"
|
||||
|
||||
# Remove current volume
|
||||
docker volume rm "$full_volume_name" 2>/dev/null || true
|
||||
|
||||
# Create new volume
|
||||
docker volume create "$full_volume_name"
|
||||
|
||||
# Restore data
|
||||
docker run --rm \
|
||||
-v "$full_volume_name":/data \
|
||||
-v "$backup_path/volumes":/backup \
|
||||
alpine tar xzf "/backup/$(basename "$volume_backup")" -C /data
|
||||
|
||||
info "Restored volume: $volume_name"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Start services
|
||||
info "Starting services..."
|
||||
docker-compose -f docker-compose.yml -f docker-compose.production.yml up -d
|
||||
|
||||
# Wait for services to start
|
||||
sleep 20
|
||||
|
||||
# Check health
|
||||
if check_services_health; then
|
||||
success "Full rollback completed successfully!"
|
||||
else
|
||||
warning "Full rollback completed but some services may not be healthy"
|
||||
warning "You may need to check logs: docker-compose logs"
|
||||
fi
|
||||
}
|
||||
|
||||
# Emergency stop
|
||||
emergency_stop() {
|
||||
warning "Performing emergency stop of all ROA2WEB services..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Stop all compose services
|
||||
docker-compose -f docker-compose.yml -f docker-compose.production.yml down -v 2>/dev/null || true
|
||||
docker-compose -f docker-compose.yml down -v 2>/dev/null || true
|
||||
|
||||
# Stop any remaining ROA2WEB containers
|
||||
docker ps -q --filter "name=roa-" | xargs -r docker stop
|
||||
|
||||
success "Emergency stop completed"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
local action=${1:-quick}
|
||||
|
||||
case $action in
|
||||
"quick")
|
||||
info "=== ROA2WEB Quick Rollback ==="
|
||||
quick_rollback
|
||||
;;
|
||||
"full")
|
||||
info "=== ROA2WEB Full Rollback ==="
|
||||
full_rollback "$2"
|
||||
;;
|
||||
"list")
|
||||
list_rollback_targets
|
||||
;;
|
||||
"emergency")
|
||||
emergency_stop
|
||||
;;
|
||||
"health")
|
||||
check_services_health
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {quick|full [backup_name]|list|emergency|health}"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " quick - Quick rollback using previous Docker images"
|
||||
echo " full - Full rollback using backup (restores config + volumes)"
|
||||
echo " list - List available rollback targets"
|
||||
echo " emergency - Emergency stop all services"
|
||||
echo " health - Check current services health"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 quick # Quick rollback"
|
||||
echo " $0 full # Full rollback to last backup"
|
||||
echo " $0 full backup_20240131_143022 # Full rollback to specific backup"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user