fix(deploy): inventory-aware orchestration and correct override paths

- orchestrate-deploy.sh: read nodes from inventory/topology.yaml instead of hardcoded list
- orchestrate-deploy.sh: LTE nodes (chelsty-infra, chelsty-ha) use ConnectTimeout=30, non-fatal on failure
- deploy-node.sh: service discovery falls back to services.yaml if no services.txt
- deploy-node.sh: override path corrected to hosts/<node>/runtime/<service>/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
oskar 2026-05-20 14:50:01 +02:00
parent dc483ae31a
commit b02c8bb50e
2 changed files with 49 additions and 24 deletions

View file

@ -8,6 +8,7 @@ set -e
REPO_PATH="${HOME}/homelab-codex-ws" REPO_PATH="${HOME}/homelab-codex-ws"
RUNTIME_PATH="/opt/homelab" RUNTIME_PATH="/opt/homelab"
HOSTNAME=$(hostname | tr '[:lower:]' '[:upper:]') HOSTNAME=$(hostname | tr '[:lower:]' '[:upper:]')
HOST_DIR="${REPO_PATH}/hosts/$(hostname | tr '[:upper:]' '[:lower:]')"
echo "--- Starting Deployment on ${HOSTNAME} ---" echo "--- Starting Deployment on ${HOSTNAME} ---"
@ -22,37 +23,47 @@ echo "Pulling latest changes..."
git pull git pull
# 2. Identify Services # 2. Identify Services
# Based on our convention, we look for services assigned to this host SERVICES=()
# For now, we'll check if a 'services.txt' exists in the host folder if [ -f "${HOST_DIR}/services.txt" ]; then
SERVICE_LIST="${REPO_PATH}/hosts/$(hostname | tr '[:upper:]' '[:lower:]')/services.txt" mapfile -t SERVICES < <(grep -v '^\s*#' "${HOST_DIR}/services.txt" | grep -v '^\s*$')
elif [ -f "${HOST_DIR}/services.yaml" ]; then
SERVICES=($(python3 -c "
import yaml, sys
try:
with open('${HOST_DIR}/services.yaml', 'r') as f:
data = yaml.safe_load(f)
if data and 'services' in data:
if isinstance(data['services'], dict):
print(' '.join(data['services'].keys()))
elif isinstance(data['services'], list):
print(' '.join(data['services']))
except Exception as e:
print(f'Error parsing YAML: {e}', file=sys.stderr)
sys.exit(1)
"))
fi
if [ ! -f "$SERVICE_LIST" ]; then if [ ${#SERVICES[@]} -eq 0 ]; then
echo "No services.txt found for ${HOSTNAME}. Skipping service deployment." echo "No services found for ${HOSTNAME}. Skipping service deployment."
exit 0 exit 0
fi fi
# 3. Deploy Services # 3. Deploy Services
while IFS= read -r service || [ -n "$service" ]; do for service in "${SERVICES[@]}"; do
[[ "$service" =~ ^#.*$ ]] && continue # Skip comments
[[ -z "$service" ]] && continue # Skip empty lines
echo "Deploying service: ${service}..." echo "Deploying service: ${service}..."
COMPOSE_FILE="${REPO_PATH}/services/${service}/docker-compose.yml" COMPOSE_FILE="${REPO_PATH}/services/${service}/docker-compose.yml"
if [ ! -f "$COMPOSE_FILE" ]; then if [ ! -f "$COMPOSE_FILE" ]; then
echo "Warning: Compose file not found for ${service} at ${COMPOSE_FILE}" echo "Warning: Compose file not found for ${service} at ${COMPOSE_FILE}"
continue continue
fi fi
# Target directory in runtime
TARGET_DIR="${RUNTIME_PATH}/services/${service}" TARGET_DIR="${RUNTIME_PATH}/services/${service}"
mkdir -p "$TARGET_DIR" mkdir -p "$TARGET_DIR"
# We use the compose file from the repo directly OVERRIDE_FILE="${HOST_DIR}/runtime/${service}/docker-compose.override.yml"
# but we can also handle overrides here
OVERRIDE_FILE="${RUNTIME_PATH}/config/${service}/docker-compose.override.yml"
COMPOSE_CMD="docker compose -f ${COMPOSE_FILE}" COMPOSE_CMD="docker compose -f ${COMPOSE_FILE}"
if [ -f "$OVERRIDE_FILE" ]; then if [ -f "$OVERRIDE_FILE" ]; then
echo "Using override file for ${service}" echo "Using override file for ${service}"
@ -60,7 +71,6 @@ while IFS= read -r service || [ -n "$service" ]; do
fi fi
$COMPOSE_CMD up -d --remove-orphans $COMPOSE_CMD up -d --remove-orphans
done
done < "$SERVICE_LIST"
echo "--- Deployment Complete ---" echo "--- Deployment Complete ---"

View file

@ -1,15 +1,30 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# orchestrate-deploy.sh - To be run on SATURN # orchestrate-deploy.sh - To be run on SATURN
# Triggers deployment on remote execution nodes. # Triggers deployment on remote execution nodes via inventory.
set -e set -e
HOSTS=("solaria" "piha" "vps") REPO_PATH="${HOME}/homelab-codex-ws"
USER="oskar" # Default user USER="oskar"
for HOST in "${HOSTS[@]}"; do while IFS=' ' read -r HOST TAG; do
echo ">>> Triggering deployment on ${HOST}..." echo ">>> Triggering deployment on ${HOST}..."
ssh "${USER}@${HOST}" "bash ~/homelab-codex-ws/scripts/deploy/deploy-node.sh" if [[ "$TAG" == "lte" ]]; then
done ssh -o ConnectTimeout=30 "${USER}@${HOST}" "bash ~/homelab-codex-ws/scripts/deploy/deploy-node.sh" || \
echo "WARNING: Deployment on ${HOST} failed or timed out (LTE/intermittent node, skipping)"
else
ssh "${USER}@${HOST}" "bash ~/homelab-codex-ws/scripts/deploy/deploy-node.sh"
fi
done < <(python3 -c "
import yaml, sys
with open('${REPO_PATH}/inventory/topology.yaml') as f:
data = yaml.safe_load(f)
skip = {'saturn', 'solaria'}
for name, info in (data.get('nodes') or {}).items():
if name in skip:
continue
uplink = ((info or {}).get('connectivity') or {}).get('uplink', '')
print(name, 'lte' if uplink == 'lte' else 'standard')
")
echo ">>> All deployments triggered." echo ">>> All deployments triggered."