Files
club-3090/scripts/maintenance/list-image-pins.sh
T
noonghunnaandClaude Opus 4.7 00366a58d7
Release / release (push) Failing after 53s
reorg: services/ consolidation + gpu-mode under git + ComfyUI + pin tracker + path updates
The dev rig had grown across three home dirs (`/opt/ai/compose/`, `/opt/ai/github/`,
`/home/wasif/`) and three repos (single-3090, dual-3090, club-3090). Disk-out
on `/` (97% used) forced a cleanup; rather than just prune, we consolidated
the layout across the whole stack while we were at it. This commit captures
what landed inside this repo.

Services consolidation:
- services/{ollama,openwebui,litellm,qdrant,searxng}/ migrated in from
  /opt/ai/compose/<svc>/ (zero functional change — same docker-compose.yml).
- services/litellm/config.yaml rewritten: explicit routes for current
  primaries (qwen3.6-27b-autoround → :8010, gemma-4-31b-autoround → :8030).
  Removed `* → ollama/*` wildcard.
- services/comfyui/ migrated in (was /opt/ai/compose/comfyui/) — wired into
  gpu-mode with full mutex against vLLM/SGLang.

scripts/gpu-mode.sh under git:
- Was a loose /opt/ai/gpu-mode.sh outside any repo. Symlinked at
  /usr/local/bin/gpu-mode.
- Five Gemma 4 31B modes added: gemma, gemma-dflash, gemma-int8,
  gemma-dflash-int8, gemma-awq.
- One ComfyUI mode (mutex with all LLM serving).
- prune / prune-all subcommands (safe image prune; aggressive variant adds
  build cache --keep-storage 5GB + dangling networks).
- gpu-mode status now shows Docker disk + /var/lib/docker + /tmp sizes.
- compose_at() passes --env-file <repo>/.env so MODEL_DIR resolves
  regardless of which compose dir gpu-mode cd's into. Fixes the recurring
  "MODEL_DIR not set, defaulting to ../../../../../models-cache" warning.
- stderr no longer swallowed by compose_at() (real errors surface).
- Cross-model VRAM mutex: every Qwen mode stop_all_gemma + stop_comfyui
  and vice-versa.

scripts/maintenance/ — new hygiene-tools subdir:
- list-image-pins.sh: engine-agnostic pin auditor. Scans every compose's
  `image:` line, groups by `<repo>:<tag>`, flags pin-drift (multiple tags
  per repo), ranks composes by patch surface.

Pin tracking:
- docs/UPSTREAM.md gains a "Pinned images" section: table of every pinned
  image, why each pin exists, retirement candidate criteria.
- docs/NIGHTLY_BUMP_RUNBOOK.md (new): 7-step procedure for bumping pinned
  engine images (scope → branch → patch survival → boot → verify-full +
  verify-stress → bench delta → land → retire). Engine-specific notes
  for vLLM nightly hashes, llama.cpp digest pinning, SGLang variants.

Path updates from the engine + model dir consolidation:
- /opt/ai/vllm-src/ → /opt/ai/engines/vllm/primary/
  (in setup.sh, INTERNALS.md, several patch READMEs, docs/HARDWARE.md,
   docs/FAQ.md, docs/DUAL_CARD.md, docs/UPSTREAM.md, models/qwen3.6-27b/
   CHANGELOG.md)
- /mnt/models/gguf/qwen3.6-27b/ → /mnt/models/huggingface/qwen3.6-27b-gguf/
  (in models/qwen3.6-27b/llama-cpp/{compose/single/*.yml, recipes/*.sh,
   README.md}, docs/engines/LLAMA_CPP.md)

CHANGELOG.md narrative gap fill:
- 2026-05-10 entry for this reorg.
- 2026-05-09 entry for compose convention formalization (topology
  promoted to dir level, profile schema, Status enum + Caveats, cliff
  CI swap, Discord launch).
- 2026-05-08 entry for Gemma 4 INT8 PTH unblock + 262K validation.
- 2026-05-07 entry for power-cap-sweep campaign + HARDWARE.md cross-rig
  charts + cross-rig benchmark rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-10 16:57:03 +00:00

137 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# list-image-pins.sh — audit which container images each club-3090 compose pins,
# what patches each compose mounts, and which composes share a pin.
#
# Engine-agnostic — works for vLLM, llama.cpp, SGLang, Luce, xtransformers, or
# any engine whose composes use `image: <repo>:<tag>`. Output groups composes
# by `<repo>:<tag>` so you can see at a glance:
# - which composes share a pin (= safe to bump together)
# - which patches each compose adds (= migration cost per compose)
# - which engines have pin-drift (multiple tags of the same repo)
#
# Usage:
# bash scripts/maintenance/list-image-pins.sh # default: club-3090 root auto-detected
# REPO=/path/to/club-3090 bash scripts/maintenance/list-image-pins.sh
# bash scripts/maintenance/list-image-pins.sh --filter vllm # only show vllm/* repos
#
# When to run:
# - Before bumping an engine pin (see docs/NIGHTLY_BUMP_RUNBOOK.md)
# - After landing a new compose, to verify it joined an existing pin not a new one
# - Periodically to surface accumulated pin sprawl across engines
set -euo pipefail
REPO="${REPO:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
FILTER=""
while [ $# -gt 0 ]; do
case "$1" in
--filter) FILTER="$2"; shift 2 ;;
--filter=*) FILTER="${1#--filter=}"; shift ;;
-h|--help) sed -n '2,21p' "$0"; exit 0 ;;
*) echo "unknown arg: $1" >&2; exit 2 ;;
esac
done
if [ ! -d "$REPO/models" ]; then
echo "error: $REPO does not look like a club-3090 repo (no models/ dir)" >&2
exit 1
fi
CYAN=$'\033[0;36m'
GREEN=$'\033[0;32m'
YELLOW=$'\033[1;33m'
NC=$'\033[0m'
echo ""
if [ -n "$FILTER" ]; then
echo "${CYAN}═══ Image pins across ${REPO} (filter: $FILTER) ═══${NC}"
else
echo "${CYAN}═══ Image pins across ${REPO} ═══${NC}"
fi
echo ""
# Build temp file: image_repo_tag<TAB>compose-relpath<TAB>patch-list
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
shopt -s nullglob
# Walk all engine compose dirs: vllm, llama-cpp, sglang, luce, xtransformers, etc.
# Pattern: models/<model>/<engine>/compose/<topology>/<file>.yml
for f in "$REPO"/models/*/*/compose/*/*.yml "$REPO"/models/*/*/compose/*.yml; do
[ -f "$f" ] || continue
# Extract first `image: <repo>:<tag>` line. Match repo/tag flexibly so we
# cover stable tags (server-cuda), nightly hashes, semver, etc.
image=$(grep -E "^[[:space:]]*image:[[:space:]]+" "$f" 2>/dev/null \
| head -1 \
| sed -E 's/^[[:space:]]*image:[[:space:]]+//' \
| tr -d '"' | awk '{print $1}' || true)
if [ -z "$image" ]; then
continue # No image: line, skip (might be an override-only compose)
fi
# Apply filter if set
if [ -n "$FILTER" ] && [[ "$image" != *"$FILTER"* ]]; then
continue
fi
patches=$(grep -oE "patches/[a-zA-Z0-9_./-]+" "$f" 2>/dev/null \
| sed -E 's|^(patches/[a-zA-Z0-9_-]+).*|\1|' \
| sort -u | tr '\n' ',' | sed 's/,$//' || true)
rel="${f#$REPO/}"
printf "%s\t%s\t%s\n" "$image" "$rel" "${patches:-none}" >> "$tmp"
done
if [ ! -s "$tmp" ]; then
echo "${YELLOW}(no compose files matched)${NC}"
exit 0
fi
# Per-image summary, sorted by repo+tag
echo "${CYAN}── Pin distribution ──${NC}"
printf "%-72s %s\n" "Image" "Composes"
printf "%-72s %s\n" "-----" "--------"
awk -F'\t' '{print $1}' "$tmp" | sort | uniq -c | sort -rn \
| awk '{cnt=$1; $1=""; sub(/^ /, ""); printf "%-72s %d\n", $0, cnt}'
# Highlight engines with pin DRIFT (same repo, multiple tags)
echo ""
echo "${CYAN}── Pin-drift detection ──${NC}"
drift=$(awk -F'\t' '{print $1}' "$tmp" | awk -F: '{print $1}' | sort -u | while read repo; do
ntags=$(awk -F'\t' -v r="$repo" '$1 ~ "^"r":" {print $1}' "$tmp" | sort -u | wc -l)
if [ "$ntags" -gt 1 ]; then
printf " ${YELLOW}%s${NC} has %d distinct tags pinned\n" "$repo" "$ntags"
fi
done)
if [ -n "$drift" ]; then
echo "$drift"
echo " ${YELLOW}^^${NC} consider consolidating to one tag per repo (see docs/NIGHTLY_BUMP_RUNBOOK.md)"
else
echo " ${GREEN}✓ No drift — every repo pins exactly one tag.${NC}"
fi
# Per-pin compose breakdown
echo ""
echo "${CYAN}── Per-pin compose + patch breakdown ──${NC}"
images=$(awk -F'\t' '{print $1}' "$tmp" | sort -u)
for img in $images; do
echo ""
echo "${GREEN}● $img${NC}"
awk -F'\t' -v img="$img" '$1==img {
printf " %-58s patches=%s\n", $2, $3
}' "$tmp" | sort
done
# Patch surface ranking
echo ""
echo "${CYAN}── Patch surface (highest = most expensive to migrate when pin bumps) ──${NC}"
echo ""
awk -F'\t' '$3 != "none" {
n = split($3, a, ",")
print n "\t" $2 "\t" $3
}' "$tmp" | sort -rn | head -10 | awk -F'\t' '{
printf " %d patches %s\n (%s)\n", $1, $2, $3
}'
echo ""
echo "${YELLOW}Tip:${NC} See docs/NIGHTLY_BUMP_RUNBOOK.md for the bump procedure."
echo ""