@@ -2118,6 +2118,12 @@ spec:
21182118 }
21192119 adm_port=$(service_port "$adm" https-webhook)
21202120 ctl_port=$(service_port "$ctl" https)
2121+ adm_cluster_ip=$(kubectl -n "$ns" get svc "$adm" -o jsonpath='{.spec.clusterIP}')
2122+ [ -n "$adm_cluster_ip" ] && [ "$adm_cluster_ip" != None ] || {
2123+ echo "SETUP FAILURE: $adm must have a real ClusterIP, found ${adm_cluster_ip:-<empty>}" >&2
2124+ kubectl -n "$ns" get svc "$adm" -o yaml >&2 2>&1 || true
2125+ exit 1
2126+ }
21212127 [ -n "$adm_port" ] || {
21222128 echo "SETUP FAILURE: $adm must expose exactly one TCP https-webhook port" >&2
21232129 kubectl -n "$ns" get svc "$adm" -o yaml >&2 2>&1 || true
@@ -2140,10 +2146,11 @@ spec:
21402146 echo "$n"
21412147 }
21422148
2143- # Exact ready admission coordinates. The IP and backend port come
2144- # from the same EndpointSlice as the ready condition; selecting them
2145- # independently from .items[0] could probe an unready replica while a
2146- # different replica kept the aggregate Service readiness above zero.
2149+ # Exact ready admission coordinates. The Pod identity, IP and backend
2150+ # port come from the same EndpointSlice as the ready condition;
2151+ # selecting them independently from .items[0] could probe an unready
2152+ # replica while a different replica kept aggregate readiness above
2153+ # zero.
21472154 ready_admission_backends() {
21482155 kubectl -n "$ns" get endpointslice -l "kubernetes.io/service-name=$adm" -o json | jq -r '
21492156 .items[]? as $slice
@@ -2155,21 +2162,32 @@ spec:
21552162 | select(.conditions.ready == true)
21562163 | select(.targetRef.kind == "Pod")
21572164 | select((.targetRef.name // "") != "")
2165+ | select((.targetRef.uid // "") != "")
21582166 | .targetRef.name as $pod
2167+ | .targetRef.uid as $uid
21592168 | .addresses[]?
21602169 | select(type == "string" and length > 0)
2161- | [$pod, ., ($port.port | tostring)]
2170+ | [$pod, $uid, ., ($port.port | tostring)]
21622171 | @tsv
21632172 ' | sort -u
21642173 }
21652174
2166- # Pod identity plus restart count, as one string. Compared for
2167- # equality across the probe window, so a restart AND a replacement
2168- # both show up -- a crash-looping controller can satisfy a readiness
2169- # check at both ends of a window it spent dying in the middle of.
2175+ # Pod identity, IP and every container restart count, as one string.
2176+ # Compared for equality across the probe window, so a restart AND a
2177+ # replacement both show up -- a crash-looping controller can satisfy
2178+ # a readiness check at both ends of a window it spent dying in the
2179+ # middle of.
21702180 controller_generation() {
2171- kubectl -n "$ns" get pod -l "$sel" \
2172- -o jsonpath='{range .items[*]}{.metadata.name}/{.metadata.uid}={range .status.containerStatuses[*]}{.name}:{.restartCount},{end}{"\n"}{end}' | sort
2181+ generation=$(kubectl -n "$ns" get pod -l "$sel" \
2182+ -o jsonpath='{range .items[*]}{.metadata.name}/{.metadata.uid}/{.status.podIP}={range .status.containerStatuses[*]}{.name}:{.restartCount},{end}{"\n"}{end}') || {
2183+ echo "SETUP FAILURE: unable to read ingress-nginx controller generation" >&2
2184+ return 1
2185+ }
2186+ [ -n "$generation" ] || {
2187+ echo "SETUP FAILURE: ingress-nginx controller generation is empty" >&2
2188+ return 1
2189+ }
2190+ printf '%s\n' "$generation" | sort
21732191 }
21742192
21752193 # Precondition. Both Services are backed by the same controller pods,
@@ -2194,29 +2212,30 @@ spec:
21942212 done
21952213
21962214 backend=$(ready_admission_backends | head -1)
2197- [ -n "$backend" ] || { echo "SETUP FAILURE: $adm has no complete ready Pod/IP/port coordinate" >&2; exit 1; }
2215+ [ -n "$backend" ] || { echo "SETUP FAILURE: $adm has no complete ready Pod/UID/ IP/port coordinate" >&2; exit 1; }
21982216 tab=$(printf '\t')
21992217 backend_fields=$(printf '%s\n' "$backend" | awk -F "$tab" '{ print NF }')
2200- [ "$backend_fields" -eq 3 ] || { echo "SETUP FAILURE: malformed ready backend coordinate: $backend" >&2; exit 1; }
2218+ [ "$backend_fields" -eq 4 ] || { echo "SETUP FAILURE: malformed ready backend coordinate: $backend" >&2; exit 1; }
22012219 pod_name=$(printf '%s\n' "$backend" | cut -f1)
2202- pod_ip=$(printf '%s\n' "$backend" | cut -f2)
2203- hook_port=$(printf '%s\n' "$backend" | cut -f3)
2204- [ -n "$pod_name" ] && [ -n "$pod_ip" ] && [ -n "$hook_port" ] || {
2220+ pod_uid=$(printf '%s\n' "$backend" | cut -f2)
2221+ pod_ip=$(printf '%s\n' "$backend" | cut -f3)
2222+ hook_port=$(printf '%s\n' "$backend" | cut -f4)
2223+ [ -n "$pod_name" ] && [ -n "$pod_uid" ] && [ -n "$pod_ip" ] && [ -n "$hook_port" ] || {
22052224 echo "SETUP FAILURE: incomplete ready backend coordinate: $backend" >&2
22062225 exit 1
22072226 }
22082227
22092228 selected_backend_ready() {
22102229 ready_admission_backends | awk -F "$tab" \
2211- -v pod="$pod_name" -v ip="$pod_ip" -v port="$hook_port" '
2212- $1 == pod && $2 == ip && $3 == port { found = 1 }
2230+ -v pod="$pod_name" -v uid="$pod_uid" -v ip="$pod_ip" -v port="$hook_port" '
2231+ $1 == pod && $2 == uid && $3 == ip && $4 == port { found = 1 }
22132232 END { exit !found }
22142233 '
22152234 }
22162235
22172236 require_selected_backend() {
22182237 selected_backend_ready && return 0
2219- echo "SETUP FAILURE: selected admission backend $pod_name ($pod_ip:$hook_port) was not ready $1" >&2
2238+ echo "SETUP FAILURE: selected admission backend $pod_name/$pod_uid ($pod_ip:$hook_port) was not ready $1" >&2
22202239 kubectl -n "$ns" get endpointslice -l "kubernetes.io/service-name=$adm" -o yaml >&2 2>&1 || true
22212240 kubectl -n "$ns" get pod "$pod_name" -o wide >&2 2>&1 || true
22222241 exit 1
@@ -2228,6 +2247,14 @@ spec:
22282247 # instant. Six samples over 30s, all of which must be live and show no
22292248 # restart or replacement.
22302249 gen_before=$(controller_generation)
2250+ printf '%s\n' "$gen_before" | awk \
2251+ -v prefix="${pod_name}/${pod_uid}/${pod_ip}=" '
2252+ index($0, prefix) == 1 { found = 1 }
2253+ END { exit !found }
2254+ ' || {
2255+ echo "SETUP FAILURE: selected admission backend is not a current controller Pod: $backend" >&2
2256+ exit 1
2257+ }
22312258 i=0
22322259 while [ "$i" -lt 6 ]; do
22332260 sleep 5
@@ -2249,7 +2276,7 @@ spec:
22492276 exit 1
22502277 }
22512278
2252- echo "probing from $ns: expect reachable ${ctl}:${ctl_port}, denied ${adm}:${adm_port}, denied ${pod_name}@${pod_ip}:${hook_port}"
2279+ echo "probing from $ns: expect reachable ${ctl}:${ctl_port}, denied ${adm}@${adm_cluster_ip} :${adm_port}, denied ${pod_name}/${pod_uid }@${pod_ip}:${hook_port}"
22532280
22542281 kubectl -n "$ns" delete pod "$probe" --ignore-not-found --wait=true --timeout=60s
22552282 # busybox:musl is staged onto every node by hack/e2e-prepull-images.sh,
@@ -2283,7 +2310,7 @@ spec:
22832310 - name: CTL_PORT
22842311 value: "${ctl_port}"
22852312 - name: ADM_HOST
2286- value: "${adm}.${ns}.svc "
2313+ value: "${adm_cluster_ip} "
22872314 - name: ADM_PORT
22882315 value: "${adm_port}"
22892316 - name: POD_IP
0 commit comments