diff --git a/command/agent/health_endpoint.go b/command/agent/health_endpoint.go new file mode 100644 index 000000000..7a1c8a365 --- /dev/null +++ b/command/agent/health_endpoint.go @@ -0,0 +1,125 @@ +package agent + +import ( + "github.com/hashicorp/consul/consul/structs" + "net/http" + "strings" +) + +func (s *HTTPServer) HealthChecksInState(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + // Set default DC + args := structs.ChecksInStateRequest{ + Datacenter: s.agent.config.Datacenter, + } + + // Check for other DC + params := req.URL.Query() + if other := params.Get("dc"); other != "" { + args.Datacenter = other + } + + // Pull out the service name + args.State = strings.TrimPrefix(req.URL.Path, "/v1/health/state/") + if args.State == "" { + resp.WriteHeader(400) + resp.Write([]byte("Missing check state")) + return nil, nil + } + + // Make the RPC request + var out structs.HealthChecks + if err := s.agent.RPC("Health.ChecksInState", &args, &out); err != nil { + return nil, err + } + return out, nil +} + +func (s *HTTPServer) HealthNodeChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + // Set default DC + args := structs.NodeSpecificRequest{ + Datacenter: s.agent.config.Datacenter, + } + + // Check for other DC + params := req.URL.Query() + if other := params.Get("dc"); other != "" { + args.Datacenter = other + } + + // Pull out the service name + args.Node = strings.TrimPrefix(req.URL.Path, "/v1/health/node/") + if args.Node == "" { + resp.WriteHeader(400) + resp.Write([]byte("Missing node name")) + return nil, nil + } + + // Make the RPC request + var out structs.HealthChecks + if err := s.agent.RPC("Health.NodeChecks", &args, &out); err != nil { + return nil, err + } + return out, nil +} + +func (s *HTTPServer) HealthServiceChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + // Set default DC + args := structs.ServiceSpecificRequest{ + Datacenter: s.agent.config.Datacenter, + } + + // Check for other DC + params := req.URL.Query() + if other := params.Get("dc"); other != "" { + args.Datacenter = other + } + + // Pull out the service name + args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/health/checks/") + if args.ServiceName == "" { + resp.WriteHeader(400) + resp.Write([]byte("Missing service name")) + return nil, nil + } + + // Make the RPC request + var out structs.HealthChecks + if err := s.agent.RPC("Health.ServiceChecks", &args, &out); err != nil { + return nil, err + } + return out, nil +} + +func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + // Set default DC + args := structs.ServiceSpecificRequest{ + Datacenter: s.agent.config.Datacenter, + } + + // Check for other DC + params := req.URL.Query() + if other := params.Get("dc"); other != "" { + args.Datacenter = other + } + + // Check for a tag + if _, ok := params["tag"]; ok { + args.ServiceTag = params.Get("tag") + args.TagFilter = true + } + + // Pull out the service name + args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/health/service/") + if args.ServiceName == "" { + resp.WriteHeader(400) + resp.Write([]byte("Missing service name")) + return nil, nil + } + + // Make the RPC request + var out structs.CheckServiceNodes + if err := s.agent.RPC("Health.ServiceNodes", &args, &out); err != nil { + return nil, err + } + return out, nil +} diff --git a/command/agent/http.go b/command/agent/http.go index 5e43a99fb..bedb1efea 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -65,6 +65,11 @@ func (s *HTTPServer) registerHandlers() { s.mux.HandleFunc("/v1/catalog/service/", s.wrap(s.CatalogServiceNodes)) s.mux.HandleFunc("/v1/catalog/node/", s.wrap(s.CatalogNodeServices)) + s.mux.HandleFunc("/v1/health/node/", s.wrap(s.HealthNodeChecks)) + s.mux.HandleFunc("/v1/health/checks/", s.wrap(s.HealthServiceChecks)) + s.mux.HandleFunc("/v1/health/state/", s.wrap(s.HealthChecksInState)) + s.mux.HandleFunc("/v1/health/service/", s.wrap(s.HealthServiceNodes)) + s.mux.HandleFunc("/v1/agent/services", s.wrap(s.AgentServices)) s.mux.HandleFunc("/v1/agent/members", s.wrap(s.AgentMembers)) s.mux.HandleFunc("/v1/agent/join/", s.wrap(s.AgentJoin)) diff --git a/command/agent/http_api.md b/command/agent/http_api.md index 79486bb1b..1cb25871c 100644 --- a/command/agent/http_api.md +++ b/command/agent/http_api.md @@ -16,15 +16,11 @@ The current URLs supported are: * /v1/catalog/service// : Lists the nodes in a given service * /v1/catalog/node// : Lists the services provided by a node -* Health system (future): -* /v1/health/register : Registers a new health check -* /v1/health/deregister : Deregisters a health check -* /v1/health/pass: Pass a health check -* /v1/health/warn: Warn on a health check -* /v1/health/fail: Fail a health check +* Health system: * /v1/health/node/: Returns the health info of a node -* /v1/health/service/: Returns the health info of a service -* /v1/health/query/: Returns the checks in a given state +* /v1/health/checks/: Returns the checks of a service +* /v1/health/service/: Returns the nodes and health info of a service +* /v1/health/state/: Returns the checks in a given state * /v1/status/leader : Returns the current Raft leader * /v1/status/peers : Returns the current Raft peer set @@ -35,3 +31,10 @@ The current URLs supported are: * /v1/agent/join/ : Instructs the local agent to join a node * /v1/agent/force-leave/: Instructs the agent to force a node into the left state +## Future (interacts with local state?) +* /v1/health/register : Registers a new health check +* /v1/health/deregister : Deregisters a health check +* /v1/health/pass: Pass a health check +* /v1/health/warn: Warn on a health check +* /v1/health/fail: Fail a health check +