agent.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package api
  2. import (
  3. "fmt"
  4. )
  5. // AgentCheck represents a check known to the agent
  6. type AgentCheck struct {
  7. Node string
  8. CheckID string
  9. Name string
  10. Status string
  11. Notes string
  12. Output string
  13. ServiceID string
  14. ServiceName string
  15. }
  16. // AgentService represents a service known to the agent
  17. type AgentService struct {
  18. ID string
  19. Service string
  20. Tags []string
  21. Port int
  22. Address string
  23. EnableTagOverride bool
  24. }
  25. // AgentMember represents a cluster member known to the agent
  26. type AgentMember struct {
  27. Name string
  28. Addr string
  29. Port uint16
  30. Tags map[string]string
  31. Status int
  32. ProtocolMin uint8
  33. ProtocolMax uint8
  34. ProtocolCur uint8
  35. DelegateMin uint8
  36. DelegateMax uint8
  37. DelegateCur uint8
  38. }
  39. // AgentServiceRegistration is used to register a new service
  40. type AgentServiceRegistration struct {
  41. ID string `json:",omitempty"`
  42. Name string `json:",omitempty"`
  43. Tags []string `json:",omitempty"`
  44. Port int `json:",omitempty"`
  45. Address string `json:",omitempty"`
  46. EnableTagOverride bool `json:",omitempty"`
  47. Check *AgentServiceCheck
  48. Checks AgentServiceChecks
  49. }
  50. // AgentCheckRegistration is used to register a new check
  51. type AgentCheckRegistration struct {
  52. ID string `json:",omitempty"`
  53. Name string `json:",omitempty"`
  54. Notes string `json:",omitempty"`
  55. ServiceID string `json:",omitempty"`
  56. AgentServiceCheck
  57. }
  58. // AgentServiceCheck is used to create an associated
  59. // check for a service
  60. type AgentServiceCheck struct {
  61. Script string `json:",omitempty"`
  62. DockerContainerID string `json:",omitempty"`
  63. Shell string `json:",omitempty"` // Only supported for Docker.
  64. Interval string `json:",omitempty"`
  65. Timeout string `json:",omitempty"`
  66. TTL string `json:",omitempty"`
  67. HTTP string `json:",omitempty"`
  68. TCP string `json:",omitempty"`
  69. Status string `json:",omitempty"`
  70. }
  71. type AgentServiceChecks []*AgentServiceCheck
  72. // Agent can be used to query the Agent endpoints
  73. type Agent struct {
  74. c *Client
  75. // cache the node name
  76. nodeName string
  77. }
  78. // Agent returns a handle to the agent endpoints
  79. func (c *Client) Agent() *Agent {
  80. return &Agent{c: c}
  81. }
  82. // Self is used to query the agent we are speaking to for
  83. // information about itself
  84. func (a *Agent) Self() (map[string]map[string]interface{}, error) {
  85. r := a.c.newRequest("GET", "/v1/agent/self")
  86. _, resp, err := requireOK(a.c.doRequest(r))
  87. if err != nil {
  88. return nil, err
  89. }
  90. defer resp.Body.Close()
  91. var out map[string]map[string]interface{}
  92. if err := decodeBody(resp, &out); err != nil {
  93. return nil, err
  94. }
  95. return out, nil
  96. }
  97. // NodeName is used to get the node name of the agent
  98. func (a *Agent) NodeName() (string, error) {
  99. if a.nodeName != "" {
  100. return a.nodeName, nil
  101. }
  102. info, err := a.Self()
  103. if err != nil {
  104. return "", err
  105. }
  106. name := info["Config"]["NodeName"].(string)
  107. a.nodeName = name
  108. return name, nil
  109. }
  110. // Checks returns the locally registered checks
  111. func (a *Agent) Checks() (map[string]*AgentCheck, error) {
  112. r := a.c.newRequest("GET", "/v1/agent/checks")
  113. _, resp, err := requireOK(a.c.doRequest(r))
  114. if err != nil {
  115. return nil, err
  116. }
  117. defer resp.Body.Close()
  118. var out map[string]*AgentCheck
  119. if err := decodeBody(resp, &out); err != nil {
  120. return nil, err
  121. }
  122. return out, nil
  123. }
  124. // Services returns the locally registered services
  125. func (a *Agent) Services() (map[string]*AgentService, error) {
  126. r := a.c.newRequest("GET", "/v1/agent/services")
  127. _, resp, err := requireOK(a.c.doRequest(r))
  128. if err != nil {
  129. return nil, err
  130. }
  131. defer resp.Body.Close()
  132. var out map[string]*AgentService
  133. if err := decodeBody(resp, &out); err != nil {
  134. return nil, err
  135. }
  136. return out, nil
  137. }
  138. // Members returns the known gossip members. The WAN
  139. // flag can be used to query a server for WAN members.
  140. func (a *Agent) Members(wan bool) ([]*AgentMember, error) {
  141. r := a.c.newRequest("GET", "/v1/agent/members")
  142. if wan {
  143. r.params.Set("wan", "1")
  144. }
  145. _, resp, err := requireOK(a.c.doRequest(r))
  146. if err != nil {
  147. return nil, err
  148. }
  149. defer resp.Body.Close()
  150. var out []*AgentMember
  151. if err := decodeBody(resp, &out); err != nil {
  152. return nil, err
  153. }
  154. return out, nil
  155. }
  156. // ServiceRegister is used to register a new service with
  157. // the local agent
  158. func (a *Agent) ServiceRegister(service *AgentServiceRegistration) error {
  159. r := a.c.newRequest("PUT", "/v1/agent/service/register")
  160. r.obj = service
  161. _, resp, err := requireOK(a.c.doRequest(r))
  162. if err != nil {
  163. return err
  164. }
  165. resp.Body.Close()
  166. return nil
  167. }
  168. // ServiceDeregister is used to deregister a service with
  169. // the local agent
  170. func (a *Agent) ServiceDeregister(serviceID string) error {
  171. r := a.c.newRequest("PUT", "/v1/agent/service/deregister/"+serviceID)
  172. _, resp, err := requireOK(a.c.doRequest(r))
  173. if err != nil {
  174. return err
  175. }
  176. resp.Body.Close()
  177. return nil
  178. }
  179. // PassTTL is used to set a TTL check to the passing state
  180. func (a *Agent) PassTTL(checkID, note string) error {
  181. return a.UpdateTTL(checkID, note, "pass")
  182. }
  183. // WarnTTL is used to set a TTL check to the warning state
  184. func (a *Agent) WarnTTL(checkID, note string) error {
  185. return a.UpdateTTL(checkID, note, "warn")
  186. }
  187. // FailTTL is used to set a TTL check to the failing state
  188. func (a *Agent) FailTTL(checkID, note string) error {
  189. return a.UpdateTTL(checkID, note, "fail")
  190. }
  191. // UpdateTTL is used to update the TTL of a check
  192. func (a *Agent) UpdateTTL(checkID, note, status string) error {
  193. switch status {
  194. case "pass":
  195. case "warn":
  196. case "fail":
  197. default:
  198. return fmt.Errorf("Invalid status: %s", status)
  199. }
  200. endpoint := fmt.Sprintf("/v1/agent/check/%s/%s", status, checkID)
  201. r := a.c.newRequest("PUT", endpoint)
  202. r.params.Set("note", note)
  203. _, resp, err := requireOK(a.c.doRequest(r))
  204. if err != nil {
  205. return err
  206. }
  207. resp.Body.Close()
  208. return nil
  209. }
  210. // CheckRegister is used to register a new check with
  211. // the local agent
  212. func (a *Agent) CheckRegister(check *AgentCheckRegistration) error {
  213. r := a.c.newRequest("PUT", "/v1/agent/check/register")
  214. r.obj = check
  215. _, resp, err := requireOK(a.c.doRequest(r))
  216. if err != nil {
  217. return err
  218. }
  219. resp.Body.Close()
  220. return nil
  221. }
  222. // CheckDeregister is used to deregister a check with
  223. // the local agent
  224. func (a *Agent) CheckDeregister(checkID string) error {
  225. r := a.c.newRequest("PUT", "/v1/agent/check/deregister/"+checkID)
  226. _, resp, err := requireOK(a.c.doRequest(r))
  227. if err != nil {
  228. return err
  229. }
  230. resp.Body.Close()
  231. return nil
  232. }
  233. // Join is used to instruct the agent to attempt a join to
  234. // another cluster member
  235. func (a *Agent) Join(addr string, wan bool) error {
  236. r := a.c.newRequest("PUT", "/v1/agent/join/"+addr)
  237. if wan {
  238. r.params.Set("wan", "1")
  239. }
  240. _, resp, err := requireOK(a.c.doRequest(r))
  241. if err != nil {
  242. return err
  243. }
  244. resp.Body.Close()
  245. return nil
  246. }
  247. // ForceLeave is used to have the agent eject a failed node
  248. func (a *Agent) ForceLeave(node string) error {
  249. r := a.c.newRequest("PUT", "/v1/agent/force-leave/"+node)
  250. _, resp, err := requireOK(a.c.doRequest(r))
  251. if err != nil {
  252. return err
  253. }
  254. resp.Body.Close()
  255. return nil
  256. }
  257. // EnableServiceMaintenance toggles service maintenance mode on
  258. // for the given service ID.
  259. func (a *Agent) EnableServiceMaintenance(serviceID, reason string) error {
  260. r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID)
  261. r.params.Set("enable", "true")
  262. r.params.Set("reason", reason)
  263. _, resp, err := requireOK(a.c.doRequest(r))
  264. if err != nil {
  265. return err
  266. }
  267. resp.Body.Close()
  268. return nil
  269. }
  270. // DisableServiceMaintenance toggles service maintenance mode off
  271. // for the given service ID.
  272. func (a *Agent) DisableServiceMaintenance(serviceID string) error {
  273. r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID)
  274. r.params.Set("enable", "false")
  275. _, resp, err := requireOK(a.c.doRequest(r))
  276. if err != nil {
  277. return err
  278. }
  279. resp.Body.Close()
  280. return nil
  281. }
  282. // EnableNodeMaintenance toggles node maintenance mode on for the
  283. // agent we are connected to.
  284. func (a *Agent) EnableNodeMaintenance(reason string) error {
  285. r := a.c.newRequest("PUT", "/v1/agent/maintenance")
  286. r.params.Set("enable", "true")
  287. r.params.Set("reason", reason)
  288. _, resp, err := requireOK(a.c.doRequest(r))
  289. if err != nil {
  290. return err
  291. }
  292. resp.Body.Close()
  293. return nil
  294. }
  295. // DisableNodeMaintenance toggles node maintenance mode off for the
  296. // agent we are connected to.
  297. func (a *Agent) DisableNodeMaintenance() error {
  298. r := a.c.newRequest("PUT", "/v1/agent/maintenance")
  299. r.params.Set("enable", "false")
  300. _, resp, err := requireOK(a.c.doRequest(r))
  301. if err != nil {
  302. return err
  303. }
  304. resp.Body.Close()
  305. return nil
  306. }