Files
Rendezvous/scripts/smoke-deployment.sh
KyuubiYoru de753b99e6
quality-gate / quality (push) Successful in 2m47s
quality-gate / container (push) Failing after 2m18s
fix(deploy): validate complete smoke logs (#1)
2026-07-17 00:58:28 +02:00

140 lines
5.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SERVICE_URL="${RENDEZVOUS_SMOKE_HTTP_URL:-http://127.0.0.1:8080/}"
MEDIATOR="${RENDEZVOUS_SMOKE_UDP_ENDPOINT:-127.0.0.1:9050}"
TIMEOUT_SECONDS="${RENDEZVOUS_SMOKE_TIMEOUT_SECONDS:-30}"
LOCAL_KEY="${RENDEZVOUS_SMOKE_LOCAL_KEY:-$ROOT/deploy/compose/secrets/signing-key}"
PROJECT="$ROOT/src/FinalFactory.Rendezvous.TestClient/FinalFactory.Rendezvous.TestClient.csproj"
BUILD_CONFIGURATION="${RENDEZVOUS_SMOKE_CONFIGURATION:-Release}"
GAME_ID="${RENDEZVOUS_SMOKE_GAME_ID:-space-game}"
ENVIRONMENT_ID="${RENDEZVOUS_SMOKE_ENVIRONMENT_ID:-smoke}"
REGION="${RENDEZVOUS_SMOKE_REGION:-local}"
PROTOCOL_VERSION="${RENDEZVOUS_SMOKE_PROTOCOL_VERSION:-1}"
for command in curl dotnet jq mktemp tail; do
command -v "$command" >/dev/null || {
printf 'Missing required command: %s\n' "$command" >&2
exit 2
}
done
if [[ ! "$TIMEOUT_SECONDS" =~ ^[0-9]+$ ]] || (( TIMEOUT_SECONDS < 1 || TIMEOUT_SECONDS > 300 )); then
printf 'RENDEZVOUS_SMOKE_TIMEOUT_SECONDS must be an integer from 1 through 300.\n' >&2
exit 2
fi
if [[ ! "$PROTOCOL_VERSION" =~ ^[0-9]+$ ]] || (( PROTOCOL_VERSION < 1 )); then
printf 'RENDEZVOUS_SMOKE_PROTOCOL_VERSION must be a positive integer.\n' >&2
exit 2
fi
for scoped_value in "$GAME_ID" "$ENVIRONMENT_ID" "$REGION"; do
if [[ -z "$scoped_value" ]]; then
printf 'Smoke game, environment, and region values must not be empty.\n' >&2
exit 2
fi
done
local_credential() {
if [[ "$GAME_ID" != space-game || "$ENVIRONMENT_ID" != smoke \
|| "$REGION" != local || "$PROTOCOL_VERSION" != 1 ]]; then
printf 'The local credential helper supports only space-game/smoke/local protocol 1. Supply RENDEZVOUS_PUBLISHER_CREDENTIAL for any other scope.\n' >&2
exit 2
fi
RENDEZVOUS_SMOKE_LOCAL_KEY="$LOCAL_KEY" \
"$ROOT/scripts/mint-local-publisher-credential.sh"
}
credential="${RENDEZVOUS_PUBLISHER_CREDENTIAL:-}"
if [[ -z "$credential" ]]; then
credential="$(local_credential)"
fi
export RENDEZVOUS_PUBLISHER_CREDENTIAL="$credential"
curl --fail --silent --show-error --max-time 5 "${SERVICE_URL%/}/health/live" >/dev/null
curl --fail --silent --show-error --max-time 5 "${SERVICE_URL%/}/health/ready" >/dev/null
temp_dir="$(mktemp -d)"
host_log="$temp_dir/host.jsonl"
join_log="$temp_dir/join.jsonl"
host_pid=''
sanitize_log() {
jq -Rrc 'fromjson? | {
event: (.event // "unknown"),
status: (.status // "unknown"),
phase: (.phase // "unknown"),
hasListingId: (((.listingId // "") | length) > 0)
}' "$1"
}
cleanup() {
local status="$?"
if [[ -n "$host_pid" ]] && kill -0 "$host_pid" 2>/dev/null; then
kill -TERM "$host_pid" 2>/dev/null || true
wait "$host_pid" 2>/dev/null || true
fi
if [[ "$status" -ne 0 ]]; then
printf 'Deployment smoke failed; sanitized diagnostic events follow.\n' >&2
[[ -f "$host_log" ]] && sanitize_log "$host_log" >&2 || true
[[ -f "$join_log" ]] && sanitize_log "$join_log" >&2 || true
fi
rm -rf "$temp_dir"
return "$status"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
dotnet run --project "$PROJECT" --configuration "$BUILD_CONFIGURATION" --no-build -- \
host --service "$SERVICE_URL" --mediator "$MEDIATOR" \
--game "$GAME_ID" --environment "$ENVIRONMENT_ID" --region "$REGION" --protocol "$PROTOCOL_VERSION" \
--script --json --exit-after-echo --timeout-seconds "$TIMEOUT_SECONDS" \
>"$host_log" 2>&1 &
host_pid="$!"
ready=false
listing_id=''
for ((iteration = 0; iteration < TIMEOUT_SECONDS * 4; iteration++)); do
if listing_id="$(jq -er '
select(.event == "host.ready" and .status == "ready")
| .listingId // empty
' "$host_log" 2>/dev/null | tail -n 1)" && [[ -n "$listing_id" ]]; then
ready=true
break
fi
if ! kill -0 "$host_pid" 2>/dev/null; then
printf 'Host diagnostic stopped before it became ready.\n' >&2
sanitize_log "$host_log" >&2 || true
exit 1
fi
sleep 0.25
done
if [[ "$ready" != true ]]; then
printf 'Host diagnostic did not report a ready listing within %s seconds.\n' "$TIMEOUT_SECONDS" >&2
exit 1
fi
dotnet run --project "$PROJECT" --configuration "$BUILD_CONFIGURATION" --no-build -- \
join --service "$SERVICE_URL" --mediator "$MEDIATOR" \
--game "$GAME_ID" --environment "$ENVIRONMENT_ID" --region "$REGION" --protocol "$PROTOCOL_VERSION" \
--listing "$listing_id" --script --json --timeout-seconds "$TIMEOUT_SECONDS" \
>"$join_log" 2>&1
wait "$host_pid"
host_pid=''
if ! jq -s -e '
any(.[]; .event == "host.direct-traffic" and .status == "verified")
and any(.[]; .event == "host.deregistered" and .status == "complete")
' "$host_log" >/dev/null; then
printf 'Host diagnostic did not complete authenticated traffic and deregistration.\n' >&2
exit 1
fi
if ! jq -s -e '
any(.[]; .event == "join.direct-traffic" and .status == "verified")
and any(.[]; .event == "join.outcome-report" and .status == "accepted")
' "$join_log" >/dev/null; then
printf 'Join diagnostic did not complete authenticated traffic and outcome reporting.\n' >&2
exit 1
fi
printf 'Rendezvous deployment smoke passed: HTTP live/ready and authenticated UDP mediation/direct traffic.\n'