Per maintainer call: "cluster" conventionally means multiple networked machines (a non-goal here — LiteLLM fronts multi-host) and is best reserved for a future enterprise/multi-node meaning. "Pod" is the accurate analogy for what this is — one model on a GPU subset on ONE host (k8s/RunPod sense). The capability is unchanged; only the name. Scoped rename (cluster→pod, case-aware) across the pod feature ONLY: - scripts/cluster.sh → scripts/pod.sh; test-cluster-cli.sh → test-pod-cli.sh; docs/CLUSTERS.md → docs/PODS.md - estate_cli.py verbs + wording; app.py (ClusterCreateScreen→PodCreateScreen, action_new_cluster→new_pod, _populate_clusters→_populate_pods, #cluster-view →#pod-view, the [N] help/empty-state text); services.py cluster_create_plan →pod_create_plan; data.py kind cluster_create→pod_create; tests + doc pointers (HARDWARE/MULTI_CARD/README/c3-README) - UNTOUCHED (unrelated "cluster"): compat.py + test-profiles-compat.sh (the VRAM-topology classifier), services.py:1863 / test_services.py (the scene- table "cluster by group" verb), older docs, .venv Also folds in the [N] discoverability fix (n was already bound to serving_switch — moved to N; empty-estate now shows a "no pods — [N] new pod" affordance + a help entry) and a heterogeneous-rig section in PODS.md: one homogeneous pod per card family (2×3090 · GB10 · 6000 Pro) is the clean pattern — mixing families in one TP pod makes NCCL wait on the slowest + wastes VRAM; a worked 2-pod lifecycle walkthrough. Verified: test-pod-cli + estate/gpu/profiles guards green; 25 c3 pod/binding + 239 fast tests green; pod.sh live create/list/D1-reject on 2×3090; zero stray "cluster" in pod files (scene-verb preserved); no CLUSTERS.md links left; PODS.md leak-clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm
56 lines
1.8 KiB
Bash
Executable File
56 lines
1.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# pod.sh — GPU-pod management (#610 Phase A′).
|
||
#
|
||
# A "pod" = a named model on a chosen GPU set + port (an estate instance).
|
||
# This is the ergonomic front over the estate CLI (estate_cli.py owns the
|
||
# schema, validate_estate, kv-calc fit, and boot/down — ONE validation path
|
||
# shared with hand-written estate files and, later, the c3 wizard).
|
||
#
|
||
# Usage:
|
||
# bash scripts/pod.sh create <name> --gpus 1,2 --slug vllm/dual [--port N]
|
||
# bash scripts/pod.sh list [--json]
|
||
# bash scripts/pod.sh status [--json]
|
||
# bash scripts/pod.sh up <name> # boot just this pod
|
||
# bash scripts/pod.sh down <name> # stop just this pod
|
||
# bash scripts/pod.sh rm <name> # remove from the estate file
|
||
#
|
||
# The artifact is the estate file (default scripts/lib/profiles/estate.yml;
|
||
# override with --file). GPU indices stay index-based in the file and are
|
||
# resolved to UUIDs at boot (#610 Phase A) so pods land on the cards they
|
||
# claimed on both container runtimes (classic nvidia + CDI/NixOS).
|
||
set -euo pipefail
|
||
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
ESTATE_CLI="${ROOT_DIR}/scripts/lib/profiles/estate_cli.py"
|
||
|
||
usage() {
|
||
sed -n '2,26p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||
}
|
||
|
||
cmd="${1:-}"
|
||
[[ -n "$cmd" ]] || { usage; exit 2; }
|
||
shift || true
|
||
|
||
case "$cmd" in
|
||
create|list|status|rm)
|
||
exec python3 "$ESTATE_CLI" "$cmd" "$@"
|
||
;;
|
||
up)
|
||
name="${1:-}"; shift || true
|
||
[[ -n "$name" ]] || { echo "pod.sh up <name>" >&2; exit 2; }
|
||
exec python3 "$ESTATE_CLI" boot --only "$name" "$@"
|
||
;;
|
||
down)
|
||
name="${1:-}"; shift || true
|
||
[[ -n "$name" ]] || { echo "pod.sh down <name>" >&2; exit 2; }
|
||
exec python3 "$ESTATE_CLI" down --only "$name" "$@"
|
||
;;
|
||
-h|--help|help)
|
||
usage
|
||
;;
|
||
*)
|
||
echo "pod.sh: unknown command '$cmd'" >&2
|
||
usage
|
||
exit 2
|
||
;;
|
||
esac
|