Skip to content

Commit

Permalink
Merge pull request #3914 from nats-io/jsz-mon-raft
Browse files Browse the repository at this point in the history
Add raft query parameter to /jsz to include raft group info
  • Loading branch information
derekcollison committed Feb 27, 2023
2 parents 0269132 + 8910643 commit 9cca47c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 14 deletions.
56 changes: 42 additions & 14 deletions server/monitor.go
Expand Up @@ -2638,6 +2638,7 @@ type JSzOptions struct {
LeaderOnly bool `json:"leader_only,omitempty"`
Offset int `json:"offset,omitempty"`
Limit int `json:"limit,omitempty"`
RaftGroups bool `json:"raft,omitempty"`
}

// HealthzOptions are options passed to Healthz
Expand All @@ -2654,15 +2655,24 @@ type ProfilezOptions struct {
Debug int `json:"debug"`
}

// StreamDetail shows information about the stream state and its consumers.
type StreamDetail struct {
Name string `json:"name"`
Created time.Time `json:"created"`
Cluster *ClusterInfo `json:"cluster,omitempty"`
Config *StreamConfig `json:"config,omitempty"`
State StreamState `json:"state,omitempty"`
Consumer []*ConsumerInfo `json:"consumer_detail,omitempty"`
Mirror *StreamSourceInfo `json:"mirror,omitempty"`
Sources []*StreamSourceInfo `json:"sources,omitempty"`
Name string `json:"name"`
Created time.Time `json:"created"`
Cluster *ClusterInfo `json:"cluster,omitempty"`
Config *StreamConfig `json:"config,omitempty"`
State StreamState `json:"state,omitempty"`
Consumer []*ConsumerInfo `json:"consumer_detail,omitempty"`
Mirror *StreamSourceInfo `json:"mirror,omitempty"`
Sources []*StreamSourceInfo `json:"sources,omitempty"`
RaftGroup string `json:"stream_raft_group,omitempty"`
ConsumerRaftGroups []*RaftGroupDetail `json:"consumer_raft_groups,omitempty"`
}

// RaftGroupDetail shows information details about the Raft group.
type RaftGroupDetail struct {
Name string `json:"name"`
RaftGroup string `json:"raft_group,omitempty"`
}

type AccountDetail struct {
Expand Down Expand Up @@ -2698,7 +2708,7 @@ type JSInfo struct {
AccountDetails []*AccountDetail `json:"account_details,omitempty"`
}

func (s *Server) accountDetail(jsa *jsAccount, optStreams, optConsumers, optCfg bool) *AccountDetail {
func (s *Server) accountDetail(jsa *jsAccount, optStreams, optConsumers, optCfg, optRaft bool) *AccountDetail {
jsa.mu.RLock()
acc := jsa.account
name := acc.GetName()
Expand Down Expand Up @@ -2737,7 +2747,8 @@ func (s *Server) accountDetail(jsa *jsAccount, optStreams, optConsumers, optCfg

if optStreams {
for _, stream := range streams {
ci := s.js.clusterInfo(stream.raftGroup())
rgroup := stream.raftGroup()
ci := s.js.clusterInfo(rgroup)
var cfg *StreamConfig
if optCfg {
c := stream.config()
Expand All @@ -2752,17 +2763,28 @@ func (s *Server) accountDetail(jsa *jsAccount, optStreams, optConsumers, optCfg
Mirror: stream.mirrorInfo(),
Sources: stream.sourcesInfo(),
}
if optRaft && rgroup != nil {
sdet.RaftGroup = rgroup.Name
sdet.ConsumerRaftGroups = make([]*RaftGroupDetail, 0)
}
if optConsumers {
for _, consumer := range stream.getPublicConsumers() {
cInfo := consumer.info()
if cInfo == nil {
continue
}

if !optCfg {
cInfo.Config = nil
}
sdet.Consumer = append(sdet.Consumer, cInfo)
if optRaft {
crgroup := consumer.raftGroup()
if crgroup != nil {
sdet.ConsumerRaftGroups = append(sdet.ConsumerRaftGroups,
&RaftGroupDetail{cInfo.Name, crgroup.Name},
)
}
}
}
}
detail.Streams = append(detail.Streams, sdet)
Expand All @@ -2786,7 +2808,7 @@ func (s *Server) JszAccount(opts *JSzOptions) (*AccountDetail, error) {
if !ok {
return nil, fmt.Errorf("account %q not jetstream enabled", acc)
}
return s.accountDetail(jsa, opts.Streams, opts.Consumer, opts.Config), nil
return s.accountDetail(jsa, opts.Streams, opts.Consumer, opts.Config, opts.RaftGroups), nil
}

// helper to get cluster info from node via dummy group
Expand Down Expand Up @@ -2913,7 +2935,7 @@ func (s *Server) Jsz(opts *JSzOptions) (*JSInfo, error) {
}
// if wanted, obtain accounts/streams/consumer
for _, jsa := range accounts {
detail := s.accountDetail(jsa, opts.Streams, opts.Consumer, opts.Config)
detail := s.accountDetail(jsa, opts.Streams, opts.Consumer, opts.Config, opts.RaftGroups)
jsi.AccountDetails = append(jsi.AccountDetails, detail)
}
return jsi, nil
Expand Down Expand Up @@ -2952,6 +2974,10 @@ func (s *Server) HandleJsz(w http.ResponseWriter, r *http.Request) {
if err != nil {
return
}
rgroups, err := decodeBool(w, r, "raft")
if err != nil {
return
}

l, err := s.Jsz(&JSzOptions{
r.URL.Query().Get("acc"),
Expand All @@ -2961,7 +2987,9 @@ func (s *Server) HandleJsz(w http.ResponseWriter, r *http.Request) {
config,
leader,
offset,
limit})
limit,
rgroups,
})
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
Expand Down
28 changes: 28 additions & 0 deletions server/monitor_test.go
Expand Up @@ -4310,6 +4310,9 @@ func TestMonitorJsz(t *testing.T) {
if info.AccountDetails[0].Streams[0].Consumer[0].Config != nil {
t.Fatal("Config expected to not be present")
}
if len(info.AccountDetails[0].Streams[0].ConsumerRaftGroups) != 0 {
t.Fatalf("expected consumer raft groups to not be returned by %s but got %v", url, info)
}
}
})
t.Run("config", func(t *testing.T) {
Expand Down Expand Up @@ -4393,6 +4396,31 @@ func TestMonitorJsz(t *testing.T) {
}
}
})
t.Run("raftgroups", func(t *testing.T) {
for _, url := range []string{monUrl1, monUrl2} {
info := readJsInfo(url + "?acc=ACC&consumers=true&raft=true")
if len(info.AccountDetails) != 1 {
t.Fatalf("expected account ACC to be returned by %s but got %v", url, info)
}
if len(info.AccountDetails[0].Streams[0].Consumer) == 0 {
t.Fatalf("expected consumers to be returned by %s but got %v", url, info)
}
if len(info.AccountDetails[0].Streams[0].ConsumerRaftGroups) == 0 {
t.Fatalf("expected consumer raft groups to be returned by %s but got %v", url, info)
}
srgroup := info.AccountDetails[0].Streams[0].RaftGroup
if len(srgroup) == 0 {
t.Fatal("expected stream raft group info to be included")
}
crgroup := info.AccountDetails[0].Streams[0].ConsumerRaftGroups[0]
if crgroup.Name != "my-consumer-replicated" {
t.Fatalf("expected consumer name to be included in raft group info, got: %v", crgroup.Name)
}
if len(crgroup.RaftGroup) == 0 {
t.Fatal("expected consumer raft group info to be included")
}
}
})
}

func TestMonitorReloadTLSConfig(t *testing.T) {
Expand Down

0 comments on commit 9cca47c

Please sign in to comment.