mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:31:07 -05:00
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
2263 lines
86 KiB
Bash
Executable File
2263 lines
86 KiB
Bash
Executable File
#!/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"
|