github.com/bigcommerce/nomad@v0.9.3-bc/command/operator_raft_remove.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/nomad/api" 8 "github.com/posener/complete" 9 ) 10 11 type OperatorRaftRemoveCommand struct { 12 Meta 13 } 14 15 func (c *OperatorRaftRemoveCommand) Help() string { 16 helpText := ` 17 Usage: nomad operator raft remove-peer [options] 18 19 Remove the Nomad server with given -peer-address from the Raft configuration. 20 21 There are rare cases where a peer may be left behind in the Raft quorum even 22 though the server is no longer present and known to the cluster. This command 23 can be used to remove the failed server so that it is no longer affects the 24 Raft quorum. If the server still shows in the output of the "nomad 25 server-members" command, it is preferable to clean up by simply running "nomad 26 server-force-leave" instead of this command. 27 28 General Options: 29 30 ` + generalOptionsUsage() + ` 31 32 Remove Peer Options: 33 34 -peer-address="IP:port" 35 Remove a Nomad server with given address from the Raft configuration. 36 37 -peer-id="id" 38 Remove a Nomad server with the given ID from the Raft configuration. 39 ` 40 return strings.TrimSpace(helpText) 41 } 42 43 func (c *OperatorRaftRemoveCommand) AutocompleteFlags() complete.Flags { 44 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 45 complete.Flags{ 46 "-peer-address": complete.PredictAnything, 47 "-peer-id": complete.PredictAnything, 48 }) 49 } 50 51 func (c *OperatorRaftRemoveCommand) AutocompleteArgs() complete.Predictor { 52 return complete.PredictNothing 53 } 54 55 func (c *OperatorRaftRemoveCommand) Synopsis() string { 56 return "Remove a Nomad server from the Raft configuration" 57 } 58 59 func (c *OperatorRaftRemoveCommand) Name() string { return "operator raft remove-peer" } 60 61 func (c *OperatorRaftRemoveCommand) Run(args []string) int { 62 var peerAddress string 63 var peerID string 64 65 flags := c.Meta.FlagSet("raft", FlagSetClient) 66 flags.Usage = func() { c.Ui.Output(c.Help()) } 67 68 flags.StringVar(&peerAddress, "peer-address", "", "") 69 flags.StringVar(&peerID, "peer-id", "", "") 70 if err := flags.Parse(args); err != nil { 71 c.Ui.Error(fmt.Sprintf("Failed to parse args: %v", err)) 72 return 1 73 } 74 75 // Set up a client. 76 client, err := c.Meta.Client() 77 if err != nil { 78 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 79 return 1 80 } 81 operator := client.Operator() 82 83 if err := raftRemovePeers(peerAddress, peerID, operator); err != nil { 84 c.Ui.Error(fmt.Sprintf("Error removing peer: %v", err)) 85 return 1 86 } 87 if peerAddress != "" { 88 c.Ui.Output(fmt.Sprintf("Removed peer with address %q", peerAddress)) 89 } else { 90 c.Ui.Output(fmt.Sprintf("Removed peer with id %q", peerID)) 91 } 92 93 return 0 94 } 95 96 func raftRemovePeers(address, id string, operator *api.Operator) error { 97 if len(address) == 0 && len(id) == 0 { 98 return fmt.Errorf("an address or id is required for the peer to remove") 99 } 100 if len(address) > 0 && len(id) > 0 { 101 return fmt.Errorf("cannot give both an address and id") 102 } 103 104 // Try to kick the peer. 105 if len(address) > 0 { 106 if err := operator.RaftRemovePeerByAddress(address, nil); err != nil { 107 return err 108 } 109 } else { 110 if err := operator.RaftRemovePeerByID(id, nil); err != nil { 111 return err 112 } 113 } 114 115 return nil 116 }