#!/bin/bash set -euo pipefail # ds_install.sh SERVICE # # Handles the full install lifecycle on the remote server in a single SSH session. # Called after the local dropshell has rsynced new template + config to a staging folder. # # Remote directory layout: # services/SERVICE/config/ ← live service config # services/SERVICE/template/ ← live template scripts # services/SERVICE/_staging/config/ ← new config (rsynced by local) # services/SERVICE/_staging/template/ ← new template (rsynced by local) # # Flow: # 1. Run install-pre.sh from STAGING (new code + new config) → validate # 2. Run uninstall.sh from LIVE (old code + old config) → stop old service # 3. Swap staging → live (atomic replacement) # 4. Run install.sh from LIVE (now the new version) # # If any step fails, the script exits immediately (set -e). # If install-pre.sh fails, the old service is untouched. # -- Determine paths -- SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")" AGENT_PATH="$(dirname "${SCRIPT_PATH}")" DROPSHELL_DIR="$(dirname "${AGENT_PATH}")" # Export for scripts that need them export AGENT_PATH export DROPSHELL_DIR # -- Source common functions -- source "${AGENT_PATH}/common.sh" # -- Validate arguments -- if [[ $# -lt 1 ]]; then echo "Usage: ds_install.sh SERVICE [TEMP_DIR]" >&2 exit 1 fi SERVICE="$1" export SERVICE export TEMP_DIR="${2:-}" export DOCKER_CLI_HINTS=false SERVICE_DIR="${DROPSHELL_DIR}/services/${SERVICE}" LIVE_CONFIG="${SERVICE_DIR}/config" LIVE_TEMPLATE="${SERVICE_DIR}/template" STAGING_DIR="${SERVICE_DIR}/_staging" STAGING_CONFIG="${STAGING_DIR}/config" STAGING_TEMPLATE="${STAGING_DIR}/template" # -- Validate staging exists -- [[ -d "${STAGING_CONFIG}" ]] || _die "Staging config not found at ${STAGING_CONFIG}" [[ -d "${STAGING_TEMPLATE}" ]] || _die "Staging template not found at ${STAGING_TEMPLATE}" [[ -f "${DROPSHELL_DIR}/server_info.env" ]] || _die "Missing server_info.env" # -- Helper: source env for a given template/config pair -- load_env() { local template_dir="$1" local config_dir="$2" # Find template_info.env local tinfo="${template_dir}/template_info.env" if [[ ! -f "${tinfo}" ]]; then tinfo="${template_dir}/config/.template_info.env" fi [[ -f "${tinfo}" ]] || _die "Missing template_info.env in ${template_dir}" # Must have service.env [[ -f "${config_dir}/service.env" ]] || _die "Missing service.env in ${config_dir}" # Source in order: server_info → template_info → service.env set -a source "${DROPSHELL_DIR}/server_info.env" source "${tinfo}" source "${config_dir}/service.env" set +a export CONFIG_PATH="${config_dir}" export TEMPLATE_PATH="${template_dir}" } # ═══════════════════════════════════════════════════════════════════ # STEP 1: Run install-pre.sh from STAGING (new code + new config) # ═══════════════════════════════════════════════════════════════════ if [[ -f "${STAGING_TEMPLATE}/install-pre.sh" ]]; then echo "── Step 1: Running install-pre.sh (new version) ──" load_env "${STAGING_TEMPLATE}" "${STAGING_CONFIG}" cd "${STAGING_TEMPLATE}" if ! bash ./install-pre.sh; then echo "install-pre.sh failed — aborting install. Old service is untouched." rm -rf "${STAGING_DIR}" exit 1 fi else echo "── Step 1: No install-pre.sh — skipping ──" fi # ═══════════════════════════════════════════════════════════════════ # STEP 2: Run uninstall.sh from LIVE (old code + old config) # ═══════════════════════════════════════════════════════════════════ if [[ -d "${LIVE_TEMPLATE}" ]] && [[ -f "${LIVE_TEMPLATE}/uninstall.sh" ]]; then echo "── Step 2: Running uninstall.sh (old version) ──" load_env "${LIVE_TEMPLATE}" "${LIVE_CONFIG}" cd "${LIVE_TEMPLATE}" # Uninstall is best-effort — don't abort if it fails bash ./uninstall.sh || echo "Warning: uninstall.sh failed, continuing anyway" else echo "── Step 2: No existing service to uninstall ──" fi # ═══════════════════════════════════════════════════════════════════ # STEP 3: Swap staging → live # ═══════════════════════════════════════════════════════════════════ echo "── Step 3: Swapping staging to live ──" # Remove old live (if exists) rm -rf "${LIVE_TEMPLATE}" "${LIVE_CONFIG}" # Move staging into place mkdir -p "${SERVICE_DIR}" mv "${STAGING_CONFIG}" "${LIVE_CONFIG}" mv "${STAGING_TEMPLATE}" "${LIVE_TEMPLATE}" rm -rf "${STAGING_DIR}" # ═══════════════════════════════════════════════════════════════════ # STEP 4: Run install.sh from LIVE (now the new version) # ═══════════════════════════════════════════════════════════════════ echo "── Step 4: Running install.sh (new version) ──" load_env "${LIVE_TEMPLATE}" "${LIVE_CONFIG}" cd "${LIVE_TEMPLATE}" bash ./install.sh || _die "install.sh failed" echo "── Install complete for ${SERVICE} ──"