Files
n8n-install/scripts/04_wizard.sh
Yury Kossakovsky 2ac966908d Update PostgreSQL image syntax and add TODO for volume renaming
- Modified the PostgreSQL image definition in docker-compose.yml to use a more robust syntax for the version variable.
- Added a TODO comment in docker-compose.yml to rename the volume for clarity in future updates.
- Simplified the service selection wizard in 04_wizard.sh by removing unnecessary dynamic sizing calculations.
2025-11-05 10:18:35 -07:00

276 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Script to guide user through service selection
# Source utility functions, if any, assuming it's in the same directory
# and .env is in the parent directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ENV_FILE="$PROJECT_ROOT/.env"
# Source the utilities file
source "$(dirname "$0")/utils.sh"
# UTILS_SCRIPT="$SCRIPT_DIR/utils.sh" # Uncomment if utils.sh contains relevant functions
# if [ -f "$UTILS_SCRIPT" ]; then
# source "$UTILS_SCRIPT"
# fi
# Function to check if whiptail is installed
check_whiptail() {
if ! command -v whiptail &> /dev/null; then
log_error "'whiptail' is not installed."
log_info "This tool is required for the interactive service selection."
log_info "On Debian/Ubuntu, you can install it using: sudo apt-get install whiptail"
log_info "Please install whiptail and try again."
exit 1
fi
}
# Call the check
check_whiptail
# Store original DEBIAN_FRONTEND and set to dialog for whiptail
ORIGINAL_DEBIAN_FRONTEND="$DEBIAN_FRONTEND"
export DEBIAN_FRONTEND=dialog
# --- Read current COMPOSE_PROFILES from .env ---
CURRENT_PROFILES_VALUE=""
if [ -f "$ENV_FILE" ]; then
LINE_CONTENT=$(grep "^COMPOSE_PROFILES=" "$ENV_FILE" || echo "")
if [ -n "$LINE_CONTENT" ]; then
# Get value after '=', remove potential surrounding quotes
CURRENT_PROFILES_VALUE=$(echo "$LINE_CONTENT" | cut -d'=' -f2- | sed 's/^"//' | sed 's/"$//')
fi
fi
# Prepare comma-separated current profiles for easy matching, adding leading/trailing commas
current_profiles_for_matching=",$CURRENT_PROFILES_VALUE,"
# --- Define available services and their descriptions ---
# Base service definitions (tag, description)
base_services_data=(
"cloudflare-tunnel" "Cloudflare Tunnel (Zero-Trust Secure Access)"
"comfyui" "ComfyUI (Node-based Stable Diffusion UI)"
"crawl4ai" "Crawl4ai (Web Crawler for AI)"
"dify" "Dify (AI Application Development Platform with LLMOps)"
"flowise" "Flowise (AI Agent Builder)"
"gotenberg" "Gotenberg (Document Conversion API)"
"langfuse" "Langfuse Suite (AI Observability - includes Clickhouse, Minio)"
"letta" "Letta (Agent Server & SDK)"
"lightrag" "LightRAG (Graph-based RAG with knowledge graphs)"
"libretranslate" "LibreTranslate (Self-hosted translation API - 50+ languages)"
"monitoring" "Monitoring Suite (Prometheus, Grafana, cAdvisor, Node-Exporter)"
"n8n" "n8n, n8n-worker, n8n-import (Workflow Automation)"
"neo4j" "Neo4j (Graph Database)"
"ollama" "Ollama (Local LLM Runner - select hardware in next step)"
"open-webui" "Open WebUI (ChatGPT-like Interface)"
"paddleocr" "PaddleOCR (OCR API Server)"
"portainer" "Portainer (Docker management UI)"
"postgresus" "Postgresus (PostgreSQL backups & monitoring)"
"postiz" "Postiz (Social publishing platform)"
"python-runner" "Python Runner (Run your custom Python code from ./python-runner)"
"qdrant" "Qdrant (Vector Database)"
"ragapp" "RAGApp (Open-source RAG UI + API)"
"ragflow" "RAGFlow (Deep document understanding RAG engine)"
"searxng" "SearXNG (Private Metasearch Engine)"
"supabase" "Supabase (Backend as a Service)"
"waha" "WAHA WhatsApp HTTP API (NOWEB engine)"
"weaviate" "Weaviate (Vector Database with API Key Auth)"
)
services=() # This will be the final array for whiptail
# Populate the services array for whiptail based on current profiles or defaults
idx=0
while [ $idx -lt ${#base_services_data[@]} ]; do
tag="${base_services_data[idx]}"
description="${base_services_data[idx+1]}"
status="OFF" # Default to OFF
if [ -n "$CURRENT_PROFILES_VALUE" ] && [ "$CURRENT_PROFILES_VALUE" != '""' ]; then # Check if .env has profiles
if [[ "$tag" == "ollama" ]]; then
if [[ "$current_profiles_for_matching" == *",cpu,"* || \
"$current_profiles_for_matching" == *",gpu-nvidia,"* || \
"$current_profiles_for_matching" == *",gpu-amd,"* ]]; then
status="ON"
fi
elif [[ "$current_profiles_for_matching" == *",$tag,"* ]]; then
status="ON"
fi
else
# .env has no COMPOSE_PROFILES or it's empty/just quotes, use hardcoded defaults
case "$tag" in
"n8n"|"portainer"|"monitoring"|"postgresus") status="ON" ;;
*) status="OFF" ;;
esac
fi
services+=("$tag" "$description" "$status")
idx=$((idx + 2))
done
# Use whiptail to display the checklist
num_services=$(( ${#services[@]} / 3 ))
CHOICES=$(whiptail --title "Service Selection Wizard" --checklist \
"Choose the services you want to deploy.\nUse ARROW KEYS to navigate, SPACEBAR to select/deselect, ENTER to confirm." 32 90 $num_services \
"${services[@]}" \
3>&1 1>&2 2>&3)
# Restore original DEBIAN_FRONTEND
if [ -n "$ORIGINAL_DEBIAN_FRONTEND" ]; then
export DEBIAN_FRONTEND="$ORIGINAL_DEBIAN_FRONTEND"
else
unset DEBIAN_FRONTEND
fi
# Exit if user pressed Cancel or Esc
exitstatus=$?
if [ $exitstatus -ne 0 ]; then
log_info "Service selection cancelled by user. Exiting wizard."
log_info "No changes made to service profiles. Default services will be used."
# Set COMPOSE_PROFILES to empty to ensure only core services run
if [ ! -f "$ENV_FILE" ]; then
touch "$ENV_FILE"
fi
if grep -q "^COMPOSE_PROFILES=" "$ENV_FILE"; then
sed -i.bak "/^COMPOSE_PROFILES=/d" "$ENV_FILE"
fi
echo "COMPOSE_PROFILES=" >> "$ENV_FILE"
exit 0
fi
# Process selected services
selected_profiles=()
ollama_selected=0
ollama_profile=""
if [ -n "$CHOICES" ]; then
# Whiptail returns a string like "tag1" "tag2" "tag3"
# We need to remove quotes and convert to an array
temp_choices=()
eval "temp_choices=($CHOICES)"
for choice in "${temp_choices[@]}"; do
if [ "$choice" == "ollama" ]; then
ollama_selected=1
else
selected_profiles+=("$choice")
fi
done
fi
# Enforce mutual exclusivity between Dify and Supabase (compact)
if printf '%s\n' "${selected_profiles[@]}" | grep -qx "dify" && \
printf '%s\n' "${selected_profiles[@]}" | grep -qx "supabase"; then
CHOSEN_EXCLUSIVE=$(whiptail --title "Conflict: Dify and Supabase" --default-item "supabase" --radiolist \
"Dify and Supabase are mutually exclusive. Choose which one to keep." 15 78 2 \
"dify" "Keep Dify (AI App Platform)" OFF \
"supabase" "Keep Supabase (Backend as a Service)" ON \
3>&1 1>&2 2>&3)
[ -z "$CHOSEN_EXCLUSIVE" ] && CHOSEN_EXCLUSIVE="supabase"
to_remove=$([ "$CHOSEN_EXCLUSIVE" = "dify" ] && echo "supabase" || echo "dify")
tmp=()
for p in "${selected_profiles[@]}"; do
[ "$p" = "$to_remove" ] || tmp+=("$p")
done
selected_profiles=("${tmp[@]}")
log_info "Mutual exclusivity enforced: kept '$CHOSEN_EXCLUSIVE', removed '$to_remove'."
fi
# If Ollama was selected, prompt for the hardware profile
if [ $ollama_selected -eq 1 ]; then
# Determine default selected Ollama hardware profile from .env
default_ollama_hardware="cpu" # Fallback default
ollama_hw_on_cpu="OFF"
ollama_hw_on_gpu_nvidia="OFF"
ollama_hw_on_gpu_amd="OFF"
# Check current_profiles_for_matching which includes commas, e.g., ",cpu,"
if [[ "$current_profiles_for_matching" == *",cpu,"* ]]; then
ollama_hw_on_cpu="ON"
default_ollama_hardware="cpu"
elif [[ "$current_profiles_for_matching" == *",gpu-nvidia,"* ]]; then
ollama_hw_on_gpu_nvidia="ON"
default_ollama_hardware="gpu-nvidia"
elif [[ "$current_profiles_for_matching" == *",gpu-amd,"* ]]; then
ollama_hw_on_gpu_amd="ON"
default_ollama_hardware="gpu-amd"
else
# If ollama was selected in the main list, but no specific hardware profile was previously set,
# default to CPU ON for the radiolist.
ollama_hw_on_cpu="ON"
default_ollama_hardware="cpu"
fi
ollama_hardware_options=(
"cpu" "CPU (Recommended for most users)" "$ollama_hw_on_cpu"
"gpu-nvidia" "NVIDIA GPU (Requires NVIDIA drivers & CUDA)" "$ollama_hw_on_gpu_nvidia"
"gpu-amd" "AMD GPU (Requires ROCm drivers)" "$ollama_hw_on_gpu_amd"
)
CHOSEN_OLLAMA_PROFILE=$(whiptail --title "Ollama Hardware Profile" --default-item "$default_ollama_hardware" --radiolist \
"Choose the hardware profile for Ollama. This will be added to your Docker Compose profiles." 15 78 3 \
"${ollama_hardware_options[@]}" \
3>&1 1>&2 2>&3)
ollama_exitstatus=$?
if [ $ollama_exitstatus -eq 0 ] && [ -n "$CHOSEN_OLLAMA_PROFILE" ]; then
selected_profiles+=("$CHOSEN_OLLAMA_PROFILE")
ollama_profile="$CHOSEN_OLLAMA_PROFILE" # Store for user message
log_info "Ollama hardware profile selected: $CHOSEN_OLLAMA_PROFILE"
else
log_info "Ollama hardware profile selection cancelled or no choice made. Ollama will not be configured with a specific hardware profile."
# ollama_selected remains 1, but no specific profile is added.
# This means "ollama" won't be in COMPOSE_PROFILES unless a hardware profile is chosen.
ollama_selected=0 # Mark as not fully selected if profile choice is cancelled
fi
fi
if [ ${#selected_profiles[@]} -eq 0 ]; then
log_info "No optional services selected."
COMPOSE_PROFILES_VALUE=""
else
log_info "You have selected the following service profiles to be deployed:"
# Join the array into a comma-separated string
COMPOSE_PROFILES_VALUE=$(IFS=,; echo "${selected_profiles[*]}")
for profile in "${selected_profiles[@]}"; do
# Check if the current profile is an Ollama hardware profile that was chosen
if [[ "$profile" == "cpu" || "$profile" == "gpu-nvidia" || "$profile" == "gpu-amd" ]]; then
if [ "$profile" == "$ollama_profile" ]; then # ollama_profile stores the CHOSEN_OLLAMA_PROFILE from this wizard run
echo " - Ollama ($profile profile)"
else # This handles a (highly unlikely) non-Ollama service named "cpu", "gpu-nvidia", or "gpu-amd"
echo " - $profile"
fi
else
echo " - $profile"
fi
done
fi
# Update or add COMPOSE_PROFILES in .env file
# Ensure .env file exists (it should have been created by 03_generate_secrets.sh or exist from previous run)
if [ ! -f "$ENV_FILE" ]; then
log_warning "'.env' file not found at $ENV_FILE. Creating it."
touch "$ENV_FILE"
fi
# Remove existing COMPOSE_PROFILES line if it exists
if grep -q "^COMPOSE_PROFILES=" "$ENV_FILE"; then
# Using a different delimiter for sed because a profile name might contain '/' (unlikely here)
sed -i.bak "\|^COMPOSE_PROFILES=|d" "$ENV_FILE"
fi
# Add the new COMPOSE_PROFILES line
echo "COMPOSE_PROFILES=${COMPOSE_PROFILES_VALUE}" >> "$ENV_FILE"
if [ -z "$COMPOSE_PROFILES_VALUE" ]; then
log_info "Only core services (Caddy, Postgres, Redis) will be started."
else
log_info "The following Docker Compose profiles will be active: ${COMPOSE_PROFILES_VALUE}"
fi
# Make the script executable (though install.sh calls it with bash)
chmod +x "$SCRIPT_DIR/04_wizard.sh"
exit 0