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  }