#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" STACK_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" CONTROL_PLANE_ENV="${STACK_DIR}/../control-plane/.env" EXAMPLE="${STACK_DIR}/../control-plane/.env.example" cd "${STACK_DIR}" if [[ ! -f "${CONTROL_PLANE_ENV}" ]]; then cp "${EXAMPLE}" "${CONTROL_PLANE_ENV}" echo "Created ${CONTROL_PLANE_ENV} from example" fi set -a # shellcheck disable=SC1091 source "${CONTROL_PLANE_ENV}" set +a export CONTROL_PLANE_ENV="${CONTROL_PLANE_ENV}" CURVE_PATH="${CURVE_PATH:-/etc/gpu-fan/curve.json}" export CURVE_PATH if [[ ! -f "${CURVE_PATH}" ]]; then if [[ "${EUID}" -eq 0 ]]; then mkdir -p "$(dirname "${CURVE_PATH}")" cp curve.default.json "${CURVE_PATH}" else mkdir -p "${STACK_DIR}/config" CURVE_PATH="${STACK_DIR}/config/curve.json" export CURVE_PATH [[ -f "${CURVE_PATH}" ]] || cp curve.default.json "${CURVE_PATH}" echo "Using local curve: ${CURVE_PATH}" fi fi if [[ ! -d .venv ]]; then python3 -m venv .venv .venv/bin/pip install -q -r requirements.txt fi if [[ "${EUID}" -ne 0 ]]; then echo "ERROR: Fan control requires root. Use:" echo " sudo -E ${SCRIPT_DIR}/start.sh" echo "Or install system-wide:" echo " sudo ${SCRIPT_DIR}/install.sh && sudo systemctl start gpu-fan" exit 1 fi if systemctl is-active --quiet gpu-fan 2>/dev/null; then echo "ERROR: gpu-fan.service is already running (systemd)." echo " Use: sudo systemctl stop gpu-fan" echo " Or: sudo journalctl -u gpu-fan -f" echo "" echo "Do not run scripts/start.sh alongside systemd — one instance only." exit 1 fi PORT="${GPU_FAN_API_PORT:-18090}" HOST="${GPU_FAN_API_HOST:-127.0.0.1}" if ss -tln "sport = :${PORT}" 2>/dev/null | grep -q LISTEN; then echo "ERROR: Port ${PORT} is already in use." echo "" ss -tlnp "sport = :${PORT}" 2>/dev/null || ss -tln "sport = :${PORT}" echo "" echo "Common causes:" echo " - Suspended foreground start (Ctrl+Z) — run: jobs -l && kill %" echo " - Orphan process — run: sudo ${SCRIPT_DIR}/status.sh" echo " - systemd still stopping — wait a few seconds" exit 1 fi echo "=== GPU Fan Control (foreground) ===" echo "Agent API: http://${HOST}:${PORT}" echo "Curve: ${CURVE_PATH}" echo "" echo "Stop with Ctrl+C (not Ctrl+Z — suspended process keeps the port)." echo "" exec .venv/bin/python app.py