chore(docker): both rigs' centrals on the shared SQL Server inbound key store; delete sync-inbound-api-keys.sh (superseded); verify-delmia-notifier.sh preflight is now the proof that both nodes see a key minted on one — drill green with no file copy, takeover 28 s

Claude-Session: https://claude.ai/code/session_013L3XdmVii9i5sY4FChU8pB
This commit is contained in:
Joseph Doherty
2026-09-02 23:31:21 -04:00
parent d6fd8c400c
commit a83cc8613d
5 changed files with 36 additions and 54 deletions
+10 -7
View File
@@ -6,11 +6,14 @@ set -euo pipefail
# graceful handover) + rejoin. Requires: seed-delmia-sim.sh + seed-delmia-api.sh already run, and
# DELMIA_API_KEY exported (the token printed by seed-delmia-api.sh).
#
# PREREQUISITE the first run of this script found the hard way (2026-09-02): inbound API keys are a
# PER-NODE SQLite store, so the key minted through the active node does not exist on the standby
# and every call after a takeover answers 401 KeyNotFound. Run `bash docker/sync-inbound-api-keys.sh`
# after seed-delmia-api.sh (and again after re-minting a key). The preflight below lists the key
# via each node's own management API and refuses to start the drill if either node lacks it.
# HISTORY (2026-09-02): the first run of this script found that inbound API keys were a PER-NODE
# SQLite store, so the key minted through the active node did not exist on the standby and every
# call after a takeover answered 401 KeyNotFound (deferred-work register row 108; the rig carried
# a sync-inbound-api-keys.sh file-copy workaround). Both rig centrals now run
# ScadaBridge__InboundApi__ApiKeyStore__Provider=SqlServer (one shared zbauth schema in the config
# DB), so the preflight below — which lists the key via EACH node's own management API — is no
# longer a gate that needs a script to satisfy: it is the proof that a key minted on one node is
# visible on the other without any file copy.
#
# The notifier is run as the managed build (dotnet WWNotifier.dll) from a scratch copy so the
# API key is written to THAT copy's appsettings.json (ScadaBridge:ApiKey) and never into the
@@ -57,12 +60,12 @@ wait_for() { # $1 url $2 path $3 seconds
ACT=$(active); STB=$(other "$ACT")
echo "== active=central-$ACT standby=central-$STB"
echo "== preflight: the notifier's key must be present in BOTH nodes' key stores"
echo "== preflight/proof: the key minted on the active node must be visible from BOTH nodes (shared store, no file copy)"
CLI="$PROJECT_ROOT/src/ZB.MOM.WW.ScadaBridge.CLI/bin/Debug/net10.0/scadabridge"
KEY_ID="${DELMIA_API_KEY#sbk_}"; KEY_ID="${KEY_ID%%_*}"
for n in a b; do
if "$CLI" security api-key list --url "$(url_of "$n")" --format=json --username "${SCADABRIDGE_USERNAME:-multi-role}" --password "${SCADABRIDGE_PASSWORD:-password}" | grep -q "\"keyId\":\"$KEY_ID\""; then echo " central-$n: key $KEY_ID present"
else echo "FAIL: central-$n does not hold key $KEY_ID — run: bash docker/sync-inbound-api-keys.sh $ACT $STB" >&2; exit 1; fi
else echo "FAIL: central-$n does not see key $KEY_ID — is ScadaBridge__InboundApi__ApiKeyStore__Provider=SqlServer set on both centrals (docker-compose.yml)?" >&2; exit 1; fi
done
echo "== A baseline (active first)"; write_cfg "$(url_of "$ACT"),$(url_of "$STB")" "$DELMIA_API_KEY"; notify A YES