Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying a status field when registering checks. #859

Merged
merged 2 commits into from
May 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type AgentServiceCheck struct {
Timeout string `json:",omitempty"`
TTL string `json:",omitempty"`
HTTP string `json:",omitempty"`
Status string `json:",omitempty"`
}
type AgentServiceChecks []*AgentServiceCheck

Expand Down
109 changes: 107 additions & 2 deletions api/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,50 @@ func TestAgent_Services(t *testing.T) {
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()
if err != nil {
t.Fatalf("err: %v", err)
Expand All @@ -68,15 +112,38 @@ func TestAgent_Services(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
if _, ok := checks["service:foo"]; !ok {
chk, ok := checks["service:foo"]
if !ok {
t.Fatalf("missing check: %v", checks)
}

if chk.Status != "passing" {
t.Fatalf("Bad: %#v", chk)
}
if err := agent.ServiceDeregister("foo"); err != nil {
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) {
c, s := makeClient(t)
defer s.stop()
Expand Down Expand Up @@ -224,9 +291,47 @@ func TestAgent_Checks(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
if _, ok := checks["foo"]; !ok {
chk, ok := checks["foo"]
if !ok {
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 {
t.Fatalf("err: %v", err)
Expand Down
3 changes: 3 additions & 0 deletions command/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,9 @@ func (a *Agent) AddService(service *structs.NodeService, chkTypes CheckTypes, pe
ServiceID: service.ID,
ServiceName: service.Service,
}
if chkType.Status != "" {
check.Status = chkType.Status
}
if err := a.AddCheck(check, chkType, persist); err != nil {
return err
}
Expand Down
11 changes: 11 additions & 0 deletions command/agent/agent_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
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
health := args.HealthCheck(s.agent.config.NodeName)

Expand Down Expand Up @@ -192,6 +198,11 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
// Verify the check type
chkTypes := args.CheckTypes()
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() {
resp.WriteHeader(400)
resp.Write([]byte("Must provide TTL or Script and Interval!"))
Expand Down
79 changes: 79 additions & 0 deletions command/agent/agent_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,85 @@ func TestHTTPAgentRegisterCheck(t *testing.T) {
if _, ok := srv.agent.checkTTLs["test"]; !ok {
t.Fatalf("missing test check ttl")
}

// 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) {
Expand Down
45 changes: 44 additions & 1 deletion command/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,53 @@ func TestAgent_AddCheck(t *testing.T) {
}

// 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")
}

// 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
if _, ok := agent.checkMonitors["mem"]; !ok {
t.Fatalf("missing mem monitor")
Expand Down
2 changes: 2 additions & 0 deletions command/agent/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type CheckType struct {
Timeout time.Duration
TTL time.Duration

Status string

Notes string
}
type CheckTypes []*CheckType
Expand Down
4 changes: 4 additions & 0 deletions command/agent/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type CheckDefinition struct {
Name string
Notes string
ServiceID string
Status string
CheckType `mapstructure:",squash"`
}

Expand All @@ -57,6 +58,9 @@ func (c *CheckDefinition) HealthCheck(node string) *structs.HealthCheck {
Notes: c.Notes,
ServiceID: c.ServiceID,
}
if c.Status != "" {
health.Status = c.Status
}
if health.CheckID == "" && health.Name != "" {
health.CheckID = health.Name
}
Expand Down
6 changes: 6 additions & 0 deletions consul/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ const (
HealthCritical = "critical"
)

func ValidStatus(s string) bool {
return s == HealthPassing ||
s == HealthWarning ||
s == HealthCritical
}

const (
// Client tokens have rules applied
ACLTypeClient = "client"
Expand Down