github.com/Iqoqo/consul@v1.4.5/agent/consul/operator_raft_endpoint.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/hashicorp/consul/acl"
     8  	"github.com/hashicorp/consul/agent/metadata"
     9  	"github.com/hashicorp/consul/agent/structs"
    10  	"github.com/hashicorp/raft"
    11  	"github.com/hashicorp/serf/serf"
    12  )
    13  
    14  // RaftGetConfiguration is used to retrieve the current Raft configuration.
    15  func (op *Operator) RaftGetConfiguration(args *structs.DCSpecificRequest, reply *structs.RaftConfigurationResponse) error {
    16  	if done, err := op.srv.forward("Operator.RaftGetConfiguration", args, args, reply); done {
    17  		return err
    18  	}
    19  
    20  	// This action requires operator read access.
    21  	rule, err := op.srv.ResolveToken(args.Token)
    22  	if err != nil {
    23  		return err
    24  	}
    25  	if rule != nil && !rule.OperatorRead() {
    26  		return acl.ErrPermissionDenied
    27  	}
    28  
    29  	// We can't fetch the leader and the configuration atomically with
    30  	// the current Raft API.
    31  	future := op.srv.raft.GetConfiguration()
    32  	if err := future.Error(); err != nil {
    33  		return err
    34  	}
    35  
    36  	// Index the Consul information about the servers.
    37  	serverMap := make(map[raft.ServerAddress]serf.Member)
    38  	for _, member := range op.srv.serfLAN.Members() {
    39  		valid, parts := metadata.IsConsulServer(member)
    40  		if !valid {
    41  			continue
    42  		}
    43  
    44  		addr := (&net.TCPAddr{IP: member.Addr, Port: parts.Port}).String()
    45  		serverMap[raft.ServerAddress(addr)] = member
    46  	}
    47  
    48  	// Fill out the reply.
    49  	leader := op.srv.raft.Leader()
    50  	reply.Index = future.Index()
    51  	for _, server := range future.Configuration().Servers {
    52  		node := "(unknown)"
    53  		raftProtocolVersion := "unknown"
    54  		if member, ok := serverMap[server.Address]; ok {
    55  			node = member.Name
    56  			raftProtocolVersion = member.Tags["raft_vsn"]
    57  		}
    58  
    59  		entry := &structs.RaftServer{
    60  			ID:              server.ID,
    61  			Node:            node,
    62  			Address:         server.Address,
    63  			Leader:          server.Address == leader,
    64  			Voter:           server.Suffrage == raft.Voter,
    65  			ProtocolVersion: raftProtocolVersion,
    66  		}
    67  		reply.Servers = append(reply.Servers, entry)
    68  	}
    69  	return nil
    70  }
    71  
    72  // RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
    73  // quorum but no longer known to Serf or the catalog) by address in the form of
    74  // "IP:port". The reply argument is not used, but it required to fulfill the RPC
    75  // interface.
    76  func (op *Operator) RaftRemovePeerByAddress(args *structs.RaftRemovePeerRequest, reply *struct{}) error {
    77  	if done, err := op.srv.forward("Operator.RaftRemovePeerByAddress", args, args, reply); done {
    78  		return err
    79  	}
    80  
    81  	// This is a super dangerous operation that requires operator write
    82  	// access.
    83  	rule, err := op.srv.ResolveToken(args.Token)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	if rule != nil && !rule.OperatorWrite() {
    88  		return acl.ErrPermissionDenied
    89  	}
    90  
    91  	// Since this is an operation designed for humans to use, we will return
    92  	// an error if the supplied address isn't among the peers since it's
    93  	// likely they screwed up.
    94  	{
    95  		future := op.srv.raft.GetConfiguration()
    96  		if err := future.Error(); err != nil {
    97  			return err
    98  		}
    99  		for _, s := range future.Configuration().Servers {
   100  			if s.Address == args.Address {
   101  				args.ID = s.ID
   102  				goto REMOVE
   103  			}
   104  		}
   105  		return fmt.Errorf("address %q was not found in the Raft configuration",
   106  			args.Address)
   107  	}
   108  
   109  REMOVE:
   110  	// The Raft library itself will prevent various forms of foot-shooting,
   111  	// like making a configuration with no voters. Some consideration was
   112  	// given here to adding more checks, but it was decided to make this as
   113  	// low-level and direct as possible. We've got ACL coverage to lock this
   114  	// down, and if you are an operator, it's assumed you know what you are
   115  	// doing if you are calling this. If you remove a peer that's known to
   116  	// Serf, for example, it will come back when the leader does a reconcile
   117  	// pass.
   118  	minRaftProtocol, err := op.srv.autopilot.MinRaftProtocol()
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	var future raft.Future
   124  	if minRaftProtocol >= 2 {
   125  		future = op.srv.raft.RemoveServer(args.ID, 0, 0)
   126  	} else {
   127  		future = op.srv.raft.RemovePeer(args.Address)
   128  	}
   129  	if err := future.Error(); err != nil {
   130  		op.srv.logger.Printf("[WARN] consul.operator: Failed to remove Raft peer %q: %v",
   131  			args.Address, err)
   132  		return err
   133  	}
   134  
   135  	op.srv.logger.Printf("[WARN] consul.operator: Removed Raft peer %q", args.Address)
   136  	return nil
   137  }
   138  
   139  // RaftRemovePeerByID is used to kick a stale peer (one that is in the Raft
   140  // quorum but no longer known to Serf or the catalog) by address in the form of
   141  // "IP:port". The reply argument is not used, but is required to fulfill the RPC
   142  // interface.
   143  func (op *Operator) RaftRemovePeerByID(args *structs.RaftRemovePeerRequest, reply *struct{}) error {
   144  	if done, err := op.srv.forward("Operator.RaftRemovePeerByID", args, args, reply); done {
   145  		return err
   146  	}
   147  
   148  	// This is a super dangerous operation that requires operator write
   149  	// access.
   150  	rule, err := op.srv.ResolveToken(args.Token)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	if rule != nil && !rule.OperatorWrite() {
   155  		return acl.ErrPermissionDenied
   156  	}
   157  
   158  	// Since this is an operation designed for humans to use, we will return
   159  	// an error if the supplied id isn't among the peers since it's
   160  	// likely they screwed up.
   161  	{
   162  		future := op.srv.raft.GetConfiguration()
   163  		if err := future.Error(); err != nil {
   164  			return err
   165  		}
   166  		for _, s := range future.Configuration().Servers {
   167  			if s.ID == args.ID {
   168  				args.Address = s.Address
   169  				goto REMOVE
   170  			}
   171  		}
   172  		return fmt.Errorf("id %q was not found in the Raft configuration",
   173  			args.ID)
   174  	}
   175  
   176  REMOVE:
   177  	// The Raft library itself will prevent various forms of foot-shooting,
   178  	// like making a configuration with no voters. Some consideration was
   179  	// given here to adding more checks, but it was decided to make this as
   180  	// low-level and direct as possible. We've got ACL coverage to lock this
   181  	// down, and if you are an operator, it's assumed you know what you are
   182  	// doing if you are calling this. If you remove a peer that's known to
   183  	// Serf, for example, it will come back when the leader does a reconcile
   184  	// pass.
   185  	minRaftProtocol, err := op.srv.autopilot.MinRaftProtocol()
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	var future raft.Future
   191  	if minRaftProtocol >= 2 {
   192  		future = op.srv.raft.RemoveServer(args.ID, 0, 0)
   193  	} else {
   194  		future = op.srv.raft.RemovePeer(args.Address)
   195  	}
   196  	if err := future.Error(); err != nil {
   197  		op.srv.logger.Printf("[WARN] consul.operator: Failed to remove Raft peer with id %q: %v",
   198  			args.ID, err)
   199  		return err
   200  	}
   201  
   202  	op.srv.logger.Printf("[WARN] consul.operator: Removed Raft peer with id %q", args.ID)
   203  	return nil
   204  }