github.com/djenriquez/nomad-1@v0.8.1/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) Run(args []string) int { 60 var peerAddress string 61 var peerID string 62 63 flags := c.Meta.FlagSet("raft", FlagSetClient) 64 flags.Usage = func() { c.Ui.Output(c.Help()) } 65 66 flags.StringVar(&peerAddress, "peer-address", "", "") 67 flags.StringVar(&peerID, "peer-id", "", "") 68 if err := flags.Parse(args); err != nil { 69 c.Ui.Error(fmt.Sprintf("Failed to parse args: %v", err)) 70 return 1 71 } 72 73 // Set up a client. 74 client, err := c.Meta.Client() 75 if err != nil { 76 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 77 return 1 78 } 79 operator := client.Operator() 80 81 if err := raftRemovePeers(peerAddress, peerID, operator); err != nil { 82 c.Ui.Error(fmt.Sprintf("Error removing peer: %v", err)) 83 return 1 84 } 85 if peerAddress != "" { 86 c.Ui.Output(fmt.Sprintf("Removed peer with address %q", peerAddress)) 87 } else { 88 c.Ui.Output(fmt.Sprintf("Removed peer with id %q", peerID)) 89 } 90 91 return 0 92 } 93 94 func raftRemovePeers(address, id string, operator *api.Operator) error { 95 if len(address) == 0 && len(id) == 0 { 96 return fmt.Errorf("an address or id is required for the peer to remove") 97 } 98 if len(address) > 0 && len(id) > 0 { 99 return fmt.Errorf("cannot give both an address and id") 100 } 101 102 // Try to kick the peer. 103 if len(address) > 0 { 104 if err := operator.RaftRemovePeerByAddress(address, nil); err != nil { 105 return err 106 } 107 } else { 108 if err := operator.RaftRemovePeerByID(id, nil); err != nil { 109 return err 110 } 111 } 112 113 return nil 114 }