Skip to content

Commit fd0a0fa

Browse files
myasnikovdaniillexfrei
authored andcommitted
test(networking): bind deny probe to live pod
Require a real admission ClusterIP and carry the EndpointSlice target UID into the direct-backend coordinate. Tie that coordinate to a non-empty current Pod snapshot so stale endpoints or masked list failures cannot produce a policy verdict. Assisted-By: LLM Signed-off-by: Myasnikov Daniil <[email protected]>
1 parent f318157 commit fd0a0fa

1 file changed

Lines changed: 48 additions & 21 deletions

File tree

‎hack/e2e-chainsaw/gateway/chainsaw-test.yaml‎

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)