#!/usr/bin/env bash # Build the Go probe agent and (re)install it on every node listed in data/seed/probes.yaml. # # deploy/bin/probes.sh build cross-compile dist/ip-probe-{darwin-arm64,linux-amd64} # deploy/bin/probes.sh keys print probe ids + keys from the production API (BHS64b) # deploy/bin/probes.sh install [probe_id…] push binary + installer to the node(s) and (re)start the service # deploy/bin/probes.sh status /healthz of every probe # # Sudo passwords for the rented Macs live OUTSIDE the repo in ~/.internetpressure/sudo.txt (" " per # line; nodes with passwordless sudo are simply absent). Keys are read from the production Postgres through # `docker compose run --rm cli probe-key ` on BHS64b and never written to disk here. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" AGENT="$REPO_ROOT/services/probe-agent" SUDO_FILE="$HOME/.internetpressure/sudo.txt" INGEST_URL="${IP_INGEST_URL:-https://$IP_DOMAIN/ingest/v1}" probes_nodes() { # "probe_id node" pairs from the seed python3 - "$REPO_ROOT/data/seed/probes.yaml" <<'EOF' import sys, yaml for p in yaml.safe_load(open(sys.argv[1]))["probes"]: print(p["probe_id"], p["node"]) EOF } probe_key() { compose "run --rm --no-deps -T cli probe-key $1" 2>/dev/null | tail -1 | tr -d '\r'; } sudo_pw() { [[ -f "$SUDO_FILE" ]] && awk -v n="$1" '$1==n {print $2}' "$SUDO_FILE" || true; } install_one() { local pid="$1" node="$2" key="$3" local os arch bin os=$(ssh -n -o BatchMode=yes -o ConnectTimeout=20 "$node" 'uname -s | tr A-Z a-z') || { warn "$node unreachable"; return 1; } arch=$(ssh -n -o BatchMode=yes "$node" 'uname -m') case "$arch" in arm64|aarch64) arch=arm64;; x86_64|amd64) arch=amd64;; esac bin="$AGENT/dist/ip-probe-$os-$arch" [[ -x "$bin" ]] || die "missing $bin (run: probes.sh build)" log "$pid → $node ($os/$arch)" ssh -n -o BatchMode=yes "$node" 'mkdir -p ~/ip-probe/dist ~/ip-probe/deploy/launchd ~/ip-probe/deploy/systemd' scp -q "$bin" "$node:~/ip-probe/dist/" scp -q "$AGENT/deploy/install.sh" "$node:~/ip-probe/deploy/install.sh" scp -q "$AGENT/deploy/launchd/io.internetpressure.probe.plist" "$node:~/ip-probe/deploy/launchd/" scp -q "$AGENT/deploy/systemd/ip-probe.service" "$node:~/ip-probe/deploy/systemd/" local pw; pw=$(sudo_pw "$node") if [[ -n "$pw" ]]; then ssh -n -o BatchMode=yes "$node" "chmod +x ~/ip-probe/deploy/install.sh; printf '%s\n' '$pw' | sudo -S -p '' bash ~/ip-probe/deploy/install.sh '$pid' '$key' '$INGEST_URL' 2>&1 | tail -6" else ssh -n -o BatchMode=yes "$node" "chmod +x ~/ip-probe/deploy/install.sh; sudo -n bash ~/ip-probe/deploy/install.sh '$pid' '$key' '$INGEST_URL' 2>&1 | tail -6" fi } cmd="${1:-status}"; shift || true case "$cmd" in build) (cd "$AGENT" && make build) ;; keys) while read -r pid node; do printf '%-12s %-8s %s\n' "$pid" "$node" "$(probe_key "$pid")"; done < <(probes_nodes) ;; install) want=("$@") while read -r pid node; do if [[ ${#want[@]} -gt 0 ]] && [[ ! " ${want[*]} " =~ " $pid " ]]; then continue; fi key=$(probe_key "$pid") [[ "$key" =~ ^[0-9a-f]{64}$ ]] || { warn "no key for $pid (seed the registry first)"; continue; } install_one "$pid" "$node" "$key" || true done < <(probes_nodes) ;; status) while read -r pid node; do printf '%-12s %-8s ' "$pid" "$node" ssh -n -o BatchMode=yes -o ConnectTimeout=15 "$node" 'curl -s -m 3 http://127.0.0.1:9381/healthz' 2>/dev/null | head -c 200 || printf 'unreachable' echo done < <(probes_nodes) ;; *) die "unknown command $cmd" ;; esac