From e85b401eb9aab09fdc960b6cd08be782e7034ca3 Mon Sep 17 00:00:00 2001 From: Kyle Havlovitz Date: Wed, 15 Feb 2017 13:30:07 -0800 Subject: [PATCH 1/2] Split operator raft command into subcommands --- command/operator.go | 133 +----------------- command/operator_raft.go | 98 +++++++++++++ command/operator_raft_list.go | 81 +++++++++++ command/operator_raft_list_test.go | 55 ++++++++ command/operator_raft_remove.go | 83 +++++++++++ command/operator_raft_remove_test.go | 59 ++++++++ command/operator_raft_test.go | 22 +++ command/operator_test.go | 50 ------- commands.go | 27 ++++ .../docs/commands/operator.html.markdown.erb | 71 ++-------- .../commands/operator/raft.html.markdown.erb | 34 +++++ .../raft/list-peers.html.markdown.erb | 42 ++++++ .../raft/remove-peer.html.markdown.erb | 29 ++++ website/source/layouts/docs.erb | 25 +++- 14 files changed, 560 insertions(+), 249 deletions(-) create mode 100644 command/operator_raft.go create mode 100644 command/operator_raft_list.go create mode 100644 command/operator_raft_list_test.go create mode 100644 command/operator_raft_remove.go create mode 100644 command/operator_raft_remove_test.go create mode 100644 command/operator_raft_test.go create mode 100644 website/source/docs/commands/operator/raft.html.markdown.erb create mode 100644 website/source/docs/commands/operator/raft/list-peers.html.markdown.erb create mode 100644 website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb diff --git a/command/operator.go b/command/operator.go index cf16040b7a..b9189a3059 100644 --- a/command/operator.go +++ b/command/operator.go @@ -1,13 +1,10 @@ package command import ( - "fmt" "strings" - "flag" - "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/command/base" - "github.com/ryanuber/columnize" + "github.com/mitchellh/cli" ) // OperatorCommand is used to provide various low-level tools for Consul @@ -18,7 +15,7 @@ type OperatorCommand struct { func (c *OperatorCommand) Help() string { helpText := ` -Usage: consul operator [action] [options] +Usage: consul operator [options] Provides cluster-level tools for Consul operators, such as interacting with the Raft subsystem. NOTE: Use this command with extreme caution, as improper @@ -30,139 +27,15 @@ Usage: consul operator [action] [options] Run consul operator with no arguments for help on that subcommand. - -Subcommands: - - raft View and modify Consul's Raft configuration. ` return strings.TrimSpace(helpText) } func (c *OperatorCommand) Run(args []string) int { - if len(args) < 1 { - c.Ui.Error("A subcommand must be specified") - c.Ui.Error("") - c.Ui.Error(c.Help()) - return 1 - } - - var err error - subcommand := args[0] - switch subcommand { - case "raft": - err = c.raft(args[1:]) - default: - err = fmt.Errorf("unknown subcommand %q", subcommand) - } - - if err != nil { - c.Ui.Error(fmt.Sprintf("Operator %q subcommand failed: %v", subcommand, err)) - return 1 - } - return 0 + return cli.RunResultHelp } // Synopsis returns a one-line description of this command. func (c *OperatorCommand) Synopsis() string { return "Provides cluster-level tools for Consul operators" } - -const raftHelp = ` -Operator Raft Subcommand: - - The raft subcommand can be used in two modes: - - consul operator raft -list-peers - - Displays the current Raft peer configuration. - - consul operator raft -remove-peer -address="IP:port" - - Removes Consul server with given -address from the Raft configuration. - - There are rare cases where a peer may be left behind in the Raft quorum even - though the server is no longer present and known to the cluster. This - command can be used to remove the failed server so that it is no longer - affects the Raft quorum. If the server still shows in the output of the - "consul members" command, it is preferable to clean up by simply running - "consul force-leave" instead of this command. - -` - -// raft handles the raft subcommands. -func (c *OperatorCommand) raft(args []string) error { - f := c.Command.NewFlagSet(c) - - // Parse verb arguments. - var listPeers, removePeer bool - f.BoolVar(&listPeers, "list-peers", false, - "If this flag is provided, the current Raft peer configuration will be "+ - "displayed. If the cluster is in an outage state without a leader, you may need "+ - "to set -stale to 'true' to get the configuration from a non-leader server.") - f.BoolVar(&removePeer, "remove-peer", false, - "If this flag is provided, the Consul server with the given -address will be "+ - "removed from the Raft configuration.") - - // Parse other arguments. - var address string - f.StringVar(&address, "address", "", - "The address to remove from the Raft configuration.") - - if err := c.Command.Parse(args); err != nil { - if err == flag.ErrHelp { - c.Ui.Output("") - c.Ui.Output(strings.TrimSpace(raftHelp + c.Command.Help())) - return nil - } - return err - } - - // Set up a client. - client, err := c.Command.HTTPClient() - if err != nil { - return fmt.Errorf("error connecting to Consul agent: %s", err) - } - operator := client.Operator() - - // Dispatch based on the verb argument. - if listPeers { - // Fetch the current configuration. - q := &api.QueryOptions{ - AllowStale: c.Command.HTTPStale(), - } - reply, err := operator.RaftGetConfiguration(q) - if err != nil { - return err - } - - // Format it as a nice table. - result := []string{"Node|ID|Address|State|Voter"} - for _, s := range reply.Servers { - state := "follower" - if s.Leader { - state = "leader" - } - result = append(result, fmt.Sprintf("%s|%s|%s|%s|%v", - s.Node, s.ID, s.Address, state, s.Voter)) - } - c.Ui.Output(columnize.SimpleFormat(result)) - } else if removePeer { - // TODO (slackpad) Once we expose IDs, add support for removing - // by ID, add support for that. - if len(address) == 0 { - return fmt.Errorf("an address is required for the peer to remove") - } - - // Try to kick the peer. - if err := operator.RaftRemovePeerByAddress(address, nil); err != nil { - return err - } - c.Ui.Output(fmt.Sprintf("Removed peer with address %q", address)) - } else { - c.Ui.Output(c.Help()) - c.Ui.Output("") - c.Ui.Output(strings.TrimSpace(raftHelp + c.Command.Help())) - } - - return nil -} diff --git a/command/operator_raft.go b/command/operator_raft.go new file mode 100644 index 0000000000..1b51d01dad --- /dev/null +++ b/command/operator_raft.go @@ -0,0 +1,98 @@ +package command + +import ( + "flag" + "fmt" + "strings" + + "github.com/hashicorp/consul/command/base" +) + +type OperatorRaftCommand struct { + base.Command +} + +func (c *OperatorRaftCommand) Help() string { + helpText := ` +Usage: consul operator raft [options] + +The Raft operator command is used to interact with Consul's Raft subsystem. The +command can be used to verify Raft peers or in rare cases to recover quorum by +removing invalid peers. + +Subcommands: + + list-peers Display the current Raft peer configuration + remove-peer Remove a Consul server from the Raft configuration + +` + + return strings.TrimSpace(helpText) +} + +func (c *OperatorRaftCommand) Synopsis() string { + return "Provides cluster-level tools for Consul operators" +} + +func (c *OperatorRaftCommand) Run(args []string) int { + if result := c.raft(args); result != nil { + c.Ui.Error(result.Error()) + return 1 + } + return 0 +} + +// raft handles the raft subcommands. +func (c *OperatorRaftCommand) raft(args []string) error { + f := c.Command.NewFlagSet(c) + + // Parse verb arguments. + var listPeers, removePeer bool + f.BoolVar(&listPeers, "list-peers", false, + "If this flag is provided, the current Raft peer configuration will be "+ + "displayed. If the cluster is in an outage state without a leader, you may need "+ + "to set -stale to 'true' to get the configuration from a non-leader server.") + f.BoolVar(&removePeer, "remove-peer", false, + "If this flag is provided, the Consul server with the given -address will be "+ + "removed from the Raft configuration.") + + // Parse other arguments. + var address string + f.StringVar(&address, "address", "", + "The address to remove from the Raft configuration.") + + c.Command.HideFlags("list-peers", "remove-peer", "address") + + if err := c.Command.Parse(args); err != nil { + if err == flag.ErrHelp { + return nil + } + return err + } + + // Set up a client. + client, err := c.Command.HTTPClient() + if err != nil { + return fmt.Errorf("error connecting to Consul agent: %s", err) + } + operator := client.Operator() + + // Dispatch based on the verb argument. + if listPeers { + result, err := raftListPeers(operator, c.Command.HTTPStale()) + if err != nil { + c.Ui.Error(fmt.Sprintf("Error getting peers: %v", err)) + } + c.Ui.Output(result) + } else if removePeer { + if err := raftRemovePeers(address, operator); err != nil { + return fmt.Errorf("Error removing peer: %v", err) + } + c.Ui.Output(fmt.Sprintf("Removed peer with address %q", address)) + } else { + c.Ui.Output(c.Help()) + return nil + } + + return nil +} diff --git a/command/operator_raft_list.go b/command/operator_raft_list.go new file mode 100644 index 0000000000..c5285a56c6 --- /dev/null +++ b/command/operator_raft_list.go @@ -0,0 +1,81 @@ +package command + +import ( + "flag" + "fmt" + "strings" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/command/base" + "github.com/ryanuber/columnize" +) + +type OperatorRaftListCommand struct { + base.Command +} + +func (c *OperatorRaftListCommand) Help() string { + helpText := ` +Usage: consul operator raft list-peers [options] + +Displays the current Raft peer configuration. + +` + c.Command.Help() + + return strings.TrimSpace(helpText) +} + +func (c *OperatorRaftListCommand) Synopsis() string { + return "Display the current Raft peer configuration" +} + +func (c *OperatorRaftListCommand) Run(args []string) int { + c.Command.NewFlagSet(c) + + if err := c.Command.Parse(args); err != nil { + if err == flag.ErrHelp { + return 0 + } + c.Ui.Error(fmt.Sprintf("Failed to parse args: %v", err)) + return 1 + } + + // Set up a client. + client, err := c.Command.HTTPClient() + if err != nil { + c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) + return 1 + } + + // Fetch the current configuration. + result, err := raftListPeers(client.Operator(), c.Command.HTTPStale()) + if err != nil { + c.Ui.Error(fmt.Sprintf("Error getting peers: %v", err)) + } + c.Ui.Output(result) + + return 0 +} + +func raftListPeers(operator *api.Operator, stale bool) (string, error) { + q := &api.QueryOptions{ + AllowStale: stale, + } + reply, err := operator.RaftGetConfiguration(q) + if err != nil { + return "", fmt.Errorf("Failed to retrieve raft configuration: %v", err) + } + + // Format it as a nice table. + result := []string{"Node|ID|Address|State|Voter"} + for _, s := range reply.Servers { + state := "follower" + if s.Leader { + state = "leader" + } + result = append(result, fmt.Sprintf("%s|%s|%s|%s|%v", + s.Node, s.ID, s.Address, state, s.Voter)) + } + + return columnize.SimpleFormat(result), nil +} diff --git a/command/operator_raft_list_test.go b/command/operator_raft_list_test.go new file mode 100644 index 0000000000..45de8b77ee --- /dev/null +++ b/command/operator_raft_list_test.go @@ -0,0 +1,55 @@ +package command + +import ( + "strings" + "testing" + + "github.com/hashicorp/consul/command/base" + "github.com/mitchellh/cli" +) + +func TestOperator_Raft_ListPeers_Implements(t *testing.T) { + var _ cli.Command = &OperatorRaftListCommand{} +} + +func TestOperator_Raft_ListPeers(t *testing.T) { + a1 := testAgent(t) + defer a1.Shutdown() + waitForLeader(t, a1.httpAddr) + + // Test the legacy mode with 'consul operator raft -list-peers' + { + ui, c := testOperatorRaftCommand(t) + args := []string{"-http-addr=" + a1.httpAddr, "-list-peers"} + + 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, "leader") { + t.Fatalf("bad: %s", output) + } + } + + // Test the list-peers subcommand directly + { + ui := new(cli.MockUi) + c := OperatorRaftListCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + } + args := []string{"-http-addr=" + a1.httpAddr} + + 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, "leader") { + t.Fatalf("bad: %s", output) + } + } +} diff --git a/command/operator_raft_remove.go b/command/operator_raft_remove.go new file mode 100644 index 0000000000..99e052bcce --- /dev/null +++ b/command/operator_raft_remove.go @@ -0,0 +1,83 @@ +package command + +import ( + "flag" + "fmt" + "strings" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/command/base" +) + +type OperatorRaftRemoveCommand struct { + base.Command +} + +func (c *OperatorRaftRemoveCommand) Help() string { + helpText := ` +Usage: consul operator raft remove-peer [options] + +Remove the Consul server with given -peer-address from the Raft configuration. + +There are rare cases where a peer may be left behind in the Raft quorum even +though the server is no longer present and known to the cluster. This command +can be used to remove the failed server so that it is no longer affects the Raft +quorum. If the server still shows in the output of the "consul members" command, +it is preferable to clean up by simply running "consul force-leave" instead of +this command. + +` + c.Command.Help() + + return strings.TrimSpace(helpText) +} + +func (c *OperatorRaftRemoveCommand) Synopsis() string { + return "Remove a Consul server from the Raft configuration" +} + +func (c *OperatorRaftRemoveCommand) Run(args []string) int { + f := c.Command.NewFlagSet(c) + + var address string + f.StringVar(&address, "address", "", + "The address to remove from the Raft configuration.") + + if err := c.Command.Parse(args); err != nil { + if err == flag.ErrHelp { + return 0 + } + c.Ui.Error(fmt.Sprintf("Failed to parse args: %v", err)) + return 1 + } + + // Set up a client. + client, err := c.Command.HTTPClient() + if err != nil { + c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) + return 1 + } + + // Fetch the current configuration. + if err := raftRemovePeers(address, client.Operator()); err != nil { + c.Ui.Error(fmt.Sprintf("Error removing peer: %v", err)) + return 1 + } + c.Ui.Output(fmt.Sprintf("Removed peer with address %q", address)) + + return 0 +} + +func raftRemovePeers(address string, operator *api.Operator) error { + // TODO (slackpad) Once we expose IDs, add support for removing + // by ID, add support for that. + if len(address) == 0 { + return fmt.Errorf("an address is required for the peer to remove") + } + + // Try to kick the peer. + if err := operator.RaftRemovePeerByAddress(address, nil); err != nil { + return err + } + + return nil +} diff --git a/command/operator_raft_remove_test.go b/command/operator_raft_remove_test.go new file mode 100644 index 0000000000..a549e895c4 --- /dev/null +++ b/command/operator_raft_remove_test.go @@ -0,0 +1,59 @@ +package command + +import ( + "strings" + "testing" + + "github.com/hashicorp/consul/command/base" + "github.com/mitchellh/cli" +) + +func TestOperator_Raft_RemovePeer_Implements(t *testing.T) { + var _ cli.Command = &OperatorRaftRemoveCommand{} +} + +func TestOperator_Raft_RemovePeer(t *testing.T) { + a1 := testAgent(t) + defer a1.Shutdown() + waitForLeader(t, a1.httpAddr) + + // Test the legacy mode with 'consul operator raft -remove-peer' + { + ui, c := testOperatorRaftCommand(t) + args := []string{"-http-addr=" + a1.httpAddr, "-remove-peer", "-address=nope"} + + code := c.Run(args) + if code != 1 { + t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) + } + + // If we get this error, it proves we sent the address all they through. + output := strings.TrimSpace(ui.ErrorWriter.String()) + if !strings.Contains(output, "address \"nope\" was not found in the Raft configuration") { + t.Fatalf("bad: %s", output) + } + } + + // Test the remove-peer subcommand directly + { + ui := new(cli.MockUi) + c := OperatorRaftRemoveCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + } + args := []string{"-http-addr=" + a1.httpAddr, "-address=nope"} + + code := c.Run(args) + if code != 1 { + t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) + } + + // If we get this error, it proves we sent the address all they through. + output := strings.TrimSpace(ui.ErrorWriter.String()) + if !strings.Contains(output, "address \"nope\" was not found in the Raft configuration") { + t.Fatalf("bad: %s", output) + } + } +} diff --git a/command/operator_raft_test.go b/command/operator_raft_test.go new file mode 100644 index 0000000000..643d4cb8a3 --- /dev/null +++ b/command/operator_raft_test.go @@ -0,0 +1,22 @@ +package command + +import ( + "testing" + + "github.com/hashicorp/consul/command/base" + "github.com/mitchellh/cli" +) + +func testOperatorRaftCommand(t *testing.T) (*cli.MockUi, *OperatorRaftCommand) { + ui := new(cli.MockUi) + return ui, &OperatorRaftCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + } +} + +func TestOperator_Raft_Implements(t *testing.T) { + var _ cli.Command = &OperatorRaftCommand{} +} diff --git a/command/operator_test.go b/command/operator_test.go index d31cac0074..485f975449 100644 --- a/command/operator_test.go +++ b/command/operator_test.go @@ -1,61 +1,11 @@ package command import ( - "strings" "testing" - "github.com/hashicorp/consul/command/base" "github.com/mitchellh/cli" ) -func testOperatorCommand(t *testing.T) (*cli.MockUi, *OperatorCommand) { - ui := new(cli.MockUi) - return ui, &OperatorCommand{ - Command: base.Command{ - Ui: ui, - Flags: base.FlagSetHTTP, - }, - } -} - func TestOperator_Implements(t *testing.T) { var _ cli.Command = &OperatorCommand{} } - -func TestOperator_Raft_ListPeers(t *testing.T) { - a1 := testAgent(t) - defer a1.Shutdown() - waitForLeader(t, a1.httpAddr) - - ui, c := testOperatorCommand(t) - args := []string{"raft", "-http-addr=" + a1.httpAddr, "-list-peers"} - - 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, "leader") { - t.Fatalf("bad: %s", output) - } -} - -func TestOperator_Raft_RemovePeer(t *testing.T) { - a1 := testAgent(t) - defer a1.Shutdown() - waitForLeader(t, a1.httpAddr) - - ui, c := testOperatorCommand(t) - args := []string{"raft", "-http-addr=" + a1.httpAddr, "-remove-peer", "-address=nope"} - - code := c.Run(args) - if code != 1 { - t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) - } - - // If we get this error, it proves we sent the address all they through. - output := strings.TrimSpace(ui.ErrorWriter.String()) - if !strings.Contains(output, "address \"nope\" was not found in the Raft configuration") { - t.Fatalf("bad: %s", output) - } -} diff --git a/commands.go b/commands.go index f79c025f99..a9ed849b7b 100644 --- a/commands.go +++ b/commands.go @@ -206,6 +206,33 @@ func init() { "operator": func() (cli.Command, error) { return &command.OperatorCommand{ + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + }, nil + }, + + "operator raft": func() (cli.Command, error) { + return &command.OperatorRaftCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator raft list-peers": func() (cli.Command, error) { + return &command.OperatorRaftListCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator raft remove-peer": func() (cli.Command, error) { + return &command.OperatorRaftRemoveCommand{ Command: base.Command{ Flags: base.FlagSetHTTP, Ui: ui, diff --git a/website/source/docs/commands/operator.html.markdown.erb b/website/source/docs/commands/operator.html.markdown.erb index a25eb69a0c..6961f57627 100644 --- a/website/source/docs/commands/operator.html.markdown.erb +++ b/website/source/docs/commands/operator.html.markdown.erb @@ -28,72 +28,17 @@ endpoint. ## Usage -Usage: `consul operator [action] [options]` +```text +Usage: consul operator [options] -Run `consul operator ` with no arguments for help on that -subcommand. The following subcommands are available: + # ... -* `raft` - View and modify Consul's Raft configuration. +Subcommands: -#### API Options - -<%= partial "docs/commands/http_api_options_client" %> -<%= partial "docs/commands/http_api_options_server" %> - -## Raft Operations - -The `raft` subcommand is used to view and modify Consul's Raft configuration. -Two actions are available, as detailed in this section. - - -#### Display Peer Configuration -This action displays the current Raft peer configuration. - -Usage: `consul operator raft -list-peers -stale=[true|false]` - -* `-stale` - Optional and defaults to "false" which means the leader provides -the result. If the cluster is in an outage state without a leader, you may need -to set this to "true" to get the configuration from a non-leader server. - -The output looks like this: - -``` -Node ID Address State Voter -alice 127.0.0.1:8300 127.0.0.1:8300 follower true -bob 127.0.0.2:8300 127.0.0.2:8300 leader true -carol 127.0.0.3:8300 127.0.0.3:8300 follower true + raft Provides cluster-level tools for Consul operators ``` -`Node` is the node name of the server, as known to Consul, or "(unknown)" if -the node is stale and not known. +For more information, examples, and usage about a subcommand, click on the name +of the subcommand in the sidebar or one of the links below: -`ID` is the ID of the server. This is the same as the `Address` in Consul 0.7 -but may be upgraded to a GUID in a future version of Consul. - -`Address` is the IP:port for the server. - -`State` is either "follower" or "leader" depending on the server's role in the -Raft configuration. - -`Voter` is "true" or "false", indicating if the server has a vote in the Raft -configuration. Future versions of Consul may add support for non-voting servers. - - -#### Remove a Peer -This command removes Consul server with given address from the Raft configuration. - -There are rare cases where a peer may be left behind in the Raft configuration -even though the server is no longer present and known to the cluster. This command -can be used to remove the failed server so that it is no longer affects the -Raft quorum. If the server still shows in the output of the -[`consul members`](/docs/commands/members.html) command, it is preferable to -clean up by simply running -[`consul force-leave`](/docs/commands/force-leave.html) -instead of this command. - -Usage: `consul operator raft -remove-peer -address="IP:port"` - -* `-address` - "IP:port" for the server to remove. The port number is usually -8300, unless configured otherwise. - -The return code will indicate success or failure. +- [raft] (/docs/commands/operator/raft.html) diff --git a/website/source/docs/commands/operator/raft.html.markdown.erb b/website/source/docs/commands/operator/raft.html.markdown.erb new file mode 100644 index 0000000000..4beabfc3fe --- /dev/null +++ b/website/source/docs/commands/operator/raft.html.markdown.erb @@ -0,0 +1,34 @@ +--- +layout: "docs" +page_title: "Commands: Operator Raft" +sidebar_current: "docs-commands-operator-raft" +description: > + The operator raft subcommand is used to view and modify Consul's Raft configuration. +--- + +# Consul Operator Raft + +Command: `consul operator raft` + +The Raft operator command is used to interact with Consul's Raft subsystem. The +command can be used to verify Raft peers or in rare cases to recover quorum by +removing invalid peers. + +## Usage + +```text +Usage: consul operator raft [options] + + # ... + +Subcommands: + + list-peers Display the current Raft peer configuration + remove-peer Remove a Consul server from the Raft configuration +``` + +For more information, examples, and usage about a subcommand, click on the name +of the subcommand in the sidebar or one of the links below: + +- [list-peers] (/docs/commands/operator/raft/list-peers.html) +- [remove-peer] (/docs/commands/operator/raft/remove-peer.html) \ No newline at end of file diff --git a/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb b/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb new file mode 100644 index 0000000000..73d90820f2 --- /dev/null +++ b/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb @@ -0,0 +1,42 @@ +--- +layout: "docs" +page_title: "Commands: Operator Raft List-Peers" +sidebar_current: "docs-commands-operator-raft-list-peers" +description: > + The operator command provides cluster-level tools for Consul operators. +--- + +# Operator Raft List-Peers + +Command: `consul operator raft list-peers` + +This action displays the current Raft peer configuration. + +Usage: `consul operator raft list-peers -stale=[true|false]` + +* `-stale` - Optional and defaults to "false" which means the leader provides +the result. If the cluster is in an outage state without a leader, you may need +to set this to "true" to get the configuration from a non-leader server. + +The output looks like this: + +``` +Node ID Address State Voter +alice 127.0.0.1:8300 127.0.0.1:8300 follower true +bob 127.0.0.2:8300 127.0.0.2:8300 leader true +carol 127.0.0.3:8300 127.0.0.3:8300 follower true +``` + +`Node` is the node name of the server, as known to Consul, or "(unknown)" if +the node is stale and not known. + +`ID` is the ID of the server. This is the same as the `Address` in Consul 0.7 +but may be upgraded to a GUID in a future version of Consul. + +`Address` is the IP:port for the server. + +`State` is either "follower" or "leader" depending on the server's role in the +Raft configuration. + +`Voter` is "true" or "false", indicating if the server has a vote in the Raft +configuration. Future versions of Consul may add support for non-voting servers. diff --git a/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb b/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb new file mode 100644 index 0000000000..16bac5eb90 --- /dev/null +++ b/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb @@ -0,0 +1,29 @@ +--- +layout: "docs" +page_title: "Commands: Operator Raft Remove-Peer" +sidebar_current: "docs-commands-operator-raft-remove-peer" +description: > + The operator command provides cluster-level tools for Consul operators. +--- + +# Operator Raft Remove-Peer + +Command: `consul operator raft remove-peer` + +This command removes the Consul server with given address from the Raft configuration. + +There are rare cases where a peer may be left behind in the Raft configuration +even though the server is no longer present and known to the cluster. This command +can be used to remove the failed server so that it is no longer affects the +Raft quorum. If the server still shows in the output of the +[`consul members`](/docs/commands/members.html) command, it is preferable to +clean up by simply running +[`consul force-leave`](/docs/commands/force-leave.html) +instead of this command. + +Usage: `consul operator raft remove-peer -address="IP:port"` + +* `-address` - "IP:port" for the server to remove. The port number is usually +8300, unless configured otherwise. + +The return code will indicate success or failure. diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index 9d37c0615d..8334c8c6ea 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -15,7 +15,7 @@ > Compatibility Promise - + > Specific Version Details @@ -141,6 +141,19 @@ > operator + > @@ -279,7 +292,7 @@ > Guides - > Frequently Asked Questions From c8d0273f1b28da010ae8f740c1ec2a33e51b20af Mon Sep 17 00:00:00 2001 From: Kyle Havlovitz Date: Thu, 16 Feb 2017 11:44:14 -0800 Subject: [PATCH 2/2] Condense raft subcommand into one doc page --- command/operator_raft.go | 2 + command/operator_raft_remove.go | 2 +- .../commands/operator/raft.html.markdown.erb | 61 ++++++++++++++++--- .../raft/list-peers.html.markdown.erb | 42 ------------- .../raft/remove-peer.html.markdown.erb | 29 --------- website/source/layouts/docs.erb | 10 +-- 6 files changed, 58 insertions(+), 88 deletions(-) delete mode 100644 website/source/docs/commands/operator/raft/list-peers.html.markdown.erb delete mode 100644 website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb diff --git a/command/operator_raft.go b/command/operator_raft.go index 1b51d01dad..2f5ea26c3f 100644 --- a/command/operator_raft.go +++ b/command/operator_raft.go @@ -61,6 +61,8 @@ func (c *OperatorRaftCommand) raft(args []string) error { f.StringVar(&address, "address", "", "The address to remove from the Raft configuration.") + // Leave these flags for backwards compatibility, but hide them + // TODO: remove flags/behavior from this command in Consul 0.9 c.Command.HideFlags("list-peers", "remove-peer", "address") if err := c.Command.Parse(args); err != nil { diff --git a/command/operator_raft_remove.go b/command/operator_raft_remove.go index 99e052bcce..3ca2aaebee 100644 --- a/command/operator_raft_remove.go +++ b/command/operator_raft_remove.go @@ -17,7 +17,7 @@ func (c *OperatorRaftRemoveCommand) Help() string { helpText := ` Usage: consul operator raft remove-peer [options] -Remove the Consul server with given -peer-address from the Raft configuration. +Remove the Consul server with given -address from the Raft configuration. There are rare cases where a peer may be left behind in the Raft quorum even though the server is no longer present and known to the cluster. This command diff --git a/website/source/docs/commands/operator/raft.html.markdown.erb b/website/source/docs/commands/operator/raft.html.markdown.erb index 4beabfc3fe..b2b68f4bd0 100644 --- a/website/source/docs/commands/operator/raft.html.markdown.erb +++ b/website/source/docs/commands/operator/raft.html.markdown.erb @@ -14,12 +14,12 @@ The Raft operator command is used to interact with Consul's Raft subsystem. The command can be used to verify Raft peers or in rare cases to recover quorum by removing invalid peers. -## Usage - ```text Usage: consul operator raft [options] - # ... +The Raft operator command is used to interact with Consul's Raft subsystem. The +command can be used to verify Raft peers or in rare cases to recover quorum by +removing invalid peers. Subcommands: @@ -27,8 +27,55 @@ Subcommands: remove-peer Remove a Consul server from the Raft configuration ``` -For more information, examples, and usage about a subcommand, click on the name -of the subcommand in the sidebar or one of the links below: +## list-peers -- [list-peers] (/docs/commands/operator/raft/list-peers.html) -- [remove-peer] (/docs/commands/operator/raft/remove-peer.html) \ No newline at end of file +This command displays the current Raft peer configuration. + +Usage: `consul operator raft list-peers -stale=[true|false]` + +* `-stale` - Optional and defaults to "false" which means the leader provides +the result. If the cluster is in an outage state without a leader, you may need +to set this to "true" to get the configuration from a non-leader server. + +The output looks like this: + +``` +Node ID Address State Voter +alice 127.0.0.1:8300 127.0.0.1:8300 follower true +bob 127.0.0.2:8300 127.0.0.2:8300 leader true +carol 127.0.0.3:8300 127.0.0.3:8300 follower true +``` + +`Node` is the node name of the server, as known to Consul, or "(unknown)" if +the node is stale and not known. + +`ID` is the ID of the server. This is the same as the `Address` in Consul 0.7 +but may be upgraded to a GUID in a future version of Consul. + +`Address` is the IP:port for the server. + +`State` is either "follower" or "leader" depending on the server's role in the +Raft configuration. + +`Voter` is "true" or "false", indicating if the server has a vote in the Raft +configuration. Future versions of Consul may add support for non-voting servers. + +## remove-peer + +This command removes the Consul server with given address from the Raft configuration. + +There are rare cases where a peer may be left behind in the Raft configuration +even though the server is no longer present and known to the cluster. This command +can be used to remove the failed server so that it is no longer affects the +Raft quorum. If the server still shows in the output of the +[`consul members`](/docs/commands/members.html) command, it is preferable to +clean up by simply running +[`consul force-leave`](/docs/commands/force-leave.html) +instead of this command. + +Usage: `consul operator raft remove-peer -address="IP:port"` + +* `-address` - "IP:port" for the server to remove. The port number is usually +8300, unless configured otherwise. + +The return code will indicate success or failure. diff --git a/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb b/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb deleted file mode 100644 index 73d90820f2..0000000000 --- a/website/source/docs/commands/operator/raft/list-peers.html.markdown.erb +++ /dev/null @@ -1,42 +0,0 @@ ---- -layout: "docs" -page_title: "Commands: Operator Raft List-Peers" -sidebar_current: "docs-commands-operator-raft-list-peers" -description: > - The operator command provides cluster-level tools for Consul operators. ---- - -# Operator Raft List-Peers - -Command: `consul operator raft list-peers` - -This action displays the current Raft peer configuration. - -Usage: `consul operator raft list-peers -stale=[true|false]` - -* `-stale` - Optional and defaults to "false" which means the leader provides -the result. If the cluster is in an outage state without a leader, you may need -to set this to "true" to get the configuration from a non-leader server. - -The output looks like this: - -``` -Node ID Address State Voter -alice 127.0.0.1:8300 127.0.0.1:8300 follower true -bob 127.0.0.2:8300 127.0.0.2:8300 leader true -carol 127.0.0.3:8300 127.0.0.3:8300 follower true -``` - -`Node` is the node name of the server, as known to Consul, or "(unknown)" if -the node is stale and not known. - -`ID` is the ID of the server. This is the same as the `Address` in Consul 0.7 -but may be upgraded to a GUID in a future version of Consul. - -`Address` is the IP:port for the server. - -`State` is either "follower" or "leader" depending on the server's role in the -Raft configuration. - -`Voter` is "true" or "false", indicating if the server has a vote in the Raft -configuration. Future versions of Consul may add support for non-voting servers. diff --git a/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb b/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb deleted file mode 100644 index 16bac5eb90..0000000000 --- a/website/source/docs/commands/operator/raft/remove-peer.html.markdown.erb +++ /dev/null @@ -1,29 +0,0 @@ ---- -layout: "docs" -page_title: "Commands: Operator Raft Remove-Peer" -sidebar_current: "docs-commands-operator-raft-remove-peer" -description: > - The operator command provides cluster-level tools for Consul operators. ---- - -# Operator Raft Remove-Peer - -Command: `consul operator raft remove-peer` - -This command removes the Consul server with given address from the Raft configuration. - -There are rare cases where a peer may be left behind in the Raft configuration -even though the server is no longer present and known to the cluster. This command -can be used to remove the failed server so that it is no longer affects the -Raft quorum. If the server still shows in the output of the -[`consul members`](/docs/commands/members.html) command, it is preferable to -clean up by simply running -[`consul force-leave`](/docs/commands/force-leave.html) -instead of this command. - -Usage: `consul operator raft remove-peer -address="IP:port"` - -* `-address` - "IP:port" for the server to remove. The port number is usually -8300, unless configured otherwise. - -The return code will indicate success or failure. diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index 8334c8c6ea..f972c06607 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -143,15 +143,7 @@ operator