mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 03:29:25 +01:00
feat(install): detect existing Docker environment and offer integrated installation
Adds environment detection and integration mode to the installer:
- Scans for running Docker Compose projects, NVIDIA GPU runtime,
existing MySQL/Redis containers, and Docker networks
- Offers standalone (full isolated stack) vs integrated mode
- Integrated mode:
- Joins an existing Docker network so NOMAD services are discoverable
by other containers and vice versa
- Optionally reuses existing MySQL with user-provided credentials
- Optionally reuses existing Redis
- Detects NVIDIA containers already using the GPU and confirms
coexistence (Docker/NVIDIA handle time-sharing automatically)
- Generates a tailored compose file (removes unneeded services,
configures external network)
- Persists integration config to /opt/project-nomad/.integration
for use by helper scripts and updates
- NOMAD always manages its own compose file — user's compose is
never modified
This commit is contained in:
parent
86575bfc73
commit
b510d4580e
|
|
@ -1,5 +1,10 @@
|
|||
# Release Notes
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Features
|
||||
- **Install**: The installer now detects existing Docker Compose environments and offers an integrated installation mode. In integrated mode, NOMAD can join an existing Docker network for service discovery, reuse an existing MySQL or Redis instead of duplicating them, and coexist with other NVIDIA GPU containers (GPU time-sharing is automatic). NOMAD always manages its own compose file — the user's existing compose is never modified.
|
||||
|
||||
## Version 1.29.0 - March 11, 2026
|
||||
|
||||
### Features
|
||||
|
|
|
|||
|
|
@ -30,20 +30,43 @@ GREEN='\033[1;32m' # Light Green.
|
|||
|
||||
WHIPTAIL_TITLE="Project N.O.M.A.D Installation"
|
||||
NOMAD_DIR="/opt/project-nomad"
|
||||
MANAGEMENT_COMPOSE_FILE_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/management_compose.yaml"
|
||||
ENTRYPOINT_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/entrypoint.sh"
|
||||
SIDECAR_UPDATER_DOCKERFILE_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/sidecar-updater/Dockerfile"
|
||||
SIDECAR_UPDATER_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/sidecar-updater/update-watcher.sh"
|
||||
START_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/start_nomad.sh"
|
||||
STOP_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/stop_nomad.sh"
|
||||
UPDATE_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/update_nomad.sh"
|
||||
|
||||
# Base URL for downloading install assets. Override to test from a fork/branch:
|
||||
# sudo NOMAD_INSTALL_BASE_URL="https://raw.githubusercontent.com/trek-e/project-nomad/refs/heads/feature/compose-integration" bash install_nomad.sh
|
||||
NOMAD_INSTALL_BASE_URL="${NOMAD_INSTALL_BASE_URL:-https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main}"
|
||||
|
||||
MANAGEMENT_COMPOSE_FILE_URL="${NOMAD_INSTALL_BASE_URL}/install/management_compose.yaml"
|
||||
ENTRYPOINT_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/entrypoint.sh"
|
||||
SIDECAR_UPDATER_DOCKERFILE_URL="${NOMAD_INSTALL_BASE_URL}/install/sidecar-updater/Dockerfile"
|
||||
SIDECAR_UPDATER_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/sidecar-updater/update-watcher.sh"
|
||||
START_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/start_nomad.sh"
|
||||
STOP_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/stop_nomad.sh"
|
||||
UPDATE_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/update_nomad.sh"
|
||||
WAIT_FOR_IT_SCRIPT_URL="https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh"
|
||||
COLLECT_DISK_INFO_SCRIPT_URL="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/collect_disk_info.sh"
|
||||
COLLECT_DISK_INFO_SCRIPT_URL="${NOMAD_INSTALL_BASE_URL}/install/collect_disk_info.sh"
|
||||
|
||||
script_option_debug='true'
|
||||
accepted_terms='false'
|
||||
local_ip_address=''
|
||||
|
||||
# Installation mode: 'standalone' or 'integrated'
|
||||
INSTALL_MODE='standalone'
|
||||
|
||||
# Integration settings (populated during detection/prompting)
|
||||
EXISTING_COMPOSE_PROJECT=''
|
||||
EXISTING_COMPOSE_FILE=''
|
||||
REUSE_MYSQL=false
|
||||
REUSE_REDIS=false
|
||||
EXTERNAL_MYSQL_HOST=''
|
||||
EXTERNAL_MYSQL_PORT=''
|
||||
EXTERNAL_MYSQL_USER=''
|
||||
EXTERNAL_MYSQL_PASSWORD=''
|
||||
EXTERNAL_MYSQL_DATABASE=''
|
||||
EXTERNAL_REDIS_HOST=''
|
||||
EXTERNAL_REDIS_PORT=''
|
||||
EXISTING_DOCKER_NETWORK=''
|
||||
DETECTED_NVIDIA_RUNTIME=false
|
||||
|
||||
###################################################################################################################################################################################################
|
||||
# #
|
||||
# Functions #
|
||||
|
|
@ -524,6 +547,397 @@ get_local_ip() {
|
|||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
###################################################################################################################################################################################################
|
||||
# #
|
||||
# Docker Environment Detection & Integration #
|
||||
# #
|
||||
###################################################################################################################################################################################################
|
||||
|
||||
detect_docker_environment() {
|
||||
# Detect existing Docker Compose projects, services, GPU runtime, and networks.
|
||||
# Sets global variables used by prompt_installation_mode and compose generation.
|
||||
|
||||
echo -e "\n${YELLOW}#${RESET} Scanning existing Docker environment...\\n"
|
||||
|
||||
# --- Compose projects ---
|
||||
local compose_projects=""
|
||||
if docker compose ls --format json &>/dev/null; then
|
||||
compose_projects=$(docker compose ls --format json 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [[ -n "$compose_projects" && "$compose_projects" != "[]" ]]; then
|
||||
echo -e "${GREEN}#${RESET} Existing Docker Compose projects detected:"
|
||||
docker compose ls 2>/dev/null | tail -n +2 | while IFS= read -r line; do
|
||||
echo -e " ${WHITE_R}${line}${RESET}"
|
||||
done
|
||||
echo ""
|
||||
else
|
||||
echo -e "${GREEN}#${RESET} No existing Docker Compose projects detected.\\n"
|
||||
fi
|
||||
|
||||
# --- NVIDIA runtime ---
|
||||
if docker info 2>/dev/null | grep -qi "nvidia"; then
|
||||
DETECTED_NVIDIA_RUNTIME=true
|
||||
echo -e "${GREEN}#${RESET} NVIDIA container runtime is available on this Docker host."
|
||||
|
||||
# Find containers currently using NVIDIA GPU
|
||||
local gpu_containers
|
||||
gpu_containers=$(docker ps --format '{{.Names}}' 2>/dev/null | while read -r cname; do
|
||||
local rt
|
||||
rt=$(docker inspect --format '{{.HostConfig.Runtime}}' "$cname" 2>/dev/null)
|
||||
local devreqs
|
||||
devreqs=$(docker inspect --format '{{.HostConfig.DeviceRequests}}' "$cname" 2>/dev/null)
|
||||
if [[ "$rt" == "nvidia" ]] || echo "$devreqs" | grep -qi "nvidia" 2>/dev/null; then
|
||||
echo "$cname"
|
||||
fi
|
||||
done)
|
||||
|
||||
if [[ -n "$gpu_containers" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} Containers currently using NVIDIA GPU:"
|
||||
echo "$gpu_containers" | while IFS= read -r c; do
|
||||
echo -e " ${WHITE_R}• ${c}${RESET}"
|
||||
done
|
||||
echo ""
|
||||
echo -e "${GREEN}#${RESET} NOMAD's AI Assistant will share the GPU with these containers."
|
||||
echo -e " ${WHITE_R}Docker and NVIDIA handle GPU time-sharing automatically —${RESET}"
|
||||
echo -e " ${WHITE_R}no exclusive access is needed.${RESET}"
|
||||
else
|
||||
echo -e "${GREEN}#${RESET} No containers currently using the GPU."
|
||||
fi
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}#${RESET} NVIDIA container runtime not detected.\\n"
|
||||
fi
|
||||
|
||||
# --- Existing MySQL ---
|
||||
local existing_mysql
|
||||
existing_mysql=$(docker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}' 2>/dev/null | grep -i mysql | head -1)
|
||||
if [[ -n "$existing_mysql" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} Existing MySQL container detected: ${WHITE_R}$(echo "$existing_mysql" | cut -f1)${RESET}"
|
||||
fi
|
||||
|
||||
# --- Existing Redis ---
|
||||
local existing_redis
|
||||
existing_redis=$(docker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}' 2>/dev/null | grep -i redis | head -1)
|
||||
if [[ -n "$existing_redis" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} Existing Redis container detected: ${WHITE_R}$(echo "$existing_redis" | cut -f1)${RESET}"
|
||||
fi
|
||||
|
||||
# --- Docker networks ---
|
||||
# Store the default bridge and any compose-created networks for later use
|
||||
echo ""
|
||||
}
|
||||
|
||||
prompt_installation_mode() {
|
||||
# If Docker has no running containers at all, skip the prompt — go standalone.
|
||||
local running_count
|
||||
running_count=$(docker ps -q 2>/dev/null | wc -l)
|
||||
|
||||
if [[ "$running_count" -eq 0 ]]; then
|
||||
echo -e "${GREEN}#${RESET} No running containers detected. Using standalone installation.\\n"
|
||||
INSTALL_MODE='standalone'
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}#${RESET} Docker is already running services on this system.\\n"
|
||||
echo -e " ${WHITE_R}1) Standalone${RESET} — Full isolated stack (own MySQL, Redis, network)"
|
||||
echo -e " Best for: dedicated NOMAD devices, clean installs"
|
||||
echo ""
|
||||
echo -e " ${WHITE_R}2) Integrated${RESET} — Join existing Docker environment"
|
||||
echo -e " • Connects to an existing Docker network so services can discover each other"
|
||||
echo -e " • Can reuse an existing MySQL and/or Redis instead of duplicating them"
|
||||
echo -e " • GPU is shared automatically with other NVIDIA containers"
|
||||
echo -e " • NOMAD manages its own compose file — your existing compose is never modified"
|
||||
echo -e " Best for: servers already running Docker services (media, home automation, etc.)"
|
||||
echo ""
|
||||
|
||||
local choice=""
|
||||
while [[ -z "$choice" ]]; do
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") Installation mode [1]: " choice
|
||||
choice="${choice:-1}"
|
||||
case "$choice" in
|
||||
1) INSTALL_MODE='standalone' ;;
|
||||
2) INSTALL_MODE='integrated' ;;
|
||||
*) echo -e "${RED}#${RESET} Invalid choice. Enter 1 or 2."; choice="" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$INSTALL_MODE" == "standalone" ]]; then
|
||||
echo -e "\n${GREEN}#${RESET} Using standalone installation.\\n"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}#${RESET} Using integrated installation.\\n"
|
||||
|
||||
# --- Network selection ---
|
||||
prompt_network_selection
|
||||
|
||||
# --- MySQL reuse ---
|
||||
prompt_mysql_reuse
|
||||
|
||||
# --- Redis reuse ---
|
||||
prompt_redis_reuse
|
||||
}
|
||||
|
||||
prompt_network_selection() {
|
||||
echo -e "${YELLOW}#${RESET} Docker Networks\\n"
|
||||
|
||||
# List non-default networks (skip bridge, host, none)
|
||||
local networks
|
||||
networks=$(docker network ls --format '{{.Name}}' 2>/dev/null | grep -vE '^(bridge|host|none)$')
|
||||
|
||||
if [[ -z "$networks" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} No custom Docker networks found. NOMAD will create its own.\\n"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e " Available networks:"
|
||||
local i=0
|
||||
local net_array=()
|
||||
while IFS= read -r net; do
|
||||
i=$((i + 1))
|
||||
net_array+=("$net")
|
||||
# Show network with connected container count
|
||||
local connected
|
||||
connected=$(docker network inspect "$net" --format '{{len .Containers}}' 2>/dev/null || echo "0")
|
||||
echo -e " ${WHITE_R}${i})${RESET} ${net} (${connected} containers)"
|
||||
done <<< "$networks"
|
||||
echo -e " ${WHITE_R}$((i + 1)))${RESET} Create a new dedicated network for NOMAD"
|
||||
echo ""
|
||||
|
||||
local net_choice=""
|
||||
while [[ -z "$net_choice" ]]; do
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") Select network [${i+1}]: " net_choice
|
||||
net_choice="${net_choice:-$((i + 1))}"
|
||||
|
||||
if [[ "$net_choice" =~ ^[0-9]+$ ]] && [[ "$net_choice" -ge 1 ]] && [[ "$net_choice" -le $((i + 1)) ]]; then
|
||||
if [[ "$net_choice" -le "$i" ]]; then
|
||||
EXISTING_DOCKER_NETWORK="${net_array[$((net_choice - 1))]}"
|
||||
echo -e "${GREEN}#${RESET} NOMAD will join network: ${GREEN}${EXISTING_DOCKER_NETWORK}${RESET}\\n"
|
||||
else
|
||||
echo -e "${GREEN}#${RESET} NOMAD will create its own network.\\n"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}#${RESET} Invalid choice."; net_choice=""
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
prompt_mysql_reuse() {
|
||||
local existing_mysql_name
|
||||
existing_mysql_name=$(docker ps --format '{{.Names}}\t{{.Image}}' 2>/dev/null | grep -i mysql | head -1 | cut -f1)
|
||||
|
||||
if [[ -z "$existing_mysql_name" ]]; then
|
||||
echo -e "${GREEN}#${RESET} No existing MySQL found. NOMAD will create its own.\\n"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}#${RESET} An existing MySQL container was found: ${WHITE_R}${existing_mysql_name}${RESET}"
|
||||
echo -e " ${WHITE_R}1)${RESET} Use NOMAD's own MySQL (recommended — isolated, no risk to existing data)"
|
||||
echo -e " ${WHITE_R}2)${RESET} Reuse ${existing_mysql_name} (saves resources, but NOMAD needs a database created)"
|
||||
echo ""
|
||||
|
||||
local choice=""
|
||||
while [[ -z "$choice" ]]; do
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") MySQL preference [1]: " choice
|
||||
choice="${choice:-1}"
|
||||
case "$choice" in
|
||||
1)
|
||||
echo -e "${GREEN}#${RESET} NOMAD will use its own MySQL.\\n"
|
||||
;;
|
||||
2)
|
||||
REUSE_MYSQL=true
|
||||
echo ""
|
||||
echo -e "${YELLOW}#${RESET} To reuse ${existing_mysql_name}, NOMAD needs database credentials."
|
||||
echo -e " ${WHITE_R}NOMAD will create a database named 'nomad' if it doesn't exist.${RESET}\\n"
|
||||
|
||||
# Detect connection info from the container
|
||||
local detected_network
|
||||
detected_network=$(docker inspect --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' "$existing_mysql_name" 2>/dev/null | awk '{print $1}')
|
||||
|
||||
EXTERNAL_MYSQL_HOST="$existing_mysql_name"
|
||||
if [[ -n "$detected_network" && -z "$EXISTING_DOCKER_NETWORK" ]]; then
|
||||
# Auto-join the MySQL container's network if user didn't pick one
|
||||
EXISTING_DOCKER_NETWORK="$detected_network"
|
||||
echo -e "${GREEN}#${RESET} Auto-joining network ${GREEN}${detected_network}${RESET} (same as MySQL container)"
|
||||
fi
|
||||
|
||||
# Get port from container
|
||||
EXTERNAL_MYSQL_PORT=$(docker inspect --format '{{range $p, $conf := .Config.ExposedPorts}}{{$p}} {{end}}' "$existing_mysql_name" 2>/dev/null | grep -oP '\d+' | head -1)
|
||||
EXTERNAL_MYSQL_PORT="${EXTERNAL_MYSQL_PORT:-3306}"
|
||||
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") MySQL user [root]: " EXTERNAL_MYSQL_USER
|
||||
EXTERNAL_MYSQL_USER="${EXTERNAL_MYSQL_USER:-root}"
|
||||
|
||||
read -srp "$(echo -e "${WHITE_R}#${RESET}") MySQL password: " EXTERNAL_MYSQL_PASSWORD
|
||||
echo ""
|
||||
|
||||
EXTERNAL_MYSQL_DATABASE="nomad"
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") Database name [nomad]: " user_db
|
||||
EXTERNAL_MYSQL_DATABASE="${user_db:-nomad}"
|
||||
|
||||
echo -e "${GREEN}#${RESET} Will connect to MySQL at ${EXTERNAL_MYSQL_HOST}:${EXTERNAL_MYSQL_PORT}\\n"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}#${RESET} Invalid choice."; choice=""
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
prompt_redis_reuse() {
|
||||
local existing_redis_name
|
||||
existing_redis_name=$(docker ps --format '{{.Names}}\t{{.Image}}' 2>/dev/null | grep -i redis | head -1 | cut -f1)
|
||||
|
||||
if [[ -z "$existing_redis_name" ]]; then
|
||||
echo -e "${GREEN}#${RESET} No existing Redis found. NOMAD will create its own.\\n"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}#${RESET} An existing Redis container was found: ${WHITE_R}${existing_redis_name}${RESET}"
|
||||
echo -e " ${WHITE_R}1)${RESET} Use NOMAD's own Redis (recommended — isolated)"
|
||||
echo -e " ${WHITE_R}2)${RESET} Reuse ${existing_redis_name} (saves resources)"
|
||||
echo ""
|
||||
|
||||
local choice=""
|
||||
while [[ -z "$choice" ]]; do
|
||||
read -rp "$(echo -e "${WHITE_R}#${RESET}") Redis preference [1]: " choice
|
||||
choice="${choice:-1}"
|
||||
case "$choice" in
|
||||
1)
|
||||
echo -e "${GREEN}#${RESET} NOMAD will use its own Redis.\\n"
|
||||
;;
|
||||
2)
|
||||
REUSE_REDIS=true
|
||||
|
||||
local detected_network
|
||||
detected_network=$(docker inspect --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' "$existing_redis_name" 2>/dev/null | awk '{print $1}')
|
||||
|
||||
EXTERNAL_REDIS_HOST="$existing_redis_name"
|
||||
if [[ -n "$detected_network" && -z "$EXISTING_DOCKER_NETWORK" ]]; then
|
||||
EXISTING_DOCKER_NETWORK="$detected_network"
|
||||
echo -e "${GREEN}#${RESET} Auto-joining network ${GREEN}${detected_network}${RESET} (same as Redis container)"
|
||||
fi
|
||||
|
||||
EXTERNAL_REDIS_PORT=$(docker inspect --format '{{range $p, $conf := .Config.ExposedPorts}}{{$p}} {{end}}' "$existing_redis_name" 2>/dev/null | grep -oP '\d+' | head -1)
|
||||
EXTERNAL_REDIS_PORT="${EXTERNAL_REDIS_PORT:-6379}"
|
||||
|
||||
echo -e "${GREEN}#${RESET} Will connect to Redis at ${EXTERNAL_REDIS_HOST}:${EXTERNAL_REDIS_PORT}\\n"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}#${RESET} Invalid choice."; choice=""
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
save_integration_config() {
|
||||
# Persist integration settings so helper scripts and updates know the mode
|
||||
local config_file="${NOMAD_DIR}/.integration"
|
||||
|
||||
cat > "$config_file" <<EOF
|
||||
# Project N.O.M.A.D. Integration Configuration
|
||||
# Generated during installation — do not edit manually
|
||||
INSTALL_MODE=${INSTALL_MODE}
|
||||
EXISTING_DOCKER_NETWORK=${EXISTING_DOCKER_NETWORK}
|
||||
REUSE_MYSQL=${REUSE_MYSQL}
|
||||
REUSE_REDIS=${REUSE_REDIS}
|
||||
EXTERNAL_MYSQL_HOST=${EXTERNAL_MYSQL_HOST}
|
||||
EXTERNAL_REDIS_HOST=${EXTERNAL_REDIS_HOST}
|
||||
DETECTED_NVIDIA_RUNTIME=${DETECTED_NVIDIA_RUNTIME}
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}#${RESET} Integration config saved to ${config_file}\\n"
|
||||
}
|
||||
|
||||
generate_integrated_compose() {
|
||||
# Build a compose file tailored to the detected environment.
|
||||
# - Removes MySQL/Redis services if reusing external ones
|
||||
# - Adds external network configuration
|
||||
# - NVIDIA GPU sharing is handled at container creation time by the admin app,
|
||||
# not in the compose file (the compose only runs the admin + infra services)
|
||||
|
||||
local compose_file="${NOMAD_DIR}/compose.yml"
|
||||
|
||||
# Start from the downloaded template (already has passwords/URLs applied)
|
||||
# Now apply integration transforms:
|
||||
|
||||
# --- Remove MySQL service if reusing external ---
|
||||
if $REUSE_MYSQL; then
|
||||
echo -e "${YELLOW}#${RESET} Removing MySQL service from compose (using external)...\\n"
|
||||
|
||||
# Remove the mysql service block (from " mysql:" to the line before the next top-level service)
|
||||
# Use awk for reliable multi-line YAML block removal
|
||||
awk '
|
||||
/^ mysql:/ { skip=1; next }
|
||||
skip && /^ [a-z]/ { skip=0 }
|
||||
!skip { print }
|
||||
' "$compose_file" > "${compose_file}.tmp" && mv "${compose_file}.tmp" "$compose_file"
|
||||
|
||||
# Remove mysql from admin's depends_on block
|
||||
awk '
|
||||
/mysql:/ && prev ~ /depends_on/ { next }
|
||||
/mysql:/ && prev ~ /condition:/ { next }
|
||||
/condition: service_healthy/ && pending_mysql { pending_mysql=0; next }
|
||||
{ if (/mysql:/) { pending_mysql=1; next } }
|
||||
{ pending_mysql=0; print; prev=$0 }
|
||||
' "$compose_file" > "${compose_file}.tmp" 2>/dev/null
|
||||
# Simpler approach: just remove the mysql depends_on lines
|
||||
sed -i '/^ mysql:/,/^ condition: service_healthy$/d' "$compose_file"
|
||||
|
||||
# Point admin at external MySQL
|
||||
sed -i "s|DB_HOST=mysql|DB_HOST=${EXTERNAL_MYSQL_HOST}|g" "$compose_file"
|
||||
sed -i "s|DB_PORT=3306|DB_PORT=${EXTERNAL_MYSQL_PORT}|g" "$compose_file"
|
||||
sed -i "s|DB_USER=nomad_user|DB_USER=${EXTERNAL_MYSQL_USER}|g" "$compose_file"
|
||||
sed -i "s|DB_DATABASE=nomad|DB_DATABASE=${EXTERNAL_MYSQL_DATABASE}|g" "$compose_file"
|
||||
# Replace the generated password with the external one
|
||||
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=${EXTERNAL_MYSQL_PASSWORD}|" "$compose_file"
|
||||
# Remove the MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD lines (no longer relevant)
|
||||
rm -f "${compose_file}.tmp"
|
||||
fi
|
||||
|
||||
# --- Remove Redis service if reusing external ---
|
||||
if $REUSE_REDIS; then
|
||||
echo -e "${YELLOW}#${RESET} Removing Redis service from compose (using external)...\\n"
|
||||
|
||||
awk '
|
||||
/^ redis:/ { skip=1; next }
|
||||
skip && /^ [a-z]/ { skip=0 }
|
||||
!skip { print }
|
||||
' "$compose_file" > "${compose_file}.tmp" && mv "${compose_file}.tmp" "$compose_file"
|
||||
|
||||
# Remove redis from admin's depends_on block
|
||||
sed -i '/^ redis:/,/^ condition: service_healthy$/d' "$compose_file"
|
||||
|
||||
# Point admin at external Redis
|
||||
sed -i "s|REDIS_HOST=redis|REDIS_HOST=${EXTERNAL_REDIS_HOST}|g" "$compose_file"
|
||||
sed -i "s|REDIS_PORT=6379|REDIS_PORT=${EXTERNAL_REDIS_PORT}|g" "$compose_file"
|
||||
rm -f "${compose_file}.tmp"
|
||||
fi
|
||||
|
||||
# If both MySQL and Redis were removed, clean up the empty depends_on block
|
||||
if $REUSE_MYSQL && $REUSE_REDIS; then
|
||||
sed -i '/^ depends_on:$/d' "$compose_file"
|
||||
fi
|
||||
|
||||
# --- Add external network if selected ---
|
||||
if [[ -n "$EXISTING_DOCKER_NETWORK" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} Configuring shared Docker network: ${EXISTING_DOCKER_NETWORK}...\\n"
|
||||
|
||||
# Add networks section declaring the external network
|
||||
# and a default network pointing to it so all services join automatically
|
||||
cat >> "$compose_file" <<EOF
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: ${EXISTING_DOCKER_NETWORK}
|
||||
external: true
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}#${RESET} Compose file configured for integrated mode.\\n"
|
||||
}
|
||||
verify_gpu_setup() {
|
||||
# This function only displays GPU setup status and is completely non-blocking
|
||||
# It never exits or returns error codes - purely informational
|
||||
|
|
@ -582,6 +996,28 @@ success_message() {
|
|||
echo -e "${GREEN}#${RESET} Installation files are located at /opt/project-nomad\\n\n"
|
||||
echo -e "${GREEN}#${RESET} Project N.O.M.A.D's Command Center should automatically start whenever your device reboots. However, if you need to start it manually, you can always do so by running: ${WHITE_R}${NOMAD_DIR}/start_nomad.sh${RESET}\\n"
|
||||
echo -e "${GREEN}#${RESET} You can now access the management interface at http://localhost:8080 or http://${local_ip_address}:8080\\n"
|
||||
|
||||
if [[ "$INSTALL_MODE" == "integrated" ]]; then
|
||||
echo -e "${YELLOW}#${RESET} Integration Summary:\\n"
|
||||
if [[ -n "$EXISTING_DOCKER_NETWORK" ]]; then
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "Docker Network:" "${EXISTING_DOCKER_NETWORK}"
|
||||
fi
|
||||
if $REUSE_MYSQL; then
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "MySQL:" "Reusing ${EXTERNAL_MYSQL_HOST}"
|
||||
else
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "MySQL:" "NOMAD-managed (nomad_mysql)"
|
||||
fi
|
||||
if $REUSE_REDIS; then
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "Redis:" "Reusing ${EXTERNAL_REDIS_HOST}"
|
||||
else
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "Redis:" "NOMAD-managed (nomad_redis)"
|
||||
fi
|
||||
if $DETECTED_NVIDIA_RUNTIME; then
|
||||
printf " ${WHITE_R}%-20s${RESET} %s\\n" "NVIDIA GPU:" "Shared (auto time-sharing with other containers)"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}#${RESET} Thank you for supporting Project N.O.M.A.D!\\n"
|
||||
}
|
||||
|
||||
|
|
@ -604,6 +1040,8 @@ accept_terms
|
|||
ensure_docker_installed
|
||||
setup_nvidia_container_toolkit
|
||||
get_local_ip
|
||||
detect_docker_environment
|
||||
prompt_installation_mode
|
||||
create_nomad_directory
|
||||
download_wait_for_it_script
|
||||
download_entrypoint_script
|
||||
|
|
@ -611,6 +1049,10 @@ download_sidecar_files
|
|||
download_helper_scripts
|
||||
download_and_start_collect_disk_info_script
|
||||
download_management_compose_file
|
||||
if [[ "$INSTALL_MODE" == "integrated" ]]; then
|
||||
generate_integrated_compose
|
||||
save_integration_config
|
||||
fi
|
||||
start_management_containers
|
||||
verify_gpu_setup
|
||||
success_message
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user