#!/usr/bin/env bash # entrypoint.sh — container-startup # # Verantwoordelijkheden: # 1. Schrijfbare dirs op de bind-mounts garanderen (UID/GID matching) # 2. Health-server starten als achtergrondproces # 3. gosu naar de agent-user en daemon-loop starten # # Loopt als root tot stap 3 — daarvoor hebben we root nodig om # bind-mounts goed te zetten als de share met andere ownership is # aangemaakt. set -euo pipefail log() { printf '[entrypoint] %s\n' "$*" >&2; } : "${AGENT_UID:=1000}" : "${AGENT_GID:=1000}" : "${AGENT_STATE_DIR:=/var/run/agent}" : "${AGENT_LOG_DIR:=/var/log/agent}" : "${AGENT_REPO_CACHE:=/var/cache/repos}" : "${AGENT_HEALTH_PORT:=8080}" # ----- 0. preflight: /var/cache mount-type + writable -------------------- _cache_fs=$(stat -f -c %T /var/cache 2>/dev/null \ || stat -f /var/cache 2>/dev/null | awk '/Type:/{print $NF}') if [ "$_cache_fs" = "tmpfs" ]; then log "FATAL: /var/cache is tmpfs (likely missing bind-mount). Fix docker-compose.yml en doe \`compose up -d --force-recreate\`." exit 1 fi if ! touch /var/cache/.write-test 2>/dev/null; then log "FATAL: /var/cache niet writable als user $(id -u)." exit 1 fi rm -f /var/cache/.write-test log "/var/cache OK (fs=${_cache_fs})" # Lighter warning-only check voor log/state mounts for _d in "${AGENT_LOG_DIR}" "${AGENT_STATE_DIR}"; do _d_fs=$(stat -f -c %T "$_d" 2>/dev/null || echo unknown) if [ "$_d_fs" = "tmpfs" ]; then log "WARN: ${_d} is tmpfs — overleeft geen container-herstart." fi done # ----- 1. dirs op bind-mounts ------------------------------------------- log "ensuring directories on bind-mounts" mkdir -p \ "${AGENT_STATE_DIR}" \ "${AGENT_LOG_DIR}/runs" \ "${AGENT_LOG_DIR}/jobs" \ "${AGENT_REPO_CACHE}" \ /var/cache/npm \ /var/cache/pnpm # Alleen ownership corrigeren als de share als andere user is aangemaakt # — niet recursief op /var/cache/repos want dat kan groot zijn en de # eerste boot vertragen. chown "${AGENT_UID}:${AGENT_GID}" \ "${AGENT_STATE_DIR}" \ "${AGENT_LOG_DIR}" \ "${AGENT_LOG_DIR}/runs" \ "${AGENT_LOG_DIR}/jobs" \ "${AGENT_REPO_CACHE}" \ /var/cache/npm \ /var/cache/pnpm 2>/dev/null || true # ----- 2. health-server in de achtergrond ------------------------------- log "starting health-server on :${AGENT_HEALTH_PORT}" gosu agent node /opt/agent/bin/health-server.js \ > "${AGENT_LOG_DIR}/health-server.log" 2>&1 & HEALTH_PID=$! log "health-server pid=${HEALTH_PID}" # Initial state: starting gosu agent /bin/bash -c 'cat > "${AGENT_STATE_DIR}/state.json"' < — # that is exactly where scrum4me-mcp's resolveRepoRoot looks via its # convention fallback. log "dropping to agent user and bootstrapping repos" gosu agent /opt/agent/bin/repo-bootstrap.sh \ >> "${AGENT_LOG_DIR}/repo-bootstrap.log" 2>&1 \ || log "WARN: repo-bootstrap returned non-zero (continuing)" log "starting run-agent.sh" exec gosu agent /opt/agent/bin/run-agent.sh