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

Backport of Updated docs added explanation. into release/1.16.x #17791

3 changes: 3 additions & 0 deletions .changelog/17582.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
improved consul operator raft list-peers command added -detailed flag which will print CommitIndex in the table in response
```
17 changes: 17 additions & 0 deletions api/operator_raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,20 @@ func (op *Operator) RaftRemovePeerByID(id string, q *WriteOptions) error {
}
return nil
}

// GetAutoPilotHealth is used to query the autopilot health.
func (op *Operator) GetAutoPilotHealth(q *QueryOptions) (*OperatorHealthReply, error) {
r := op.c.newRequest("GET", "/v1/operator/autopilot/health")
r.setQueryOptions(q)
_, resp, err := op.c.doRequest(r)
if err != nil {
return nil, err
}
defer closeResponseBody(resp)

var out OperatorHealthReply
if err := decodeBody(resp, &out); err != nil {
return nil, err
}
return &out, nil
}
19 changes: 19 additions & 0 deletions api/operator_raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,22 @@ func TestAPI_OperatorRaftLeaderTransfer(t *testing.T) {
t.Fatalf("err:%v", transfer)
}
}

func TestAPI_GetAutoPilotHealth(t *testing.T) {
t.Parallel()
c, s := makeClient(t)
defer s.Stop()

operator := c.Operator()
out, err := operator.GetAutoPilotHealth(nil)
if err != nil {
t.Fatalf("err: %v", err)
}

if len(out.Servers) != 1 ||
!out.Servers[0].Leader ||
!out.Servers[0].Voter ||
out.Servers[0].LastIndex <= 0 {
t.Fatalf("bad: %v", out)
}
}
71 changes: 66 additions & 5 deletions command/operator/raft/listpeers/operator_raft_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ type cmd struct {
flags *flag.FlagSet
http *flags.HTTPFlags
help string

// flags
detailed bool
}

func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.detailed, "detailed", false,
"Outputs additional information 'commit_index' which is "+
"the index of the server's last committed Raft log entry.")
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
flags.Merge(c.flags, c.http.ServerFlags())
Expand All @@ -51,13 +57,22 @@ func (c *cmd) Run(args []string) int {
}

// Fetch the current configuration.
result, err := raftListPeers(client, c.http.Stale())
if err != nil {
c.UI.Error(fmt.Sprintf("Error getting peers: %v", err))
return 1
if c.detailed {
result, err := raftListPeersDetailed(client, c.http.Stale())
if err != nil {
c.UI.Error(fmt.Sprintf("Error getting peers: %v", err))
return 1
}
c.UI.Output(result)
} else {
result, err := raftListPeers(client, c.http.Stale())
if err != nil {
c.UI.Error(fmt.Sprintf("Error getting peers: %v", err))
return 1
}
c.UI.Output(result)
}

c.UI.Output(result)
return 0
}

Expand Down Expand Up @@ -89,6 +104,52 @@ func raftListPeers(client *api.Client, stale bool) (string, error) {
return columnize.Format(result, &columnize.Config{Delim: string([]byte{0x1f})}), nil
}

func raftListPeersDetailed(client *api.Client, stale bool) (string, error) {
q := &api.QueryOptions{
AllowStale: stale,
}
reply, err := client.Operator().RaftGetConfiguration(q)
if err != nil {
return "", fmt.Errorf("Failed to retrieve raft configuration: %v", err)
}

autoPilotReply, err := client.Operator().GetAutoPilotHealth(q)
if err != nil {
return "", fmt.Errorf("Failed to retrieve autopilot health: %v", err)
}

serverHealthDataMap := make(map[string]api.ServerHealth)

for _, serverHealthData := range autoPilotReply.Servers {
serverHealthDataMap[serverHealthData.ID] = serverHealthData
}

// Format it as a nice table.
result := []string{"Node\x1fID\x1fAddress\x1fState\x1fVoter\x1fRaftProtocol\x1fCommitIndex"}
for _, s := range reply.Servers {
raftProtocol := s.ProtocolVersion

if raftProtocol == "" {
raftProtocol = "<=1"
}
state := "follower"
if s.Leader {
state = "leader"
}

serverHealthData, ok := serverHealthDataMap[s.ID]
if ok {
result = append(result, fmt.Sprintf("%s\x1f%s\x1f%s\x1f%s\x1f%v\x1f%s\x1f%v",
s.Node, s.ID, s.Address, state, s.Voter, raftProtocol, serverHealthData.LastIndex))
} else {
result = append(result, fmt.Sprintf("%s\x1f%s\x1f%s\x1f%s\x1f%v\x1f%s\x1f%v",
s.Node, s.ID, s.Address, state, s.Voter, raftProtocol, ""))
}
}

return columnize.Format(result, &columnize.Config{Delim: string([]byte{0x1f})}), nil
}

func (c *cmd) Synopsis() string {
return synopsis
}
Expand Down
27 changes: 27 additions & 0 deletions command/operator/raft/listpeers/operator_raft_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,33 @@ func TestOperatorRaftListPeersCommand(t *testing.T) {
}
}

func TestOperatorRaftListPeersCommandDetailed(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}

t.Parallel()
a := agent.NewTestAgent(t, ``)
defer a.Shutdown()

expected := fmt.Sprintf("%s %s 127.0.0.1:%d leader true 3 1",
a.Config.NodeName, a.Config.NodeID, a.Config.ServerPort)

// Test the list-peers subcommand directly
ui := cli.NewMockUi()
c := New(ui)
args := []string{"-http-addr=" + a.HTTPAddr(), "-detailed"}

code := c.Run(args)
if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
output := strings.TrimSpace(ui.OutputWriter.String())
if !strings.Contains(output, expected) {
t.Fatalf("bad: %q, %q", output, expected)
}
}

func TestOperatorRaftListPeersCommand_verticalBar(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
Expand Down
4 changes: 4 additions & 0 deletions website/content/commands/operator/raft.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ configuration.
we recommend setting this option to `true.
Default is `false`.

- `-detailed` - Outputs additional information 'commit_index' which is
the index of the server's last committed Raft log entry.
Default is `false`.

## remove-peer

Corresponding HTTP API Endpoint: [\[DELETE\] /v1/operator/raft/peer](/consul/api-docs/operator/raft#delete-raft-peer)
Expand Down