438484fdca
v2-ci / unit-tests (push) Has been cancelled
Probe 'failover <primary> <backup> <mode> <dir>' drives ScadaBridge's own DataConnectionActor (production primary/backup machine, real DataConnectionFactory, default DataConnectionOptions, FailoverRetryCount 3) against two servers; run.py loses the primary (SIGKILL or SIGSTOP) once the probe reports a steady primary, and the probe requires Bad quality on loss, "Connected to backup", the backup's own value, a fresh ConditionRefresh replaying the native condition, and a write via the backup. rig-failover.sh runs the same probe against the local docker-dev central pair. Matrix legs gain a UNS subscription case and a Server-object alarm subscription on the reconnected session whose ConditionRefresh must replay the active condition (11 cases). run.py gains --versions, --suites, --failover-modes and --failover-loss. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
47 lines
2.5 KiB
Bash
Executable File
47 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ScadaBridge#125 — the failover probe against the REAL docker-dev OtOpcUa pair (central-1 :4840 /
|
|
# central-2 :4841), not the in-process fixture. ScadaBridge's DataConnectionActor connects to central-1
|
|
# as primary and central-2 as backup; once it reports a steady primary, central-1's container is killed
|
|
# (docker kill = abrupt loss) and the probe must land on central-2 with Good values and a fresh
|
|
# ConditionRefresh. central-1 is started again afterwards. LOCAL docker-dev only — never a wonder box.
|
|
#
|
|
# Usage: rig-failover.sh <Probe.dll> <new-result-directory>
|
|
# Anonymous (OpcUa:AllowAnonymous=true on the rig) cannot write there, so writes are off; the rig deploys
|
|
# no active native alarm, so the alarm check is "ConditionRefresh completes on each node" only.
|
|
set -euo pipefail
|
|
probe=$1; out=$2
|
|
primary_container=${RIG_PRIMARY_CONTAINER:-otopcua-dev-central-1-1}
|
|
backup_container=${RIG_BACKUP_CONTAINER:-otopcua-dev-central-2-1}
|
|
mkdir -p "$out"
|
|
for c in "$primary_container" "$backup_container"; do
|
|
mkdir -p "$out/server-certs/$c"
|
|
docker cp "$c:/app/pki/own/certs/." "$out/server-certs/$c/"
|
|
done
|
|
export SCADABRIDGE_PROBE_ANONYMOUS=1
|
|
export SCADABRIDGE_PROBE_SERVER_CERTS="$out/server-certs/$primary_container:$out/server-certs/$backup_container"
|
|
export SCADABRIDGE_PROBE_FAILOVER_TAGS=${RIG_TAGS:-"nsu=https://zb.com/otopcua/raw;s=int3b-mb-01/plc/HR100,nsu=https://zb.com/otopcua/uns;s=a/l/e1/HR5"}
|
|
export SCADABRIDGE_PROBE_FAILOVER_WRITE_TAG=none
|
|
export SCADABRIDGE_PROBE_FAILOVER_BACKUP_VALUE=none
|
|
export SCADABRIDGE_PROBE_FAILOVER_ALARM_PREFIX=none
|
|
dotnet "$probe" failover opc.tcp://localhost:${RIG_PRIMARY_PORT:-4840} opc.tcp://localhost:${RIG_BACKUP_PORT:-4841} None "$out/consumer" \
|
|
> "$out/consumer.log" 2>&1 &
|
|
pid=$!
|
|
for _ in $(seq 1 1500); do
|
|
[[ -f "$out/consumer/primary-ready" ]] && break
|
|
kill -0 "$pid" 2>/dev/null || break
|
|
sleep 0.1
|
|
done
|
|
status=0
|
|
if [[ -f "$out/consumer/primary-ready" ]]; then
|
|
python3 -c 'from datetime import datetime, timezone; print(datetime.now(timezone.utc).isoformat())' > "$out/consumer/primary-killed.tmp"
|
|
docker kill "$primary_container" > /dev/null
|
|
mv "$out/consumer/primary-killed.tmp" "$out/consumer/primary-killed"
|
|
wait "$pid" || status=$?
|
|
docker start "$primary_container" > /dev/null
|
|
else
|
|
wait "$pid" || status=$?
|
|
fi
|
|
docker inspect "$primary_container" "$backup_container" --format '{{.Name}} {{.Config.Image}} {{.Image}} {{.State.Status}}' > "$out/containers.txt"
|
|
echo "probe exit $status; result $out/consumer/result.json"
|
|
exit "$status"
|