github.com/DerekStrickland/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 }