agent.go 8.2 KB

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