github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/command/operator/raft/removepeer/operator_raft_remove.go (about)

     1  package removepeer
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  
     7  	"github.com/hashicorp/consul/api"
     8  	"github.com/hashicorp/consul/command/flags"
     9  	"github.com/mitchellh/cli"
    10  )
    11  
    12  func New(ui cli.Ui) *cmd {
    13  	c := &cmd{UI: ui}
    14  	c.init()
    15  	return c
    16  }
    17  
    18  type cmd struct {
    19  	UI    cli.Ui
    20  	flags *flag.FlagSet
    21  	http  *flags.HTTPFlags
    22  	help  string
    23  
    24  	// flags
    25  	address string
    26  	id      string
    27  }
    28  
    29  func (c *cmd) init() {
    30  	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
    31  	c.flags.StringVar(&c.address, "address", "",
    32  		"The address to remove from the Raft configuration.")
    33  	c.flags.StringVar(&c.id, "id", "",
    34  		"The ID to remove from the Raft configuration.")
    35  
    36  	c.http = &flags.HTTPFlags{}
    37  	flags.Merge(c.flags, c.http.ClientFlags())
    38  	flags.Merge(c.flags, c.http.ServerFlags())
    39  	c.help = flags.Usage(help, c.flags)
    40  }
    41  
    42  func (c *cmd) Run(args []string) int {
    43  	if err := c.flags.Parse(args); err != nil {
    44  		if err == flag.ErrHelp {
    45  			return 0
    46  		}
    47  		c.UI.Error(fmt.Sprintf("Failed to parse args: %v", err))
    48  		return 1
    49  	}
    50  
    51  	// Set up a client.
    52  	client, err := c.http.APIClient()
    53  	if err != nil {
    54  		c.UI.Error(fmt.Sprintf("Error initializing client: %s", err))
    55  		return 1
    56  	}
    57  
    58  	// Fetch the current configuration.
    59  	if err := raftRemovePeers(c.address, c.id, client.Operator()); err != nil {
    60  		c.UI.Error(fmt.Sprintf("Error removing peer: %v", err))
    61  		return 1
    62  	}
    63  	if c.address != "" {
    64  		c.UI.Output(fmt.Sprintf("Removed peer with address %q", c.address))
    65  	} else {
    66  		c.UI.Output(fmt.Sprintf("Removed peer with id %q", c.id))
    67  	}
    68  
    69  	return 0
    70  }
    71  
    72  func raftRemovePeers(address, id string, operator *api.Operator) error {
    73  	if len(address) == 0 && len(id) == 0 {
    74  		return fmt.Errorf("an address or id is required for the peer to remove")
    75  	}
    76  	if len(address) > 0 && len(id) > 0 {
    77  		return fmt.Errorf("cannot give both an address and id")
    78  	}
    79  
    80  	// Try to kick the peer.
    81  	if len(address) > 0 {
    82  		if err := operator.RaftRemovePeerByAddress(address, nil); err != nil {
    83  			return err
    84  		}
    85  	} else {
    86  		if err := operator.RaftRemovePeerByID(id, nil); err != nil {
    87  			return err
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func (c *cmd) Synopsis() string {
    95  	return synopsis
    96  }
    97  
    98  func (c *cmd) Help() string {
    99  	return c.help
   100  }
   101  
   102  const synopsis = "Remove a Consul server from the Raft configuration"
   103  const help = `
   104  Usage: consul operator raft remove-peer [options]
   105  
   106    Remove the Consul server with given -address from the Raft configuration.
   107  
   108    There are rare cases where a peer may be left behind in the Raft quorum even
   109    though the server is no longer present and known to the cluster. This command
   110    can be used to remove the failed server so that it is no longer affects the Raft
   111    quorum. If the server still shows in the output of the "consul members" command,
   112    it is preferable to clean up by simply running "consul force-leave" instead of
   113    this command.
   114  `