#!/usr/bin/env bash set -euo pipefail ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) KUBECONFIG=${KUBECONFIG:-/home/worsch/.kube/config-railiance01} KUBECTL_BIN=${KUBECTL_BIN:-kubectl} EXPECTED_CLUSTER_UID=${RAILIANCE01_CLUSTER_UID:-a553c742-0115-43d4-99a4-a5ca56fe0786} NAMESPACE=apps-pg-isolation-probe DB_HOST=apps-pg-rw.databases.svc.cluster.local K=("$KUBECTL_BIN" --kubeconfig="$KUBECONFIG") pass=0 fail=0 namespace_created=0 cleanup() { if [[ "$namespace_created" == 1 && "${KEEP:-0}" != 1 ]]; then "${K[@]}" delete namespace "$NAMESPACE" --wait=false >/dev/null 2>&1 || true fi } trap cleanup EXIT record() { local outcome=$1 name=$2 detail=${3:-} if [[ "$outcome" == pass ]]; then pass=$((pass + 1)) printf 'PASS|%s%s\n' "$name" "${detail:+|$detail}" else fail=$((fail + 1)) printf 'FAIL|%s%s\n' "$name" "${detail:+|$detail}" fi } psql_as() { local pod=$1 role=$2 database=$3 sql=$4 "${K[@]}" exec -n "$NAMESPACE" "$pod" -- \ psql -X -v ON_ERROR_STOP=1 -At -h "$DB_HOST" -U "$role" -d "$database" -c "$sql" } psql_super() { local sql=$1 "${K[@]}" exec -n databases apps-pg-1 -c postgres -- \ psql -X -v ON_ERROR_STOP=1 -U postgres -d postgres -At -c "$sql" } expect_value() { local name=$1 pod=$2 role=$3 database=$4 sql=$5 expected=$6 got if ! got=$(psql_as "$pod" "$role" "$database" "$sql" 2>&1); then record fail "$name" "query failed" elif [[ "$got" == "$expected" ]]; then record pass "$name" "$got" else record fail "$name" "expected=$expected got=$got" fi } expect_denied() { local name=$1 pod=$2 role=$3 database=$4 sql=$5 if psql_as "$pod" "$role" "$database" "$sql" >/dev/null 2>&1; then record fail "$name" "attempt succeeded" else record pass "$name" "denied" fi } copy_secret() { local name=$1 "${K[@]}" get secret "$name" -n databases -o json \ | jq --arg ns "$NAMESPACE" \ 'del(.metadata.annotations, .metadata.creationTimestamp, .metadata.resourceVersion, .metadata.uid, .metadata.ownerReferences, .metadata.managedFields) | .metadata.namespace=$ns' \ | "${K[@]}" apply -f - >/dev/null } measure_vergabe_ms() { local start end start=$(date +%s%3N) for _ in 1 2 3 4 5; do psql_as vergabe-probe vergabe vergabe_db 'SELECT 1' >/dev/null done end=$(date +%s%3N) echo $((end - start)) } uid=$("${K[@]}" get namespace kube-system -o jsonpath='{.metadata.uid}') if [[ "$uid" != "$EXPECTED_CLUSTER_UID" ]]; then echo "REFUSING: expected railiance01 UID $EXPECTED_CLUSTER_UID, got $uid" >&2 exit 2 fi if "${K[@]}" get namespace "$NAMESPACE" >/dev/null 2>&1; then echo "REFUSING: probe namespace already exists: $NAMESPACE" >&2 exit 2 fi "${K[@]}" apply -f "$ROOT/helm/apps-pg-isolation-probe.yaml" >/dev/null namespace_created=1 copy_secret coulomb-social-app-credentials copy_secret vergabe-app-credentials "${K[@]}" wait --for=condition=Ready pod/coulomb-probe pod/vergabe-probe \ -n "$NAMESPACE" --timeout=60s >/dev/null echo 'SECTION|consumer-boundary' expect_value 'coulomb own database connects' coulomb-probe coulomb_social coulomb_social_db 'SELECT 1' 1 expect_value 'vergabe own database connects' vergabe-probe vergabe vergabe_db 'SELECT 1' 1 expect_denied 'coulomb cannot connect to vergabe database' coulomb-probe coulomb_social vergabe_db 'SELECT 1' expect_denied 'vergabe cannot connect to coulomb database' vergabe-probe vergabe coulomb_social_db 'SELECT 1' expect_denied 'coulomb cannot connect to platform bootstrap database' coulomb-probe coulomb_social apps_meta 'SELECT 1' expect_denied 'consumer cannot alter peer role' coulomb-probe coulomb_social coulomb_social_db 'ALTER ROLE vergabe CONNECTION LIMIT 999' expect_value 'coulomb sees its own table' coulomb-probe coulomb_social coulomb_social_db 'SELECT count(*) FROM members_user' 1 expect_value 'coulomb statement timeout binds' coulomb-probe coulomb_social coulomb_social_db 'SHOW statement_timeout' 15s expect_value 'coulomb idle transaction timeout binds' coulomb-probe coulomb_social coulomb_social_db 'SHOW idle_in_transaction_session_timeout' 15s expect_value 'coulomb connection limit is 20' coulomb-probe coulomb_social coulomb_social_db "SELECT rolconnlimit FROM pg_roles WHERE rolname=current_user" 20 expect_denied 'overlong statement is terminated' coulomb-probe coulomb_social coulomb_social_db 'SELECT pg_sleep(20)' echo 'SECTION|noisy-neighbour-connection-saturation' baseline_ms=$(measure_vergabe_ms) existing=$(psql_super "SELECT count(*) FROM pg_stat_activity WHERE usename='coulomb_social'") hold=$((20 - existing)) if (( hold < 1 )); then record fail 'saturation setup has free role slots' "existing=$existing" else "${K[@]}" exec -n "$NAMESPACE" coulomb-probe -- sh -c ' count=$1 i=1 while [ "$i" -le "$count" ]; do psql -X -v ON_ERROR_STOP=1 -At -h "$2" -U coulomb_social -d coulomb_social_db -c "\! sleep 25" >/dev/null 2>&1 & i=$((i + 1)) done wait ' sh "$hold" "$DB_HOST" & saturator_pid=$! saturated=0 for _ in $(seq 1 50); do current=$(psql_super "SELECT count(*) FROM pg_stat_activity WHERE usename='coulomb_social'") if [[ "$current" == 20 ]]; then saturated=1; break; fi sleep 0.2 done if [[ "$saturated" == 1 ]]; then record pass 'coulomb reaches its declared connection ceiling' 'connections=20' else record fail 'coulomb reaches its declared connection ceiling' "connections=$current" fi expect_denied 'coulomb excess connection is rejected' coulomb-probe coulomb_social coulomb_social_db 'SELECT 1' if during_ms=$(measure_vergabe_ms); then record pass 'vergabe remains available during peer saturation' "baseline_5q_ms=$baseline_ms saturated_5q_ms=$during_ms" else during_ms=unavailable record fail 'vergabe remains available during peer saturation' fi wait "$saturator_pid" || true fi echo "SUMMARY|passed=$pass|failed=$fail|baseline_5q_ms=$baseline_ms|saturated_5q_ms=${during_ms:-not-run}" (( fail == 0 ))