#!/usr/bin/env bash set -Eeuo pipefail # ---------- logging helpers ---------- ts() { date +"%Y-%m-%d %H:%M:%S"; } log() { echo "[$(ts)] [INFO] $*"; } warn(){ echo "[$(ts)] [WARN] $*" >&2; } err() { echo "[$(ts)] [ERROR] $*" >&2; } die() { err "$*"; exit 1; } dump_diag() { warn "Diagnostics:" docker compose ps || true echo warn "docker ps (name=mssql2025):" docker ps --filter "name=mssql2025" || true echo warn "Last 250 lines of container logs (mssql2025):" docker logs --tail=250 mssql2025 2>/dev/null || warn "No logs available." } on_error() { local exit_code=$? err "Start failed (exit code=$exit_code)." dump_diag exit "$exit_code" } trap on_error ERR # ---------- go to repo root ---------- cd "$(dirname "$0")/.." # ---------- preflight ---------- command -v docker >/dev/null 2>&1 || die "docker is not installed or not in PATH." docker info >/dev/null 2>&1 || die "docker daemon not reachable. Start docker service (sudo systemctl start docker)." [[ -f .env ]] || die "Missing .env. Create it first: cp .env.example .env (then edit MSSQL_SA_PASSWORD)." # Load .env set -a # shellcheck disable=SC1091 source .env set +a [[ -n "${MSSQL_SA_PASSWORD:-}" ]] || die "MSSQL_SA_PASSWORD is empty in .env" # Validate MSSQL_PID for SQL Server 2025 containers case "${MSSQL_PID:-Developer}" in "Enterprise Developer"|"EnterpriseDeveloper"|"Enterprise_Developer") cat >&2 <<'EOF' [ERROR] MSSQL_PID is set to "Enterprise Developer", which SQL Server 2025 containers reject. Fix: edit .env and set: MSSQL_PID=Developer (or: DeveloperStandard) EOF exit 2 ;; Developer|DeveloperStandard|Express|Evaluation|Standard|Enterprise) ;; *) warn "MSSQL_PID='${MSSQL_PID}' is unusual. If SQL Server errors about PID format, set MSSQL_PID=Developer." ;; esac log "Hard-resetting previous instance (if any)..." # Bring down compose stack (remove orphans), but do NOT delete volumes because we use bind mounts (./data) docker compose down --remove-orphans >/dev/null 2>&1 || true # If there is a stray container with same name, kill it too (outside compose) if docker ps -a --format '{{.Names}}' | grep -qx 'mssql2025'; then warn "Found stray container named mssql2025; removing it..." docker rm -f mssql2025 >/dev/null 2>&1 || true fi log "Starting fresh container..." log "Settings: port=${MSSQL_PORT:-1433}, pid=${MSSQL_PID:-Developer}, cpuset=0-7, cpus=8.0" # Ensure image is present (optional but nice) docker compose pull >/dev/null 2>&1 || true # Force recreate every time to avoid “stuck” states docker compose up -d --force-recreate --remove-orphans # ---------- wait for healthy ---------- log "Waiting for container healthcheck to become healthy..." max_seconds=180 sleep_step=2 elapsed=0 while (( elapsed < max_seconds )); do state="$(docker inspect -f '{{.State.Status}}' mssql2025 2>/dev/null || true)" health="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}no-healthcheck{{end}}' mssql2025 2>/dev/null || true)" printf "\r[%s] state=%-10s health=%-12s elapsed=%3ss/%ss" "$(ts)" "${state:-unknown}" "${health:-unknown}" "$elapsed" "$max_seconds" if [[ "$health" == "healthy" ]]; then echo log "SQL Server is healthy ✅" log "Connect: localhost,${MSSQL_PORT:-1433} (user: sa)" exit 0 fi if [[ "$state" == "exited" ]]; then echo err "Container exited before becoming healthy." dump_diag exit 1 fi sleep "$sleep_step" elapsed=$((elapsed + sleep_step)) done echo err "Timed out waiting for SQL Server to become healthy (${max_seconds}s)." dump_diag exit 1