From abbc8bff2bbfb22ee5d846f53b518eb916631522 Mon Sep 17 00:00:00 2001 From: pingqiu Date: Thu, 26 Mar 2026 19:16:45 -0700 Subject: [PATCH] fix: canonicalize host in AllocateBlockVolumeResponse (CP13-2 follow-up) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AllocateBlockVolumeResponse used bs.ListenAddr() to derive replica addresses. When the VS binds to ":port" (no explicit IP), host resolved to empty string, producing ":dataPort" as the replica address. This ":port" propagated through master assignments to both primary and replica sides. Now canonicalizes empty/wildcard host using PreferredOutboundIP() before constructing replication addresses. Also exported PreferredOutboundIP for use by the server package. This is the source fix — all downstream paths (heartbeat, API response, assignment) inherit the canonical address. Co-Authored-By: Claude Opus 4.6 (1M context) --- weed/server/volume_grpc_block.go | 5 +++++ weed/server/volume_server_block.go | 3 +++ weed/storage/blockvol/net_util.go | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/weed/server/volume_grpc_block.go b/weed/server/volume_grpc_block.go index f18458675..5d069bbbd 100644 --- a/weed/server/volume_grpc_block.go +++ b/weed/server/volume_grpc_block.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb" + "github.com/seaweedfs/seaweedfs/weed/storage/blockvol" ) // AllocateBlockVolume creates a new block volume on this volume server. @@ -31,6 +32,10 @@ func (vs *VolumeServer) AllocateBlockVolume(_ context.Context, req *volume_serve if idx := strings.LastIndex(host, ":"); idx >= 0 { host = host[:idx] } + // Canonicalize: if host is empty (VS bound to ":port"), resolve to routable IP. + if host == "" || host == "0.0.0.0" || host == "::" || host == "[::]" { + host = blockvol.PreferredOutboundIP() + } resp := &volume_server_pb.AllocateBlockVolumeResponse{ Path: path, diff --git a/weed/server/volume_server_block.go b/weed/server/volume_server_block.go index 728f40841..c5e0390d8 100644 --- a/weed/server/volume_server_block.go +++ b/weed/server/volume_server_block.go @@ -370,6 +370,9 @@ func (bs *BlockService) setupPrimaryReplication(path, replicaDataAddr, replicaCt return } // Track replication state for heartbeat reporting (R1-4). + // These addresses are what the primary ships to — they come from the + // master's assignment. They should already be canonical (from + // AllocateBlockVolumeResponse), but if not, they'll be reported as-is. bs.replMu.Lock() if bs.replStates == nil { bs.replStates = make(map[string]*volReplState) diff --git a/weed/storage/blockvol/net_util.go b/weed/storage/blockvol/net_util.go index 4c3f3fc73..eed07d2bb 100644 --- a/weed/storage/blockvol/net_util.go +++ b/weed/storage/blockvol/net_util.go @@ -27,7 +27,7 @@ func canonicalizeListenerAddr(addr net.Addr, advertisedHost string) string { // Wildcard bind — use advertised host or fallback. host := advertisedHost if host == "" { - host = preferredOutboundIP() + host = PreferredOutboundIP() } if host == "" { // Last resort: return raw address (will be ":port"). @@ -42,7 +42,8 @@ func canonicalizeListenerAddr(addr net.Addr, advertisedHost string) string { // // This is a fallback — callers should prefer an explicitly configured // advertised host when available. -func preferredOutboundIP() string { +// PreferredOutboundIP returns the machine's preferred outbound IP as a string. +func PreferredOutboundIP() string { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { return ""