diff --git a/scripts/03_generate_secrets.sh b/scripts/03_generate_secrets.sh index fd0e150..524a262 100755 --- a/scripts/03_generate_secrets.sh +++ b/scripts/03_generate_secrets.sh @@ -187,19 +187,8 @@ else fi fi -# Determine N8N_WORKFLOWS_IMPORTED_EVER based on RUN_N8N_IMPORT and existing values -N8N_WORKFLOWS_IMPORTED_EVER_VALUE="false" # Default to false -if [[ -n "${existing_env_vars[N8N_WORKFLOWS_IMPORTED_EVER]}" ]]; then - N8N_WORKFLOWS_IMPORTED_EVER_VALUE="${existing_env_vars[N8N_WORKFLOWS_IMPORTED_EVER]}" - log_info "Using existing N8N_WORKFLOWS_IMPORTED_EVER value from .env: $N8N_WORKFLOWS_IMPORTED_EVER_VALUE" -else - # If N8N_WORKFLOWS_IMPORTED_EVER is not in .env, set it based on RUN_N8N_IMPORT choice - if [[ "$RUN_N8N_IMPORT" == "true" ]]; then - N8N_WORKFLOWS_IMPORTED_EVER_VALUE="true" - fi - # No else needed, it's already defaulted to false - log_info "Setting N8N_WORKFLOWS_IMPORTED_EVER based on current import choice (or default): $N8N_WORKFLOWS_IMPORTED_EVER_VALUE" -fi +# Set N8N_WORKFLOWS_IMPORTED_EVER_VALUE based on RUN_N8N_IMPORT +N8N_WORKFLOWS_IMPORTED_EVER_VALUE="$RUN_N8N_IMPORT" # Prompt for number of n8n workers echo "" # Add a newline for better formatting diff --git a/scripts/apply_update.sh b/scripts/apply_update.sh index 97b544f..6e15375 100755 --- a/scripts/apply_update.sh +++ b/scripts/apply_update.sh @@ -28,15 +28,35 @@ fi cd "$PROJECT_ROOT" -# Stop all services -log_info "Stopping all services..." -$COMPOSE_CMD down || { - log_warning "Failed to stop containers with 'docker compose down'. Continuing with update anyway..."; -} +# Stop all services for project 'localai' +log_info "Stopping all services for project 'localai'..." +PROJECT_CONTAINERS=$(docker ps -a -q --filter "label=com.docker.compose.project=localai") +if [ -n "$PROJECT_CONTAINERS" ]; then + docker stop $PROJECT_CONTAINERS || log_warning "Some containers for project 'localai' failed to stop." + docker rm $PROJECT_CONTAINERS || log_warning "Some containers for project 'localai' failed to be removed." +else + log_info "No containers found for project 'localai' to stop/remove." +fi -# Pull latest versions of all containers -log_info "Pulling latest versions of all containers..." -$COMPOSE_CMD pull || { log_error "Failed to pull Docker images. Check network connection and Docker Hub status."; exit 1; } +# Pull latest versions of all potentially needed containers +log_info "Pulling latest versions of all potentially needed containers..." +COMPOSE_FILES_FOR_PULL=("-f" "$PROJECT_ROOT/docker-compose.yml") +SUPABASE_DOCKER_DIR="$PROJECT_ROOT/supabase/docker" +SUPABASE_COMPOSE_FILE_PATH="$SUPABASE_DOCKER_DIR/docker-compose.yml" + +# Check if Supabase directory and its docker-compose.yml exist +if [ -d "$SUPABASE_DOCKER_DIR" ] && [ -f "$SUPABASE_COMPOSE_FILE_PATH" ]; then + COMPOSE_FILES_FOR_PULL+=("-f" "$SUPABASE_COMPOSE_FILE_PATH") + log_info "Supabase docker-compose.yml found, will be included in pull." +else + log_info "Supabase docker-compose.yml not found or directory does not exist, skipping for pull." +fi + +# Use the project name "localai" for consistency +$COMPOSE_CMD -p "localai" "${COMPOSE_FILES_FOR_PULL[@]}" pull --ignore-buildable || { + log_error "Failed to pull Docker images. Check network connection and Docker Hub status." + exit 1 +} # --- Run Service Selection Wizard --- log_info "Running Service Selection Wizard to update service choices..." diff --git a/start_services.py b/start_services.py index 0215de3..db5fffd 100755 --- a/start_services.py +++ b/start_services.py @@ -14,18 +14,18 @@ import time import argparse import platform import sys -from dotenv import dotenv_values, load_dotenv +from dotenv import dotenv_values def is_supabase_enabled(): - """Check if 'supabase' is in COMPOSE_PROFILES in the environment.""" - # Relies on load_dotenv() being called in main() - compose_profiles = os.environ.get("COMPOSE_PROFILES", "") + """Check if 'supabase' is in COMPOSE_PROFILES in .env file.""" + env_values = dotenv_values(".env") + compose_profiles = env_values.get("COMPOSE_PROFILES", "") return "supabase" in compose_profiles.split(',') -def run_command(cmd, cwd=None, env=None): +def run_command(cmd, cwd=None): """Run a shell command and print it.""" print("Running:", " ".join(cmd)) - subprocess.run(cmd, cwd=cwd, check=True, env=env) + subprocess.run(cmd, cwd=cwd, check=True) def clone_supabase_repo(): """Clone the Supabase repository using sparse checkout if not already present.""" @@ -60,92 +60,17 @@ def prepare_supabase_env(): shutil.copyfile(env_example_path, env_path) def stop_existing_containers(): - """Stop and remove all existing containers for our unified project ('localai').""" - print("Stopping and removing all existing containers for the unified project 'localai'...") - - compose_files_args = ["-f", "docker-compose.yml"] - - # Only include Supabase compose file if Supabase is enabled - if is_supabase_enabled(): - supabase_docker_dir = os.path.join("supabase", "docker") - supabase_compose_file = os.path.join(supabase_docker_dir, "docker-compose.yml") - if os.path.exists(supabase_compose_file): - print(f"Supabase is enabled and compose file found at {supabase_compose_file}, adding to commands.") - compose_files_args.extend(["-f", supabase_compose_file]) - else: - # This case should ideally not happen if Supabase is enabled and cloned properly - print(f"Supabase is enabled but its compose file was not found at {supabase_compose_file}.") - else: - # If Supabase is not enabled, we don't include its compose file. - # Lingering Supabase containers will be handled by force_stop_lingering_containers() - print("Supabase is not enabled, its compose file will not be used for stop/rm Docker Compose commands.") - # We also check if the Supabase compose file path exists to provide more context, - # as it might exist from a previous run where Supabase was enabled. - supabase_compose_file_if_exists = os.path.join("supabase", "docker", "docker-compose.yml") - if os.path.exists(supabase_compose_file_if_exists): - print(f"Note: Supabase compose file exists at {supabase_compose_file_if_exists} but is not being used as Supabase is disabled.") - - base_cmd_prefix = ["docker", "compose", "-p", "localai"] + compose_files_args - - # Prepare an environment for stop/rm that has COMPOSE_PROFILES explicitly removed - # to ensure these commands affect all services in the specified compose files. - env_for_stop_rm = os.environ.copy() - env_for_stop_rm.pop("COMPOSE_PROFILES", None) # Remove COMPOSE_PROFILES if it exists - - # Explicitly stop all services defined in the compose files - stop_cmd = base_cmd_prefix + ["stop"] - print("Attempting to stop all services...") - run_command(stop_cmd, env=env_for_stop_rm) - - # Explicitly remove all stopped containers - rm_cmd = base_cmd_prefix + ["rm", "-f"] - print("Attempting to remove all stopped services...") - run_command(rm_cmd, env=env_for_stop_rm) - - # Force stop containers that might be running outside of compose management - force_stop_lingering_containers() - -def force_stop_lingering_containers(): - """Force stop and remove specific containers that might be lingering.""" - print("Force stopping and removing any lingering service containers...") - - # Define service container patterns that we want to ensure are stopped - # These are containers that might be running but not managed by the current compose setup - container_patterns = [ - "qdrant", "langfuse", "grafana", "crawl4ai", "letta", "clickhouse", - "node-exporter", "minio", "cadvisor", "open-webui", "ollama", - "prometheus", "searxng", "supabase-", "localai-langfuse-", - "localai-clickhouse-", "localai-minio-", "realtime-dev.supabase-" + """Stop and remove existing containers for our unified project ('localai').""" + print("Stopping and removing existing containers for the unified project 'localai'...") + cmd = [ + "docker", "compose", + "-p", "localai", + "-f", "docker-compose.yml" ] - - try: - # Get list of all running containers - result = subprocess.run( - ["docker", "ps", "--format", "{{.Names}}"], - capture_output=True, text=True, check=True - ) - running_containers = result.stdout.strip().split('\n') - - containers_to_stop = [] - for container in running_containers: - if container and any(pattern in container for pattern in container_patterns): - containers_to_stop.append(container) - - if containers_to_stop: - print(f"Found lingering containers: {', '.join(containers_to_stop)}") - # Stop containers - subprocess.run(["docker", "stop"] + containers_to_stop, check=True) - print("Stopped lingering containers.") - # Remove containers - subprocess.run(["docker", "rm", "-f"] + containers_to_stop, check=True) - print("Removed lingering containers.") - else: - print("No lingering containers found.") - - except subprocess.CalledProcessError as e: - print(f"Error during force stop: {e}") - except Exception as e: - print(f"Unexpected error during force stop: {e}") + if is_supabase_enabled(): + cmd.extend(["-f", "supabase/docker/docker-compose.yml"]) + cmd.append("down") + run_command(cmd) def start_supabase(): """Start the Supabase services (using its compose file).""" @@ -153,18 +78,16 @@ def start_supabase(): print("Supabase is not enabled, skipping start.") return print("Starting Supabase services...") - # Pass os.environ.copy() to ensure it uses the correct COMPOSE_PROFILES run_command([ "docker", "compose", "-p", "localai", "-f", "supabase/docker/docker-compose.yml", "up", "-d" - ], env=os.environ.copy()) + ]) def start_local_ai(): """Start the local AI services (using its compose file).""" print("Starting local AI services...") cmd = ["docker", "compose", "-p", "localai"] cmd.extend(["-f", "docker-compose.yml", "up", "-d"]) - # Pass os.environ.copy() to ensure it uses the correct COMPOSE_PROFILES - run_command(cmd, env=os.environ.copy()) + run_command(cmd) def generate_searxng_secret_key(): """Generate a secret key for SearXNG based on the current platform.""" @@ -307,8 +230,6 @@ def check_and_fix_docker_compose_for_searxng(): print(f"Error checking/modifying docker-compose.yml for SearXNG: {e}") def main(): - load_dotenv(".env") # Load/Reload .env into os.environ - if is_supabase_enabled(): clone_supabase_repo() prepare_supabase_env()