mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-03 14:47:04 +00:00
fuse test: keep derived filer gRPC port below the ephemeral floor (#10334)
The FUSE harness picks the filer HTTP port and lets "weed mount" derive the filer gRPC port as HTTP+10000. freePort kept the HTTP port under the Linux ephemeral floor (32768) but not the derived gRPC port, which ranged up to 42000. When the gRPC port landed above the floor an outbound connection could transiently hold it, so mini relocated its filer gRPC port while mount kept dialing HTTP+10000, timing the mount out. Cap the HTTP port at 22000 so the gRPC sibling stays at or below 32000, and verify both ports are bindable before returning.
This commit is contained in:
@@ -86,35 +86,47 @@ func NewFuseTestFramework(t *testing.T, config *TestConfig) *FuseTestFramework {
|
||||
}
|
||||
}
|
||||
|
||||
// freePort asks the OS for a free TCP port in a range where the gRPC
|
||||
// offset (port + 10000) won't collide with well-known ports.
|
||||
// Stay below the Linux ephemeral floor (32768) so the kernel does not
|
||||
// reuse the chosen port for an outbound connection between close() here
|
||||
// and re-bind in the child "weed mini" process.
|
||||
// grpcPortOffset mirrors weed's HTTP->gRPC port convention (gRPC = HTTP + offset);
|
||||
// "weed mount" derives the filer gRPC port from the filer HTTP address the same way.
|
||||
const grpcPortOffset = 10000
|
||||
|
||||
// freePort returns a free filer HTTP port whose gRPC sibling (port+grpcPortOffset)
|
||||
// is also free. Both must stay below the Linux ephemeral floor (32768): a gRPC port
|
||||
// above it can be transiently grabbed by an outbound connection, forcing mini to
|
||||
// relocate its filer gRPC port while "weed mount" keeps dialing HTTP+10000 — the
|
||||
// mount then never connects and the test times out. Capping HTTP at 22000 keeps the
|
||||
// gRPC port at or below 32000.
|
||||
func freePort(t *testing.T) int {
|
||||
t.Helper()
|
||||
const (
|
||||
minServicePort = 20000
|
||||
maxServicePort = 32000
|
||||
maxServicePort = 22000
|
||||
)
|
||||
|
||||
portCount := maxServicePort - minServicePort + 1
|
||||
start := minServicePort + int(time.Now().UnixNano()%int64(portCount))
|
||||
|
||||
for attempt := 0; attempt < 512; attempt++ {
|
||||
for attempt := 0; attempt < portCount; attempt++ {
|
||||
port := minServicePort + (start-minServicePort+attempt)%portCount
|
||||
l, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(port)))
|
||||
if err != nil {
|
||||
continue
|
||||
if portIsFree(port) && portIsFree(port+grpcPortOffset) {
|
||||
return port
|
||||
}
|
||||
l.Close()
|
||||
return port
|
||||
}
|
||||
|
||||
t.Fatalf("failed to allocate port <= %d after repeated attempts", maxServicePort)
|
||||
t.Fatalf("failed to allocate a free HTTP/gRPC port pair in [%d,%d]", minServicePort, maxServicePort)
|
||||
return 0
|
||||
}
|
||||
|
||||
// portIsFree reports whether a TCP port can currently be bound on 127.0.0.1.
|
||||
func portIsFree(port int) bool {
|
||||
l, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(port)))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
l.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
// Setup starts "weed mini" and mounts the FUSE filesystem.
|
||||
func (f *FuseTestFramework) Setup(config *TestConfig) error {
|
||||
if f.isSetup {
|
||||
|
||||
Reference in New Issue
Block a user