_entrypoint_discovery_test.sh 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env bash
  2. # Runs image/discover.sh against mentatd status taken from the four GLM boxes
  3. # (fixtures/mentat, addresses moved to the documentation ranges), with
  4. # mentat_query answering from the fixtures and sleep stubbed out. Needs only
  5. # bash and python3. Exit status is the number of failures.
  6. set -euo pipefail
  7. here=$(cd "$(dirname "$0")" && pwd)
  8. disc="$here/../../image/discover.sh"
  9. tmp=$(mktemp -d)
  10. trap 'rm -rf "$tmp"' EXIT
  11. fails=0
  12. check() {
  13. if [[ "$2" == "$3" ]]; then echo " ok $1"
  14. else echo " FAIL $1: got '$2', want '$3'"; fails=$(( fails + 1 )); fi
  15. }
  16. # One box's boot as far as the entrypoint takes discovery, in a clean
  17. # environment. $1 is the fixture directory, $2 the box (the last octet of its
  18. # address), the rest VAR=value settings from .env. Both waits are bounded, so
  19. # a broken parse ends in a failure while sleep is stubbed. Prints
  20. # VLLM_HOST_IP|FABRIC_SUBNETS|CLUSTER_SUBNET|MENTAT_NODE_IP|HEAD_HOST|ROLE|queries
  21. # on stdout, and the entrypoint's own messages on stderr.
  22. boot() {
  23. local fx=$1 node=$2; shift 2
  24. : > "$tmp/queries"
  25. env -i PATH="$PATH" DISC="$disc" FX="$fx" NODE="$node" QLOG="$tmp/queries" \
  26. TP=4 MENTAT_GROUP=glm53 RAY_ADDRESS=127.0.0.1:6379 \
  27. FABRIC_WAIT_S=600 WORKER_WAIT_S=600 "$@" bash -c '
  28. set -euo pipefail
  29. . "$DISC"
  30. mentat_query() {
  31. echo "$1" >> "$QLOG"
  32. case "$1" in
  33. local) cat "$FX/local-$NODE.json" 2>/dev/null ;;
  34. group) cat "$FX/group-glm53.json" 2>/dev/null ;;
  35. esac
  36. }
  37. sleep() { :; }
  38. # As entrypoint.sh does, in order.
  39. _elect=""
  40. [[ -z "${ROLE:-}" && -z "${HEAD_HOST:-}" ]] && _elect=1
  41. discover_network >&2
  42. CLUSTER_SUBNET="${CLUSTER_SUBNET:-${FABRIC_SUBNETS%% *}}"
  43. if [[ -n "$_elect" ]]; then elect_head >&2; else fixed_role; fi
  44. echo "${VLLM_HOST_IP:-}|${FABRIC_SUBNETS:-}|${CLUSTER_SUBNET:-}|${MENTAT_NODE_IP:-}|${HEAD_HOST:-}|${ROLE:-}|$(sort -u "$QLOG" | tr "\n" " ")"
  45. '
  46. }
  47. # A copy of the fixtures with $2 (python, `local` and `group` as dicts keyed
  48. # by box) applied, in directory $1.
  49. variant() {
  50. mkdir -p "$1"
  51. python3 - "$here/fixtures/mentat" "$1" "$2" <<'PY'
  52. import json, os, sys
  53. src, dst, edit = sys.argv[1:]
  54. local = {n: json.load(open(f"{src}/local-{n}.json")) for n in ("36", "70", "77", "93")}
  55. group = json.load(open(f"{src}/group-glm53.json"))
  56. agents = group["groups"]["glm53"]["agents"]
  57. exec(edit)
  58. for n, d in local.items():
  59. json.dump(d, open(f"{dst}/local-{n}.json", "w"))
  60. json.dump(group, open(f"{dst}/group-glm53.json", "w"))
  61. PY
  62. }
  63. echo "== all four boxes, as the fleet tags them today (one rdma root)"
  64. for n in 36 70 77 93; do
  65. role=worker; [[ $n == 36 ]] && role=head
  66. check "box .$n" "$(boot "$here/fixtures/mentat" $n 2>/dev/null)" \
  67. "192.0.2.$n|198.18.0.|198.18.0.|192.0.2.$n|192.0.2.36|$role|group local "
  68. done
  69. boot "$here/fixtures/mentat" 70 2>&1 >/dev/null | grep '^election:' | sed 's/^/ /'
  70. echo "== both PCIe roots tagged rdma, listed out of order"
  71. variant "$tmp/roots" '
  72. for n, d in local.items():
  73. a = f"198.19.0.{n}"
  74. d["addrs"].insert(1, a)
  75. d["addr_tags"][a] = ["connectx", "rdma"]
  76. d["addr_ifaces"][a] = "enP2p1s0f1np1"'
  77. for n in 36 93; do
  78. check "box .$n prefixes" "$(boot "$tmp/roots" $n 2>/dev/null | cut -d'|' -f2,3)" \
  79. "198.18.0. 198.19.0.|198.18.0."
  80. done
  81. echo "== nothing tagged lan: VLLM_HOST_IP falls back to the daemon's node_ip"
  82. variant "$tmp/nolan" 'local["70"]["addr_tags"]["192.0.2.70"] = []'
  83. check "box .70" "$(boot "$tmp/nolan" 70 2>/dev/null | cut -d'|' -f1)" "192.0.2.70"
  84. echo "== a gone agent and a register-only agent below the lowest box"
  85. variant "$tmp/stale" '
  86. agents["glm53@glm53@192.0.2.5"] = dict(agents["glm53@glm53@192.0.2.36"],
  87. node_ip="192.0.2.5", alive=False, gone_since_ms=1790624000000)
  88. agents["glm53@glm53-api@192.0.2.4"] = dict(agents["glm53@glm53@192.0.2.36"],
  89. node_ip="192.0.2.4", machine={"cpus": 20, "gpus": [], "memory": 0})'
  90. for n in 36 77; do
  91. role=worker; [[ $n == 36 ]] && role=head
  92. check "box .$n" "$(boot "$tmp/stale" $n 2>/dev/null | cut -d'|' -f5,6)" "192.0.2.36|$role"
  93. done
  94. echo "== fewer than TP live agents: keeps waiting, then WORKER_WAIT_S ends it"
  95. variant "$tmp/three" 'agents["glm53@glm53@192.0.2.77"]["alive"] = False'
  96. set +e
  97. out=$(boot "$tmp/three" 70 WORKER_WAIT_S=65 2>&1); rc=$?
  98. set -e
  99. check "exit status" "$rc" 1
  100. check "waited" "$(grep -c '^electing: waiting for 4 agents in group glm53, have 3' <<< "$out")" 2
  101. check "reason" "$(grep -o 'FATAL: only 3 of 4 agents.*' <<< "$out")" \
  102. "FATAL: only 3 of 4 agents in group glm53 after 65s (192.0.2.36 192.0.2.70 192.0.2.93)"
  103. echo "== mentatd not answering, or no rdma address: FABRIC_WAIT_S ends the wait"
  104. set +e
  105. out=$(boot "$tmp/none" 70 FABRIC_WAIT_S=30 2>&1); rc=$?
  106. set -e
  107. check "no daemon" "$rc $(grep -c '^FATAL: no answer from mentatd' <<< "$out")" "1 1"
  108. variant "$tmp/nordma" 'local["70"]["addr_tags"]["198.18.0.1"] = ["connectx"]'
  109. set +e
  110. out=$(boot "$tmp/nordma" 70 FABRIC_WAIT_S=30 2>&1); rc=$?
  111. set -e
  112. check "no rdma" "$rc $(grep -c '^FATAL: mentatd lists no address tagged rdma' <<< "$out")" "1 1"
  113. echo "== explicit settings skip discovery"
  114. check "all four set" \
  115. "$(boot /nonexistent 70 ROLE=worker HEAD_HOST=192.0.2.93 VLLM_HOST_IP=192.0.2.70 CLUSTER_SUBNET=10.0.0. 2>/dev/null)" \
  116. "192.0.2.70||10.0.0.||192.0.2.93|worker|"
  117. check "HEAD_HOST alone: a box that is not HEAD_HOST works" \
  118. "$(boot /nonexistent 70 HEAD_HOST=192.0.2.93 VLLM_HOST_IP=192.0.2.70 CLUSTER_SUBNET=10.0.0. 2>/dev/null | cut -d'|' -f5-)" \
  119. "192.0.2.93|worker|"
  120. check "HEAD_HOST alone: the box at HEAD_HOST leads" \
  121. "$(boot /nonexistent 93 HEAD_HOST=192.0.2.93 VLLM_HOST_IP=192.0.2.93 CLUSTER_SUBNET=10.0.0. 2>/dev/null | cut -d'|' -f5-)" \
  122. "192.0.2.93|head|"
  123. check "roles set, networking from mentat" \
  124. "$(boot "$here/fixtures/mentat" 70 ROLE=worker HEAD_HOST=192.0.2.93 2>/dev/null)" \
  125. "192.0.2.70|198.18.0.|198.18.0.||192.0.2.93|worker|local "
  126. check "networking set, roles elected" \
  127. "$(boot "$here/fixtures/mentat" 93 VLLM_HOST_IP=192.0.2.93 CLUSTER_SUBNET=10.0.0. 2>/dev/null)" \
  128. "192.0.2.93||10.0.0.|192.0.2.93|192.0.2.36|worker|group local "
  129. check "FABRIC_SUBNETS alone names CLUSTER_SUBNET" \
  130. "$(boot /nonexistent 70 ROLE=worker HEAD_HOST=192.0.2.93 VLLM_HOST_IP=192.0.2.70 "FABRIC_SUBNETS=10.0.0. 10.0.1." 2>/dev/null)" \
  131. "192.0.2.70|10.0.0. 10.0.1.|10.0.0.||192.0.2.93|worker|"
  132. echo "$fails failure(s)"
  133. exit "$fails"