github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/nomad/operator_endpoint.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/hashicorp/nomad/nomad/structs"
     8  	"github.com/hashicorp/raft"
     9  	"github.com/hashicorp/serf/serf"
    10  )
    11  
    12  // Operator endpoint is used to perform low-level operator tasks for Nomad.
    13  type Operator struct {
    14  	srv *Server
    15  }
    16  
    17  // RaftGetConfiguration is used to retrieve the current Raft configuration.
    18  func (op *Operator) RaftGetConfiguration(args *structs.GenericRequest, reply *structs.RaftConfigurationResponse) error {
    19  	if done, err := op.srv.forward("Operator.RaftGetConfiguration", args, args, reply); done {
    20  		return err
    21  	}
    22  
    23  	// We can't fetch the leader and the configuration atomically with
    24  	// the current Raft API.
    25  	future := op.srv.raft.GetConfiguration()
    26  	if err := future.Error(); err != nil {
    27  		return err
    28  	}
    29  
    30  	// Index the Nomad information about the servers.
    31  	serverMap := make(map[raft.ServerAddress]serf.Member)
    32  	for _, member := range op.srv.serf.Members() {
    33  		valid, parts := isNomadServer(member)
    34  		if !valid {
    35  			continue
    36  		}
    37  
    38  		addr := (&net.TCPAddr{IP: member.Addr, Port: parts.Port}).String()
    39  		serverMap[raft.ServerAddress(addr)] = member
    40  	}
    41  
    42  	// Fill out the reply.
    43  	leader := op.srv.raft.Leader()
    44  	reply.Index = future.Index()
    45  	for _, server := range future.Configuration().Servers {
    46  		node := "(unknown)"
    47  		if member, ok := serverMap[server.Address]; ok {
    48  			node = member.Name
    49  		}
    50  
    51  		entry := &structs.RaftServer{
    52  			ID:      server.ID,
    53  			Node:    node,
    54  			Address: server.Address,
    55  			Leader:  server.Address == leader,
    56  			Voter:   server.Suffrage == raft.Voter,
    57  		}
    58  		reply.Servers = append(reply.Servers, entry)
    59  	}
    60  	return nil
    61  }
    62  
    63  // RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
    64  // quorum but no longer known to Serf or the catalog) by address in the form of
    65  // "IP:port". The reply argument is not used, but it required to fulfill the RPC
    66  // interface.
    67  func (op *Operator) RaftRemovePeerByAddress(args *structs.RaftPeerByAddressRequest, reply *struct{}) error {
    68  	if done, err := op.srv.forward("Operator.RaftRemovePeerByAddress", args, args, reply); done {
    69  		return err
    70  	}
    71  
    72  	// Since this is an operation designed for humans to use, we will return
    73  	// an error if the supplied address isn't among the peers since it's
    74  	// likely they screwed up.
    75  	{
    76  		future := op.srv.raft.GetConfiguration()
    77  		if err := future.Error(); err != nil {
    78  			return err
    79  		}
    80  		for _, s := range future.Configuration().Servers {
    81  			if s.Address == args.Address {
    82  				goto REMOVE
    83  			}
    84  		}
    85  		return fmt.Errorf("address %q was not found in the Raft configuration",
    86  			args.Address)
    87  	}
    88  
    89  REMOVE:
    90  	// The Raft library itself will prevent various forms of foot-shooting,
    91  	// like making a configuration with no voters. Some consideration was
    92  	// given here to adding more checks, but it was decided to make this as
    93  	// low-level and direct as possible. We've got ACL coverage to lock this
    94  	// down, and if you are an operator, it's assumed you know what you are
    95  	// doing if you are calling this. If you remove a peer that's known to
    96  	// Serf, for example, it will come back when the leader does a reconcile
    97  	// pass.
    98  	future := op.srv.raft.RemovePeer(args.Address)
    99  	if err := future.Error(); err != nil {
   100  		op.srv.logger.Printf("[WARN] nomad.operator: Failed to remove Raft peer %q: %v",
   101  			args.Address, err)
   102  		return err
   103  	}
   104  
   105  	op.srv.logger.Printf("[WARN] nomad.operator: Removed Raft peer %q", args.Address)
   106  	return nil
   107  }