OCPBUGS-97809: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes#1557
Conversation
WalkthroughThis PR updates the netqueue e2e performance test to discover multi-queue NICs before profile changes, normalize and restore the PerformanceProfile baseline, and validate selector updates by polling NIC combined channel counts against the reserved CPU count. ChangesNetqueue e2e test refactor
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Test as Netqueue test
participant Profile as PerformanceProfile
participant Nodes as worker nodes
participant Tuned as tuned pod
participant NIC as Node NIC
Test->>Profile: read reserved CPU cpuset
Test->>Nodes: discover multi-queue NICs
Nodes-->>Test: baseline NIC snapshot
Test->>Profile: normalize Spec.Net baseline
Test->>Profile: update device selectors
Profile->>Tuned: render devices_udev_regex
Test->>Tuned: wait for tuned config update
Tuned-->>Test: config confirmed
Test->>NIC: poll combined channels
NIC-->>Test: channel counts
Test->>Test: wait until counts match reservedCPUCount
Test->>Profile: restore initial spec after suite
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (13 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: oblau The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
…n netqueue suite
strings.ContainsAny(s, chars) reports whether ANY character in chars
appears in s -- it does not check for a substring. Since device is a NIC
name like "enP2s2f0np0", this check was true for almost any tuned output
containing common letters, regardless of whether that specific device name
actually appeared in devices_udev_regex. Replace with strings.Contains in
the 4 tests that assert tuned picked up the configured device filter:
test_id 40543, 40545, 72051, 40668.
Every netqueue test body was wrapped in a guard like:
if profile.Spec.Net.UserLevelNetworking != nil && *ULN && len(Devices) == 0 { ... }
This guard was true in the common case only because BeforeEach
unconditionally set Net whenever it was nil, and AfterEach unconditionally
reverted to the initial profile after every test. If the *initial* cluster
profile already had a non-nil Net with ULN=false or leftover Devices, the
guard evaluated false and the entire test body was skipped -- the test
reported PASS while verifying nothing. Guards removed from test_id 40308,
40543, 40545, 72051, and 40668.
Once the guard is gone, test_id 40308 and 40542 are identical bodies
(both call checkDeviceSetWithReservedCPU unconditionally). Dropping 40542
as a duplicate; 40308 covers the same case.
getReservedCPUSize re-parsed profile.Spec.CPU.Reserved into a cpuset on
every 5s poll, even though the value is static for the
whole test run. Compute it once as reservedCPUCount in the BeforeAll and
thread it through instead: checkDeviceSetWithReservedCPU's signature
changes from taking the whole *performancev2.PerformanceProfile to taking
reservedCPUCount int directly. getReservedCPUSize is removed.
AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
…BeforeAll/AfterAll pass - BeforeEach (enable ULN) and AfterEach (revert to initial) never isolated tests: both call profiles.UpdateWithRetry with no wait after, so the next test's own update fires before tuned reconciles the previous one. - Example: test A AfterEach reverts the profile, but test B immediately calls UpdateWithRetry with its own Devices before that revert lands -- B can still see A leftover devices_udev_regex even though "cleanup" ran in between. - No test actually needs a clean starting profile: each one fully overwrites profile.Spec.Net itself or polls until its own expected state converges. The per-test revert bought nothing. - Replaced with one BeforeAll (set baseline once) and one AfterAll (revert once, only if state changed). Side effect: total profile updates per run drop from 10-16 to 5-6.
…tead of per-test rediscovery - checkDeviceSupport was called independently by every test, re-running ethtool discovery over the tuned pod each time. checkDeviceSetWithReservedCPU then polled that same rediscovery every 5s while waiting for convergence. A slow update and a broken feature produced the same timeout -> Skip. - Split checkDeviceSupport into discoverMultiQueueNICs (per-node NIC enumeration, now via nodes.GetNodeInterfaces/node_inspector instead of tuned-pod exec) and getCombinedChannels (single NIC -> combined channel count). One does discovery, one does the ethtool read; each is reusable on its own. - discoverMultiQueueNICs runs once in BeforeAll into baselineMultiQueueNICs (map[string]map[nodes.NodeInterface]int); BeforeAll Skips the whole suite upfront if none are found. Tests read from this baseline instead of rediscovering. - checkDeviceSetWithReservedCPU -> waitForNICsToMatchReservedCPU: no longer mutates a caller map or rediscovers, just polls the baseline. Also fixes a real bug -- the old function returned success on the first NIC that matched reservedCPUCount, even for tests asserting all supported NICs converge. - getRandomNodeDevice updated for the new map type, returns a NodeInterface instead of a bare string. Drops its defensive empty-name check -- discoverMultiQueueNICs never inserts zero-value entries, unlike the old checkDeviceSupport. - 40543/40545/72051/40668 now pull their target device from the baseline instead of calling checkDeviceSupport themselves. profile updates use `var err error` explicitly to avoid re-shadowing the Describe-scoped profile var now that device is a struct, not a string, everywhere. AI Attribution: AIA Human-AI blend, Content edits, New content, Human-initiated, Reviewed, opus 4.6 high v1.0
…line
- checkDeviceSupport split into discoverMultiQueueNICs (enumeration) and
getCombinedChannels (per-NIC ethtool parsing). Discovery now runs once in
BeforeAll into baselineMultiQueueNICs, Skipping the whole suite upfront if
none are found, instead of each test re-discovering and skipping
individually.
- checkDeviceSetWithReservedCPU -> waitForNICsToMatchReservedCPU: takes a
NIC map to poll instead of rediscovering. Also fixes a bug where it
returned success on the first matching NIC instead of waiting for all of
them to converge.
- getRandomNodeDevice: updated for the new map type, returns a
NodeInterface, drops its now-unneeded empty-name guard.
- Each test builds its own scoped NIC map (targetNICs/matchedNICs/
expectedNICs) instead of polling the full baseline, so convergence checks
validate only the NICs that test actually touches. Per-test
checkDeviceSupport+Skip guards removed, BeforeAll already guarantees them.
- Skip-on-error replaced with Expect(err).ToNot(HaveOccurred()) throughout.
- profile.Spec.Net setup now only sets .Devices (UserLevelNetworking=true
comes from the BeforeAll baseline).
- var err error added before some profile fetches so profile, err = ...
assigns the Describe-scoped var instead of shadowing it.
- nodes.GetByName moved before scoped-map-building/profile update in every
test, to keep the exec call out of the post-update ethtool blackout
window.
- 40545: wildcard check now searches for the derived udev-regex form
("iface.*") instead of the literal device name, since tuned stores
wildcards as regex in devices_udev_regex.
- 72051: pick device only from nodes with >=2 NICs, a single-NIC node can't
demonstrate negation. Restored the negative assertion (pre/post
combined-channel comparison on the negated NIC) lost when
checkDeviceSupport was removed. Tuned-config check now searches for the
negated pattern ("!iface") instead of the bare device name, to avoid a
false positive from a leftover config.
- 40668: tuned-config check upgraded to a 3-way match (interface name +
vendor ID + device ID); it previously only checked the interface name.
AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
3c75326 to
c67d344
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/e2e/performanceprofile/functests/1_performance/netqueues.go`:
- Around line 403-405: The discovery logic in getAvailableCombinedChannels is
incorrectly treating Combined: 1 as unsupported, which later makes
waitForNICsToMatchReservedCPU time out during convergence. Update the channel
filtering so only truly single-channel NICs are excluded during discovery, and
allow a valid combined value of 1 to be returned as available; keep the fix
localized to getAvailableCombinedChannels and any related call sites around the
combinedChannels check.
- Around line 145-146: The shell-based command construction in the performance
profile tests is interpolating untrusted values into bash, which can allow
injection via profile paths or interface names. Update the command-building in
the affected test helpers, especially the logic around tunedCmd and the
ethtool/grep pipeline, to use argv-style exec calls instead of bash -c and pass
the path/interface as separate arguments. Keep the existing test behavior in the
relevant helpers by locating the command assembly near tunedCmd and the other
matching blocks, and remove any shell string concatenation.
- Line 178: The wildcard matching in the target NIC filtering logic ignores the
error returned by filepath.Match, which can hide malformed patterns and produce
an incomplete target set. Update the matching check in the netqueues selection
code to handle the error explicitly: keep the match result for nic.Name, and if
filepath.Match returns an error, surface it through the surrounding control flow
instead of discarding it. Use the existing netqueues matching path and the
filepath.Match call site to locate the fix.
- Around line 237-249: Build the negative-match expectation from the full
baseline node NIC map, not only nodesWithMultipleNICs, so single-NIC workers are
also validated against the cluster-wide !<iface> profile. Update the
expectedNICs construction in the netqueues test to iterate over the complete
nodes/NIC inventory while still excluding device.Name, and keep the existing
unique symbols like expectedNICs, nodesWithMultipleNICs, and device.Name to
locate the logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 83224ca6-eca4-410d-aa29-30a6b46383af
📒 Files selected for processing (1)
test/e2e/performanceprofile/functests/1_performance/netqueues.go
…ests
- Converted remaining plain `//` comments to By() calls; unified the 4
tests' tuned-config-check block (identical By text, no blank lines) --
they run the same grep, differing only in what they search for.
- Added a By() before each test's final convergence check (previously
unlabeled); all now end in "converged to reserved CPU count".
- Added testlog.Infof after each getRandomNodeDevice call, logging which
NIC/node the run picked.
- 40545/40668: added missing By("Updating the performance profile"),
matching 40543. 72051: split its stale "Enable ULN..." By into the same
two-step shape as the other tests.
- 40668: removed a redundant duplicate nodes.GetByName call.
- AfterAll now logs the profile diff before reverting, mirroring
BeforeAll's equivalent branch.
- Added a top-of-file comment on the ARM ethtool -L blackout window, and
a doc comment on getRandomNodeDevice explaining its random-pick trick.
AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
c67d344 to
c463c66
Compare
|
/retest |
1 similar comment
|
/retest |
|
@oblau: This pull request references Jira Issue OCPBUGS-97809, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
The bug has been updated to refer to the pull request using the external bug tracker. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
/verified by oblau |
|
@oblau: This PR has been marked as verified by DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
@oblau: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
| } | ||
| By("Updating the performance profile") | ||
|
|
||
| By("Ensuring a baseline of UserLevelNetworking=true, no device filter") |
There was a problem hiding this comment.
what is the device filter here?
There was a problem hiding this comment.
"Device filter" = profile.Spec.Net.Devices which limits which NICs get netqueue tuning from UserLevelNetworking . Baseline profile should have UserLevelNetworking with no device filters.
This is a rework of the netqueues test suite
Investigation started from ARM CI hitting unexpected timeouts, but it
uncovered that most of these tests could never actually fail in the first
place, regardless of whether the feature worked:
4 of the 5 tuned-config assertions used
strings.ContainsAnyinstead ofstrings.Contains-- ContainsAny matches on individual characters, notsubstrings, so these checks passed for almost any tuned output.
Every test body was wrapped in a guard that was only ever true because
BeforeEach/AfterEach forced a specific profile state around it; if the
cluster's real starting state differed, the guard evaluated false and
the entire test body was skipped -- reported as a PASS.
Convergence-check failures called
Skip(...)instead of failing,turning "the feature is broken" into "test skipped, no signal."
On top of that, on ARM
ethtool -Lon the br-ex uplink NIC causes ~30s ofnode unreachability, and every test independently re-discovered NICs via
exec during/after profile updates, so it kept landing exec calls inside
that blackout window. The resulting timeout looked identical whether the
feature was actually broken or NIC discovery was just slow -- there was
no way to tell them apart. Between that and the bugs above masking real
signal, this was enough to justify a full rework of the test structure
rather than a handful of small patches.
Changes:
strings.ContainsAny->strings.Containsbug in all 4affected tuned-config assertions.
bodies now always execute and assert for real.
the guard above was gone).
BeforeEach/AfterEachprofile setup/teardown with asingle
BeforeAll/AfterAllpass -- cuts profile updates (and theirethtool blackouts) per suite run from 10-16 down to 5-6.
BeforeAllinto abaseline map instead of every test (and every poll tick) rediscovering
them; each test now builds its own scoped view of that baseline before
triggering a profile update, so exec calls needing node access happen
before the blackout window, not during/after it. Skips the suite
upfront if no multi-queue-capable NICs are found.
reserved CPU count, instead of returning success on the first matching
NIC anywhere -- meaningfully stricter for the "all devices" and
wildcard/vendor-ID tests.
Summary by CodeRabbit