github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/command/agent/agent_endpoint.go (about) 1 package agent 2 3 import ( 4 "net" 5 "net/http" 6 "strings" 7 8 "github.com/hashicorp/nomad/nomad/structs" 9 "github.com/hashicorp/serf/serf" 10 ) 11 12 type Member struct { 13 Name string 14 Addr net.IP 15 Port uint16 16 Tags map[string]string 17 Status string 18 ProtocolMin uint8 19 ProtocolMax uint8 20 ProtocolCur uint8 21 DelegateMin uint8 22 DelegateMax uint8 23 DelegateCur uint8 24 } 25 26 func nomadMember(m serf.Member) Member { 27 return Member{ 28 Name: m.Name, 29 Addr: m.Addr, 30 Port: m.Port, 31 Tags: m.Tags, 32 Status: m.Status.String(), 33 ProtocolMin: m.ProtocolMin, 34 ProtocolMax: m.ProtocolMax, 35 ProtocolCur: m.ProtocolCur, 36 DelegateMin: m.DelegateMin, 37 DelegateMax: m.DelegateMax, 38 DelegateCur: m.DelegateCur, 39 } 40 } 41 42 func (s *HTTPServer) AgentSelfRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 43 if req.Method != "GET" { 44 return nil, CodedError(405, ErrInvalidMethod) 45 } 46 47 // Get the member as a server 48 var member serf.Member 49 srv := s.agent.Server() 50 if srv != nil { 51 member = srv.LocalMember() 52 } 53 54 self := agentSelf{ 55 Config: s.agent.config, 56 Member: nomadMember(member), 57 Stats: s.agent.Stats(), 58 } 59 return self, nil 60 } 61 62 func (s *HTTPServer) AgentJoinRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 63 if req.Method != "PUT" && req.Method != "POST" { 64 return nil, CodedError(405, ErrInvalidMethod) 65 } 66 srv := s.agent.Server() 67 if srv == nil { 68 return nil, CodedError(501, ErrInvalidMethod) 69 } 70 71 // Get the join addresses 72 query := req.URL.Query() 73 addrs := query["address"] 74 if len(addrs) == 0 { 75 return nil, CodedError(400, "missing address to join") 76 } 77 78 // Attempt the join 79 num, err := srv.Join(addrs) 80 var errStr string 81 if err != nil { 82 errStr = err.Error() 83 } 84 return joinResult{num, errStr}, nil 85 } 86 87 func (s *HTTPServer) AgentMembersRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 88 if req.Method != "GET" { 89 return nil, CodedError(405, ErrInvalidMethod) 90 } 91 args := &structs.GenericRequest{} 92 var out structs.ServerMembersResponse 93 if err := s.agent.RPC("Status.Members", args, &out); err != nil { 94 return nil, err 95 } 96 97 return out, nil 98 } 99 100 func (s *HTTPServer) AgentForceLeaveRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 101 if req.Method != "PUT" && req.Method != "POST" { 102 return nil, CodedError(405, ErrInvalidMethod) 103 } 104 srv := s.agent.Server() 105 if srv == nil { 106 return nil, CodedError(501, ErrInvalidMethod) 107 } 108 109 // Get the node to eject 110 node := req.URL.Query().Get("node") 111 if node == "" { 112 return nil, CodedError(400, "missing node to force leave") 113 } 114 115 // Attempt remove 116 err := srv.RemoveFailedNode(node) 117 return nil, err 118 } 119 120 // AgentServersRequest is used to query the list of servers used by the Nomad 121 // Client for RPCs. This endpoint can also be used to update the list of 122 // servers for a given agent. 123 func (s *HTTPServer) AgentServersRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 124 switch req.Method { 125 case "PUT", "POST": 126 return s.updateServers(resp, req) 127 case "GET": 128 return s.listServers(resp, req) 129 default: 130 return nil, CodedError(405, ErrInvalidMethod) 131 } 132 } 133 134 func (s *HTTPServer) listServers(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 135 client := s.agent.Client() 136 if client == nil { 137 return nil, CodedError(501, ErrInvalidMethod) 138 } 139 140 peers := s.agent.client.GetServers() 141 return peers, nil 142 } 143 144 func (s *HTTPServer) updateServers(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 145 client := s.agent.Client() 146 if client == nil { 147 return nil, CodedError(501, ErrInvalidMethod) 148 } 149 150 // Get the servers from the request 151 servers := req.URL.Query()["address"] 152 if len(servers) == 0 { 153 return nil, CodedError(400, "missing server address") 154 } 155 156 // Set the servers list into the client 157 s.agent.logger.Printf("[TRACE] Adding servers %+q to the client's primary server list", servers) 158 if err := client.SetServers(servers); err != nil { 159 s.agent.logger.Printf("[ERR] Attempt to add servers %q to client failed: %v", servers, err) 160 //TODO is this the right error to return? 161 return nil, CodedError(400, err.Error()) 162 } 163 return nil, nil 164 } 165 166 // KeyringOperationRequest allows an operator to install/delete/use keys 167 func (s *HTTPServer) KeyringOperationRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 168 srv := s.agent.Server() 169 if srv == nil { 170 return nil, CodedError(501, ErrInvalidMethod) 171 } 172 173 kmgr := srv.KeyManager() 174 var sresp *serf.KeyResponse 175 var err error 176 177 // Get the key from the req body 178 var args structs.KeyringRequest 179 180 //Get the op 181 op := strings.TrimPrefix(req.URL.Path, "/v1/agent/keyring/") 182 183 switch op { 184 case "list": 185 sresp, err = kmgr.ListKeys() 186 case "install": 187 if err := decodeBody(req, &args); err != nil { 188 return nil, CodedError(500, err.Error()) 189 } 190 sresp, err = kmgr.InstallKey(args.Key) 191 case "use": 192 if err := decodeBody(req, &args); err != nil { 193 return nil, CodedError(500, err.Error()) 194 } 195 sresp, err = kmgr.UseKey(args.Key) 196 case "remove": 197 if err := decodeBody(req, &args); err != nil { 198 return nil, CodedError(500, err.Error()) 199 } 200 sresp, err = kmgr.RemoveKey(args.Key) 201 default: 202 return nil, CodedError(404, "resource not found") 203 } 204 205 if err != nil { 206 return nil, err 207 } 208 kresp := structs.KeyringResponse{ 209 Messages: sresp.Messages, 210 Keys: sresp.Keys, 211 NumNodes: sresp.NumNodes, 212 } 213 return kresp, nil 214 } 215 216 type agentSelf struct { 217 Config *Config `json:"config"` 218 Member Member `json:"member,omitempty"` 219 Stats map[string]map[string]string `json:"stats"` 220 } 221 222 type joinResult struct { 223 NumJoined int `json:"num_joined"` 224 Error string `json:"error"` 225 }