Browse Source

fix: canonicalize host in AllocateBlockVolumeResponse (CP13-2 follow-up)

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) <noreply@anthropic.com>
feature/sw-block
pingqiu 3 days ago
parent
commit
abbc8bff2b
  1. 5
      weed/server/volume_grpc_block.go
  2. 3
      weed/server/volume_server_block.go
  3. 5
      weed/storage/blockvol/net_util.go

5
weed/server/volume_grpc_block.go

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb" "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. // 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 { if idx := strings.LastIndex(host, ":"); idx >= 0 {
host = host[:idx] 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{ resp := &volume_server_pb.AllocateBlockVolumeResponse{
Path: path, Path: path,

3
weed/server/volume_server_block.go

@ -370,6 +370,9 @@ func (bs *BlockService) setupPrimaryReplication(path, replicaDataAddr, replicaCt
return return
} }
// Track replication state for heartbeat reporting (R1-4). // 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() bs.replMu.Lock()
if bs.replStates == nil { if bs.replStates == nil {
bs.replStates = make(map[string]*volReplState) bs.replStates = make(map[string]*volReplState)

5
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. // Wildcard bind — use advertised host or fallback.
host := advertisedHost host := advertisedHost
if host == "" { if host == "" {
host = preferredOutboundIP()
host = PreferredOutboundIP()
} }
if host == "" { if host == "" {
// Last resort: return raw address (will be ":port"). // 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 // This is a fallback — callers should prefer an explicitly configured
// advertised host when available. // 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") conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil { if err != nil {
return "" return ""

Loading…
Cancel
Save