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 }