diff --git a/server/monitor.go b/server/monitor.go index c6b16b2142b..cf0bbecf5eb 100644 --- a/server/monitor.go +++ b/server/monitor.go @@ -23,6 +23,7 @@ import ( "encoding/json" "expvar" "fmt" + "maps" "math" "net" "net/http" @@ -282,7 +283,9 @@ func (s *Server) Connz(opts *ConnzOptions) (*Connz, error) { s.mu.RLock() // Default to all client unless filled in above. if clist == nil { - clist = s.clients + clist = make(map[uint64]*client, len(s.clients)+len(s.leafs)) + maps.Copy(clist, s.clients) + maps.Copy(clist, s.leafs) } // copy the server id for monitoring diff --git a/server/monitor_test.go b/server/monitor_test.go index f3500f3f38e..88aa2016b11 100644 --- a/server/monitor_test.go +++ b/server/monitor_test.go @@ -27,6 +27,7 @@ import ( "path/filepath" "reflect" "runtime" + "slices" "sort" "strings" "sync" @@ -5700,8 +5701,11 @@ func TestMonitorConnzOperatorAccountNames(t *testing.T) { for pollMode := 0; pollMode < 2; pollMode++ { url := fmt.Sprintf("http://127.0.0.1:%d/connz?auth=1", s.MonitorAddr().Port) connz := pollConnz(t, s, pollMode, url, &ConnzOptions{Username: true}) - require_Equal(t, connz.NumConns, 1) - ci := connz.Conns[0] + require_Equal(t, connz.NumConns, 2) + idx := slices.IndexFunc(connz.Conns, func(c *ConnInfo) bool { + return c.Kind == kindStringMap[CLIENT] + }) + ci := connz.Conns[idx] require_Equal(t, ci.Account, accPub) require_Equal(t, ci.NameTag, accName) } @@ -5822,6 +5826,88 @@ func TestMonitorConnzSortByRTT(t *testing.T) { } } +func TestMonitorConnzIncludesLeafnodes(t *testing.T) { + content := ` + server_name: "hub" + listen: "127.0.0.1:-1" + http: "127.0.0.1:-1" + operator = "../test/configs/nkeys/op.jwt" + resolver = MEMORY + ping_interval = 1 + leafnodes { + listen: "127.0.0.1:-1" + } + ` + conf := createConfFile(t, []byte(content)) + sb, ob := RunServerWithConfig(conf) + defer sb.Shutdown() + + createAcc := func(t *testing.T) (*Account, string) { + t.Helper() + acc, akp := createAccount(sb) + kp, _ := nkeys.CreateUser() + pub, _ := kp.PublicKey() + nuc := jwt.NewUserClaims(pub) + ujwt, err := nuc.Encode(akp) + if err != nil { + t.Fatalf("Error generating user JWT: %v", err) + } + seed, _ := kp.Seed() + creds := genCredsFile(t, ujwt, seed) + return acc, creds + } + acc, mycreds := createAcc(t) + leafName := "my-leaf-node" + + content = ` + port: -1 + http: "127.0.0.1:-1" + ping_interval = 1 + server_name: %s + accounts { + %s { + users [ + {user: user1, password: pwd} + ] + } + } + leafnodes { + remotes = [ + { + account: "%s" + url: nats-leaf://127.0.0.1:%d + credentials: '%s' + } + ] + } + ` + config := fmt.Sprintf(content, + leafName, + acc.Name, + acc.Name, ob.LeafNode.Port, mycreds) + conf = createConfFile(t, []byte(config)) + sa, _ := RunServerWithConfig(conf) + defer sa.Shutdown() + + checkFor(t, time.Second, 15*time.Millisecond, func() error { + if n := sa.NumLeafNodes(); n != 1 { + return fmt.Errorf("Expected 1 leaf connection, got %v", n) + } + return nil + }) + + for test, options := range map[string]*ConnzOptions{ + "WithoutAccount": {}, + "WithAccount": {Account: acc.Name}, + } { + t.Run(test, func(t *testing.T) { + c := pollConnz(t, sb, 1, "http://127.0.0.1:%d/connz", options) + require_Equal(t, c.NumConns, 1) + require_Equal(t, c.Conns[0].Kind, kindStringMap[LEAF]) + }) + } +} + // https://github.com/nats-io/nats-server/issues/4144 func TestMonitorAccountszMappingOrderReporting(t *testing.T) { conf := createConfFile(t, []byte(`