#!/bin/bash # ============================================== # AzerothCore Docker Cleanup Script # ============================================== # This script provides various levels of cleanup for AzerothCore Docker resources # Usage: ./cleanup.sh [--soft] [--hard] [--nuclear] [--dry-run] set -e # Exit on any error # Change to the project root directory (parent of scripts directory) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" cd "$PROJECT_ROOT" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' MAGENTA='\033[0;35m' NC='\033[0m' # No Color # Script options CLEANUP_LEVEL="" DRY_RUN=false FORCE=false PRESERVE_BACKUPS=false # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in --soft) CLEANUP_LEVEL="soft" shift ;; --hard) CLEANUP_LEVEL="hard" shift ;; --nuclear) CLEANUP_LEVEL="nuclear" shift ;; --dry-run) DRY_RUN=true shift ;; --force) FORCE=true shift ;; --preserve-backups) PRESERVE_BACKUPS=true shift ;; -h|--help) echo "AzerothCore Docker Cleanup Script" echo "" echo "Usage: $0 [CLEANUP_LEVEL] [OPTIONS]" echo "" echo "CLEANUP LEVELS:" echo " --soft Stop containers only (preserves data)" echo " --hard Stop containers + remove containers + networks (preserves volumes/data)" echo " --nuclear Complete removal: containers + networks + volumes + images (DESTROYS ALL DATA)" echo "" echo "OPTIONS:" echo " --dry-run Show what would be done without actually doing it" echo " --preserve-backups Keep database backup files when cleaning storage" echo " --force Skip confirmation prompts" echo " --help Show this help message" echo "" echo "EXAMPLES:" echo " $0 --soft # Stop all containers" echo " $0 --hard --dry-run # Show what hard cleanup would do" echo " $0 --nuclear --force # Complete removal without prompts" exit 0 ;; *) echo "Unknown option $1" echo "Use --help for usage information" exit 1 ;; esac done # Function to print colored output print_status() { local status=$1 local message=$2 case $status in "INFO") echo -e "${BLUE}ℹ️ ${message}${NC}" ;; "SUCCESS") echo -e "${GREEN}✅ ${message}${NC}" ;; "WARNING") echo -e "${YELLOW}⚠️ ${message}${NC}" ;; "ERROR") echo -e "${RED}❌ ${message}${NC}" ;; "DANGER") echo -e "${RED}💀 ${message}${NC}" ;; "HEADER") echo -e "\n${MAGENTA}=== ${message} ===${NC}" ;; esac } # Function to execute command with dry-run support execute_command() { local description=$1 local command=$2 if [ "$DRY_RUN" = true ]; then print_status "INFO" "[DRY RUN] Would execute: $description" echo " Command: $command" else print_status "INFO" "Executing: $description" if eval "$command"; then print_status "SUCCESS" "Completed: $description" else print_status "WARNING" "Failed or no action needed: $description" fi fi } # Function to get confirmation get_confirmation() { local message=$1 if [ "$FORCE" = true ]; then print_status "INFO" "Force mode enabled, skipping confirmation" return 0 fi echo -e "${YELLOW}⚠️ ${message}${NC}" read -p "Are you sure? (yes/no): " response case $response in yes|YES|y|Y) return 0 ;; *) print_status "INFO" "Operation cancelled by user" exit 0 ;; esac } # Function to show current resources show_current_resources() { print_status "HEADER" "CURRENT AZEROTHCORE RESOURCES" echo -e "${BLUE}Containers:${NC}" if docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | grep -E "ac-|acore" | head -20; then echo "" else echo " No AzerothCore containers found" fi echo -e "${BLUE}Networks:${NC}" if docker network ls --format "table {{.Name}}\t{{.Driver}}\t{{.Scope}}" | grep -E "azerothcore|acore"; then echo "" else echo " No AzerothCore networks found" fi echo -e "${BLUE}Volumes:${NC}" if docker volume ls --format "table {{.Name}}\t{{.Driver}}" | grep -E "ac_|acore|azerothcore"; then echo "" else echo " No AzerothCore volumes found" fi echo -e "${BLUE}Images:${NC}" if docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -E "acore|azerothcore|phpmyadmin|keira3|uprightbass360.*playerbots" | head -10; then echo "" else echo " No AzerothCore-related images found" fi } # Function to perform soft cleanup soft_cleanup() { print_status "HEADER" "SOFT CLEANUP - STOPPING CONTAINERS" get_confirmation "This will stop all AzerothCore containers but preserve all data." # Stop modules layer (if exists) execute_command "Stop modules layer" \ "docker compose --env-file docker-compose-azerothcore-modules-custom.env -f docker-compose-azerothcore-modules.yml down 2>/dev/null || docker compose --env-file docker-compose-azerothcore-modules.env -f docker-compose-azerothcore-modules.yml down 2>/dev/null || true" # Stop tools layer (if exists) execute_command "Stop tools layer" \ "docker compose --env-file docker-compose-azerothcore-tools-custom.env -f docker-compose-azerothcore-tools.yml down 2>/dev/null || docker compose --env-file docker-compose-azerothcore-tools.env -f docker-compose-azerothcore-tools.yml down 2>/dev/null || true" # Stop services layer execute_command "Stop services layer" \ "docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml down 2>/dev/null || docker compose --env-file docker-compose-azerothcore-services.env -f docker-compose-azerothcore-services.yml down" # Stop database layer execute_command "Stop database layer" \ "docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml down 2>/dev/null || docker compose --env-file docker-compose-azerothcore-database.env -f docker-compose-azerothcore-database.yml down" print_status "SUCCESS" "Soft cleanup completed - all containers stopped" print_status "INFO" "Data volumes and images are preserved" print_status "INFO" "Use deployment script to restart services" } # Function to perform hard cleanup hard_cleanup() { print_status "HEADER" "HARD CLEANUP - REMOVING CONTAINERS AND NETWORKS" get_confirmation "This will remove all containers and networks but preserve data volumes and images." # Remove containers and networks execute_command "Remove modules layer (containers + networks)" \ "docker compose --env-file docker-compose-azerothcore-modules-custom.env -f docker-compose-azerothcore-modules.yml down --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-modules.env -f docker-compose-azerothcore-modules.yml down --remove-orphans 2>/dev/null || true" execute_command "Remove tools layer (containers + networks)" \ "docker compose --env-file docker-compose-azerothcore-tools-custom.env -f docker-compose-azerothcore-tools.yml down --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-tools.env -f docker-compose-azerothcore-tools.yml down --remove-orphans 2>/dev/null || true" execute_command "Remove services layer (containers + networks)" \ "docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml down --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-services.env -f docker-compose-azerothcore-services.yml down --remove-orphans" execute_command "Remove database layer (containers + networks)" \ "docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml down --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-database.env -f docker-compose-azerothcore-database.yml down --remove-orphans" # Clean up any remaining AzerothCore containers execute_command "Remove any remaining AzerothCore containers" \ "docker ps -a --format '{{.Names}}' | grep -E '^ac-' | xargs -r docker rm -f" # Clean up AzerothCore networks execute_command "Remove AzerothCore networks" \ "docker network ls --format '{{.Name}}' | grep -E 'azerothcore|acore' | xargs -r docker network rm" print_status "SUCCESS" "Hard cleanup completed - containers and networks removed" print_status "INFO" "Data volumes and images are preserved" print_status "INFO" "Run full deployment script to recreate the stack" } # Function to perform nuclear cleanup nuclear_cleanup() { print_status "HEADER" "NUCLEAR CLEANUP - COMPLETE REMOVAL" print_status "DANGER" "THIS WILL DESTROY ALL DATA AND REMOVE EVERYTHING!" get_confirmation "This will permanently delete ALL AzerothCore data, containers, networks, volumes, and images. This action CANNOT be undone!" # Stop and remove everything execute_command "Stop and remove modules layer (with volumes)" \ "docker compose --env-file docker-compose-azerothcore-modules-custom.env -f docker-compose-azerothcore-modules.yml down --volumes --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-modules.env -f docker-compose-azerothcore-modules.yml down --volumes --remove-orphans 2>/dev/null || true" execute_command "Stop and remove tools layer (with volumes)" \ "docker compose --env-file docker-compose-azerothcore-tools-custom.env -f docker-compose-azerothcore-tools.yml down --volumes --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-tools.env -f docker-compose-azerothcore-tools.yml down --volumes --remove-orphans 2>/dev/null || true" execute_command "Stop and remove services layer (with volumes)" \ "docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml down --volumes --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-services.env -f docker-compose-azerothcore-services.yml down --volumes --remove-orphans 2>/dev/null || true" execute_command "Stop and remove database layer (with volumes)" \ "docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml down --volumes --remove-orphans 2>/dev/null || docker compose --env-file docker-compose-azerothcore-database.env -f docker-compose-azerothcore-database.yml down --volumes --remove-orphans 2>/dev/null || true" # Remove any remaining containers execute_command "Remove any remaining AzerothCore containers" \ "docker ps -a --format '{{.Names}}' | grep -E '^ac-|acore' | xargs -r docker rm -f" # Remove networks execute_command "Remove AzerothCore networks" \ "docker network ls --format '{{.Name}}' | grep -E 'azerothcore|acore' | xargs -r docker network rm" # Remove volumes execute_command "Remove AzerothCore volumes" \ "docker volume ls --format '{{.Name}}' | grep -E '^ac_|acore|azerothcore' | xargs -r docker volume rm" # Remove images execute_command "Remove AzerothCore server images" \ "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^acore/' | xargs -r docker rmi" execute_command "Remove mod-playerbots images" \ "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^uprightbass360/azerothcore-wotlk-playerbots' | xargs -r docker rmi" execute_command "Remove related tool images" \ "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E 'phpmyadmin|uprightbass360/keira3' | xargs -r docker rmi" # Clean up local data directories if [ "$PRESERVE_BACKUPS" = true ]; then # Create a function to clean storage while preserving backups cleanup_storage_preserve_backups() { if [ -d "./storage" ]; then # Find the storage path from environment files STORAGE_ROOT=$(grep "^STORAGE_ROOT=" docker-compose-azerothcore-database*.env 2>/dev/null | head -1 | cut -d'=' -f2 || echo "/nfs/containers") BACKUP_PATH="${STORAGE_ROOT}/azerothcore/backups" # Temporarily move backups if they exist if [ -d "${BACKUP_PATH}" ]; then print_status "INFO" "Preserving backups at ${BACKUP_PATH}" sudo mkdir -p /tmp/azerothcore-backups-preserve 2>/dev/null || mkdir -p /tmp/azerothcore-backups-preserve sudo cp -r "${BACKUP_PATH}" /tmp/azerothcore-backups-preserve/ 2>/dev/null || cp -r "${BACKUP_PATH}" /tmp/azerothcore-backups-preserve/ fi # Remove storage directories sudo rm -rf ./storage 2>/dev/null || rm -rf ./storage 2>/dev/null || true # Restore backups if they were preserved if [ -d "/tmp/azerothcore-backups-preserve/backups" ]; then sudo mkdir -p "${STORAGE_ROOT}/azerothcore" 2>/dev/null || mkdir -p "${STORAGE_ROOT}/azerothcore" sudo mv /tmp/azerothcore-backups-preserve/backups "${BACKUP_PATH}" 2>/dev/null || mv /tmp/azerothcore-backups-preserve/backups "${BACKUP_PATH}" sudo rm -rf /tmp/azerothcore-backups-preserve 2>/dev/null || rm -rf /tmp/azerothcore-backups-preserve print_status "SUCCESS" "Backups preserved at ${BACKUP_PATH}" fi fi # Still remove ./backups directory (local backups, not NFS backups) sudo rm -rf ./backups 2>/dev/null || rm -rf ./backups 2>/dev/null || true } execute_command "Remove storage directories (preserving backups)" \ "cleanup_storage_preserve_backups" else execute_command "Remove local storage directories" \ "sudo rm -rf ./storage ./backups 2>/dev/null || rm -rf ./storage ./backups 2>/dev/null || true" fi # System cleanup execute_command "Clean up unused Docker resources" \ "docker system prune -af --volumes" print_status "SUCCESS" "Nuclear cleanup completed - everything removed" print_status "DANGER" "ALL AZEROTHCORE DATA HAS BEEN PERMANENTLY DELETED" print_status "INFO" "Run full deployment script to start fresh" } # Function to show cleanup summary show_cleanup_summary() { local level=$1 print_status "HEADER" "CLEANUP SUMMARY" case $level in "soft") echo -e "${GREEN}✅ Containers: Stopped${NC}" echo -e "${BLUE}ℹ️ Networks: Preserved${NC}" echo -e "${BLUE}ℹ️ Volumes: Preserved (data safe)${NC}" echo -e "${BLUE}ℹ️ Images: Preserved${NC}" echo "" echo -e "${GREEN}Next steps:${NC}" echo " • To restart: cd scripts && ./deploy-and-check.sh --skip-deploy" echo " • To deploy fresh: cd scripts && ./deploy-and-check.sh" ;; "hard") echo -e "${GREEN}✅ Containers: Removed${NC}" echo -e "${GREEN}✅ Networks: Removed${NC}" echo -e "${BLUE}ℹ️ Volumes: Preserved (data safe)${NC}" echo -e "${BLUE}ℹ️ Images: Preserved${NC}" echo "" echo -e "${GREEN}Next steps:${NC}" echo " • To deploy: cd scripts && ./deploy-and-check.sh" ;; "nuclear") echo -e "${RED}💀 Containers: DESTROYED${NC}" echo -e "${RED}💀 Networks: DESTROYED${NC}" echo -e "${RED}💀 Volumes: DESTROYED${NC}" echo -e "${RED}💀 Images: DESTROYED${NC}" echo -e "${RED}💀 Data: PERMANENTLY DELETED${NC}" echo "" echo -e "${YELLOW}Next steps:${NC}" echo " • To start fresh: cd scripts && ./deploy-and-check.sh" echo " • This will re-download ~15GB of client data" ;; esac } # Main execution main() { print_status "HEADER" "AZEROTHCORE CLEANUP SCRIPT" # Check if docker is available if ! command -v docker &> /dev/null; then print_status "ERROR" "Docker is not installed or not in PATH" exit 1 fi # Show help if no cleanup level specified if [ -z "$CLEANUP_LEVEL" ]; then echo "Please specify a cleanup level:" echo " --soft Stop containers only (safe)" echo " --hard Remove containers + networks (preserves data)" echo " --nuclear Complete removal (DESTROYS ALL DATA)" echo "" echo "Use --help for more information" exit 1 fi # Show current resources show_current_resources # Execute cleanup based on level case $CLEANUP_LEVEL in "soft") soft_cleanup ;; "hard") hard_cleanup ;; "nuclear") nuclear_cleanup ;; esac # Show final summary show_cleanup_summary "$CLEANUP_LEVEL" print_status "SUCCESS" "🧹 Cleanup completed successfully!" } # Run main function main "$@"