fix(bin): replace lsof with /dev/tcp in server check_port; remove dea…#3105
fix(bin): replace lsof with /dev/tcp in server check_port; remove dea…#3105bitflicker64 wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3105 +/- ##
============================================
- Coverage 37.43% 36.55% -0.89%
+ Complexity 520 498 -22
============================================
Files 808 808
Lines 69581 69594 +13
Branches 9165 9169 +4
============================================
- Hits 26048 25440 -608
- Misses 40750 41402 +652
+ Partials 2783 2752 -31 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@copilot review |
imbajin
left a comment
There was a problem hiding this comment.
Blocking: yes. Summary: The new probe can miss or stall on real port conflicts, and the corrected command detection exposes a broken curl-only path. Evidence: static review of 6395c0c; bash -n passed; codecov/project is failing on this head.
imbajin
left a comment
There was a problem hiding this comment.
Blocking: yes. Summary: The fallback probe can execute configuration text as shell code and misparses a supported IPv6 URL form; the no-lsof branch matrix also remains untested. Evidence: exact-head static review, bash -n on all three changed scripts, and controlled reproductions for command execution and [::1]:8080 parsing.
imbajin
left a comment
There was a problem hiding this comment.
Blocking: yes. Summary: The listener-table probes can reject valid binds or silently skip collision detection, and the PD startup test still does not enforce its new lsof-free cleanup path. Evidence: exact-head static inspection, targeted shell reproductions, the 19-test check_port suite, and successful visible checks.
|
|
||
| local in_use=0 | ||
| if command_available "ss"; then | ||
| if ss -ltn 2>/dev/null | grep -qE "(:${port}\b|:${port}$)"; then |
There was a problem hiding this comment.
ss expression can even match the target digits inside an IPv6 address (for example, [2001:db8:8080::1]:9090 matches a check for port 8080). A listener on another specific interface can therefore reject a valid bind, while an IPv6 hextet can produce the same false positive. Please parse the local-address field and compare the configured host/port with wildcard and dual-stack conflict semantics, then add distinct-address and IPv6-hextet regressions.
| fi | ||
|
|
||
| local in_use=0 | ||
| if command_available "ss"; then |
There was a problem hiding this comment.
ss exits nonzero, this branch neither distinguishes that failure from an empty listener table nor tries netstat or /dev/tcp; the same silent-free result occurs when both netstat invocations fail. Please capture each probe's execution status, advance to the next layer on failure, and add cases where a present tool returns nonzero.
| lsof -ti :8620 | xargs kill -9 2>/dev/null || true | ||
| lsof -ti :8686 | xargs kill -9 2>/dev/null || true | ||
| # kill anything still holding the PD port (fuser avoids lsof dependency) | ||
| fuser -k 8620/tcp 2>/dev/null || true |
There was a problem hiding this comment.
fuser, but the PD workflow preflight still requires lsof curl java and never checks fuser. An lsof-free environment therefore skips the revised suite, while a runner without fuser executes it with silently ineffective port cleanup. Please remove the obsolete lsof gate, require fuser (or make cleanup dependency-free), and fail explicitly when cleanup cannot release the test ports.
There was a problem hiding this comment.
Blocking: yes — 6.0/10 on current head d315ae8. The main direction and CI are good, but the following issues still need to be addressed before merge.
New current-head findings:
- Hostname inputs bypass collision detection:
ss -n/netstat -nreport numeric addresses, so a supported value such aslocalhostis missed. - The real-listener test can pass without creating its listener: fixed port 54321 may already be occupied and Python bind success is not verified.
Existing comments that remain applicable on d315ae8 (not reposted; +1 used for deduplication):
- No hard deadline without the external
timeoutcommand: the raw/dev/tcpfallback can still stall on dropped SYN packets. - URL normalization is still incomplete: bracketed IPv6 was fixed, but leading/trailing whitespace accepted by
ServerOptionsstill bypasses this check. - Endpoint/dual-stack conflict semantics remain incomplete: the old IPv6-hextet false positive was fixed, but IPv4 and
IPV6_V6ONLYIPv6 wildcard listeners are still treated as unconditional cross-family conflicts. fusercleanup remains unenforced: Linux startup tests usefuserwithout checking that it exists and suppress cleanup failures.
Please do not treat these linked threads as fully resolved merely because some are outdated or marked resolved against older revisions; the specific residual behaviors above were revalidated on the current head.
| if command_available "ss"; then | ||
| if out=$(ss -ltn 2>/dev/null); then | ||
| port_checked=1 | ||
| if echo "$out" | grep -qE "$linux_pattern"; then |
There was a problem hiding this comment.
ss -n and netstat -n report numeric addresses, but this pattern compares them with the configured hostname text. ServerOptionsTest.testUrlNormalizationPreservesHostnameCase explicitly supports hostnames; with restserver.url=http://localhost:8080 and ss reporting 127.0.0.1:8080, this branch sets port_checked=1, misses the listener, and never reaches the resolving /dev/tcp fallback. A controlled run on this head returns success (port free) for that occupied endpoint. Please resolve hostnames to their IPv4/IPv6 addresses before matching, or use a deadline-bounded probe for hostname inputs, and add a hostname-to-numeric-listener regression.
| python3 -m http.server 54321 --bind 127.0.0.1 >/dev/null 2>&1 & | ||
| PY_PID=$! | ||
| trap "kill -9 $PY_PID 2>/dev/null || true" EXIT | ||
| sleep 1 # wait for it to bind |
There was a problem hiding this comment.
check_port connects to the unrelated listener, and the test still passes. Please bind port 0 and return the selected port to the test (or at least assert child liveness/readiness before calling check_port) so this cannot produce a false-positive green result.
|
fixing remaining issues |
9d75341 to
745a8bb
Compare
…-test suite Replace lsof with layered probe (ss → netstat → /dev/tcp) in server check_port to eliminate startup hang in Kubernetes pods where ulimit -n can be ~1 billion causing lsof to scan the entire FD table. Core changes (server util.sh): - ss -ltn: kernel socket table query, no FD scan - netstat -ltn / netstat -an: fallback for systems without ss - bash /dev/tcp with timeout 1: last resort, null-command probe - Hostname resolution (getent/dscacheutil) for localhost → numeric IP - Address-family-aware wildcard matching (no cross-family false conflicts) - ss non-zero exit fallthrough to netstat - No-timeout watchdog with 2s hard deadline - URL whitespace stripping (handles ServerOptions edge case) - IPv6 bracket notation parsing - Octal-safe port validation via $((10#port)) - curl -fL for HTTP error detection (was curl -L) PD and Store util.sh: - Remove dead check_port (never called by PD/Store startup scripts) - Fix command_available return-value inversion bug - Fix curl download path from broken concatenation to basename output - curl -fL for HTTP error detection CI and cleanup: - fuser preflight check in server-ci.yml (Linux port cleanup) - OS-aware cleanup in test-start-hugegraph*.sh (lsof on macOS, fuser on Linux) - Warning when neither tool available Tests (test-check-port.sh, 34 tests, 0 failures): - ss branch: IPv4/IPv6 occupied/free, wildcard, dot-escaping guard - netstat branch: Linux/BSD formats, IP octet false-positive guard - /dev/tcp: timeout mock, real ephemeral-port listener with liveness check - Host/port conflict: cross-family wildcard, specific IP vs loopback - Tool failure fallthrough: ss→netstat, ss+netstat→/dev/tcp - Hostname collision: localhost resolution, unresolved fallthrough - URL normalization + IPv6 hextet guard - Edge cases: empty URL, port >65535, port 0, non-numeric - download() curl fallback: PD, Store, failure propagation - SKIP exit-code handling for setup failures Closes apache#3105
745a8bb to
21829e6
Compare
…-test suite Replace lsof with layered probe (ss → netstat → /dev/tcp) in server check_port to eliminate startup hang in Kubernetes pods where ulimit -n can be ~1 billion causing lsof to scan the entire FD table. Server util.sh: - ss -ltn, netstat -ltn/-an, bash /dev/tcp with timeout 1 - Hostname resolution (getent/dscacheutil) for localhost → numeric IP - Address-family-aware wildcard matching (no cross-family conflicts) - ss non-zero exit → automatic fallthrough to netstat - Watchdog with 2s hard deadline when timeout unavailable - URL whitespace stripping, IPv6 bracket parsing - Octal-safe port validation via $((10#port)) - curl -fL for HTTP error detection PD and Store util.sh: - Remove dead check_port (never called by PD/Store) - Fix command_available return-value inversion - Fix download() curl path, add curl -fL CI and cleanup: - fuser preflight check on Linux, OS-aware port cleanup - Warning when neither lsof nor fuser available Tests: test-check-port.sh — 34 mock-driven tests, 0 failures
937624c to
6f87b8f
Compare
Purpose of the PR
Fix a startup hang in kind/Kubernetes environments caused by
lsofscanning an enormous file descriptor table, and remove deadcheck_portcode from pd/store.Main Changes
hugegraph-server/.../util.shlsof -i :PORTwith a layered probe:ss -ltn→netstat -ltn/netstat -an→bash /dev/tcpwithtimeout 1getent/dscacheutilbefore matching againstss -n/netstat -noutputssexits non-zero/dev/tcpwhentimeoutis unavailablehttp://[::1]:8080and[::1]:8080)curl -fLindownload()so HTTP errors exit non-zerohugegraph-pd/.../util.shandhugegraph-store/.../util.shcheck_port— never called by PD or Store startup scriptscommand_available: was using command substitution that always produced empty resultdownload()curl branch: was writing to broken path; now usesmkdir -p+basenamecurl -fL.github/workflows/server-ci.ymllsoffrom preflight prerequisitesfuserpreflight check on Linux for port cleanuptest-start-hugegraph*.shlsof -ti :PORT | xargs kill -9with OS-aware cleanup (fuser -k PORT/tcpon Linux,lsofon macOS)Tests
New
test-check-port.sh— 34 mock-driven unit tests coveringss, GNUnetstat, BSDnetstat,/dev/tcp+timeout, real ephemeral-port listener, IPv4/IPv6, wildcard vs specific-address matching, tool-failure fallthrough, hostname resolution, URL whitespace normalization, IPv6 hextet guard, edge cases, anddownload()curl fallback for PD and Store.Verifying these changes
lsofremoved from CI preflight;fuserenforced on Linuxulimit -n— starts without hangingDoes this PR potentially affect the following parts?
Documentation Status
Doc - No Need