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