| 1 | #!/usr/bin/env bash |
| 2 | # scripts/region-service-gate.sh <probe-host> <expected-version> [<edge-eip> ...] |
| 3 | # |
| 4 | # Nearest-region spec §17 step 6: before CONSOLE_APP_REGIONS goes on, every |
| 5 | # eligible region must serve a fresh probe instance through the REAL public |
| 6 | # path — from outside through public DNS (skip with GATE_SKIP_PUBLIC=1), and |
| 7 | # through every armed edge that is NOT the instance's box. Passes only on |
| 8 | # 2xx with X-Carlos-Version equal to the deployed build. Proxies are |
| 9 | # disabled and ~/.curlrc ignored, and each explicit-edge check verifies it |
| 10 | # connected to the EIP it named, so no intermediary can stand in for an |
| 11 | # edge. GATE_PORT and GATE_INSECURE exist for tests only. |
| 12 | set -uo pipefail |
| 13 | host="${1:?usage: region-service-gate.sh <probe-host> <expected-version> [<edge-eip> ...]}" |
| 14 | want="${2:?usage: region-service-gate.sh <probe-host> <expected-version> [<edge-eip> ...]}" |
| 15 | shift 2 |
| 16 | port="${GATE_PORT:-443}" |
| 17 | insecure="" |
| 18 | [ "${GATE_INSECURE:-}" = 1 ] && insecure="-k" |
| 19 | unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY all_proxy |
| 20 | hdr="$(mktemp "${TMPDIR:-/tmp}/region-gate.XXXXXX")" |
| 21 | trap 'rm -f "$hdr"' EXIT |
| 22 | fail=0 |
| 23 | check() { # <label> <expected-ip or ""> [curl args...] |
| 24 | local label="$1" eip="$2"; shift 2 |
| 25 | local out res count ip status version |
| 26 | # -q must be first: it stops curl reading ~/.curlrc. $insecure is |
| 27 | # unquoted on purpose so that empty expands to nothing (bash 3.2 safe). |
| 28 | # The status is curl's own final %{http_code}, never a header that happens |
| 29 | # to start with "HTTP". The version is read only from the final response's |
| 30 | # header block: -D also dumps 1xx blocks (103 Early Hints), so the block |
| 31 | # starts again at every real status line ("HTTP/x.y NNN"). |
| 32 | out="$(curl -q -s $insecure --noproxy '*' -D "$hdr" -o /dev/null -w '%{remote_ip} %{http_code}' --max-time 20 "$@" "https://$host:$port/")" || { |
| 33 | echo "FAIL $label: request failed"; fail=1; return; } |
| 34 | read -r ip status <<<"$out" |
| 35 | if [ -n "$eip" ] && [ "$ip" != "$eip" ]; then |
| 36 | echo "FAIL $label: connected to $ip, not $eip"; fail=1; return |
| 37 | fi |
| 38 | # n counts the version headers in the final block, apart from their values, |
| 39 | # so an empty value still counts. More than one is a failure. |
| 40 | res="$(awk -F': *' '/^HTTP\/[0-9.]+ [0-9][0-9][0-9]/ {n=0; v=""; next} tolower($1)=="x-carlos-version" {gsub(/\r/,"",$2); v = (n ? v "," $2 : $2); n++} END {print n+0, v}' "$hdr")" |
| 41 | count="${res%% *}"; version="${res#* }" |
| 42 | if [[ "$status" != 2* ]]; then echo "FAIL $label: status $status"; fail=1; return; fi |
| 43 | if [ "$count" != 1 ] || [ "$version" != "$want" ]; then echo "FAIL $label: X-Carlos-Version '$version', want '$want'"; fail=1; return; fi |
| 44 | echo "ok $label: $status $version" |
| 45 | } |
| 46 | [ "${GATE_SKIP_PUBLIC:-}" = 1 ] || check "public DNS" "" |
| 47 | for eip in "$@"; do |
| 48 | check "via edge $eip" "$eip" --resolve "$host:$port:$eip" |
| 49 | done |
| 50 | exit "$fail" |
| 51 | |