Files
claudetools/clients/prairie-schooner/verify-cutover.sh
Howard Enos 941de499c2 sync: auto-sync from HOWARD-HOME at 2026-07-14 19:13:30
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-07-14 19:13:30
2026-07-14 19:14:01 -07:00

74 lines
4.9 KiB
Bash

#!/usr/bin/env bash
# Prairie Schooner — post-cutover verification (fire after the morning cable swap)
# Usage: bash clients/prairie-schooner/verify-cutover.sh
# Read-only. Dispatches checks via GuruRMM to TPS-TINA (network/UNC/Q:) and TPS-SVR (services).
set -u
cd "$(git rev-parse --show-toplevel)" || exit 1
eval "$(bash .claude/scripts/rmm-auth.sh 2>/dev/null)" || { echo "[ERROR] RMM auth failed"; exit 1; }
AGENTS=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN")
resolve(){ echo "$AGENTS" | jq -r --arg h "$1" '[.[]|select(.hostname|ascii_downcase==($h|ascii_downcase))][0].id // empty'; }
TINA=$(resolve TPS-Tina); SVR=$(resolve TPS-SERVER)
[ -z "$TINA" ] || [ -z "$SVR" ] && { echo "[ERROR] could not resolve agents (TINA=$TINA SERVER=$SVR)"; exit 1; }
echo "[INFO] TPS-Tina=$TINA TPS-SERVER=$SVR"
WS_SYS='
$ErrorActionPreference="Continue"
$ip=Get-NetIPConfiguration | Where-Object{$_.IPv4DefaultGateway} | Select-Object -First 1
Write-Output ("IP: " + $ip.IPv4Address.IPAddress + " GW: " + $ip.IPv4DefaultGateway.NextHop)
Write-Output ("DNS: " + (($ip.DNSServer | ForEach-Object{$_.ServerAddresses}) -join ", "))
Write-Output ("GW ping: " + (Test-Connection 192.168.1.1 -Count 1 -Quiet))
Write-Output ("Internet ping 1.1.1.1: " + (Test-Connection 1.1.1.1 -Count 1 -Quiet))
try{$r=Resolve-DnsName tps.local -Server 192.168.1.125 -ErrorAction Stop; Write-Output ("DNS via .125 tps.local: OK -> " + (($r|ForEach-Object{$_.IPAddress}) -join ","))}catch{Write-Output "DNS via .125: FAIL"}
try{$r=Resolve-DnsName tps.local -Server 192.168.1.135 -ErrorAction Stop; Write-Output "DNS via .135: OK"}catch{Write-Output "DNS via .135: FAIL"}
Write-Output ("UNC \\tps-server\Quickbooks (LIVE QB path): " + (Test-Path "\\tps-server\Quickbooks"))
Write-Output ("UNC \\tps-svr\Share (staging): " + (Test-Path "\\tps-svr\Share"))
foreach($d in @("192.168.1.141","192.168.1.142","192.168.1.146","192.168.1.145")){ Write-Output ("ping " + $d + ": " + (Test-Connection $d -Count 1 -Quiet)) }
$c=New-Object Net.Sockets.TcpClient; $h=$c.BeginConnect("192.168.1.145",443,$null,$null)
Write-Output ("NVR 443: " + ($h.AsyncWaitHandle.WaitOne(1500) -and $c.Connected)); $c.Close()
$ext=(Resolve-DnsName myip.opendns.com -Server resolver1.opendns.com -ErrorAction SilentlyContinue).IPAddress
Write-Output ("Public egress: " + $ext + " (SonicWall was 184.176.147.183 - should be DIFFERENT now)")'
WS_USER='net use | Select-String "Q:"
Write-Output ("Q:\ accessible: " + (Test-Path Q:\))
Write-Output ("company file visible: " + (Test-Path "Q:\schoonerQB2025.QBW"))'
SVR_SYS='
Get-Service | Where-Object{$_.Name -like "QBDBMgr*" -or $_.Name -like "QBCFMonitor*" -or $_.Name -eq "DNS" -or $_.Name -eq "NTDS"} | ForEach-Object{ Write-Output ($_.Name + ": " + $_.Status) }
Get-SmbShare | Where-Object{$_.Name -eq "Quickbooks"} | ForEach-Object{ Write-Output ("share " + $_.Name + " -> " + $_.Path) }
Get-SmbSession | Group-Object ClientComputerName | ForEach-Object{ Write-Output ("SMB client: " + $_.Name + " (" + $_.Count + ")") }
Write-Output ("Internet: " + (Test-Connection 1.1.1.1 -Count 1 -Quiet))'
dispatch(){ # agent_id script timeout [context]
local pl
if [ "${4:-}" = "user" ]; then
pl=$(jq -n --arg cmd "$2" --argjson to "$3" '{command_type:"powershell",command:$cmd,timeout_seconds:$to,context:"user_session"}')
else
pl=$(jq -n --arg cmd "$2" --argjson to "$3" '{command_type:"powershell",command:$cmd,timeout_seconds:$to}')
fi
curl -s -X POST "$RMM/api/agents/$1/command" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$pl" | jq -r '.command_id // empty'
}
poll(){ local R ST; for i in $(seq 1 24); do sleep 5
R=$(curl -s "$RMM/api/commands/$1" -H "Authorization: Bearer $TOKEN"); ST=$(echo "$R"|jq -r '.status')
case "$ST" in completed|failed|cancelled|interrupted) break;; esac; done
echo "== status: $ST (exit $(echo "$R"|jq -r '.exit_code'))"
echo "$R" | jq -r '.stdout // ""'
local E=$(echo "$R" | jq -r '.stderr // ""'); [ -n "$E" ] && { echo "-- stderr --"; echo "$E"; }
}
C1=$(dispatch "$TINA" "$WS_SYS" 90)
C2=$(dispatch "$TINA" "$WS_USER" 60 user)
C3=$(dispatch "$SVR" "$SVR_SYS" 60)
echo "[INFO] dispatched: tina-net=$C1 tina-user=$C2 svr=$C3"
echo; echo "##### TPS-TINA network/UNC #####"; poll "$C1"
echo; echo "##### TPS-TINA Q: mapping (user session — needs someone logged in) #####"; poll "$C2"
echo; echo "##### TPS-SERVER (old, still the QB host) services/shares #####"; poll "$C3"
bash .claude/scripts/post-bot-alert.sh "[RMM] Howard ran post-cutover verification on TPS-Tina + TPS-SVR (Prairie Schooner UDM swap) -> cmd:${C1:0:8},${C2:0:8},${C3:0:8}" >/dev/null 2>&1
echo
echo "[INFO] NETWORK-SWAP-ONLY pass criteria: GW ping True, internet True, DNS .125 + .135 OK,"
echo "[INFO] UNC \\\\tps-server\\Quickbooks True, Q: -> \\\\tps-server\\Quickbooks + company file True,"
echo "[INFO] QBDBMgr Running on TPS-SERVER, phones+NVR ping True, egress != 184.176.147.183."