#!/usr/bin/env bash # T53: DestinationRule top-level vs subset trafficPolicy merge semantics # # Claim under test: subset trafficPolicy does NOT deep-merge with top-level # trafficPolicy at the field level; it replaces the whole connectionPool # block wholesale. Here: top-level sets connectionPool.tcp.tcpKeepalive, # subset v1 sets a different connectionPool.tcp field (maxConnections) only. # Prediction under test: subset v1's cluster loses tcpKeepalive entirely, # while the default (no-subset) cluster keeps it. # # NOTE (environmental correction): harness-notes.md states the cluster's # real DNS domain is homelab.local and instructs using *.svc.homelab.local # in all manifests. That is correct for CoreDNS/kubelet, but WRONG for # DestinationRule/VirtualService `host:` matching in this cluster: istiod # runs with an explicit `--domain cluster.local` flag (see # `kubectl -n istio-system get deploy istiod -o jsonpath='{.spec.template.spec.containers[0].args}'`), # so Istio's internal Kubernetes-service hostnames are always # `..svc.cluster.local`, independent of the real kubeadm # clusterDomain. Using svc.homelab.local in host fields makes # `istioctl analyze` report "Referenced host not found" / "does not match # any services in the mesh", and no subset policy attaches at all. This # script therefore uses svc.cluster.local for DestinationRule/VirtualService # hosts, matching every other pre-existing DestinationRule in this cluster. set -euo pipefail NS="istio-vt-t53" WORKDIR="$(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} ===" kubectl create namespace "${NS}" kubectl label namespace "${NS}" istio-injection=enabled echo "=== apply manifest.yaml ===" kubectl apply -f "${WORKDIR}/manifest.yaml" echo "=== wait for workloads ===" kubectl -n "${NS}" wait --for=condition=Ready pod/client --timeout=90s kubectl -n "${NS}" wait --for=condition=available deploy/subset-echo-v1 --timeout=60s kubectl -n "${NS}" get pods -o wide echo "=== sanity: istioctl analyze (expect no host-matching errors) ===" istioctl analyze -n "${NS}" || true sleep 5 echo "=== observe: default cluster vs subset 'v1' cluster tcpKeepalive/maxConnections ===" istioctl proxy-config cluster "client.${NS}" \ --fqdn "subset-echo.${NS}.svc.cluster.local" -o json \ | jq '.[] | {name, tcpKeepalive: .upstreamConnectionOptions.tcpKeepalive, maxConn: .circuitBreakers.thresholds[0].maxConnections}' # Expected: # outbound|80||subset-echo..svc.cluster.local -> tcpKeepalive present, maxConn = 4294967295 (unset sentinel) # outbound|80|v1|subset-echo..svc.cluster.local -> tcpKeepalive null (gone), maxConn = 33