Initial import: bare-metal stacks, Server UI, GPU fan, tutorials.
Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI, control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# Self-test: curve logic, NVML read, API (dry-run). Full fan write needs sudo.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
STACK_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
cd "${STACK_DIR}"
|
||||
|
||||
mkdir -p config
|
||||
cp -n curve.default.json config/curve.json 2>/dev/null || true
|
||||
|
||||
export CURVE_PATH="${STACK_DIR}/config/curve.json"
|
||||
export DRY_RUN=true
|
||||
export GPU_FAN_PORT=18090
|
||||
|
||||
echo "=== 1. Curve logic ==="
|
||||
.venv/bin/python -c "
|
||||
from fan_controller import parse_curve, interpolate_speed
|
||||
pts = parse_curve({'30':50,'40':65,'50':80,'55':90,'60':100,'70':100})
|
||||
assert interpolate_speed(45, pts) in (72, 73)
|
||||
assert interpolate_speed(70, pts) == 100
|
||||
print('OK')
|
||||
"
|
||||
|
||||
echo "=== 2. NVML read ==="
|
||||
.venv/bin/python -c "
|
||||
import pynvml
|
||||
pynvml.nvmlInit()
|
||||
h = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||||
t = pynvml.nvmlDeviceGetTemperature(h, pynvml.NVML_TEMPERATURE_GPU)
|
||||
print(f'GPU temp: {t}C')
|
||||
pynvml.nvmlShutdown()
|
||||
print('OK')
|
||||
"
|
||||
|
||||
echo "=== 3. API dry-run (background) ==="
|
||||
.venv/bin/python app.py &
|
||||
APP_PID=$!
|
||||
trap 'kill $APP_PID 2>/dev/null || true' EXIT
|
||||
sleep 2
|
||||
|
||||
STATUS=$(curl -sf "http://127.0.0.1:${GPU_FAN_PORT}/api/status")
|
||||
echo "$STATUS" | .venv/bin/python -m json.tool | head -20
|
||||
|
||||
TARGET=$(echo "$STATUS" | .venv/bin/python -c "import sys,json; print(json.load(sys.stdin)['target_speed_pct'])")
|
||||
TEMP=$(echo "$STATUS" | .venv/bin/python -c "import sys,json; print(json.load(sys.stdin)['temperature_c'])")
|
||||
echo "Temp=${TEMP}C target=${TARGET}%"
|
||||
|
||||
curl -sf -X PUT "http://127.0.0.1:${GPU_FAN_PORT}/api/curve" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"points":[{"temp":30,"speed":50},{"temp":40,"speed":65},{"temp":50,"speed":80},{"temp":55,"speed":90},{"temp":60,"speed":100},{"temp":70,"speed":100}]}' \
|
||||
| .venv/bin/python -m json.tool >/dev/null
|
||||
echo "Curve PUT: OK"
|
||||
|
||||
curl -sf -X POST "http://127.0.0.1:${GPU_FAN_PORT}/api/mode" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mode":"manual","speed":100}' >/dev/null
|
||||
echo "Mode manual 100%: OK"
|
||||
|
||||
kill $APP_PID 2>/dev/null || true
|
||||
trap - EXIT
|
||||
|
||||
echo ""
|
||||
if sudo -n true 2>/dev/null; then
|
||||
echo "=== 4. Fan write (root) ==="
|
||||
sudo -n env CURVE_PATH="$CURVE_PATH" .venv/bin/python -c "
|
||||
from pathlib import Path
|
||||
from fan_controller import FanController
|
||||
c = FanController(Path('$CURVE_PATH'), 0, 2.0)
|
||||
c.init_nvml()
|
||||
c.set_mode('manual', 50)
|
||||
m = c.update_once()
|
||||
print(f\"Applied: {m['temperature_c']}C -> {m['target_speed_pct']}%\")
|
||||
c.set_mode('auto')
|
||||
c.update_once()
|
||||
c.shutdown()
|
||||
print('OK')
|
||||
"
|
||||
else
|
||||
echo "=== 4. Fan write (root) — SKIP (sudo needs password) ==="
|
||||
echo " Run: sudo scripts/install.sh && sudo systemctl start gpu-fan"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All automated checks passed."
|
||||
Reference in New Issue
Block a user