Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add raft query parameter to /jsz to include raft group info #3914

Merged
merged 1 commit into from Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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