Merge branch 'Heuriskein-master'

This commit is contained in:
Armon Dadgar 2015-05-11 16:48:24 -07:00
commit cdfb9945d6
9 changed files with 260 additions and 6 deletions

View File

@ -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

View File

@ -59,6 +59,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)
@ -71,15 +115,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) {
t.Parallel()
c, s := makeClient(t)
@ -231,9 +298,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)

View File

@ -669,6 +669,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, token); err != nil {
return err
}

View File

@ -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)
@ -196,6 +202,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!"))

View File

@ -3,14 +3,15 @@ package agent
import (
"errors"
"fmt"
"github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/consul/testutil"
"github.com/hashicorp/serf/serf"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/consul/testutil"
"github.com/hashicorp/serf/serf"
)
func TestHTTPAgentServices(t *testing.T) {
@ -285,6 +286,84 @@ func TestHTTPAgentRegisterCheck(t *testing.T) {
if token := srv.agent.state.CheckToken("test"); 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) {

View File

@ -352,10 +352,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")

View File

@ -39,6 +39,8 @@ type CheckType struct {
Timeout time.Duration
TTL time.Duration
Status string
Notes string
}
type CheckTypes []*CheckType

View File

@ -47,6 +47,7 @@ type CheckDefinition struct {
Notes string
ServiceID string
Token string
Status string
CheckType `mapstructure:",squash"`
}
@ -59,6 +60,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
}

View File

@ -45,6 +45,12 @@ const (
HealthCritical = "critical"
)
func ValidStatus(s string) bool {
return s == HealthPassing ||
s == HealthWarning ||
s == HealthCritical
}
const (
// Client tokens have rules applied
ACLTypeClient = "client"