diff --git a/scripts/08_fix_permissions.sh b/scripts/08_fix_permissions.sh new file mode 100755 index 0000000..7fc454f --- /dev/null +++ b/scripts/08_fix_permissions.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# ============================================================================= +# 08_fix_permissions.sh - Fix file ownership after installation +# ============================================================================= +# This script fixes file ownership when the installer was run with sudo. +# It detects the real user who invoked the installation and sets proper +# ownership for all project files. +# +# Usage: bash scripts/08_fix_permissions.sh +# ============================================================================= + +set -e + +# Source the utilities file +source "$(dirname "$0")/utils.sh" + +# Initialize paths +init_paths + +log_info "Fixing file permissions..." + +# Get the real user who ran the installer +REAL_USER=$(get_real_user) +REAL_GROUP=$(id -gn "$REAL_USER" 2>/dev/null || echo "$REAL_USER") + +log_info "Detected user: $REAL_USER (group: $REAL_GROUP)" + +# Skip if running as root without sudo (e.g., in Docker) +if [[ "$REAL_USER" == "root" ]]; then + log_info "Running as root user, no permission changes needed." + exit 0 +fi + +# Fix ownership of the entire project directory +if [[ -d "$PROJECT_ROOT" ]]; then + log_info "Setting ownership of $PROJECT_ROOT to $REAL_USER:$REAL_GROUP" + chown -R "$REAL_USER:$REAL_GROUP" "$PROJECT_ROOT" + + # Ensure .env has restricted permissions (readable only by owner) + if [[ -f "$ENV_FILE" ]]; then + chmod 600 "$ENV_FILE" + log_info "Set restrictive permissions on .env file" + fi + + # Ensure scripts are executable + chmod +x "$SCRIPT_DIR"/*.sh 2>/dev/null || true + chmod +x "$PROJECT_ROOT"/*.py 2>/dev/null || true + + log_success "File permissions fixed successfully!" +else + log_error "Project root not found: $PROJECT_ROOT" + exit 1 +fi diff --git a/scripts/apply_update.sh b/scripts/apply_update.sh index 1f5c6f8..213ab75 100755 --- a/scripts/apply_update.sh +++ b/scripts/apply_update.sh @@ -58,6 +58,9 @@ bash "$SCRIPT_DIR/05_configure_services.sh" || { } log_success "Service configuration completed." +# Clean up legacy n8n worker containers from old naming convention +cleanup_legacy_n8n_workers + # Pull latest versions of selected containers based on updated .env log_info "Pulling latest versions of selected containers..." COMPOSE_FILES_FOR_PULL=("-f" "$PROJECT_ROOT/docker-compose.yml") diff --git a/scripts/install.sh b/scripts/install.sh index 7c0e8e6..8e78a7c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -3,7 +3,7 @@ # install.sh - Main installation orchestrator for n8n-install # ============================================================================= # This script runs the complete installation process by sequentially executing -# 7 installation steps: +# 8 installation steps: # 1. System Preparation - updates packages, installs utilities, configures firewall # 2. Docker Installation - installs Docker and Docker Compose # 3. Secret Generation - creates .env file with secure passwords and secrets @@ -11,6 +11,7 @@ # 5. Service Configuration - prompts for API keys and service-specific settings # 6. Service Launch - starts all selected services via Docker Compose # 7. Final Report - displays credentials and access URLs +# 8. Fix Permissions - ensures correct file ownership for the invoking user # # Usage: sudo bash scripts/install.sh # ============================================================================= @@ -55,6 +56,7 @@ required_scripts=( "05_configure_services.sh" "06_run_services.sh" "07_final_report.sh" + "08_fix_permissions.sh" ) missing_scripts=() @@ -97,31 +99,31 @@ fi # Run installation steps sequentially using their full paths -show_step 1 7 "System Preparation" +show_step 1 8 "System Preparation" bash "$SCRIPT_DIR/01_system_preparation.sh" || { log_error "System Preparation failed"; exit 1; } log_success "System preparation complete!" -show_step 2 7 "Installing Docker" +show_step 2 8 "Installing Docker" bash "$SCRIPT_DIR/02_install_docker.sh" || { log_error "Docker Installation failed"; exit 1; } log_success "Docker installation complete!" -show_step 3 7 "Generating Secrets and Configuration" +show_step 3 8 "Generating Secrets and Configuration" bash "$SCRIPT_DIR/03_generate_secrets.sh" || { log_error "Secret/Config Generation failed"; exit 1; } log_success "Secret/Config Generation complete!" -show_step 4 7 "Running Service Selection Wizard" +show_step 4 8 "Running Service Selection Wizard" bash "$SCRIPT_DIR/04_wizard.sh" || { log_error "Service Selection Wizard failed"; exit 1; } log_success "Service Selection Wizard complete!" -show_step 5 7 "Configure Services" +show_step 5 8 "Configure Services" bash "$SCRIPT_DIR/05_configure_services.sh" || { log_error "Configure Services failed"; exit 1; } log_success "Configure Services complete!" -show_step 6 7 "Running Services" +show_step 6 8 "Running Services" bash "$SCRIPT_DIR/06_run_services.sh" || { log_error "Running Services failed"; exit 1; } log_success "Running Services complete!" -show_step 7 7 "Generating Final Report" +show_step 7 8 "Generating Final Report" # --- Installation Summary --- log_info "Installation Summary:" echo -e " ${GREEN}*${NC} System updated and basic utilities installed" @@ -133,6 +135,12 @@ echo -e " ${GREEN}*${NC} '.env' generated with secure passwords and secrets" echo -e " ${GREEN}*${NC} Services launched via Docker Compose" bash "$SCRIPT_DIR/07_final_report.sh" || { log_error "Final Report Generation failed"; exit 1; } +log_success "Final Report generated!" + +show_step 8 8 "Fixing File Permissions" +bash "$SCRIPT_DIR/08_fix_permissions.sh" || { log_error "Fix Permissions failed"; exit 1; } +log_success "File permissions fixed!" + log_success "Installation complete!" -exit 0 \ No newline at end of file +exit 0 \ No newline at end of file diff --git a/scripts/utils.sh b/scripts/utils.sh index b1baf1a..310f455 100755 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -605,6 +605,91 @@ wt_parse_choices() { read -ra arr <<< "$cleaned" } +#============================================================================= +# LEGACY CONTAINER CLEANUP +#============================================================================= + +# Remove legacy n8n worker containers from previous naming convention +# Old format: localai-n8n-worker-N (N = 1-10) +# New format: n8n-worker-N (managed by docker-compose.n8n-workers.yml) +# Usage: cleanup_legacy_n8n_workers +cleanup_legacy_n8n_workers() { + local removed_count=0 + local container_name + + log_info "Checking for legacy n8n worker containers..." + + for i in {1..10}; do + container_name="localai-n8n-worker-$i" + + # Check if container exists (running or stopped) + if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then + log_info "Removing legacy container: $container_name" + docker stop "$container_name" 2>/dev/null || true + docker rm -f "$container_name" 2>/dev/null || true + removed_count=$((removed_count + 1)) + fi + done + + if [ $removed_count -gt 0 ]; then + log_success "Removed $removed_count legacy n8n worker container(s)" + else + log_info "No legacy n8n worker containers found" + fi +} + +#============================================================================= +# USER DETECTION +#============================================================================= + +# Get the real user who invoked the script (even when running with sudo) +# Usage: real_user=$(get_real_user) +# Returns: username of the real user, or "root" if cannot determine +get_real_user() { + # Try SUDO_USER first (set by sudo) + if [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != "root" ]]; then + echo "$SUDO_USER" + return 0 + fi + + # Try logname (gets login name) + local logname_user + logname_user=$(logname 2>/dev/null) || true + if [[ -n "$logname_user" && "$logname_user" != "root" ]]; then + echo "$logname_user" + return 0 + fi + + # Try who am i (gets TTY user) + local who_user + who_user=$(who am i 2>/dev/null | awk '{print $1}') || true + if [[ -n "$who_user" && "$who_user" != "root" ]]; then + echo "$who_user" + return 0 + fi + + # Check if we're in a user's home directory + local current_dir="$PWD" + if [[ "$current_dir" =~ ^/home/([^/]+) ]]; then + local home_user="${BASH_REMATCH[1]}" + if id "$home_user" &>/dev/null; then + echo "$home_user" + return 0 + fi + fi + + # Fallback to current user + whoami +} + +# Get the home directory of the real user +# Usage: real_home=$(get_real_user_home) +get_real_user_home() { + local real_user + real_user=$(get_real_user) + eval echo "~$real_user" +} + #============================================================================= # DIRECTORY PRESERVATION (for git updates) #=============================================================================