Refactor service management in start_services.py and scripts

- Updated the is_supabase_enabled function to read COMPOSE_PROFILES from the .env file instead of os.environ, improving clarity.
- Simplified the run_command function by removing the unused env parameter.
- Refined the stop_existing_containers function to streamline the shutdown process for the 'localai' project, conditionally including the Supabase compose file.
- Enhanced logging for better user feedback during service management operations.
- Adjusted the scripts for generating secrets and applying updates to improve clarity and functionality.
This commit is contained in:
Yury Kossakovsky
2025-05-22 14:09:28 -06:00
parent 1c2b348ee3
commit f5aa8a5ddf
3 changed files with 48 additions and 118 deletions

View File

@@ -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

View File

@@ -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..."

View File

@@ -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()