Files
club-3090/scripts/preflight.sh
T
noonghunnaandClaude Opus 4.7 abc06c3e33 UX polish: pre-flight checks + cards-first wizard + PNG embeds
- scripts/preflight.sh (new) — sourceable library: docker, GPU >= N,
  disk free, GPU-idle warning, running-container note. Each error has
  an actionable Fix: hint instead of a cryptic mid-run crash.
- scripts/setup.sh + scripts/launch.sh wire pre-flight in early.
  launch.sh adds --no-preflight escape hatch.
- launch.sh wizard inverted: cards → workload → auto-pick engine.
  Newcomers can answer "how many GPUs" and "what do I want to do" but
  rarely "vLLM or llama.cpp" — engine falls out of the pick with a
  one-paragraph why. --engine override still works (filters the
  workload list to that engine).
- Embedded charts swapped SVG → PNG in README + SINGLE_CARD +
  DUAL_CARD + qwen3.6-27b/README. Clicking a PNG on GitHub opens a
  viewable image; SVGs open as raw XML. SVG remains the editable
  source — re-export PNG when SVG changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-29 14:29:19 +00:00

130 lines
5.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
#
# Pre-flight checks library. Sourced by setup.sh and launch.sh — not run
# directly. Functions return 0 on success, 1 on failure (caller decides
# whether to exit). Soft warnings print and return 0.
#
# Functions:
# preflight_docker — docker binary + 'docker compose' subcommand work
# preflight_gpu [min] — nvidia-smi works, GPU detected, count >= min
# preflight_disk <path> <gb>— free space at path covers <gb> gigabytes
# preflight_gpu_idle — warn if GPUs have significant VRAM already in use
# preflight_running — warn if a club-3090 container is already up
#
# Style: each function prints one or more "[preflight] ..." lines.
# Hard failures get a one-line ERROR + a "Fix:" hint.
# Avoid double-sourcing.
[[ -n "${_PREFLIGHT_LOADED:-}" ]] && return 0
_PREFLIGHT_LOADED=1
preflight_docker() {
if ! command -v docker >/dev/null 2>&1; then
echo "[preflight] ERROR: 'docker' not found in PATH." >&2
echo " Fix: install Docker — https://docs.docker.com/engine/install/" >&2
return 1
fi
if ! docker compose version >/dev/null 2>&1; then
echo "[preflight] ERROR: 'docker compose' subcommand not available." >&2
echo " Fix: install Docker Compose v2 plugin (legacy 'docker-compose' is unsupported)." >&2
return 1
fi
if ! docker info >/dev/null 2>&1; then
echo "[preflight] ERROR: 'docker info' failed — daemon not running or no permission." >&2
echo " Fix: 'sudo systemctl start docker' OR add your user to the 'docker' group" >&2
echo " ('sudo usermod -aG docker \$USER' + log out/in)." >&2
return 1
fi
echo "[preflight] docker: $(docker --version | awk '{print $3}' | tr -d ',') (compose v2 ok)"
return 0
}
preflight_gpu() {
local min_count="${1:-1}"
if ! command -v nvidia-smi >/dev/null 2>&1; then
echo "[preflight] ERROR: 'nvidia-smi' not found — no NVIDIA driver detected." >&2
echo " Fix: install NVIDIA driver R550+ (CUDA 12.4+)." >&2
return 1
fi
local gpu_lines
gpu_lines=$(nvidia-smi -L 2>/dev/null || true)
local gpu_count
gpu_count=$(echo "$gpu_lines" | grep -c '^GPU ' || true)
if [[ "$gpu_count" -lt "$min_count" ]]; then
echo "[preflight] ERROR: needs ${min_count} GPU(s), found ${gpu_count}." >&2
if [[ "$gpu_count" -eq 0 ]]; then
echo " Fix: confirm 'nvidia-smi' lists your GPU(s); check driver/PCIe wiring." >&2
else
echo " Fix: pick a single-card variant, or install/wire the second GPU." >&2
fi
return 1
fi
echo "[preflight] gpu: ${gpu_count}× detected"
echo "$gpu_lines" | sed 's/^/[preflight] /'
# nvidia-container-toolkit check — needed for docker GPU access.
if ! docker info 2>/dev/null | grep -qi 'Runtimes:.*nvidia'; then
echo "[preflight] WARN: Docker doesn't list the 'nvidia' runtime. If 'docker compose up' fails" >&2
echo " with 'unknown runtime' or 'could not select device driver', install:" >&2
echo " https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/" >&2
fi
return 0
}
preflight_disk() {
local path="$1"
local need_gb="$2"
# Walk up to find an existing parent (path may not exist yet).
while [[ -n "$path" && ! -d "$path" ]]; do
path="$(dirname "$path")"
done
local avail_kb
avail_kb=$(df -Pk "$path" 2>/dev/null | awk 'NR==2 {print $4}')
if [[ -z "$avail_kb" ]]; then
echo "[preflight] WARN: could not check free space at ${path}" >&2
return 0
fi
local avail_gb=$(( avail_kb / 1024 / 1024 ))
if [[ "$avail_gb" -lt "$need_gb" ]]; then
echo "[preflight] ERROR: only ${avail_gb} GB free at ${path}, need ~${need_gb} GB." >&2
echo " Fix: free space, or set MODEL_DIR=<path-on-larger-volume> and re-run." >&2
return 1
fi
echo "[preflight] disk: ${avail_gb} GB free at ${path} (need ~${need_gb} GB)"
return 0
}
preflight_gpu_idle() {
command -v nvidia-smi >/dev/null 2>&1 || return 0
local mem_used_lines
mem_used_lines=$(nvidia-smi --query-gpu=index,memory.used --format=csv,noheader,nounits 2>/dev/null || true)
[[ -z "$mem_used_lines" ]] && return 0
local warned=0
while IFS=, read -r idx used; do
used=$(echo "$used" | tr -d ' ')
# Threshold: 1 GiB. Below that is desktop / X server / kernel modules — fine.
if [[ "$used" -gt 1024 ]]; then
if [[ $warned -eq 0 ]]; then
echo "[preflight] WARN: GPU(s) already have significant VRAM in use:" >&2
warned=1
fi
echo "[preflight] GPU $idx: ${used} MiB in use" >&2
fi
done <<< "$mem_used_lines"
if [[ $warned -eq 1 ]]; then
echo "[preflight] Boot may OOM. Free VRAM with 'nvidia-smi' / 'docker stop ...' first." >&2
fi
return 0
}
preflight_running() {
command -v docker >/dev/null 2>&1 || return 0
local running
running=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^(vllm-qwen36-27b|llama-cpp-qwen36-27b)' || true)
if [[ -n "$running" ]]; then
echo "[preflight] note: a club-3090 container is already running:"
echo "$running" | sed 's/^/[preflight] /'
echo "[preflight] 'switch.sh' will bring it down before booting the new variant."
fi
return 0
}