2014-01-04 01:15:51 +00:00
|
|
|
package agent
|
|
|
|
|
|
|
|
import (
|
2014-01-30 23:35:38 +00:00
|
|
|
"fmt"
|
2014-01-30 23:18:05 +00:00
|
|
|
"github.com/hashicorp/consul/consul/structs"
|
2014-05-27 22:09:28 +00:00
|
|
|
"github.com/hashicorp/serf/serf"
|
2014-01-04 01:15:51 +00:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2014-05-27 22:09:28 +00:00
|
|
|
type AgentSelf struct {
|
|
|
|
Config *Config
|
|
|
|
Member serf.Member
|
|
|
|
}
|
|
|
|
|
2014-05-25 23:59:48 +00:00
|
|
|
func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-05-27 22:09:28 +00:00
|
|
|
return AgentSelf{
|
|
|
|
Config: s.agent.config,
|
|
|
|
Member: s.agent.LocalMember(),
|
|
|
|
}, nil
|
2014-05-25 23:59:48 +00:00
|
|
|
}
|
|
|
|
|
2014-01-04 01:15:51 +00:00
|
|
|
func (s *HTTPServer) AgentServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-21 19:52:25 +00:00
|
|
|
services := s.agent.state.Services()
|
2014-01-21 01:00:52 +00:00
|
|
|
return services, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-21 19:52:25 +00:00
|
|
|
checks := s.agent.state.Checks()
|
2014-01-21 01:00:52 +00:00
|
|
|
return checks, nil
|
2014-01-04 01:15:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentMembers(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
|
|
|
// Check if the WAN is being queried
|
|
|
|
wan := false
|
|
|
|
if other := req.URL.Query().Get("wan"); other != "" {
|
|
|
|
wan = true
|
|
|
|
}
|
|
|
|
if wan {
|
|
|
|
return s.agent.WANMembers(), nil
|
|
|
|
} else {
|
|
|
|
return s.agent.LANMembers(), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentJoin(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
|
|
|
// Check if the WAN is being queried
|
|
|
|
wan := false
|
|
|
|
if other := req.URL.Query().Get("wan"); other != "" {
|
|
|
|
wan = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the address
|
|
|
|
addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/join/")
|
|
|
|
if wan {
|
|
|
|
_, err := s.agent.JoinWAN([]string{addr})
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, err
|
2014-01-04 01:15:51 +00:00
|
|
|
} else {
|
|
|
|
_, err := s.agent.JoinLAN([]string{addr})
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, err
|
2014-01-04 01:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentForceLeave(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
|
|
|
addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/force-leave/")
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, s.agent.ForceLeave(addr)
|
2014-01-04 01:15:51 +00:00
|
|
|
}
|
2014-01-30 22:58:36 +00:00
|
|
|
|
|
|
|
func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:35:38 +00:00
|
|
|
var args CheckDefinition
|
2014-04-21 22:02:36 +00:00
|
|
|
// Fixup the type decode of TTL or Interval
|
|
|
|
decodeCB := func(raw interface{}) error {
|
|
|
|
return FixupCheckType(raw)
|
|
|
|
}
|
|
|
|
if err := decodeBody(req, &args, decodeCB); err != nil {
|
2014-01-30 23:35:38 +00:00
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify the check has a name
|
|
|
|
if args.Name == "" {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Missing check name"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the health check
|
2014-02-03 23:15:35 +00:00
|
|
|
health := args.HealthCheck(s.agent.config.NodeName)
|
2014-01-30 23:35:38 +00:00
|
|
|
|
|
|
|
// Verify the check type
|
|
|
|
chkType := &args.CheckType
|
|
|
|
if !chkType.Valid() {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Must provide TTL or Script and Interval!"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the check
|
2014-11-25 03:24:32 +00:00
|
|
|
return nil, s.agent.AddCheck(health, chkType, true)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:18:05 +00:00
|
|
|
checkID := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/")
|
2014-11-26 07:58:02 +00:00
|
|
|
return nil, s.agent.RemoveCheck(checkID, true)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentCheckPass(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:18:05 +00:00
|
|
|
checkID := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/pass/")
|
|
|
|
note := req.URL.Query().Get("note")
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, s.agent.UpdateCheck(checkID, structs.HealthPassing, note)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentCheckWarn(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:18:05 +00:00
|
|
|
checkID := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/warn/")
|
|
|
|
note := req.URL.Query().Get("note")
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, s.agent.UpdateCheck(checkID, structs.HealthWarning, note)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentCheckFail(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:18:05 +00:00
|
|
|
checkID := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/fail/")
|
|
|
|
note := req.URL.Query().Get("note")
|
2014-02-19 22:27:01 +00:00
|
|
|
return nil, s.agent.UpdateCheck(checkID, structs.HealthCritical, note)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:35:38 +00:00
|
|
|
var args ServiceDefinition
|
2014-04-21 22:02:36 +00:00
|
|
|
// Fixup the type decode of TTL or Interval if a check if provided
|
|
|
|
decodeCB := func(raw interface{}) error {
|
|
|
|
rawMap, ok := raw.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2014-04-25 02:44:27 +00:00
|
|
|
|
|
|
|
var check interface{}
|
|
|
|
for k, v := range rawMap {
|
|
|
|
if strings.ToLower(k) == "check" {
|
|
|
|
check = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if check == nil {
|
2014-04-21 22:02:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
2014-04-25 02:44:27 +00:00
|
|
|
|
2014-04-21 22:02:36 +00:00
|
|
|
return FixupCheckType(check)
|
|
|
|
}
|
|
|
|
if err := decodeBody(req, &args, decodeCB); err != nil {
|
2014-01-30 23:35:38 +00:00
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify the service has a name
|
|
|
|
if args.Name == "" {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Missing service name"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2014-02-03 23:15:35 +00:00
|
|
|
// Get the node service
|
|
|
|
ns := args.NodeService()
|
2014-01-30 23:35:38 +00:00
|
|
|
|
|
|
|
// Verify the check type
|
2014-02-03 23:15:35 +00:00
|
|
|
chkType := args.CheckType()
|
2014-01-30 23:35:38 +00:00
|
|
|
if chkType != nil && !chkType.Valid() {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Must provide TTL or Script and Interval!"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the check
|
2014-11-25 03:24:32 +00:00
|
|
|
return nil, s.agent.AddService(ns, chkType, true)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *HTTPServer) AgentDeregisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2014-01-30 23:18:05 +00:00
|
|
|
serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/")
|
2014-11-26 07:58:02 +00:00
|
|
|
return nil, s.agent.RemoveService(serviceID, true)
|
2014-01-30 22:58:36 +00:00
|
|
|
}
|
2015-01-15 08:16:34 +00:00
|
|
|
|
|
|
|
func (s *HTTPServer) AgentServiceMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2015-01-15 09:17:35 +00:00
|
|
|
// Only PUT supported
|
|
|
|
if req.Method != "PUT" {
|
|
|
|
resp.WriteHeader(405)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2015-01-15 08:16:34 +00:00
|
|
|
// Ensure we have a service ID
|
|
|
|
serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/")
|
|
|
|
if serviceID == "" {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Missing service ID"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have some action
|
|
|
|
params := req.URL.Query()
|
|
|
|
if _, ok := params["enable"]; !ok {
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte("Missing value for enable"))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var enable bool
|
|
|
|
raw := params.Get("enable")
|
|
|
|
switch raw {
|
|
|
|
case "true":
|
|
|
|
enable = true
|
|
|
|
case "false":
|
|
|
|
enable = false
|
|
|
|
default:
|
|
|
|
resp.WriteHeader(400)
|
|
|
|
resp.Write([]byte(fmt.Sprintf("Invalid value for enable: %q", raw)))
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2015-01-15 09:17:35 +00:00
|
|
|
var err error
|
2015-01-15 08:16:34 +00:00
|
|
|
if enable {
|
2015-01-15 09:17:35 +00:00
|
|
|
if err = s.agent.EnableServiceMaintenance(serviceID); err != nil {
|
|
|
|
resp.WriteHeader(409)
|
|
|
|
resp.Write([]byte(err.Error()))
|
|
|
|
}
|
2015-01-15 08:16:34 +00:00
|
|
|
} else {
|
2015-01-15 09:17:35 +00:00
|
|
|
if err = s.agent.DisableServiceMaintenance(serviceID); err != nil {
|
|
|
|
resp.WriteHeader(409)
|
|
|
|
resp.Write([]byte(err.Error()))
|
|
|
|
}
|
2015-01-15 08:16:34 +00:00
|
|
|
}
|
2015-01-15 09:17:35 +00:00
|
|
|
return nil, err
|
2015-01-15 08:16:34 +00:00
|
|
|
}
|