mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-06-13 23:36:45 +03:00
master: accept volume-server Ping targets on follower masters (#9614)
cluster.check asks every master to ping every volume server, but the Ping gate validated volume-server targets only against the local topology. Only the leader receives volume-server heartbeats, so a follower's topology is empty and every probe through it failed with "unknown ping target ... of type volumeServer". Fall back to the volume-server set the master learns over its own MasterClient subscription to the leader, the same source the filer gate already trusts. The anti-SSRF intent is preserved: Ping still only dials recognized cluster members.
This commit is contained in:
@@ -170,10 +170,17 @@ func (ms *MasterServer) isKnownPingTarget(ctx context.Context, target string, ta
|
||||
case cluster.FilerType, cluster.BrokerType, cluster.S3Type:
|
||||
return ms.Cluster.IsKnownNode(targetType, addr)
|
||||
case cluster.VolumeServerType:
|
||||
if ms.Topo == nil {
|
||||
return false
|
||||
if ms.Topo != nil && ms.Topo.LookupDataNodeByAddress(addr) != nil {
|
||||
return true
|
||||
}
|
||||
return ms.Topo.LookupDataNodeByAddress(addr) != nil
|
||||
// Only the leader receives volume-server heartbeats, so a follower's
|
||||
// topology is empty. Fall back to the volume-server set the master
|
||||
// learns over its own MasterClient subscription to the leader, the
|
||||
// same source the filer gate trusts.
|
||||
if ms.MasterClient != nil {
|
||||
return ms.MasterClient.HasVolumeServer(addr)
|
||||
}
|
||||
return false
|
||||
case cluster.MasterType:
|
||||
if ms.option != nil && ms.option.Master.Equals(addr) {
|
||||
return true
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/sequence"
|
||||
"github.com/seaweedfs/seaweedfs/weed/topology"
|
||||
"github.com/seaweedfs/seaweedfs/weed/wdclient"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func TestMasterIsKnownPingTarget(t *testing.T) {
|
||||
@@ -62,6 +64,36 @@ func TestMasterIsKnownPingTarget(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// On a follower master the topology is empty because only the leader receives
|
||||
// volume-server heartbeats. The gate must then fall back to the volume-server
|
||||
// set learned over the MasterClient subscription instead of rejecting every
|
||||
// volume-server target. The positive MasterClient.HasVolumeServer lookup is
|
||||
// covered by wdclient.TestHasVolumeServer; here we lock in that an empty
|
||||
// topology no longer short-circuits to false and that the fallback is
|
||||
// nil-safe.
|
||||
func TestMasterIsKnownPingTargetFollowerEmptyTopology(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
vs := "10.0.0.10:8080.18080"
|
||||
|
||||
// No topology and no MasterClient: nothing to consult, so reject.
|
||||
bare := &MasterServer{option: &MasterOption{Master: pb.ServerAddress("10.0.0.1:9333")}}
|
||||
if bare.isKnownPingTarget(ctx, vs, cluster.VolumeServerType) {
|
||||
t.Fatalf("volume server must be unknown without topology or MasterClient")
|
||||
}
|
||||
|
||||
// Empty topology plus a MasterClient that has not learned this volume
|
||||
// server yet: still reject, but exercise the MasterClient fallback path.
|
||||
mc := wdclient.NewMasterClient(grpc.EmptyDialOption{}, "", cluster.MasterType, "", "", "", pb.ServerDiscovery{})
|
||||
follower := &MasterServer{
|
||||
option: &MasterOption{Master: pb.ServerAddress("10.0.0.1:9333")},
|
||||
Topo: topology.NewTopology("test", sequence.NewMemorySequencer(), 32*1024, 5, false),
|
||||
MasterClient: mc,
|
||||
}
|
||||
if follower.isKnownPingTarget(ctx, vs, cluster.VolumeServerType) {
|
||||
t.Fatalf("volume server must be unknown until the MasterClient learns it")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVolumeServerIsKnownPingTarget(t *testing.T) {
|
||||
seed := pb.ServerAddress("10.0.0.1:9333")
|
||||
vs := &VolumeServer{
|
||||
|
||||
Reference in New Issue
Block a user