test: cover the async delete create event received while CNS runs - #4792
Conversation
The script stops CNS, deletes a Pod, and then starts CNS again, so the pending delete file is always on disk before CNS starts. CNS reads it in the startup directory scan, which always keyed the map by the file name. The fsnotify create event path, which keyed the map by the full path and leaked the IP, never runs. The test passed on the broken code. Add a second stage that drives a real CNI delete against a CNS that keeps running. SIGSTOP on the CNS process leaves the socket open, so the CNI request times out after 15s and takes the async delete path, and the kernel queues the create event until SIGCONT. The stage then asserts that the directory drains and that the CNS container did not restart, because a restart would prove only the startup scan again. Set shareProcessNamespace on the CNS daemonset so the debug container can signal the CNS process. That is the only way to make the CNI unable to reach CNS while the watcher stays alive: both the CNI delete path and the CNS watcher use http://localhost:10090. Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Adds coverage to the async-delete integration test to exercise the live fsnotify create-event path (when CNS is running but unresponsive) rather than only the startup directory scan path, by pausing the CNS process and validating pending-delete file creation/cleanup without a CNS restart.
Changes:
- Extend
async-delete-test.shwith a second stage that SIGSTOPs CNS, drives a real CNI DEL, and waits for the watcher-driven cleanup. - Update the CNS test DaemonSet manifest to enable
shareProcessNamespaceso the debug container can signal the CNS process.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
hack/scripts/async-delete-test.sh |
Adds a second-phase test that pauses CNS to force pending-delete file creation while the fsnotify watcher is active, then verifies cleanup without restart. |
test/integration/manifests/cns/daemonset-linux.yaml |
Enables process namespace sharing so the debug container can signal CNS for the new test stage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
hack/scripts/async-delete-test.sh:83
- After
SIGSTOPsucceeds, cancelling or interrupting this test before the explicit resume leaves CNS stopped indefinitely; this DaemonSet has no liveness probe to recover node networking. Register cleanup immediately after stopping CNS (includingEXIT,HUP,INT, andTERM) and clear it only afterSIGCONTsucceeds.
kubectl exec -i $cns_pod -c debug -n kube-system -- sh -c "kill -STOP $cns_pid"
Address review feedback on the new stage. Always resume CNS. A failure between SIGSTOP and SIGCONT left the process paused for the rest of the run, so add a trap on EXIT, INT and TERM. Take one CNS pod, not every match. The jsonpath filter returned every pod on the node, which put two names in the variable during a rollout and broke the later exec calls. Use a field selector and the first running item. Do not read a failed exec as an empty directory. Both directory listings treated a transient exec error as an empty result, so the drain check could report success without ever seeing the directory. Check the command status, retry inside the wait loop, and require a listing that succeeded. Quote the pending file list when printing it, and correct the daemonset comment: SIGSTOP does stop the process, the container keeps running. Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
Evan Baker (rbtr)
left a comment
There was a problem hiding this comment.
entering the CNS container ns and pausing the process is a fascinating way to test this - totally valid and very thorough. i would have stubbed some fake deletes out on disk to see if they would be processed instead of such surgery because i don't think i could pull it off
|
/azp run Azure Container Networking PR |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Follows the review comment on #4768: the async delete e2e test misses the fsnotify create event and covers only the startup scan.
What the test misses today
The script stops CNS on the node, deletes a Pod, and then starts CNS again. The pending delete file is therefore always on disk before CNS starts. CNS reads it in the startup directory scan at
fsnotify.go:133, which keys the map by the file name and has always been correct.The other path never runs. When CNS is up but does not answer, the CNI writes the file while the watcher listens, and the watcher takes the create event at
fsnotify.go:166. That line held the defect that #4768 fixes. The e2e test passed on the broken code for 3 years.What this adds
A second stage that drives a real CNI delete against a CNS that never restarts:
SIGSTOP. The socket stays open, so the CNI request times out instead of failing fast.SIGCONT. The kernel queues the inotify event while the process is stopped and delivers it on resume, so the watcher gets a live create event.shareProcessNamespace: trueon the CNS test daemonset is what lets the debug container signal CNS. It is needed because the CNI delete path and the CNS watcher both usehttp://localhost:10090—cni/network/network.go:1108andcns/service/main.go:1076each callcnsclient.New("")— so no port or address change can break one without breaking the other, and the debug container drops all capabilities.Validation
Run on a live
swift-byocniAKS cluster, 2 nodes, CNS installed from these manifests.v1.8.12-25-g6013330eb(master, defect present)Stage 1 passing on the defective build is the point: it is why this never showed up.
CNS logs from the failing run, with the doubled path the defect produces:
The same stage on the fixed build, container restart count unchanged at 0:
Notes
sh -nandbash -nboth pass. No new dependency, no new manifest, no pipeline change.