github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/api/agent.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  )
     7  
     8  // Agent encapsulates an API client which talks to Nomad's
     9  // agent endpoints for a specific node.
    10  type Agent struct {
    11  	client *Client
    12  
    13  	// Cache static agent info
    14  	nodeName   string
    15  	datacenter string
    16  	region     string
    17  }
    18  
    19  // Agent returns a new agent which can be used to query
    20  // the agent-specific endpoints.
    21  func (c *Client) Agent() *Agent {
    22  	return &Agent{client: c}
    23  }
    24  
    25  // Self is used to query the /v1/agent/self endpoint and
    26  // returns information specific to the running agent.
    27  func (a *Agent) Self() (map[string]map[string]interface{}, error) {
    28  	var out map[string]map[string]interface{}
    29  
    30  	// Query the self endpoint on the agent
    31  	_, err := a.client.query("/v1/agent/self", &out, nil)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("failed querying self endpoint: %s", err)
    34  	}
    35  
    36  	// Populate the cache for faster queries
    37  	a.populateCache(out)
    38  
    39  	return out, nil
    40  }
    41  
    42  // populateCache is used to insert various pieces of static
    43  // data into the agent handle. This is used during subsequent
    44  // lookups for the same data later on to save the round trip.
    45  func (a *Agent) populateCache(info map[string]map[string]interface{}) {
    46  	if a.nodeName == "" {
    47  		a.nodeName, _ = info["member"]["Name"].(string)
    48  	}
    49  	if tags, ok := info["member"]["Tags"].(map[string]interface{}); ok {
    50  		if a.datacenter == "" {
    51  			a.datacenter, _ = tags["dc"].(string)
    52  		}
    53  		if a.region == "" {
    54  			a.region, _ = tags["region"].(string)
    55  		}
    56  	}
    57  }
    58  
    59  // NodeName is used to query the Nomad agent for its node name.
    60  func (a *Agent) NodeName() (string, error) {
    61  	// Return from cache if we have it
    62  	if a.nodeName != "" {
    63  		return a.nodeName, nil
    64  	}
    65  
    66  	// Query the node name
    67  	_, err := a.Self()
    68  	return a.nodeName, err
    69  }
    70  
    71  // Datacenter is used to return the name of the datacenter which
    72  // the agent is a member of.
    73  func (a *Agent) Datacenter() (string, error) {
    74  	// Return from cache if we have it
    75  	if a.datacenter != "" {
    76  		return a.datacenter, nil
    77  	}
    78  
    79  	// Query the agent for the DC
    80  	_, err := a.Self()
    81  	return a.datacenter, err
    82  }
    83  
    84  // Region is used to look up the region the agent is in.
    85  func (a *Agent) Region() (string, error) {
    86  	// Return from cache if we have it
    87  	if a.region != "" {
    88  		return a.region, nil
    89  	}
    90  
    91  	// Query the agent for the region
    92  	_, err := a.Self()
    93  	return a.region, err
    94  }
    95  
    96  // Join is used to instruct a server node to join another server
    97  // via the gossip protocol. Multiple addresses may be specified.
    98  // We attempt to join all of the hosts in the list. Returns the
    99  // number of nodes successfully joined and any error. If one or
   100  // more nodes have a successful result, no error is returned.
   101  func (a *Agent) Join(addrs ...string) (int, error) {
   102  	// Accumulate the addresses
   103  	v := url.Values{}
   104  	for _, addr := range addrs {
   105  		v.Add("address", addr)
   106  	}
   107  
   108  	// Send the join request
   109  	var resp joinResponse
   110  	_, err := a.client.write("/v1/agent/join?"+v.Encode(), nil, &resp, nil)
   111  	if err != nil {
   112  		return 0, fmt.Errorf("failed joining: %s", err)
   113  	}
   114  	if resp.Error != "" {
   115  		return 0, fmt.Errorf("failed joining: %s", resp.Error)
   116  	}
   117  	return resp.NumJoined, nil
   118  }
   119  
   120  // Members is used to query all of the known server members
   121  func (a *Agent) Members() ([]*AgentMember, error) {
   122  	var resp []*AgentMember
   123  
   124  	// Query the known members
   125  	_, err := a.client.query("/v1/agent/members", &resp, nil)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	return resp, nil
   130  }
   131  
   132  // ForceLeave is used to eject an existing node from the cluster.
   133  func (a *Agent) ForceLeave(node string) error {
   134  	_, err := a.client.write("/v1/agent/force-leave?node="+node, nil, nil, nil)
   135  	return err
   136  }
   137  
   138  // Servers is used to query the list of servers on a client node.
   139  func (a *Agent) Servers() ([]string, error) {
   140  	var resp []string
   141  	_, err := a.client.query("/v1/agent/servers", &resp, nil)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	return resp, nil
   146  }
   147  
   148  // SetServers is used to update the list of servers on a client node.
   149  func (a *Agent) SetServers(addrs []string) error {
   150  	// Accumulate the addresses
   151  	v := url.Values{}
   152  	for _, addr := range addrs {
   153  		v.Add("address", addr)
   154  	}
   155  
   156  	_, err := a.client.write("/v1/agent/servers?"+v.Encode(), nil, nil, nil)
   157  	return err
   158  }
   159  
   160  // joinResponse is used to decode the response we get while
   161  // sending a member join request.
   162  type joinResponse struct {
   163  	NumJoined int    `json:"num_joined"`
   164  	Error     string `json:"error"`
   165  }
   166  
   167  // AgentMember represents a cluster member known to the agent
   168  type AgentMember struct {
   169  	Name        string
   170  	Addr        string
   171  	Port        uint16
   172  	Tags        map[string]string
   173  	Status      string
   174  	ProtocolMin uint8
   175  	ProtocolMax uint8
   176  	ProtocolCur uint8
   177  	DelegateMin uint8
   178  	DelegateMax uint8
   179  	DelegateCur uint8
   180  }