#!/usr/bin/env bash # T30: terminationDrainDuration / istio-agent SIGTERM drain behavior verification set -euo pipefail NS=istio-vt-t30 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cleanup() { echo "--- cleanup: deleting namespace $NS ---" kubectl delete namespace "$NS" --wait=false --ignore-not-found } trap cleanup EXIT echo "=== create namespace $NS with istio-injection=enabled ===" kubectl create namespace "$NS" kubectl label namespace "$NS" istio-injection=enabled echo "=== apply manifest ===" kubectl apply -f "$SCRIPT_DIR/manifest.yaml" echo "=== wait for deployments available ===" kubectl -n "$NS" wait --for=condition=available deploy/drain-default-echo deploy/drain-good deploy/drain-bad --timeout=90s echo "=== wait for client pod ready ===" kubectl -n "$NS" wait --for=condition=Ready pod/client --timeout=90s kubectl -n "$NS" get pods -o wide echo "=== [1] default duration + who triggers it (drain-default-echo) ===" POD0=$(kubectl -n "$NS" get pod -l app=drain-default-echo -o jsonpath='{.items[0].metadata.name}') kubectl -n "$NS" delete pod "$POD0" --wait=false # poll quickly since the pod object disappears once terminated (default drain ~5s) for i in $(seq 1 12); do OUT=$(kubectl -n "$NS" logs "$POD0" -c istio-proxy 2>&1) || true if echo "$OUT" | grep -qiE 'graceful termination|drain'; then echo "$OUT" | grep -iE 'graceful termination|drain' | tail -10 break fi sleep 1 done echo "=== [2] annotation override propagation into bootstrap config_dump ===" kubectl -n "$NS" exec deploy/drain-good -c istio-proxy -- curl -s "localhost:15000/config_dump?mask=bootstrap" | grep -i terminationDrainDuration kubectl -n "$NS" exec deploy/drain-bad -c istio-proxy -- curl -s "localhost:15000/config_dump?mask=bootstrap" | grep -i terminationDrainDuration echo "=== [3] drain-good: grace(40s) > drain(20s) -> in-flight request should complete ===" ( kubectl -n "$NS" exec client -c curl -- curl -s -o /dev/null -w 'drain_good_result=%{http_code} elapsed=%{time_total}\n' \ "http://drain-good.$NS.svc.homelab.local/delay/12" > /tmp/drain_good.log 2>&1 & ) sleep 1 GPOD=$(kubectl -n "$NS" get pod -l app=drain-good -o jsonpath='{.items[0].metadata.name}') kubectl -n "$NS" delete pod "$GPOD" --wait=false sleep 15 cat /tmp/drain_good.log # expect 200, elapsed ~12s (completed) echo "=== [4] drain-bad: grace(5s) < drain requirement(20s) -> in-flight request cut short ===" ( kubectl -n "$NS" exec client -c curl -- curl -s -o /dev/null -w 'drain_bad_result=%{http_code} elapsed=%{time_total}\n' --max-time 15 \ "http://drain-bad.$NS.svc.homelab.local/delay/12" > /tmp/drain_bad.log 2>&1 & ) sleep 1 BPOD=$(kubectl -n "$NS" get pod -l app=drain-bad -o jsonpath='{.items[0].metadata.name}') kubectl -n "$NS" delete pod "$BPOD" --wait=false sleep 15 cat /tmp/drain_bad.log # expect NOT a clean 200/~12s -- cut around grace period (~5s) instead echo "=== done (namespace will be cleaned up by trap) ==="