NetVM: fleet control script (netvm-fleet.sh) for operators
This commit is contained in:
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# netvm-fleet.sh — operator fleet control over the tailnet.
|
||||
# Run on any tailnet-connected host (laptop, VM) as the operator user.
|
||||
# netvm-fleet.sh topology # egress per node, fleet-wide
|
||||
# netvm-fleet.sh up <node> # bring a node's egress up
|
||||
# netvm-fleet.sh down <node> # bring it down
|
||||
# netvm-fleet.sh ssh <node> # shell on the node
|
||||
# Node names are tailnet hostnames (see NODES.md).
|
||||
# Prereqs: targets provisioned via netvm-provision-edge.sh; this user's SSH
|
||||
# key accepted on targets. Lifecycle runs through the sudoers allowlist
|
||||
# (sudo -n), so it is audit-logged and never blanket root.
|
||||
set -euo pipefail
|
||||
REPO="${NETVM_REPO:-$HOME/Projects/NetVM}"
|
||||
OPERATOR_USER="${OPERATOR_USER:-$(whoami)}"
|
||||
|
||||
nodes() {
|
||||
awk -F'|' '/^\|/ && $2 !~ /node/ && $2 !~ /---/ { n=$2; gsub(/^ +| +$/, "", n); if (n != "") print n }' "$REPO/NODES.md"
|
||||
}
|
||||
|
||||
tail_ip() {
|
||||
NODE="$1" python3 -c "
|
||||
import json, os, subprocess, sys
|
||||
node = os.environ['NODE']
|
||||
st = json.loads(subprocess.run(['tailscale','status','--json'], capture_output=True, text=True).stdout)
|
||||
cands = list(st.get('Peer', {}).values()) + [st.get('Self', {})]
|
||||
for p in cands:
|
||||
names = {p.get('HostName',''), p.get('DNSName','').split('.')[0]}
|
||||
if node in names and p.get('TailscaleIPs'):
|
||||
print(p['TailscaleIPs'][0]); sys.exit(0)
|
||||
sys.exit(1)
|
||||
"
|
||||
}
|
||||
|
||||
run_on() { # <node> <remote-command...>
|
||||
local node="$1"; shift
|
||||
local ip
|
||||
ip=$(tail_ip "$node") || { echo "unknown tailnet node: $node"; exit 1; }
|
||||
ssh -o BatchMode=yes -o ConnectTimeout=15 "${OPERATOR_USER}@${ip}" "$@"
|
||||
}
|
||||
|
||||
cmd="${1:?usage: netvm-fleet.sh topology|up <node>|down <node>|ssh <node>}"
|
||||
case "$cmd" in
|
||||
topology)
|
||||
for n in $(nodes); do
|
||||
printf '== %s ==\n' "$n"
|
||||
run_on "$n" 'sudo -n $HOME/Projects/NetVM/bin/netvm-topology.sh' 2>&1 || echo "unreachable"
|
||||
done
|
||||
;;
|
||||
up|down)
|
||||
node="${2:?usage: netvm-fleet.sh $cmd <node>}"
|
||||
run_on "$node" "sudo -n \$HOME/Projects/NetVM/bin/netvm-node-${cmd}.sh ${node}"
|
||||
;;
|
||||
ssh)
|
||||
node="${2:?usage: netvm-fleet.sh ssh <node>}"
|
||||
ip=$(tail_ip "$node") || { echo "unknown tailnet node: $node"; exit 1; }
|
||||
exec ssh "${OPERATOR_USER}@${ip}"
|
||||
;;
|
||||
*) echo "unknown command: $cmd"; exit 1 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user