mirror of https://github.com/status-im/consul.git
Merge branch 'Heuriskein-master'
This commit is contained in:
commit
ef8027ae2a
|
@ -68,6 +68,7 @@ type AgentServiceCheck struct {
|
||||||
Timeout string `json:",omitempty"`
|
Timeout string `json:",omitempty"`
|
||||||
TTL string `json:",omitempty"`
|
TTL string `json:",omitempty"`
|
||||||
HTTP string `json:",omitempty"`
|
HTTP string `json:",omitempty"`
|
||||||
|
Status string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
type AgentServiceChecks []*AgentServiceCheck
|
type AgentServiceChecks []*AgentServiceCheck
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,50 @@ func TestAgent_Services(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services, err := agent.Services()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if _, ok := services["foo"]; !ok {
|
||||||
|
t.Fatalf("missing service: %v", services)
|
||||||
|
}
|
||||||
|
checks, err := agent.Checks()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
chk, ok := checks["service:foo"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing check: %v", checks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks should default to critical
|
||||||
|
if chk.Status != "critical" {
|
||||||
|
t.Fatalf("Bad: %#v", chk)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := agent.ServiceDeregister("foo"); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgent_Services_CheckPassing(t *testing.T) {
|
||||||
|
c, s := makeClient(t)
|
||||||
|
defer s.stop()
|
||||||
|
|
||||||
|
agent := c.Agent()
|
||||||
|
reg := &AgentServiceRegistration{
|
||||||
|
Name: "foo",
|
||||||
|
Tags: []string{"bar", "baz"},
|
||||||
|
Port: 8000,
|
||||||
|
Check: &AgentServiceCheck{
|
||||||
|
TTL: "15s",
|
||||||
|
Status: "passing",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := agent.ServiceRegister(reg); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
services, err := agent.Services()
|
services, err := agent.Services()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -71,15 +115,38 @@ func TestAgent_Services(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
if _, ok := checks["service:foo"]; !ok {
|
chk, ok := checks["service:foo"]
|
||||||
|
if !ok {
|
||||||
t.Fatalf("missing check: %v", checks)
|
t.Fatalf("missing check: %v", checks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if chk.Status != "passing" {
|
||||||
|
t.Fatalf("Bad: %#v", chk)
|
||||||
|
}
|
||||||
if err := agent.ServiceDeregister("foo"); err != nil {
|
if err := agent.ServiceDeregister("foo"); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAgent_Services_CheckBadStatus(t *testing.T) {
|
||||||
|
c, s := makeClient(t)
|
||||||
|
defer s.stop()
|
||||||
|
|
||||||
|
agent := c.Agent()
|
||||||
|
reg := &AgentServiceRegistration{
|
||||||
|
Name: "foo",
|
||||||
|
Tags: []string{"bar", "baz"},
|
||||||
|
Port: 8000,
|
||||||
|
Check: &AgentServiceCheck{
|
||||||
|
TTL: "15s",
|
||||||
|
Status: "fluffy",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := agent.ServiceRegister(reg); err == nil {
|
||||||
|
t.Fatalf("bad status accepted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAgent_ServiceAddress(t *testing.T) {
|
func TestAgent_ServiceAddress(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c, s := makeClient(t)
|
c, s := makeClient(t)
|
||||||
|
@ -231,9 +298,47 @@ func TestAgent_Checks(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
if _, ok := checks["foo"]; !ok {
|
chk, ok := checks["foo"]
|
||||||
|
if !ok {
|
||||||
t.Fatalf("missing check: %v", checks)
|
t.Fatalf("missing check: %v", checks)
|
||||||
}
|
}
|
||||||
|
if chk.Status != "critical" {
|
||||||
|
t.Fatalf("check not critical: %v", chk)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := agent.CheckDeregister("foo"); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgent_CheckStartPassing(t *testing.T) {
|
||||||
|
c, s := makeClient(t)
|
||||||
|
defer s.stop()
|
||||||
|
|
||||||
|
agent := c.Agent()
|
||||||
|
|
||||||
|
reg := &AgentCheckRegistration{
|
||||||
|
Name: "foo",
|
||||||
|
AgentServiceCheck: AgentServiceCheck{
|
||||||
|
Status: "passing",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
reg.TTL = "15s"
|
||||||
|
if err := agent.CheckRegister(reg); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checks, err := agent.Checks()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
chk, ok := checks["foo"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing check: %v", checks)
|
||||||
|
}
|
||||||
|
if chk.Status != "passing" {
|
||||||
|
t.Fatalf("check not passing: %v", chk)
|
||||||
|
}
|
||||||
|
|
||||||
if err := agent.CheckDeregister("foo"); err != nil {
|
if err := agent.CheckDeregister("foo"); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
|
|
@ -669,6 +669,9 @@ func (a *Agent) AddService(service *structs.NodeService, chkTypes CheckTypes, pe
|
||||||
ServiceID: service.ID,
|
ServiceID: service.ID,
|
||||||
ServiceName: service.Service,
|
ServiceName: service.Service,
|
||||||
}
|
}
|
||||||
|
if chkType.Status != "" {
|
||||||
|
check.Status = chkType.Status
|
||||||
|
}
|
||||||
if err := a.AddCheck(check, chkType, persist, token); err != nil {
|
if err := a.AddCheck(check, chkType, persist, token); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,12 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.Status != "" && !structs.ValidStatus(args.Status) {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte("Bad check status"))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Construct the health check
|
// Construct the health check
|
||||||
health := args.HealthCheck(s.agent.config.NodeName)
|
health := args.HealthCheck(s.agent.config.NodeName)
|
||||||
|
|
||||||
|
@ -196,6 +202,11 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
|
||||||
// Verify the check type
|
// Verify the check type
|
||||||
chkTypes := args.CheckTypes()
|
chkTypes := args.CheckTypes()
|
||||||
for _, check := range chkTypes {
|
for _, check := range chkTypes {
|
||||||
|
if check.Status != "" && !structs.ValidStatus(check.Status) {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte("Status for checks must 'passing', 'warning', 'critical', 'unknown'"))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
if !check.Valid() {
|
if !check.Valid() {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Must provide TTL or Script and Interval!"))
|
resp.Write([]byte("Must provide TTL or Script and Interval!"))
|
||||||
|
|
|
@ -3,14 +3,15 @@ package agent
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
|
||||||
"github.com/hashicorp/consul/testutil"
|
|
||||||
"github.com/hashicorp/serf/serf"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
|
"github.com/hashicorp/consul/testutil"
|
||||||
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHTTPAgentServices(t *testing.T) {
|
func TestHTTPAgentServices(t *testing.T) {
|
||||||
|
@ -285,6 +286,84 @@ func TestHTTPAgentRegisterCheck(t *testing.T) {
|
||||||
if token := srv.agent.state.CheckToken("test"); token == "" {
|
if token := srv.agent.state.CheckToken("test"); token == "" {
|
||||||
t.Fatalf("missing token")
|
t.Fatalf("missing token")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By default, checks start in critical state.
|
||||||
|
state := srv.agent.state.Checks()["test"]
|
||||||
|
if state.Status != structs.HealthCritical {
|
||||||
|
t.Fatalf("bad: %v", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTTPAgentRegisterCheckPassing(t *testing.T) {
|
||||||
|
dir, srv := makeHTTPServer(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
defer srv.Shutdown()
|
||||||
|
defer srv.agent.Shutdown()
|
||||||
|
|
||||||
|
// Register node
|
||||||
|
req, err := http.NewRequest("GET", "/v1/agent/check/register", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
args := &CheckDefinition{
|
||||||
|
Name: "test",
|
||||||
|
CheckType: CheckType{
|
||||||
|
TTL: 15 * time.Second,
|
||||||
|
},
|
||||||
|
Status: structs.HealthPassing,
|
||||||
|
}
|
||||||
|
req.Body = encodeReq(args)
|
||||||
|
|
||||||
|
obj, err := srv.AgentRegisterCheck(nil, req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if obj != nil {
|
||||||
|
t.Fatalf("bad: %v", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have a check mapping
|
||||||
|
if _, ok := srv.agent.state.Checks()["test"]; !ok {
|
||||||
|
t.Fatalf("missing test check")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := srv.agent.checkTTLs["test"]; !ok {
|
||||||
|
t.Fatalf("missing test check ttl")
|
||||||
|
}
|
||||||
|
|
||||||
|
state := srv.agent.state.Checks()["test"]
|
||||||
|
if state.Status != structs.HealthPassing {
|
||||||
|
t.Fatalf("bad: %v", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTTPAgentRegisterCheckBadStatus(t *testing.T) {
|
||||||
|
dir, srv := makeHTTPServer(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
defer srv.Shutdown()
|
||||||
|
defer srv.agent.Shutdown()
|
||||||
|
|
||||||
|
// Register node
|
||||||
|
req, err := http.NewRequest("GET", "/v1/agent/check/register", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
args := &CheckDefinition{
|
||||||
|
Name: "test",
|
||||||
|
CheckType: CheckType{
|
||||||
|
TTL: 15 * time.Second,
|
||||||
|
},
|
||||||
|
Status: "fluffy",
|
||||||
|
}
|
||||||
|
req.Body = encodeReq(args)
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
if _, err := srv.AgentRegisterCheck(resp, req); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if resp.Code != 400 {
|
||||||
|
t.Fatalf("accepted bad status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPAgentDeregisterCheck(t *testing.T) {
|
func TestHTTPAgentDeregisterCheck(t *testing.T) {
|
||||||
|
|
|
@ -352,10 +352,53 @@ func TestAgent_AddCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have a check mapping
|
// Ensure we have a check mapping
|
||||||
if _, ok := agent.state.Checks()["mem"]; !ok {
|
sChk, ok := agent.state.Checks()["mem"]
|
||||||
|
if !ok {
|
||||||
t.Fatalf("missing mem check")
|
t.Fatalf("missing mem check")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure our check is in the right state
|
||||||
|
if sChk.Status != structs.HealthCritical {
|
||||||
|
t.Fatalf("check not critical")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a TTL is setup
|
||||||
|
if _, ok := agent.checkMonitors["mem"]; !ok {
|
||||||
|
t.Fatalf("missing mem monitor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgent_AddCheck_StartPassing(t *testing.T) {
|
||||||
|
dir, agent := makeAgent(t, nextConfig())
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
defer agent.Shutdown()
|
||||||
|
|
||||||
|
health := &structs.HealthCheck{
|
||||||
|
Node: "foo",
|
||||||
|
CheckID: "mem",
|
||||||
|
Name: "memory util",
|
||||||
|
Status: structs.HealthPassing,
|
||||||
|
}
|
||||||
|
chk := &CheckType{
|
||||||
|
Script: "exit 0",
|
||||||
|
Interval: 15 * time.Second,
|
||||||
|
}
|
||||||
|
err := agent.AddCheck(health, chk, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have a check mapping
|
||||||
|
sChk, ok := agent.state.Checks()["mem"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing mem check")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure our check is in the right state
|
||||||
|
if sChk.Status != structs.HealthPassing {
|
||||||
|
t.Fatalf("check not passing")
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure a TTL is setup
|
// Ensure a TTL is setup
|
||||||
if _, ok := agent.checkMonitors["mem"]; !ok {
|
if _, ok := agent.checkMonitors["mem"]; !ok {
|
||||||
t.Fatalf("missing mem monitor")
|
t.Fatalf("missing mem monitor")
|
||||||
|
|
|
@ -39,6 +39,8 @@ type CheckType struct {
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
TTL time.Duration
|
TTL time.Duration
|
||||||
|
|
||||||
|
Status string
|
||||||
|
|
||||||
Notes string
|
Notes string
|
||||||
}
|
}
|
||||||
type CheckTypes []*CheckType
|
type CheckTypes []*CheckType
|
||||||
|
|
|
@ -47,6 +47,7 @@ type CheckDefinition struct {
|
||||||
Notes string
|
Notes string
|
||||||
ServiceID string
|
ServiceID string
|
||||||
Token string
|
Token string
|
||||||
|
Status string
|
||||||
CheckType `mapstructure:",squash"`
|
CheckType `mapstructure:",squash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +60,9 @@ func (c *CheckDefinition) HealthCheck(node string) *structs.HealthCheck {
|
||||||
Notes: c.Notes,
|
Notes: c.Notes,
|
||||||
ServiceID: c.ServiceID,
|
ServiceID: c.ServiceID,
|
||||||
}
|
}
|
||||||
|
if c.Status != "" {
|
||||||
|
health.Status = c.Status
|
||||||
|
}
|
||||||
if health.CheckID == "" && health.Name != "" {
|
if health.CheckID == "" && health.Name != "" {
|
||||||
health.CheckID = health.Name
|
health.CheckID = health.Name
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,12 @@ const (
|
||||||
HealthCritical = "critical"
|
HealthCritical = "critical"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ValidStatus(s string) bool {
|
||||||
|
return s == HealthPassing ||
|
||||||
|
s == HealthWarning ||
|
||||||
|
s == HealthCritical
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Client tokens have rules applied
|
// Client tokens have rules applied
|
||||||
ACLTypeClient = "client"
|
ACLTypeClient = "client"
|
||||||
|
|
Loading…
Reference in New Issue