#!/bin/bash # Foxhunt HFT Trading System - Rollback Script # Quickly rollback to a previous deployment version set -euo pipefail # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEPLOY_DIR="/opt/foxhunt" LOG_FILE="/home/jgrusewski/Work/foxhunt/logs-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() { echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}" } error() { log "${RED}ERROR: $1${NC}" exit 1 } warning() { log "${YELLOW}WARNING: $1${NC}" } info() { log "${BLUE}INFO: $1${NC}" } success() { log "${GREEN}SUCCESS: $1${NC}" } # Show usage show_usage() { echo "Usage: $0 " echo "" echo "Available backups:" if [[ -d "${DEPLOY_DIR}/backups" ]]; then ls -la "${DEPLOY_DIR}/backups/" | grep "^d" | awk '{print " " $9}' | grep -v "^\.$\|^\.\.$" else echo " No backups found in ${DEPLOY_DIR}/backups" fi exit 1 } # Validate backup directory validate_backup() { local backup_dir="$1" if [[ ! -d "$backup_dir" ]]; then error "Backup directory does not exist: $backup_dir" fi if [[ ! -f "$backup_dir/manifest.txt" ]]; then error "Invalid backup directory (missing manifest.txt): $backup_dir" fi info "Backup validation passed" info "Backup manifest:" cat "$backup_dir/manifest.txt" | sed 's/^/ /' } # Stop services stop_services() { info "Stopping Foxhunt services..." # Stop application services systemctl stop foxhunt-tli 2>/dev/null || warning "Failed to stop TLI service" systemctl stop foxhunt-backtesting 2>/dev/null || warning "Failed to stop backtesting service" success "Services stopped" } # Restore files from backup restore_files() { local backup_dir="$1" info "Restoring files from backup..." # Create current deployment backup before rollback local rollback_backup="${DEPLOY_DIR}/backups/pre-rollback-$(date +%Y%m%d_%H%M%S)" mkdir -p "$rollback_backup" if [[ -d "${DEPLOY_DIR}/bin" ]]; then cp -r "${DEPLOY_DIR}/bin" "$rollback_backup/" fi if [[ -d "${DEPLOY_DIR}/config" ]]; then cp -r "${DEPLOY_DIR}/config" "$rollback_backup/" fi echo "Pre-rollback backup created: $(date)" > "$rollback_backup/manifest.txt" # Restore from backup if [[ -d "$backup_dir/bin" ]]; then info "Restoring binaries..." rm -rf "${DEPLOY_DIR}/bin" cp -r "$backup_dir/bin" "${DEPLOY_DIR}/" chown -R foxhunt:foxhunt "${DEPLOY_DIR}/bin" chmod +x "${DEPLOY_DIR}/bin/"* fi if [[ -d "$backup_dir/config" ]]; then info "Restoring configuration..." rm -rf "${DEPLOY_DIR}/config" cp -r "$backup_dir/config" "${DEPLOY_DIR}/" chown -R foxhunt:foxhunt "${DEPLOY_DIR}/config" fi # Update version file echo "ROLLBACK - $(date '+%Y-%m-%d %H:%M:%S') - Restored from $backup_dir" > "${DEPLOY_DIR}/VERSION" success "Files restored from backup" } # Start services start_services() { info "Starting Foxhunt services..." # Start database stack (should already be running) systemctl start foxhunt-database-stack 2>/dev/null || warning "Database stack may already be running" # Wait a moment for databases to be ready sleep 5 # Start application services systemctl start foxhunt-tli if [[ -f "${DEPLOY_DIR}/bin/backtesting-service" ]]; then systemctl start foxhunt-backtesting fi success "Services started" } # Run health checks run_health_checks() { info "Running post-rollback health checks..." local checks_passed=0 local total_checks=3 # Check TLI service if systemctl is-active --quiet foxhunt-tli; then success "✓ TLI service is running" ((checks_passed++)) else warning "✗ TLI service is not running" fi # Check database connectivity if docker exec foxhunt-postgres pg_isready -U foxhunt &>/dev/null; then success "✓ PostgreSQL is healthy" ((checks_passed++)) else warning "✗ PostgreSQL is not healthy" fi # Check Redis if docker exec foxhunt-redis redis-cli ping &>/dev/null; then success "✓ Redis is healthy" ((checks_passed++)) else warning "✗ Redis is not healthy" fi info "Health checks: ${checks_passed}/${total_checks} passed" if [[ $checks_passed -lt $total_checks ]]; then warning "Some health checks failed. Manual intervention may be required." return 1 fi success "All health checks passed!" } # Display rollback summary show_rollback_summary() { local backup_dir="$1" info "Rollback Summary" echo "====================" echo "Rollback completed at: $(date)" echo "Restored from: $backup_dir" echo "Current version: $(cat "${DEPLOY_DIR}/VERSION" 2>/dev/null || echo "unknown")" echo "" echo "Services status:" systemctl status foxhunt-tli foxhunt-backtesting --no-pager 2>/dev/null || true echo "" echo "To check logs:" echo " - TLI: journalctl -u foxhunt-tli -f" echo " - Database Stack: docker-compose -f ${DEPLOY_DIR}/docker/docker-compose.yml logs -f" } # Main rollback function main() { local backup_dir="${1:-}" if [[ -z "$backup_dir" ]]; then show_usage fi # Check if running as root if [[ $EUID -ne 0 ]]; then error "This script must be run as root (use sudo)" fi info "Starting rollback to: $backup_dir" # Confirm rollback echo -n "Are you sure you want to rollback to this backup? (y/N): " read -r confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then info "Rollback cancelled" exit 0 fi validate_backup "$backup_dir" stop_services restore_files "$backup_dir" start_services if run_health_checks; then success "Rollback completed successfully!" else warning "Rollback completed with warnings. Please check the health check results." fi show_rollback_summary "$backup_dir" } # Run main function main "$@"