#!/bin/bash # ThrillWiki Template-Based Complete Unraid Automation Setup # This script automates the entire template-based VM creation and deployment process on Unraid # # Usage: # ./setup-template-automation.sh # Standard template-based setup # ./setup-template-automation.sh --reset # Delete VM and config, start completely fresh # ./setup-template-automation.sh --reset-vm # Delete VM only, keep configuration # ./setup-template-automation.sh --reset-config # Delete config only, keep VM # Function to show help show_help() { echo "ThrillWiki Template-Based CI/CD Automation Setup" echo "" echo "This script sets up FAST template-based VM deployment using pre-configured Ubuntu templates." echo "Template VMs deploy in 2-5 minutes instead of 20-30 minutes with autoinstall." echo "" echo "Usage:" echo " $0 Set up or update ThrillWiki template automation" echo " $0 -y Non-interactive mode, use saved configuration" echo " $0 --reset Delete VM and config, start completely fresh" echo " $0 --reset-vm Delete VM only, keep configuration" echo " $0 --reset-config Delete config only, keep VM" echo " $0 --help Show this help message" echo "" echo "Template Benefits:" echo " โšก Speed: 2-5 min deployment vs 20-30 min with autoinstall" echo " ๐Ÿ”’ Reliability: Pre-tested template eliminates installation failures" echo " ๐Ÿ’พ Efficiency: Copy-on-write disk format saves space" echo "" echo "Options:" echo " -y, --yes Non-interactive mode - use saved configuration" echo " and passwords without prompting. Requires existing" echo " configuration file with saved settings." echo "" echo "Reset Options:" echo " --reset Completely removes existing VM, disks, and config" echo " before starting fresh template-based installation" echo " --reset-vm Removes only the VM and disks, preserves saved" echo " configuration to avoid re-entering settings" echo " --reset-config Removes only the saved configuration, preserves" echo " VM and prompts for fresh configuration input" echo " --help Display this help and exit" echo "" echo "Examples:" echo " $0 # Normal template-based setup/update" echo " $0 -y # Non-interactive setup with saved config" echo " $0 --reset # Complete fresh template installation" echo " $0 --reset-vm # Fresh VM with saved settings" echo " $0 --reset-config # Re-configure existing VM" exit 0 } # Check for help flag if [[ "$1" == "--help" || "$1" == "-h" ]]; then show_help fi # Parse command line flags RESET_ALL=false RESET_VM_ONLY=false RESET_CONFIG_ONLY=false NON_INTERACTIVE=false # Process all arguments while [[ $# -gt 0 ]]; do case $1 in -y|--yes) NON_INTERACTIVE=true echo "๐Ÿค– NON-INTERACTIVE MODE: Using saved configuration only" shift ;; --reset) RESET_ALL=true echo "๐Ÿ”„ COMPLETE RESET MODE: Will delete VM and configuration" shift ;; --reset-vm) RESET_VM_ONLY=true echo "๐Ÿ”„ VM RESET MODE: Will delete VM only, keep configuration" shift ;; --reset-config) RESET_CONFIG_ONLY=true echo "๐Ÿ”„ CONFIG RESET MODE: Will delete configuration only, keep VM" shift ;; --help|-h) show_help ;; *) echo "Unknown option: $1" show_help ;; esac done set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color log() { echo -e "${BLUE}[TEMPLATE-AUTOMATION]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_template() { echo -e "${CYAN}[TEMPLATE]${NC} $1" } # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" LOG_DIR="$PROJECT_DIR/logs" # Default values DEFAULT_UNRAID_HOST="" DEFAULT_VM_NAME="thrillwiki-vm" DEFAULT_VM_MEMORY="4096" DEFAULT_VM_VCPUS="2" DEFAULT_VM_DISK_SIZE="50" DEFAULT_WEBHOOK_PORT="9000" TEMPLATE_VM_NAME="thrillwiki-template-ubuntu" # Configuration files CONFIG_FILE="$PROJECT_DIR/.thrillwiki-template-config" TOKEN_FILE="$PROJECT_DIR/.thrillwiki-github-token" # Function to save configuration save_config() { log "Saving template configuration to $CONFIG_FILE..." cat > "$CONFIG_FILE" << EOF # ThrillWiki Template-Based Automation Configuration # This file stores your settings to avoid re-entering them each time # Unraid Server Configuration UNRAID_HOST="$UNRAID_HOST" UNRAID_USER="$UNRAID_USER" VM_NAME="$VM_NAME" VM_MEMORY="$VM_MEMORY" VM_VCPUS="$VM_VCPUS" VM_DISK_SIZE="$VM_DISK_SIZE" # Template Configuration TEMPLATE_VM_NAME="$TEMPLATE_VM_NAME" DEPLOYMENT_TYPE="template-based" # Network Configuration VM_IP="$VM_IP" VM_GATEWAY="$VM_GATEWAY" VM_NETMASK="$VM_NETMASK" VM_NETWORK="$VM_NETWORK" # GitHub Configuration REPO_URL="$REPO_URL" GITHUB_USERNAME="$GITHUB_USERNAME" GITHUB_API_ENABLED="$GITHUB_API_ENABLED" GITHUB_AUTH_METHOD="$GITHUB_AUTH_METHOD" # Webhook Configuration WEBHOOK_PORT="$WEBHOOK_PORT" WEBHOOK_ENABLED="$WEBHOOK_ENABLED" # SSH Configuration (path to key, not the key content) SSH_KEY_PATH="$HOME/.ssh/thrillwiki_vm" EOF log_success "Template configuration saved to $CONFIG_FILE" } # Function to save GitHub token securely - OVERWRITE THE OLD ONE COMPLETELY save_github_token() { if [ -n "$GITHUB_TOKEN" ]; then log "๐Ÿ”’ OVERWRITING GitHub token (new token will REPLACE old one)..." # Force remove any existing token file first rm -f "$TOKEN_FILE" 2>/dev/null || true # Write new token - this COMPLETELY OVERWRITES any old token echo "$GITHUB_TOKEN" > "$TOKEN_FILE" chmod 600 "$TOKEN_FILE" # Restrict to owner read/write only log_success "โœ… NEW GitHub token saved securely (OLD TOKEN COMPLETELY REPLACED)" log "Token file: $TOKEN_FILE" else log_error "No GITHUB_TOKEN to save!" fi } # Function to load GitHub token load_github_token() { if [ -f "$TOKEN_FILE" ]; then GITHUB_TOKEN=$(cat "$TOKEN_FILE") if [ -n "$GITHUB_TOKEN" ]; then log "๐Ÿ”“ Loaded saved GitHub token for reuse" return 0 fi fi return 1 } # Function to load configuration load_config() { if [ -f "$CONFIG_FILE" ]; then log "Loading existing template configuration from $CONFIG_FILE..." source "$CONFIG_FILE" return 0 else return 1 fi } # Function for non-interactive configuration loading load_non_interactive_config() { log "=== Non-Interactive Template Configuration Loading ===" # Load saved configuration if ! load_config; then log_error "No saved template configuration found. Cannot run in non-interactive mode." log_error "Please run the script without -y flag first to create initial configuration." exit 1 fi log_success "Loaded saved template configuration successfully" # Check for required environment variables for passwords if [ -z "${UNRAID_PASSWORD:-}" ]; then log_error "UNRAID_PASSWORD environment variable not set." log_error "For non-interactive mode, set: export UNRAID_PASSWORD='your_password'" exit 1 fi # Handle GitHub authentication based on saved method if [ -n "$GITHUB_USERNAME" ] && [ "$GITHUB_API_ENABLED" = "true" ]; then # Personal access token method - try authentication script first log "Attempting to get PAT token from authentication script..." if GITHUB_TOKEN=$(python3 "$SCRIPT_DIR/../github-auth.py" token 2>/dev/null) && [ -n "$GITHUB_TOKEN" ]; then log_success "Token obtained from authentication script" elif [ -n "${GITHUB_TOKEN:-}" ]; then log "Using token from environment variable" else log_error "No GitHub PAT token available. Either:" log_error "1. Run setup interactively to configure token" log_error "2. Set GITHUB_TOKEN environment variable: export GITHUB_TOKEN='your_token'" exit 1 fi fi # Handle webhook secret if [ "$WEBHOOK_ENABLED" = "true" ]; then if [ -z "${WEBHOOK_SECRET:-}" ]; then log_error "WEBHOOK_SECRET environment variable not set." log_error "For non-interactive mode, set: export WEBHOOK_SECRET='your_secret'" exit 1 fi fi log_success "All required credentials loaded from environment variables" log "Template configuration summary:" echo " Unraid Host: $UNRAID_HOST" echo " VM Name: $VM_NAME" echo " Template VM: $TEMPLATE_VM_NAME" echo " VM IP: $VM_IP" echo " Repository: $REPO_URL" echo " GitHub Auth: $GITHUB_AUTH_METHOD" echo " Webhook Enabled: $WEBHOOK_ENABLED" echo " Deployment Type: template-based โšก" } # Function to stop and clean up existing VM before reset stop_existing_vm_for_reset() { local vm_name="$1" local unraid_host="$2" local unraid_user="$3" if [ -z "$vm_name" ] || [ -z "$unraid_host" ] || [ -z "$unraid_user" ]; then log_warning "Missing VM connection details for VM shutdown" log "VM Name: ${vm_name:-'not set'}" log "Unraid Host: ${unraid_host:-'not set'}" log "Unraid User: ${unraid_user:-'not set'}" return 0 fi log "๐Ÿ” Checking if VM '$vm_name' exists and needs to be stopped..." # Test connection first if ! ssh -o ConnectTimeout=10 "$unraid_user@$unraid_host" "echo 'Connected'" > /dev/null 2>&1; then log_warning "Cannot connect to Unraid server at $unraid_host - skipping VM shutdown" return 0 fi # Check VM status local vm_status=$(ssh "$unraid_user@$unraid_host" "virsh domstate $vm_name 2>/dev/null || echo 'not defined'") if [ "$vm_status" = "not defined" ]; then log "VM '$vm_name' does not exist - no need to stop" return 0 elif [ "$vm_status" = "shut off" ]; then log "VM '$vm_name' is already stopped - good for reset" return 0 elif [ "$vm_status" = "running" ]; then log_warning "โš ๏ธ VM '$vm_name' is currently RUNNING!" log_warning "VM must be stopped before reset to avoid conflicts." echo if [ "$NON_INTERACTIVE" = "true" ]; then log "Non-interactive mode: Automatically stopping VM..." stop_choice="y" else echo "Options:" echo " 1. Stop the VM gracefully before reset (recommended)" echo " 2. Force stop the VM before reset" echo " 3. Skip VM shutdown (may cause issues)" echo " 4. Cancel reset" echo read -p "What would you like to do? (1-4): " stop_choice fi case $stop_choice in 1|y|Y) log "Stopping VM '$vm_name' gracefully before reset..." # Try graceful shutdown first log "Attempting graceful shutdown..." if ssh "$unraid_user@$unraid_host" "virsh shutdown $vm_name"; then log "Shutdown command sent, waiting for VM to stop..." # Wait up to 60 seconds for graceful shutdown local wait_count=0 local max_wait=12 # 60 seconds (12 * 5 seconds) while [ $wait_count -lt $max_wait ]; do sleep 5 local current_status=$(ssh "$unraid_user@$unraid_host" "virsh domstate $vm_name 2>/dev/null || echo 'not defined'") if [ "$current_status" != "running" ]; then log_success "โœ… VM '$vm_name' stopped gracefully (status: $current_status)" return 0 fi ((wait_count++)) log "Waiting for graceful shutdown... ($((wait_count * 5))s)" done # If graceful shutdown didn't work, ask about force stop log_warning "Graceful shutdown took too long. VM is still running." if [ "$NON_INTERACTIVE" = "true" ]; then log "Non-interactive mode: Force stopping VM..." force_choice="y" else echo read -p "Force stop the VM? (y/n): " force_choice fi if [ "$force_choice" = "y" ] || [ "$force_choice" = "Y" ]; then log "Force stopping VM '$vm_name'..." if ssh "$unraid_user@$unraid_host" "virsh destroy $vm_name"; then log_success "โœ… VM '$vm_name' force stopped" return 0 else log_error "โŒ Failed to force stop VM" return 1 fi else log_error "VM is still running. Cannot proceed safely with reset." return 1 fi else log_error "โŒ Failed to send shutdown command to VM" return 1 fi ;; 2) log "Force stopping VM '$vm_name' before reset..." if ssh "$unraid_user@$unraid_host" "virsh destroy $vm_name"; then log_success "โœ… VM '$vm_name' force stopped" return 0 else log_error "โŒ Failed to force stop VM" return 1 fi ;; 3) log_warning "โš ๏ธ Continuing with running VM (NOT RECOMMENDED)" log_warning "This may cause conflicts during VM recreation!" return 0 ;; 4|n|N|"") log "VM reset cancelled by user" exit 0 ;; *) log_error "Invalid choice. Please select 1, 2, 3, or 4." return 1 ;; esac else log "VM '$vm_name' status: $vm_status - continuing with reset" return 0 fi } # Function to gracefully stop template VM if running stop_template_vm_if_running() { local template_status=$(ssh "$UNRAID_USER@$UNRAID_HOST" "virsh domstate $TEMPLATE_VM_NAME 2>/dev/null || echo 'not defined'") if [ "$template_status" = "running" ]; then log_warning "โš ๏ธ Template VM '$TEMPLATE_VM_NAME' is currently RUNNING!" log_warning "Template VMs must be stopped to create new instances safely." echo if [ "$NON_INTERACTIVE" = "true" ]; then log "Non-interactive mode: Automatically stopping template VM..." stop_choice="y" else echo "Options:" echo " 1. Stop the template VM gracefully (recommended)" echo " 2. Continue anyway (may cause issues)" echo " 3. Cancel setup" echo read -p "What would you like to do? (1/2/3): " stop_choice fi case $stop_choice in 1|y|Y) log "Stopping template VM gracefully..." # Try graceful shutdown first log "Attempting graceful shutdown..." if ssh "$UNRAID_USER@$UNRAID_HOST" "virsh shutdown $TEMPLATE_VM_NAME"; then log "Shutdown command sent, waiting for VM to stop..." # Wait up to 60 seconds for graceful shutdown local wait_count=0 local max_wait=12 # 60 seconds (12 * 5 seconds) while [ $wait_count -lt $max_wait ]; do sleep 5 local current_status=$(ssh "$UNRAID_USER@$UNRAID_HOST" "virsh domstate $TEMPLATE_VM_NAME 2>/dev/null || echo 'not defined'") if [ "$current_status" != "running" ]; then log_success "โœ… Template VM stopped gracefully (status: $current_status)" return 0 fi ((wait_count++)) log "Waiting for graceful shutdown... ($((wait_count * 5))s)" done # If graceful shutdown didn't work, ask about force stop log_warning "Graceful shutdown took too long. Template VM is still running." if [ "$NON_INTERACTIVE" = "true" ]; then log "Non-interactive mode: Force stopping template VM..." force_choice="y" else echo read -p "Force stop the template VM? (y/n): " force_choice fi if [ "$force_choice" = "y" ] || [ "$force_choice" = "Y" ]; then log "Force stopping template VM..." if ssh "$UNRAID_USER@$UNRAID_HOST" "virsh destroy $TEMPLATE_VM_NAME"; then log_success "โœ… Template VM force stopped" return 0 else log_error "โŒ Failed to force stop template VM" return 1 fi else log_error "Template VM is still running. Cannot proceed safely." return 1 fi else log_error "โŒ Failed to send shutdown command to template VM" return 1 fi ;; 2) log_warning "โš ๏ธ Continuing with running template VM (NOT RECOMMENDED)" log_warning "This may cause disk corruption or deployment issues!" return 0 ;; 3|n|N|"") log "Setup cancelled by user" exit 0 ;; *) log_error "Invalid choice. Please select 1, 2, or 3." return 1 ;; esac fi return 0 } # Function to check template VM availability check_template_vm() { log_template "Checking template VM availability..." # Test connection first if ! ssh -o ConnectTimeout=10 "$UNRAID_USER@$UNRAID_HOST" "echo 'Connected'" > /dev/null 2>&1; then log_error "Cannot connect to Unraid server at $UNRAID_HOST" log_error "Please verify:" log_error "1. Unraid server IP address is correct" log_error "2. SSH key authentication is set up" log_error "3. Network connectivity" return 1 fi # Check if template VM disk exists if ssh "$UNRAID_USER@$UNRAID_HOST" "test -f /mnt/user/domains/$TEMPLATE_VM_NAME/vdisk1.qcow2"; then log_template "โœ… Template VM disk found: /mnt/user/domains/$TEMPLATE_VM_NAME/vdisk1.qcow2" # Get template info template_info=$(ssh "$UNRAID_USER@$UNRAID_HOST" "qemu-img info /mnt/user/domains/$TEMPLATE_VM_NAME/vdisk1.qcow2 | grep 'virtual size' || echo 'Size info not available'") log_template "๐Ÿ“‹ Template info: $template_info" # Check and handle template VM status template_status=$(ssh "$UNRAID_USER@$UNRAID_HOST" "virsh domstate $TEMPLATE_VM_NAME 2>/dev/null || echo 'not defined'") if [ "$template_status" = "running" ]; then log_template "Template VM status: $template_status (needs to be stopped)" # Stop the template VM if running if ! stop_template_vm_if_running; then log_error "Failed to stop template VM. Cannot proceed safely." return 1 fi else log_template "โœ… Template VM status: $template_status (good for template use)" fi return 0 else log_error "โŒ Template VM disk not found!" log_error "Expected location: /mnt/user/domains/$TEMPLATE_VM_NAME/vdisk1.qcow2" log_error "" log_error "To create the template VM:" log_error "1. Create a VM named '$TEMPLATE_VM_NAME' on your Unraid server" log_error "2. Install Ubuntu 24.04 LTS with required packages" log_error "3. Configure it with Python, PostgreSQL, Nginx, etc." log_error "4. Shut it down to use as a template" log_error "" log_error "See README-template-deployment.md for detailed setup instructions" return 1 fi } # Function to prompt for configuration prompt_template_config() { # In non-interactive mode, use saved config only if [ "$NON_INTERACTIVE" = "true" ]; then load_non_interactive_config return 0 fi log "=== ThrillWiki Template-Based VM Configuration ===" echo log_template "๐Ÿš€ This setup uses TEMPLATE-BASED deployment for ultra-fast VM creation!" echo # Try to load existing config first if load_config; then log_success "Loaded existing template configuration" echo "Current settings:" echo " Unraid Host: $UNRAID_HOST" echo " VM Name: $VM_NAME" echo " Template VM: $TEMPLATE_VM_NAME" echo " VM IP: $VM_IP" echo " Repository: $REPO_URL" echo " Deployment: template-based โšก" echo read -p "Use existing configuration? (y/n): " use_existing if [ "$use_existing" = "y" ] || [ "$use_existing" = "Y" ]; then # Still need to get sensitive info that we don't save read -s -p "Enter Unraid [PASSWORD-REMOVED] echo # Handle GitHub authentication based on saved method if [ -n "$GITHUB_USERNAME" ] && [ "$GITHUB_API_ENABLED" = "true" ]; then # Try different sources for the token in order of preference log "Loading GitHub PAT token..." # 1. Try authentication script first if GITHUB_TOKEN=$(python3 "$SCRIPT_DIR/../github-auth.py" token 2>/dev/null) && [ -n "$GITHUB_TOKEN" ]; then log_success "Token obtained from authentication script" log "Using existing PAT token from authentication script" # Validate token and repository access immediately log "๐Ÿ” Validating GitHub token and repository access..." if ! validate_github_access; then log_error "โŒ GitHub token validation failed. Please check your token and repository access." log "Please try entering a new token or check your repository URL." return 1 fi # 2. Try saved token file elif load_github_token; then log_success "Token loaded from secure storage (reusing for VM reset)" # Validate token and repository access immediately log "๐Ÿ” Validating GitHub token and repository access..." if ! validate_github_access; then log_error "โŒ GitHub token validation failed. Please check your token and repository access." log "Please try entering a new token or check your repository URL." return 1 fi else log "No token found in authentication script or saved storage" read -s -p "Enter GitHub personal access token: " GITHUB_TOKEN echo # Validate the new token immediately if [ -n "$GITHUB_TOKEN" ]; then log "๐Ÿ” Validating new GitHub token..." if ! validate_github_access; then log_error "โŒ GitHub token validation failed. Please check your token and repository access." log "Please try running the setup again with a valid token." return 1 fi fi # Save the new token for future VM resets save_github_token fi fi if [ "$WEBHOOK_ENABLED" = "true" ]; then read -s -p "Enter GitHub webhook secret: " WEBHOOK_SECRET echo fi # Check template VM before proceeding if ! check_template_vm; then log_error "Template VM check failed. Please set up your template VM first." exit 1 fi return 0 fi fi # Prompt for new configuration read -p "Enter your Unraid server IP address: " UNRAID_HOST read -p "Enter Unraid username (default: root): " UNRAID_USER UNRAID_USER=${UNRAID_USER:-root} read -s -p "Enter Unraid [PASSWORD-REMOVED] echo # Note: Password not saved for security # Check template VM availability early log_template "Verifying template VM setup..." if ! check_template_vm; then log_error "Template VM setup is required before proceeding." echo read -p "Do you want to continue setup anyway? (y/n): " continue_anyway if [ "$continue_anyway" != "y" ] && [ "$continue_anyway" != "Y" ]; then log "Setup cancelled. Please set up your template VM first." log "See README-template-deployment.md for instructions." exit 1 fi log_warning "Continuing setup without verified template VM..." else log_success "Template VM verified and ready!" fi read -p "Enter VM name (default: $DEFAULT_VM_NAME): " VM_NAME VM_NAME=${VM_NAME:-$DEFAULT_VM_NAME} read -p "Enter VM memory in MB (default: $DEFAULT_VM_MEMORY): " VM_MEMORY VM_MEMORY=${VM_MEMORY:-$DEFAULT_VM_MEMORY} read -p "Enter VM vCPUs (default: $DEFAULT_VM_VCPUS): " VM_VCPUS VM_VCPUS=${VM_VCPUS:-$DEFAULT_VM_VCPUS} read -p "Enter VM disk size in GB (default: $DEFAULT_VM_DISK_SIZE): " VM_DISK_SIZE VM_DISK_SIZE=${VM_DISK_SIZE:-$DEFAULT_VM_DISK_SIZE} # Template VM name (usually fixed) read -p "Enter template VM name (default: $TEMPLATE_VM_NAME): " TEMPLATE_VM_NAME_INPUT TEMPLATE_VM_NAME=${TEMPLATE_VM_NAME_INPUT:-$TEMPLATE_VM_NAME} read -p "Enter GitHub repository URL: " REPO_URL # GitHub API Configuration - PAT Only echo log "=== GitHub Personal Access Token Configuration ===" echo "This setup requires a GitHub Personal Access Token (PAT) for repository access." echo "Both classic tokens and fine-grained tokens are supported." echo "" echo "Required token permissions:" echo " - Repository access (read/write)" echo " - Contents (read/write)" echo " - Metadata (read)" echo "" # Try to get token from authentication script first log "Checking for existing GitHub token..." if GITHUB_TOKEN=$(python3 "$SCRIPT_DIR/../github-auth.py" token 2>/dev/null) && [ -n "$GITHUB_TOKEN" ]; then # Get username from authentication script if possible if GITHUB_USERNAME=$(python3 "$SCRIPT_DIR/../github-auth.py" whoami 2>/dev/null | grep "You are authenticated as:" | cut -d: -f2 | xargs) && [ -n "$GITHUB_USERNAME" ]; then log_success "Found existing token and username from authentication script" echo "Username: $GITHUB_USERNAME" echo "Token: ${GITHUB_TOKEN:0:8}... (masked)" echo read -p "Use this existing token? (y/n): " use_existing_token if [ "$use_existing_token" != "y" ] && [ "$use_existing_token" != "Y" ]; then GITHUB_TOKEN="" GITHUB_USERNAME="" fi else log "Found token but no username, need to get username..." read -p "Enter GitHub username: " GITHUB_USERNAME fi fi # If no token found or user chose not to use existing, prompt for manual entry if [ -z "$GITHUB_TOKEN" ]; then log "Enter your GitHub credentials manually:" read -p "Enter GitHub username: " GITHUB_USERNAME read -s -p "Enter GitHub Personal Access Token (classic or fine-grained): " GITHUB_TOKEN echo fi # Validate that we have both username and token if [ -n "$GITHUB_USERNAME" ] && [ -n "$GITHUB_TOKEN" ]; then GITHUB_API_ENABLED=true GITHUB_AUTH_METHOD="token" log_success "Personal access token configured for user: $GITHUB_USERNAME" # Test the token quickly log "Testing GitHub token access..." if curl -sf -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user >/dev/null 2>&1; then log_success "โœ… GitHub token validated successfully" else log_warning "โš ๏ธ Could not validate GitHub token (API may be rate-limited)" log "Proceeding anyway - token will be tested during repository operations" fi else log_error "Both username and token are required for GitHub access" log_error "Repository cloning and auto-pull functionality will not work without proper authentication" exit 1 fi # Webhook Configuration echo read -s -p "Enter GitHub webhook secret (optional, press Enter to skip): " WEBHOOK_SECRET echo # If no webhook secret provided, disable webhook functionality if [ -z "$WEBHOOK_SECRET" ]; then log "No webhook secret provided - webhook functionality will be disabled" WEBHOOK_ENABLED=false else WEBHOOK_ENABLED=true fi read -p "Enter webhook port (default: $DEFAULT_WEBHOOK_PORT): " WEBHOOK_PORT WEBHOOK_PORT=${WEBHOOK_PORT:-$DEFAULT_WEBHOOK_PORT} # Get VM network configuration preference echo log "=== Network Configuration ===" echo "Choose network configuration method:" echo "1. DHCP (automatic IP assignment - recommended)" echo "2. Static IP (manual IP configuration)" while true; do read -p "Select option (1-2): " network_choice case $network_choice in 1) log "Using DHCP network configuration..." VM_IP="dhcp" VM_GATEWAY="192.168.20.1" VM_NETMASK="255.255.255.0" VM_NETWORK="192.168.20.0/24" NETWORK_MODE="dhcp" break ;; 2) log "Using static IP network configuration..." # Get VM IP address with proper range validation while true; do read -p "Enter VM IP address (192.168.20.10-192.168.20.100): " VM_IP if [[ "$VM_IP" =~ ^192\.168\.20\.([1-9][0-9]|100)$ ]]; then local ip_last_octet="${BASH_REMATCH[1]}" if [ "$ip_last_octet" -ge 10 ] && [ "$ip_last_octet" -le 100 ]; then break fi fi echo "Invalid IP address. Please enter an IP in the range 192.168.20.10-192.168.20.100" done VM_GATEWAY="192.168.20.1" VM_NETMASK="255.255.255.0" VM_NETWORK="192.168.20.0/24" NETWORK_MODE="static" break ;; *) echo "Invalid option. Please select 1 or 2." ;; esac done # Save configuration and GitHub token save_config save_github_token # Save token for VM resets log_success "Template configuration saved - setup complete!" } # Function to update SSH config with actual VM IP address update_ssh_config_with_ip() { local vm_name="$1" local vm_ip="$2" local ssh_config_path="$HOME/.ssh/config" log "Updating SSH config with actual IP: $vm_ip" # Check if SSH config exists and has our VM entry if [ -f "$ssh_config_path" ] && grep -q "Host $vm_name" "$ssh_config_path"; then # Update the HostName to use actual IP instead of %h placeholder if grep -A 10 "Host $vm_name" "$ssh_config_path" | grep -q "HostName %h"; then # Replace %h with actual IP sed -i.bak "/Host $vm_name/,/^Host\|^$/s/HostName %h/HostName $vm_ip/" "$ssh_config_path" log_success "SSH config updated: $vm_name now points to $vm_ip" elif grep -A 10 "Host $vm_name" "$ssh_config_path" | grep -q "HostName "; then # Update existing IP sed -i.bak "/Host $vm_name/,/^Host\|^$/s/HostName .*/HostName $vm_ip/" "$ssh_config_path" log_success "SSH config updated: $vm_name IP changed to $vm_ip" else # Add HostName line after Host line sed -i.bak "/Host $vm_name/a\\ HostName $vm_ip" "$ssh_config_path" log_success "SSH config updated: Added IP $vm_ip for $vm_name" fi # Show the updated config section log "Updated SSH config for $vm_name:" grep -A 6 "Host $vm_name" "$ssh_config_path" | head -7 else log_warning "SSH config entry for $vm_name not found, cannot update IP" fi } # Generate SSH keys for VM access setup_ssh_keys() { log "Setting up SSH keys for template VM access..." local ssh_key_path="$HOME/.ssh/thrillwiki_vm" local ssh_config_path="$HOME/.ssh/config" if [ ! -f "$ssh_key_path" ]; then ssh-keygen -t rsa -b 4096 -f "$ssh_key_path" -N "" -C "thrillwiki-template-vm-access" log_success "SSH key generated: $ssh_key_path" else log "SSH key already exists: $ssh_key_path" fi # Add SSH config entry if ! grep -q "Host $VM_NAME" "$ssh_config_path" 2>/dev/null; then cat >> "$ssh_config_path" << EOF # ThrillWiki Template VM Host $VM_NAME HostName %h User thrillwiki IdentityFile $ssh_key_path StrictHostKeyChecking no UserKnownHostsFile /dev/null EOF log_success "SSH config updated for template VM" fi # Store public key for VM setup SSH_PUBLIC_KEY=$(cat "$ssh_key_path.pub") export SSH_PUBLIC_KEY } # Setup Unraid host access setup_unraid_access() { log "Setting up Unraid server access..." local unraid_key_path="$HOME/.ssh/unraid_access" if [ ! -f "$unraid_key_path" ]; then ssh-keygen -t rsa -b 4096 -f "$unraid_key_path" -N "" -C "unraid-template-access" log "Please add this public key to your Unraid server:" echo "---" cat "$unraid_key_path.pub" echo "---" echo log "Add this to /root/.ssh/***REMOVED*** on your Unraid server" read -p "Press Enter when you've added the key..." fi # Test Unraid connection log "Testing Unraid connection..." if ssh -i "$unraid_key_path" -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$UNRAID_USER@$UNRAID_HOST" "echo 'Connected to Unraid successfully'"; then log_success "Unraid connection test passed" else log_error "Unraid connection test failed" exit 1 fi # Update SSH config for Unraid if ! grep -q "Host unraid" "$HOME/.ssh/config" 2>/dev/null; then cat >> "$HOME/.ssh/config" << EOF # Unraid Server Host unraid HostName $UNRAID_HOST User $UNRAID_USER IdentityFile $unraid_key_path StrictHostKeyChecking no EOF fi } # Create environment files for template deployment create_environment_files() { log "Creating template deployment environment files..." log "๐Ÿ”„ NEW TOKEN WILL BE WRITTEN TO ALL ENVIRONMENT FILES (overwriting any old tokens)" # Force remove old environment files first rm -f "$PROJECT_DIR/***REMOVED***.unraid" "$PROJECT_DIR/***REMOVED***.webhook" 2>/dev/null || true # Get SSH public key content safely local ssh_key_path="$HOME/.ssh/thrillwiki_vm.pub" local ssh_public_key="" if [ -f "$ssh_key_path" ]; then ssh_public_key=$(cat "$ssh_key_path") fi # Template-based Unraid VM environment - COMPLETELY NEW FILE WITH NEW TOKEN cat > "$PROJECT_DIR/***REMOVED***.unraid" << EOF # ThrillWiki Template-Based VM Configuration UNRAID_HOST=$UNRAID_HOST UNRAID_USER=$UNRAID_USER UNRAID_PASSWORD=$UNRAID_PASSWORD VM_NAME=$VM_NAME VM_MEMORY=$VM_MEMORY VM_VCPUS=$VM_VCPUS VM_DISK_SIZE=$VM_DISK_SIZE SSH_PUBLIC_KEY="$ssh_public_key" # Template Configuration TEMPLATE_VM_NAME=$TEMPLATE_VM_NAME DEPLOYMENT_TYPE=template-based # Network Configuration VM_IP=$VM_IP VM_GATEWAY=$VM_GATEWAY VM_NETMASK=$VM_NETMASK VM_NETWORK=$VM_NETWORK # GitHub Configuration REPO_URL=$REPO_URL GITHUB_USERNAME=$GITHUB_USERNAME GITHUB_TOKEN=$GITHUB_TOKEN GITHUB_API_ENABLED=$GITHUB_API_ENABLED EOF # Webhook environment (updated with VM info) cat > "$PROJECT_DIR/***REMOVED***.webhook" << EOF # ThrillWiki Template-Based Webhook Configuration WEBHOOK_PORT=$WEBHOOK_PORT WEBHOOK_SECRET=$WEBHOOK_SECRET WEBHOOK_ENABLED=$WEBHOOK_ENABLED VM_HOST=$VM_IP VM_PORT=22 VM_USER=thrillwiki VM_KEY_PATH=$HOME/.ssh/thrillwiki_vm VM_PROJECT_PATH=/home/thrillwiki/thrillwiki REPO_URL=$REPO_URL DEPLOY_BRANCH=main # Template Configuration TEMPLATE_VM_NAME=$TEMPLATE_VM_NAME DEPLOYMENT_TYPE=template-based # GitHub API Configuration GITHUB_USERNAME=$GITHUB_USERNAME GITHUB_TOKEN=$GITHUB_TOKEN GITHUB_API_ENABLED=$GITHUB_API_ENABLED EOF log_success "Template deployment environment files created" } # Install required tools install_dependencies() { log "Installing required dependencies for template deployment..." # Check for required tools local missing_tools=() local mac_tools=() command -v python3 >/dev/null 2>&1 || missing_tools+=("python3") command -v ssh >/dev/null 2>&1 || missing_tools+=("openssh-client") command -v scp >/dev/null 2>&1 || missing_tools+=("openssh-client") # Install missing tools based on platform if [ ${#missing_tools[@]} -gt 0 ]; then log "Installing missing tools: ${missing_tools[*]}" if command -v apt-get >/dev/null 2>&1; then sudo apt-get update sudo apt-get install -y "${missing_tools[@]}" elif command -v yum >/dev/null 2>&1; then sudo yum install -y "${missing_tools[@]}" elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y "${missing_tools[@]}" elif command -v brew >/dev/null 2>&1; then # macOS with Homebrew for tool in "${missing_tools[@]}"; do case $tool in python3) brew install python3 ;; openssh-client) log "OpenSSH should be available on macOS" ;; esac done else log_error "Package manager not found. Please install: ${missing_tools[*]}" exit 1 fi fi # Install Python dependencies if [ -f "$PROJECT_DIR/pyproject.toml" ]; then log "Installing Python dependencies with UV..." if ! command -v uv >/dev/null 2>&1; then curl -LsSf https://astral.sh/uv/install.sh | sh source ~/.cargo/env fi cd "$PROJECT_DIR" uv sync fi log_success "Dependencies installed for template deployment" } # Create VM using the template-based VM manager create_template_vm() { log "Creating VM from template on Unraid server..." # Export all environment variables from the file set -a # automatically export all variables source "$PROJECT_DIR/***REMOVED***.unraid" set +a # turn off automatic export # Run template-based VM setup cd "$PROJECT_DIR" python3 scripts/unraid/main_template.py setup if [ $? -eq 0 ]; then log_success "Template-based VM setup completed successfully โšก" log_template "VM deployed in minutes instead of 30+ minutes!" else log_error "Template-based VM setup failed" exit 1 fi } # Wait for template VM to be ready and get IP wait_for_template_vm() { log "๐Ÿ” Getting VM IP address from guest agent..." log_template "Template VMs should get IP immediately via guest agent!" # Export all environment variables from the file set -a # automatically export all variables source "$PROJECT_DIR/***REMOVED***.unraid" set +a # turn off automatic export # Check for IP immediately - template VMs should have guest agent running local max_attempts=12 # 3 minutes max wait (much shorter) local attempt=1 log "๐Ÿ” Phase 1: Checking guest agent for IP address..." while [ $attempt -le $max_attempts ]; do log "๐Ÿ” Attempt $attempt/$max_attempts: Querying guest agent on VM '$VM_NAME'..." # Add timeout to the IP detection to prevent hanging VM_IP_RESULT="" VM_IP="" # Use timeout command to prevent hanging (30 seconds max per attempt) if command -v timeout >/dev/null 2>&1; then VM_IP_RESULT=$(timeout 30 python3 scripts/unraid/main_template.py ip 2>&1 || echo "TIMEOUT") elif command -v gtimeout >/dev/null 2>&1; then # macOS with coreutils installed VM_IP_RESULT=$(gtimeout 30 python3 scripts/unraid/main_template.py ip 2>&1 || echo "TIMEOUT") else # Fallback for systems without timeout command - use background process with kill log "โš ๏ธ No timeout command available, using background process method..." VM_IP_RESULT=$(python3 scripts/unraid/main_template.py ip 2>&1 & PID=$! ( sleep 30 if kill -0 $PID 2>/dev/null; then kill $PID 2>/dev/null echo "TIMEOUT" fi ) & wait $PID 2>/dev/null || echo "TIMEOUT") fi # Check if we got a timeout if echo "$VM_IP_RESULT" | grep -q "TIMEOUT"; then log "โš ๏ธ IP detection timed out after 30 seconds - guest agent may not be ready" elif [ -n "$VM_IP_RESULT" ]; then # Show what we got from the query log "๐Ÿ“ Guest agent response: $(echo "$VM_IP_RESULT" | head -1)" # Extract IP from successful response VM_IP=$(echo "$VM_IP_RESULT" | grep "VM IP:" | cut -d' ' -f3) else log "โš ๏ธ No response from guest agent query" fi if [ -n "$VM_IP" ] && [ "$VM_IP" != "None" ] && [ "$VM_IP" != "null" ] && [ "$VM_IP" != "TIMEOUT" ]; then log_success "โœ… Template VM got IP address: $VM_IP โšก" # Update SSH config with actual IP update_ssh_config_with_ip "$VM_NAME" "$VM_IP" # Update webhook environment with IP sed -i.bak "s/VM_HOST=$VM_NAME/VM_HOST=$VM_IP/" "$PROJECT_DIR/***REMOVED***.webhook" break fi # Much shorter wait time since template VMs should be fast if [ $attempt -le 3 ]; then log "โณ No IP yet, waiting 5 seconds... (VM may still be booting)" sleep 5 # Very short wait for first few attempts else log "โณ Still waiting for IP... ($(($attempt * 15))s elapsed, checking every 15s)" # Show VM status to help debug - also with timeout log "๐Ÿ” Checking VM status for debugging..." if command -v timeout >/dev/null 2>&1; then VM_STATUS=$(timeout 15 python3 scripts/unraid/main_template.py status 2>&1 | head -1 || echo "Status check timed out") else VM_STATUS=$(python3 scripts/unraid/main_template.py status 2>&1 | head -1) fi if [ -n "$VM_STATUS" ]; then log "๐Ÿ“Š VM Status: $VM_STATUS" fi sleep 15 fi ((attempt++)) done if [ -z "$VM_IP" ] || [ "$VM_IP" = "None" ] || [ "$VM_IP" = "null" ]; then log_error "โŒ Template VM failed to get IP address after $((max_attempts * 15)) seconds" log_error "Guest agent may not be running or network configuration issue" log_error "Check VM console on Unraid: virsh console $VM_NAME" exit 1 fi # Phase 2: Wait for SSH connectivity (should be very fast for templates) log "๐Ÿ” Phase 2: Testing SSH connectivity to $VM_IP..." wait_for_ssh_connectivity "$VM_IP" } # Wait for SSH connectivity to be available wait_for_ssh_connectivity() { local vm_ip="$1" local max_ssh_attempts=20 # 5 minutes max wait for SSH local ssh_attempt=1 while [ $ssh_attempt -le $max_ssh_attempts ]; do log "๐Ÿ”‘ Testing SSH connection to $vm_ip... (attempt $ssh_attempt/$max_ssh_attempts)" # Test SSH connectivity with a simple command if ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o BatchMode=yes "$VM_NAME" "echo 'SSH connection successful'" >/dev/null 2>&1; then log_success "โœ… SSH connectivity established to template VM! ๐Ÿš€" return 0 fi # More detailed error for first few attempts if [ $ssh_attempt -le 3 ]; then log "โณ SSH not ready yet - VM may still be booting or initializing SSH service..." else log "โณ Still waiting for SSH... ($(($ssh_attempt * 15))s elapsed)" fi sleep 15 ((ssh_attempt++)) done log_error "โŒ SSH connection failed after $((max_ssh_attempts * 15)) seconds" log_error "VM IP: $vm_ip" log_error "Try manually: ssh $VM_NAME" log_error "Check VM console on Unraid for boot issues" exit 1 } # Configure VM for ThrillWiki using template-optimized deployment configure_template_vm() { log "๐Ÿš€ Deploying ThrillWiki to template VM..." log "This will sync the project files and set up the application" # First, sync the current project files to the VM deploy_project_files # Then run the setup script on the VM run_vm_setup_script log_success "โœ… Template VM configured and application deployed! โšก" } # Configure passwordless sudo for required operations configure_passwordless_sudo() { log "โš™๏ธ Configuring passwordless sudo for deployment operations..." # Create sudoers configuration file for thrillwiki user local sudoers_config="/tmp/thrillwiki-sudoers" cat > "$sudoers_config" << 'EOF' # ThrillWiki deployment sudo configuration # Allow thrillwiki user to run specific commands without password # File system operations for deployment thrillwiki ALL=(ALL) NOPASSWD: /bin/rm, /bin/mkdir, /bin/chown, /bin/chmod # Package management for updates thrillwiki ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get, /usr/bin/apt-cache # System service management thrillwiki ALL=(ALL) NOPASSWD: /bin/systemctl # PostgreSQL management thrillwiki ALL=(ALL) NOPASSWD: /usr/bin/sudo -u postgres * # Service file management thrillwiki ALL=(ALL) NOPASSWD: /bin/cp [AWS-SECRET-REMOVED]emd/* /etc/systemd/system/ thrillwiki ALL=(ALL) NOPASSWD: /bin/sed -i * /etc/systemd/system/thrillwiki.service EOF # Copy sudoers file to VM and install it log "๐Ÿ“‹ Copying sudoers configuration to VM..." scp "$sudoers_config" "$VM_NAME:/tmp/" # Install sudoers configuration (this requires password once) log "Installing sudo configuration (may require password this one time)..." if ssh -t "$VM_NAME" "sudo cp /tmp/thrillwiki-sudoers /etc/sudoers.d/thrillwiki && sudo chmod 440 /etc/sudoers.d/thrillwiki && sudo visudo -c"; then log_success "โœ… Passwordless sudo configured successfully" else log_error "Failed to configure passwordless sudo. Setup will continue but may prompt for passwords." # Continue anyway, as the user might have already configured this fi # Cleanup rm -f "$sudoers_config" ssh "$VM_NAME" "rm -f /tmp/thrillwiki-sudoers" } # Validate GitHub token and repository access validate_github_access() { log "๐Ÿ” Validating GitHub token and repository access..." # Extract repository path from REPO_URL local repo_path=$(echo "$REPO_URL" | sed 's|^https://github.com/||' | sed 's|/$||') if [ -z "$repo_path" ]; then repo_path="pacnpal/thrillwiki_django_no_react" # fallback log_warning "Using fallback repository path: $repo_path" fi # Test GitHub API authentication log "Testing GitHub API authentication..." if ! curl -sf -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user" > /dev/null; then log_error "โŒ GitHub token authentication failed!" log_error "The token cannot authenticate with GitHub API." if [ "$NON_INTERACTIVE" = "true" ]; then log_error "Non-interactive mode: Cannot prompt for new token." log_error "Please update your GITHUB_TOKEN environment variable with a valid token." exit 1 fi echo echo "โŒ Your GitHub token is invalid or expired!" echo "Please create a new Personal Access Token at: https://github.com/settings/tokens" echo "Required permissions: repo (full control of private repositories)" echo read -s -p "Enter a new GitHub Personal Access Token: " GITHUB_TOKEN echo if [ -z "$GITHUB_TOKEN" ]; then log_error "No token provided. Cannot continue." return 1 fi # Save the new token save_github_token # Test the new token if ! curl -sf -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user" > /dev/null; then log_error "โŒ New token is also invalid. Please check your token and try again." return 1 fi log_success "โœ… New GitHub token validated successfully" else log_success "โœ… GitHub token authentication successful" fi # Test repository access log "Testing repository access: $repo_path" local repo_response=$(curl -sf -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$repo_path") if [ $? -ne 0 ] || [ -z "$repo_response" ]; then log_error "โŒ Cannot access repository: $repo_path" log_error "This could be due to:" log_error "1. Repository doesn't exist" log_error "2. Repository is private and token lacks access" log_error "3. Token doesn't have 'repo' permissions" if [ "$NON_INTERACTIVE" = "true" ]; then log_error "Non-interactive mode: Cannot prompt for new repository." log_error "Please update your repository URL or token permissions." return 1 fi echo echo "โŒ Cannot access repository: $REPO_URL" echo "Current repository path: $repo_path" echo echo "The token has these scopes: $(curl -sf -H "Authorization: token $GITHUB_TOKEN" -I "https://api.github.com/user" | grep -i "x-oauth-scopes:" | cut -d: -f2 | xargs || echo "unknown")" echo "Required scope: 'repo' (full control of private repositories)" echo echo "Options:" echo "1. Enter a new GitHub token with 'repo' permissions" echo "2. Enter a different repository URL" echo "3. Exit and fix token permissions at https://github.com/settings/tokens" echo read -p "Select option (1-3): " repo_access_choice case $repo_access_choice in 1) echo echo "Please create a new GitHub Personal Access Token:" echo "1. Go to: https://github.com/settings/tokens/new" echo "2. Give it a name like 'ThrillWiki Template Automation'" echo "3. Check the 'repo' scope (full control of private repositories)" echo "4. Click 'Generate token'" echo "5. Copy the new token" echo read -s -p "Enter new GitHub Personal Access Token: " new_github_token echo if [ -z "$new_github_token" ]; then log_error "No token provided. Cannot continue." return 1 fi # Test the new token log "Testing new GitHub token..." if ! curl -sf -H "Authorization: token $new_github_token" "https://api.github.com/user" > /dev/null; then log_error "โŒ New token authentication failed. Please check your token." return 1 fi # Test repository access with new token log "Testing repository access with new token: $repo_path" local new_repo_response=$(curl -sf -H "Authorization: token $new_github_token" "https://api.github.com/repos/$repo_path") if [ $? -ne 0 ] || [ -z "$new_repo_response" ]; then log_error "โŒ New token still cannot access the repository." log_error "Please ensure the token has 'repo' scope and try again." return 1 fi # Token works! Update it GITHUB_TOKEN="$new_github_token" log_success "โœ… New GitHub token validated successfully" # Show new token scopes local new_scopes=$(curl -sf -H "Authorization: token $GITHUB_TOKEN" -I "https://api.github.com/user" | grep -i "x-oauth-scopes:" | cut -d: -f2 | xargs || echo "unknown") log "New token scopes: $new_scopes" # Save the new token save_github_token # Continue with validation using the new token repo_response="$new_repo_response" ;; 2) echo read -p "Enter new repository URL: " new_repo_url if [ -z "$new_repo_url" ]; then log "Setup cancelled by user" exit 0 fi REPO_URL="$new_repo_url" # Extract new repo path and test again repo_path=$(echo "$REPO_URL" | sed 's|^https://github.com/||' | sed 's|/$||') log "Testing new repository: $repo_path" repo_response=$(curl -sf -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$repo_path") if [ $? -ne 0 ] || [ -z "$repo_response" ]; then log_error "โŒ New repository is also inaccessible. Please check the URL and token permissions." return 1 fi log_success "โœ… New repository validated successfully" # Update saved configuration with new repo URL save_config ;; 3|"") log "Setup cancelled by user" echo "Please update your token permissions at: https://github.com/settings/tokens" return 1 ;; *) log_error "Invalid choice. Please select 1, 2, or 3." return 1 ;; esac else log_success "โœ… Repository access confirmed: $repo_path" fi # Show repository info local repo_name=$(echo "$repo_response" | python3 -c "import sys, json; print(json.load(sys.stdin).get('full_name', 'Unknown'))" 2>/dev/null || echo "$repo_path") local repo_private=$(echo "$repo_response" | python3 -c "import sys, json; print(json.load(sys.stdin).get('private', False))" 2>/dev/null || echo "Unknown") log "๐Ÿ“Š Repository info:" echo " Name: $repo_name" echo " Private: $repo_private" echo " URL: $REPO_URL" } # Clone project from GitHub using PAT authentication deploy_project_files() { log "๐Ÿ”„ Cloning project from GitHub repository..." # Validate GitHub access before attempting clone if ! validate_github_access; then log_error "โŒ GitHub token validation failed during deployment." log_error "Cannot proceed with repository cloning without valid GitHub access." exit 1 fi # First, configure passwordless sudo for required operations configure_passwordless_sudo # Remove any existing directory first ssh "$VM_NAME" "sudo rm -rf /home/thrillwiki/thrillwiki" # Create parent directory ssh "$VM_NAME" "sudo mkdir -p /home/thrillwiki && sudo chown thrillwiki:thrillwiki /home/thrillwiki" # Clone the repository using PAT authentication # Extract repository path from REPO_URL (already validated) local repo_path=$(echo "$REPO_URL" | sed 's|^https://github.com/||' | sed 's|/$||') local auth_url="https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/${repo_path}.git" log "Cloning repository: $REPO_URL" if ssh "$VM_NAME" "cd /home/thrillwiki && git clone '$auth_url' thrillwiki"; then log_success "โœ… Repository cloned successfully from GitHub!" else log_error "โŒ Failed to clone repository from GitHub" log_error "Repository access was validated, but clone failed. This may be due to:" log_error "1. Network connectivity issues from VM to GitHub" log_error "2. Git not installed on VM" log_error "3. Disk space issues on VM" log_error "Try manually: ssh $VM_NAME 'git --version && df -h'" exit 1 fi # Set proper ownership ssh "$VM_NAME" "sudo chown -R thrillwiki:thrillwiki /home/thrillwiki/thrillwiki" # Show repository info local commit_info=$(ssh "$VM_NAME" "cd /home/thrillwiki/thrillwiki && git log -1 --oneline") log "๐Ÿ“Š Cloned repository at commit: $commit_info" # Remove the authentication URL from git config for security ssh "$VM_NAME" "cd /home/thrillwiki/thrillwiki && git remote set-url origin $REPO_URL" log "๐Ÿ”’ Cleaned up authentication URL from git configuration" } # Run setup script on the VM after files are synchronized run_vm_setup_script() { log "โš™๏ธ Running application setup on template VM..." # Create optimized VM setup script for template VMs local vm_setup_script="/tmp/template_vm_thrillwiki_setup.sh" cat > "$vm_setup_script" << 'EOF' #!/bin/bash set -e echo "๐Ÿš€ Setting up ThrillWiki on template VM (optimized for pre-configured templates)..." # Navigate to project directory cd /home/thrillwiki/thrillwiki # Template VMs should already have most packages - just update security echo "๐Ÿ“ฆ Quick system update (template optimization)..." sudo apt update >/dev/null 2>&1 if sudo apt list --upgradable 2>/dev/null | grep -q security; then echo "๐Ÿ”’ Installing security updates..." sudo apt upgrade -y --with-new-pkgs -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" >/dev/null 2>&1 else echo "โœ… No security updates needed" fi # UV should already be installed in template echo "๐Ÿ”ง Checking UV installation..." # Check multiple possible UV locations export PATH="/home/thrillwiki/.local/bin:/home/thrillwiki/.cargo/bin:$PATH" if ! command -v uv > /dev/null 2>&1; then echo "๐Ÿ“ฅ Installing UV (not found in template)..." curl -LsSf https://astral.sh/uv/install.sh | sh # UV installer may put it in .local/bin or .cargo/bin if [ -f ~/.cargo/env ]; then source ~/.cargo/env fi # Add both possible paths export PATH="/home/thrillwiki/.local/bin:/home/thrillwiki/.cargo/bin:$PATH" # Verify installation worked if command -v uv > /dev/null 2>&1; then echo "โœ… UV installed successfully at: $(which uv)" else echo "โŒ UV installation failed or not in PATH" echo "Current PATH: $PATH" echo "Checking possible locations:" ls -la ~/.local/bin/ 2>/dev/null || echo "~/.local/bin/ not found" ls -la ~/.cargo/bin/ 2>/dev/null || echo "~/.cargo/bin/ not found" exit 1 fi else echo "โœ… UV already installed at: $(which uv)" fi # PostgreSQL should already be configured in template echo "๐Ÿ—„๏ธ Checking PostgreSQL..." if ! sudo systemctl is-active --quiet postgresql; then echo "โ–ถ๏ธ Starting PostgreSQL..." sudo systemctl start postgresql sudo systemctl enable postgresql else echo "โœ… PostgreSQL already running" fi # Configure database if not already done echo "๐Ÿ”ง Setting up database..." sudo -u postgres createdb thrillwiki 2>/dev/null || echo "๐Ÿ“‹ Database may already exist" sudo -u postgres createuser thrillwiki_user 2>/dev/null || echo "๐Ÿ‘ค User may already exist" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE thrillwiki TO thrillwiki_user;" 2>/dev/null || echo "๐Ÿ”‘ Privileges may already be set" # Install Python dependencies with UV echo "๐Ÿ“ฆ Installing Python dependencies..." UV_CMD="$(which uv)" if [ -n "$UV_CMD" ] && "$UV_CMD" sync; then echo "โœ… UV sync completed successfully" else echo "โš ๏ธ UV sync failed, falling back to pip..." python3 -m venv .venv source .venv/bin/activate pip install -e . fi # Create necessary directories echo "๐Ÿ“ Creating directories..." mkdir -p logs backups static media # Make scripts executable echo "โšก Making scripts executable..." find scripts -name "*.sh" -exec chmod +x {} \; 2>/dev/null || echo "โ„น๏ธ No shell scripts found" # Run Django setup echo "๐ŸŒ Running Django setup..." UV_CMD="$(which uv)" echo " ๐Ÿ”„ Running migrations..." if [ -n "$UV_CMD" ] && "$UV_CMD" run python manage.py migrate; then echo " โœ… Migrations completed" else echo " โš ๏ธ UV run failed, trying direct Python..." python3 manage.py migrate fi echo " ๐Ÿ“ฆ Collecting static files..." if [ -n "$UV_CMD" ] && "$UV_CMD" run python manage.py collectstatic --noinput; then echo " โœ… Static files collected" else echo " โš ๏ธ UV run failed, trying direct Python..." python3 manage.py collectstatic --noinput fi # Install systemd services if available if [ -f scripts/systemd/thrillwiki.service ]; then echo "๐Ÿ”ง Installing systemd service..." sudo cp scripts/systemd/thrillwiki.service /etc/systemd/system/ # Fix the home directory path for thrillwiki user sudo sed -i 's|/home/ubuntu|/home/thrillwiki|g' /etc/systemd/system/thrillwiki.service sudo systemctl daemon-reload sudo systemctl enable thrillwiki.service if sudo systemctl start thrillwiki.service; then echo "โœ… ThrillWiki service started successfully" else echo "โš ๏ธ Service start failed, checking logs..." sudo systemctl status thrillwiki.service --no-pager -l fi else echo "โ„น๏ธ No systemd service files found, ThrillWiki ready for manual start" echo "๐Ÿ’ก You can start it manually with: uv run python manage.py runserver 0.0.0.0:8000" fi # Test the application echo "๐Ÿงช Testing application..." sleep 3 if curl -f http://localhost:8000 >/dev/null 2>&1; then echo "โœ… ThrillWiki is responding on port 8000!" else echo "โš ๏ธ ThrillWiki may not be responding yet (this is normal for first start)" fi # Setup auto-pull functionality echo "๐Ÿ”„ Setting up auto-pull functionality..." # Create ***REMOVED*** file with GitHub token for auto-pull authentication if [ -n "${GITHUB_TOKEN:-}" ]; then echo "GITHUB_TOKEN=$GITHUB_TOKEN" > ***REMOVED*** echo "โœ… GitHub token configured for auto-pull" else echo "โš ๏ธ GITHUB_TOKEN not found - auto-pull will use fallback mode" echo "# GitHub token not available during setup" > ***REMOVED*** fi # Ensure scripts/vm directory exists and make auto-pull script executable if [ -f "scripts/vm/auto-pull.sh" ]; then chmod +x scripts/vm/auto-pull.sh # Create cron job for auto-pull (every 10 minutes) echo "โฐ Installing cron job for auto-pull (every 10 minutes)..." # Create cron entry CRON_ENTRY="*/10 * * * * [AWS-SECRET-REMOVED]uto-pull.sh >> /home/thrillwiki/logs/cron.log 2>&1" # Install cron job if not already present if ! crontab -l 2>/dev/null | grep -q "auto-pull.sh"; then # Add to existing crontab or create new one (crontab -l 2>/dev/null || echo "") | { cat echo "# ThrillWiki Auto-Pull - Update repository every 10 minutes" echo "$CRON_ENTRY" } | crontab - echo "โœ… Auto-pull cron job installed successfully" echo "๐Ÿ“‹ Cron job: $CRON_ENTRY" else echo "โœ… Auto-pull cron job already exists" fi # Ensure cron service is running if ! systemctl is-active --quiet cron 2>/dev/null; then echo "โ–ถ๏ธ Starting cron service..." sudo systemctl start cron sudo systemctl enable cron else echo "โœ… Cron service is already running" fi # Test auto-pull script echo "๐Ÿงช Testing auto-pull script..." if timeout 30 ./scripts/vm/auto-pull.sh --status; then echo "โœ… Auto-pull script test successful" else echo "โš ๏ธ Auto-pull script test failed or timed out (this may be normal)" fi echo "๐Ÿ“‹ Auto-pull setup completed:" echo " - Script: [AWS-SECRET-REMOVED]uto-pull.sh" echo " - Schedule: Every 10 minutes" echo " - Logs: /home/thrillwiki/logs/auto-pull.log" echo " - Status: Run './scripts/vm/auto-pull.sh --status' to check" else echo "โš ๏ธ Auto-pull script not found, skipping auto-pull setup" fi echo "๐ŸŽ‰ Template VM ThrillWiki setup completed successfully! โšก" echo "๐ŸŒ Application should be available at http://$(hostname -I | awk '{print $1}'):8000" echo "๐Ÿ”„ Auto-pull: Repository will be updated every 10 minutes automatically" EOF # Copy setup script to VM with progress log "๐Ÿ“‹ Copying setup script to VM..." scp "$vm_setup_script" "$VM_NAME:/tmp/" # Make it executable and run it ssh "$VM_NAME" "chmod +x /tmp/template_vm_thrillwiki_setup.sh" log "โšก Executing setup script on VM (this may take a few minutes)..." if ssh "$VM_NAME" "bash /tmp/template_vm_thrillwiki_setup.sh"; then log_success "โœ… Application setup completed successfully!" else log_error "โŒ Application setup failed" log "Try debugging with: ssh $VM_NAME 'journalctl -u thrillwiki -f'" exit 1 fi # Cleanup rm -f "$vm_setup_script" } # Start services start_template_services() { log "Starting ThrillWiki services on template VM..." # Start VM service ssh "$VM_NAME" "sudo systemctl start thrillwiki 2>/dev/null || echo 'Service may need manual start'" # Verify service is running if ssh "$VM_NAME" "systemctl is-active --quiet thrillwiki 2>/dev/null"; then log_success "ThrillWiki service started successfully on template VM โšก" else log_warning "ThrillWiki service may need manual configuration" log "Try: ssh $VM_NAME 'systemctl status thrillwiki'" fi # Get service status log "Template VM service status:" ssh "$VM_NAME" "systemctl status thrillwiki --no-pager -l 2>/dev/null || echo 'Service status not available'" } # Setup webhook listener setup_template_webhook_listener() { log "Setting up webhook listener for template deployments..." # Create webhook start script cat > "$PROJECT_DIR/start-template-webhook.sh" << 'EOF' #!/bin/bash cd "$(dirname "$0")" source ***REMOVED***.webhook echo "Starting webhook listener for template-based deployments โšก" python3 scripts/webhook-listener.py EOF chmod +x "$PROJECT_DIR/start-template-webhook.sh" log_success "Template webhook listener configured" log "You can start the webhook listener with: ./start-template-webhook.sh" } # Perform end-to-end test test_template_deployment() { log "Performing end-to-end template deployment test..." # Test VM connectivity if ssh "$VM_NAME" "echo 'Template VM connectivity test passed'"; then log_success "Template VM connectivity test passed โšก" else log_error "Template VM connectivity test failed" return 1 fi # Test ThrillWiki service if ssh "$VM_NAME" "curl -f http://localhost:8000 >/dev/null 2>&1"; then log_success "ThrillWiki service test passed on template VM โšก" else log_warning "ThrillWiki service test failed - checking logs..." ssh "$VM_NAME" "journalctl -u thrillwiki --no-pager -l | tail -20 2>/dev/null || echo 'Service logs not available'" fi # Test template deployment script log "Testing template deployment capabilities..." cd "$PROJECT_DIR/scripts/unraid" ./template-utils.sh check && log_success "Template utilities working โšก" log_success "End-to-end template deployment test completed โšก" } # Generate final instructions for template deployment generate_template_instructions() { log "Generating final template deployment instructions..." cat > "$PROJECT_DIR/TEMPLATE_SETUP_COMPLETE.md" << EOF # ThrillWiki Template-Based Automation - Setup Complete! ๐Ÿš€โšก Your ThrillWiki template-based CI/CD system has been fully automated and deployed! ## Template Deployment Benefits โšก - **Speed**: 2-5 minute VM deployment vs 20-30 minutes with autoinstall - **Reliability**: Pre-configured template eliminates installation failures - **Efficiency**: Copy-on-write disk format saves space ## VM Information - **VM Name**: $VM_NAME - **Template VM**: $TEMPLATE_VM_NAME - **VM IP**: $VM_IP - **SSH Access**: \`ssh $VM_NAME\` - **Deployment Type**: Template-based โšก ## Services Status - **ThrillWiki Service**: Running on template VM - **Database**: PostgreSQL configured in template - **Web Server**: Available at http://$VM_IP:8000 ## Next Steps ### 1. Start Template Webhook Listener \`\`\`bash ./start-template-webhook.sh \`\`\` ### 2. Configure GitHub Webhook - Go to your repository: $REPO_URL - Settings โ†’ Webhooks โ†’ Add webhook - **Payload URL**: http://YOUR_PUBLIC_IP:$WEBHOOK_PORT/webhook - **Content type**: application/json - **Secret**: (your webhook secret) - **Events**: Just the push event ### 3. Test the Template System \`\`\`bash # Test template VM connection ssh $VM_NAME # Test service status ssh $VM_NAME "systemctl status thrillwiki" # Test template utilities cd scripts/unraid ./template-utils.sh check ./template-utils.sh info # Deploy another VM from template (fast!) ./template-utils.sh deploy test-vm-2 # Make a test commit to trigger automatic deployment git add . git commit -m "Test automated template deployment" git push origin main \`\`\` ## Template Management Commands ### Template VM Management \`\`\`bash # Check template status and info ./scripts/unraid/template-utils.sh status ./scripts/unraid/template-utils.sh info # List all template-based VMs ./scripts/unraid/template-utils.sh list # Deploy new VM from template (2-5 minutes!) ./scripts/unraid/template-utils.sh deploy VM_NAME # Copy template to new VM ./scripts/unraid/template-utils.sh copy VM_NAME \`\`\` ### Python Template Scripts \`\`\`bash # Template-based deployment python3 scripts/unraid/main_template.py deploy # Template management python3 scripts/unraid/main_template.py template info python3 scripts/unraid/main_template.py template check python3 scripts/unraid/main_template.py template list # VM operations (fast with templates!) python3 scripts/unraid/main_template.py setup python3 scripts/unraid/main_template.py start python3 scripts/unraid/main_template.py ip python3 scripts/unraid/main_template.py status \`\`\` ### Service Management on Template VM \`\`\`bash # Check service status ssh $VM_NAME "systemctl status thrillwiki" # Restart service ssh $VM_NAME "sudo systemctl restart thrillwiki" # View logs ssh $VM_NAME "journalctl -u thrillwiki -f" \`\`\` ## Template Maintenance ### Updating Your Template VM \`\`\`bash # Get update instructions ./scripts/unraid/template-utils.sh update # After updating template VM manually: ./scripts/unraid/template-utils.sh check \`\`\` ### Creating Additional Template VMs You can create multiple template VMs for different purposes: - Development: \`thrillwiki-template-dev\` - Staging: \`thrillwiki-template-staging\` - Production: \`thrillwiki-template-prod\` ## Troubleshooting ### Template VM Issues 1. **Template not found**: Verify template VM exists and is stopped 2. **Template VM running**: Stop template before creating instances 3. **Deployment slow**: Template should be 5-10x faster than autoinstall ### Common Commands \`\`\`bash # Check if template is ready ./scripts/unraid/template-utils.sh check # Test template VM connectivity ssh root@unraid-server "virsh domstate $TEMPLATE_VM_NAME" # Force stop template VM if needed ssh root@unraid-server "virsh shutdown $TEMPLATE_VM_NAME" \`\`\` ### Support Files - Template Configuration: \`.thrillwiki-template-config\` - Environment: \`***REMOVED***.unraid\`, \`***REMOVED***.webhook\` - Logs: \`logs/\` directory - Documentation: \`scripts/unraid/README-template-deployment.md\` ## Performance Comparison | Operation | Autoinstall | Template | Improvement | |-----------|------------|----------|-------------| | VM Creation | 20-30 min | 2-5 min | **5-6x faster** | | Boot Time | Full install | Instant | **Instant** | | Reliability | ISO issues | Pre-tested | **Much higher** | | Total Deploy | 45+ min | ~10 min | **4-5x faster** | **Your template-based automated CI/CD system is now ready!** ๐Ÿš€โšก Every push to the main branch will automatically deploy to your template VM in minutes, not hours! EOF log_success "Template setup instructions saved to TEMPLATE_SETUP_COMPLETE.md" } # Main automation function main() { log "๐Ÿš€โšก Starting ThrillWiki Template-Based Complete Unraid Automation" echo "[AWS-SECRET-REMOVED]==========================" echo log_template "Template deployment is 5-10x FASTER than autoinstall approach!" echo # Create logs directory mkdir -p "$LOG_DIR" # Handle reset modes if [[ "$RESET_ALL" == "true" ]]; then log "๐Ÿ”„ Complete reset mode - deleting VM and configuration" echo # Load configuration first to get connection details for VM deletion if [[ -f "$CONFIG_FILE" ]]; then source "$CONFIG_FILE" log_success "Loaded existing configuration for VM deletion" else log_warning "No configuration file found, will skip VM deletion" fi # Delete existing VM if config exists if [[ -f "$CONFIG_FILE" ]]; then log "๐Ÿ—‘๏ธ Deleting existing template VM..." # Check if ***REMOVED***.unraid file exists if [ -f "$PROJECT_DIR/***REMOVED***.unraid" ]; then log "Loading environment from ***REMOVED***.unraid..." set -a source "$PROJECT_DIR/***REMOVED***.unraid" 2>/dev/null || true set +a else log_warning "***REMOVED***.unraid file not found - VM deletion may not work properly" log "The VM may not exist or may have been deleted manually" fi # Stop existing VM if running before deletion (for complete reset) log "๐Ÿ›‘ Ensuring VM is stopped before deletion..." if [ -n "${VM_NAME:-}" ] && [ -n "${UNRAID_HOST:-}" ] && [ -n "${UNRAID_USER:-}" ]; then if ! stop_existing_vm_for_reset "$VM_NAME" "$UNRAID_HOST" "$UNRAID_USER"; then log_warning "Failed to stop VM '$VM_NAME' - continuing anyway for complete reset" log_warning "VM may be forcibly deleted during reset process" fi else log_warning "Missing VM connection details - skipping VM shutdown check" fi # Debug environment loading log "Debug: VM_NAME=${VM_NAME:-'not set'}" log "Debug: UNRAID_HOST=${UNRAID_HOST:-'not set'}" # Check if main_template.py exists if [ ! -f "$SCRIPT_DIR/main_template.py" ]; then log_error "main_template.py not found at: $SCRIPT_DIR/main_template.py" log "Available files in $SCRIPT_DIR:" ls -la "$SCRIPT_DIR" log "Skipping VM deletion due to missing script..." elif [ -z "${VM_NAME:-}" ] || [ -z "${UNRAID_HOST:-}" ]; then log_warning "Missing required environment variables for VM deletion" log "VM_NAME: ${VM_NAME:-'not set'}" log "UNRAID_HOST: ${UNRAID_HOST:-'not set'}" log "Skipping VM deletion - VM may not exist or was deleted manually" else log "Found main_template.py at: $SCRIPT_DIR/main_template.py" # Run delete with timeout and better error handling log "Attempting VM deletion with timeout..." if timeout 60 python3 "$SCRIPT_DIR/main_template.py" delete 2>&1; then log_success "Template VM deleted successfully" else deletion_exit_code=$? if [ $deletion_exit_code -eq 124 ]; then log_error "โš ๏ธ VM deletion timed out after 60 seconds" else log "โš ๏ธ Template VM deletion failed (exit code: $deletion_exit_code) or VM didn't exist" fi # Continue anyway since this might be expected log "Continuing with script execution..." fi fi fi # Remove configuration files if [[ -f "$CONFIG_FILE" ]]; then rm "$CONFIG_FILE" log_success "Template configuration file removed" fi # Remove GitHub token file if [[ -f "$TOKEN_FILE" ]]; then rm "$TOKEN_FILE" log_success "GitHub token file removed" fi # Remove environment files rm -f "$PROJECT_DIR/***REMOVED***.unraid" "$PROJECT_DIR/***REMOVED***.webhook" log_success "Environment files removed" log_success "Complete reset finished - continuing with fresh template setup" echo elif [[ "$RESET_VM_ONLY" == "true" ]]; then log "๐Ÿ”„ VM-only reset mode - deleting VM, preserving configuration" echo # Load configuration to get connection details if [[ -f "$CONFIG_FILE" ]]; then source "$CONFIG_FILE" log_success "Loaded existing configuration" else log_error "No configuration file found. Cannot reset VM without connection details." echo " Run the script without reset flags first to create initial configuration." exit 1 fi # Stop existing VM if running before deletion log "๐Ÿ›‘ Ensuring VM is stopped before deletion..." if ! stop_existing_vm_for_reset "$VM_NAME" "$UNRAID_HOST" "$UNRAID_USER"; then log_error "Failed to stop VM '$VM_NAME'. Cannot proceed safely with VM deletion." log_error "Please manually stop the VM or resolve the connection issue." exit 1 fi # Delete existing VM log "๐Ÿ—‘๏ธ Deleting existing template VM..." # Check if ***REMOVED***.unraid file exists if [ -f "$PROJECT_DIR/***REMOVED***.unraid" ]; then log "Loading environment from ***REMOVED***.unraid..." set -a source "$PROJECT_DIR/***REMOVED***.unraid" 2>/dev/null || true set +a else log_warning "***REMOVED***.unraid file not found - VM deletion may not work properly" log "The VM may not exist or may have been deleted manually" fi # Debug environment loading log "Debug: VM_NAME=${VM_NAME:-'not set'}" log "Debug: UNRAID_HOST=${UNRAID_HOST:-'not set'}" # Check if main_template.py exists if [ ! -f "$SCRIPT_DIR/main_template.py" ]; then log_error "main_template.py not found at: $SCRIPT_DIR/main_template.py" log "Available files in $SCRIPT_DIR:" ls -la "$SCRIPT_DIR" log "Skipping VM deletion due to missing script..." elif [ -z "${VM_NAME:-}" ] || [ -z "${UNRAID_HOST:-}" ]; then log_warning "Missing required environment variables for VM deletion" log "VM_NAME: ${VM_NAME:-'not set'}" log "UNRAID_HOST: ${UNRAID_HOST:-'not set'}" log "Skipping VM deletion - VM may not exist or was deleted manually" else log "Found main_template.py at: $SCRIPT_DIR/main_template.py" # Run delete with timeout and better error handling log "Attempting VM deletion with timeout..." if timeout 60 python3 "$SCRIPT_DIR/main_template.py" delete 2>&1; then log_success "Template VM deleted successfully" else deletion_exit_code=$? if [ $deletion_exit_code -eq 124 ]; then log_error "โš ๏ธ VM deletion timed out after 60 seconds" else log "โš ๏ธ Template VM deletion failed (exit code: $deletion_exit_code) or VM didn't exist" fi # Continue anyway since this might be expected log "Continuing with script execution..." fi fi # Remove only environment files, keep main config rm -f "$PROJECT_DIR/***REMOVED***.unraid" "$PROJECT_DIR/***REMOVED***.webhook" log_success "Environment files removed, configuration preserved" # Check if GitHub token is available for VM recreation if [ "$GITHUB_API_ENABLED" = "true" ] && [ -n "$GITHUB_USERNAME" ]; then log "๐Ÿ” Checking for GitHub token availability..." # Try to load token from saved file if load_github_token; then log_success "โœ… GitHub token loaded from secure storage" elif GITHUB_TOKEN=$(python3 "$SCRIPT_DIR/../github-auth.py" token 2>/dev/null) && [ -n "$GITHUB_TOKEN" ]; then log_success "โœ… GitHub token obtained from authentication script" # Validate the token can access the repository immediately log "๐Ÿ” Validating token can access repository..." if ! validate_github_access; then log_error "โŒ GitHub token validation failed during VM reset." log_error "Please check your token and repository access before recreating the VM." return 1 fi # Save the token for future use save_github_token else log_warning "โš ๏ธ No GitHub token found - you'll need to provide it" echo "GitHub authentication is required for repository cloning and auto-pull." echo if [ "$NON_INTERACTIVE" = "true" ]; then if [ -n "${GITHUB_TOKEN:-}" ]; then log "Using token from environment variable" save_github_token else log_error "GITHUB_TOKEN environment variable not set for non-interactive mode" log_error "Set: export GITHUB_TOKEN='your_token'" exit 1 fi else read -s -p "Enter GitHub Personal Access Token: " GITHUB_TOKEN echo if [ -n "$GITHUB_TOKEN" ]; then save_github_token log_success "โœ… GitHub token saved for VM recreation" else log_error "GitHub token is required for repository operations" exit 1 fi fi fi fi log_success "VM reset complete - will recreate VM with saved configuration" echo elif [[ "$RESET_CONFIG_ONLY" == "true" ]]; then log "๐Ÿ”„ Config-only reset mode - deleting configuration, preserving VM" echo # Remove configuration files if [[ -f "$CONFIG_FILE" ]]; then rm "$CONFIG_FILE" log_success "Template configuration file removed" fi # Remove environment files rm -f "$PROJECT_DIR/***REMOVED***.unraid" "$PROJECT_DIR/***REMOVED***.webhook" log_success "Environment files removed" log_success "Configuration reset complete - will prompt for fresh configuration" echo fi # Collect configuration prompt_template_config # Setup steps setup_ssh_keys setup_unraid_access create_environment_files install_dependencies create_template_vm wait_for_template_vm configure_template_vm start_template_services setup_template_webhook_listener test_template_deployment generate_template_instructions echo log_success "๐ŸŽ‰โšก Template-based complete automation setup finished!" echo log "Your ThrillWiki template VM is running at: http://$VM_IP:8000" log "Start the webhook listener: ./start-template-webhook.sh" log "See TEMPLATE_SETUP_COMPLETE.md for detailed instructions" echo log_template "๐Ÿš€ Template deployment is 5-10x FASTER than traditional autoinstall!" log "The system will now automatically deploy in MINUTES when you push to GitHub!" } # Run main function and log output main "$@" 2>&1 | tee "$LOG_DIR/template-automation.log"