Implementing the health methods with tests

This commit is contained in:
Armon Dadgar 2014-01-08 12:15:01 -08:00
parent c6c0f34fe8
commit 2b79c125f2
2 changed files with 211 additions and 10 deletions

View File

@ -388,7 +388,6 @@ func parseServiceNodes(tx *MDBTxn, table *MDBTable, res []interface{}, err error
if err != nil { if err != nil {
panic(fmt.Errorf("Failed to get node services: %v", err)) panic(fmt.Errorf("Failed to get node services: %v", err))
} }
println(fmt.Sprintf("res: %#v", res))
nodes := make(structs.ServiceNodes, len(res)) nodes := make(structs.ServiceNodes, len(res))
for i, r := range res { for i, r := range res {
@ -408,8 +407,47 @@ func parseServiceNodes(tx *MDBTxn, table *MDBTable, res []interface{}, err error
} }
// EnsureCheck is used to create a check or updates it's state // EnsureCheck is used to create a check or updates it's state
func (s *StateStore) EnsureCheck() error { func (s *StateStore) EnsureCheck(check *structs.HealthCheck) error {
return nil // Ensure we have a status
if check.Status == "" {
check.Status = structs.HealthUnknown
}
// Start the txn
tx, err := s.tables.StartTxn(false)
if err != nil {
panic(fmt.Errorf("Failed to start txn: %v", err))
}
defer tx.Abort()
// Ensure the node exists
res, err := s.nodeTable.GetTxn(tx, "id", check.Node)
if err != nil {
return err
}
if len(res) == 0 {
return fmt.Errorf("Missing node registration")
}
// Ensure the service exists if specified
if check.ServiceID != "" {
res, err = s.serviceTable.GetTxn(tx, "id", check.Node, check.ServiceID)
if err != nil {
return err
}
if len(res) == 0 {
return fmt.Errorf("Missing service registration")
}
// Ensure we set the correct service
srv := res[0].(*structs.ServiceNode)
check.ServiceName = srv.ServiceName
}
// Ensure the check is set
if err := s.checkTable.InsertTxn(tx, check); err != nil {
return err
}
return tx.Commit()
} }
// DeleteNodeCheck is used to delete a node health check // DeleteNodeCheck is used to delete a node health check
@ -419,18 +457,31 @@ func (s *StateStore) DeleteNodeCheck(node, id string) error {
} }
// NodeChecks is used to get all the checks for a node // NodeChecks is used to get all the checks for a node
func (s *StateStore) NodeChecks(name string) structs.HealthChecks { func (s *StateStore) NodeChecks(node string) structs.HealthChecks {
return nil return parseHealthChecks(s.checkTable.Get("id", node))
} }
// ServiceChecks is used to get all the checks for a service // ServiceChecks is used to get all the checks for a service
func (s *StateStore) ServiceChecks(name string) structs.HealthChecks { func (s *StateStore) ServiceChecks(service string) structs.HealthChecks {
return nil return parseHealthChecks(s.checkTable.Get("service", service))
} }
// CheckInState is used to get all the checks for a service in a given state // CheckInState is used to get all the checks for a service in a given state
func (s *StateStore) ChecksInState(name string) structs.HealthChecks { func (s *StateStore) ChecksInState(state string) structs.HealthChecks {
return nil return parseHealthChecks(s.checkTable.Get("status", state))
}
// parseHealthChecks is used to handle the resutls of a Get against
// the checkTable
func parseHealthChecks(res []interface{}, err error) structs.HealthChecks {
if err != nil {
panic(fmt.Errorf("Failed to get checks: %v", err))
}
results := make([]*structs.HealthCheck, len(res))
for i, r := range res {
results[i] = r.(*structs.HealthCheck)
}
return results
} }
// Snapshot is used to create a point in time snapshot // Snapshot is used to create a point in time snapshot

View File

@ -2,6 +2,7 @@ package consul
import ( import (
"github.com/hashicorp/consul/consul/structs" "github.com/hashicorp/consul/consul/structs"
"reflect"
"sort" "sort"
"testing" "testing"
) )
@ -163,6 +164,17 @@ func TestDeleteNodeService(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
check := &structs.HealthCheck{
Node: "foo",
CheckID: "api",
Name: "Can connect",
Status: structs.HealthPassing,
ServiceID: "api",
}
if err := store.EnsureCheck(check); err != nil {
t.Fatalf("err: %v")
}
if err := store.DeleteNodeService("foo", "api"); err != nil { if err := store.DeleteNodeService("foo", "api"); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -172,6 +184,11 @@ func TestDeleteNodeService(t *testing.T) {
if ok { if ok {
t.Fatalf("has api: %#v", services) t.Fatalf("has api: %#v", services)
} }
checks := store.NodeChecks("foo")
if len(checks) != 0 {
t.Fatalf("has check: %#v", checks)
}
} }
func TestDeleteNodeService_One(t *testing.T) { func TestDeleteNodeService_One(t *testing.T) {
@ -223,8 +240,19 @@ func TestDeleteNode(t *testing.T) {
t.Fatalf("err: %v") t.Fatalf("err: %v")
} }
check := &structs.HealthCheck{
Node: "foo",
CheckID: "db",
Name: "Can connect",
Status: structs.HealthPassing,
ServiceID: "api",
}
if err := store.EnsureCheck(check); err != nil {
t.Fatalf("err: %v", err)
}
if err := store.DeleteNode("foo"); err != nil { if err := store.DeleteNode("foo"); err != nil {
t.Fatalf("err: %v") t.Fatalf("err: %v", err)
} }
services := store.NodeServices("foo") services := store.NodeServices("foo")
@ -233,6 +261,11 @@ func TestDeleteNode(t *testing.T) {
t.Fatalf("has api: %#v", services) t.Fatalf("has api: %#v", services)
} }
checks := store.NodeChecks("foo")
if len(checks) > 0 {
t.Fatalf("has checks: %v", checks)
}
found, _ := store.GetNode("foo") found, _ := store.GetNode("foo")
if found { if found {
t.Fatalf("found node") t.Fatalf("found node")
@ -504,3 +537,120 @@ func TestStoreSnapshot(t *testing.T) {
t.Fatalf("bad: %v", services) t.Fatalf("bad: %v", services)
} }
} }
func TestEnsureCheck(t *testing.T) {
store, err := NewStateStore()
if err != nil {
t.Fatalf("err: %v", err)
}
defer store.Close()
if err := store.EnsureNode(structs.Node{"foo", "127.0.0.1"}); err != nil {
t.Fatalf("err: %v", err)
}
if err := store.EnsureService("foo", "db1", "db", "master", 8000); err != nil {
t.Fatalf("err: %v")
}
check := &structs.HealthCheck{
Node: "foo",
CheckID: "db",
Name: "Can connect",
Status: structs.HealthPassing,
ServiceID: "db1",
}
if err := store.EnsureCheck(check); err != nil {
t.Fatalf("err: %v")
}
check2 := &structs.HealthCheck{
Node: "foo",
CheckID: "memory",
Name: "memory utilization",
Status: structs.HealthWarning,
}
if err := store.EnsureCheck(check2); err != nil {
t.Fatalf("err: %v")
}
checks := store.NodeChecks("foo")
if len(checks) != 2 {
t.Fatalf("bad: %v", checks)
}
if !reflect.DeepEqual(checks[0], check) {
t.Fatalf("bad: %v", checks[0])
}
if !reflect.DeepEqual(checks[1], check2) {
t.Fatalf("bad: %v", checks[1])
}
checks = store.ServiceChecks("db")
if len(checks) != 1 {
t.Fatalf("bad: %v", checks)
}
if !reflect.DeepEqual(checks[0], check) {
t.Fatalf("bad: %v", checks[0])
}
checks = store.ChecksInState(structs.HealthPassing)
if len(checks) != 1 {
t.Fatalf("bad: %v", checks)
}
if !reflect.DeepEqual(checks[0], check) {
t.Fatalf("bad: %v", checks[0])
}
checks = store.ChecksInState(structs.HealthWarning)
if len(checks) != 1 {
t.Fatalf("bad: %v", checks)
}
if !reflect.DeepEqual(checks[0], check2) {
t.Fatalf("bad: %v", checks[0])
}
}
func TestDeleteNodeCheck(t *testing.T) {
store, err := NewStateStore()
if err != nil {
t.Fatalf("err: %v", err)
}
defer store.Close()
if err := store.EnsureNode(structs.Node{"foo", "127.0.0.1"}); err != nil {
t.Fatalf("err: %v", err)
}
if err := store.EnsureService("foo", "db1", "db", "master", 8000); err != nil {
t.Fatalf("err: %v")
}
check := &structs.HealthCheck{
Node: "foo",
CheckID: "db",
Name: "Can connect",
Status: structs.HealthPassing,
ServiceID: "db1",
}
if err := store.EnsureCheck(check); err != nil {
t.Fatalf("err: %v")
}
check2 := &structs.HealthCheck{
Node: "foo",
CheckID: "memory",
Name: "memory utilization",
Status: structs.HealthWarning,
}
if err := store.EnsureCheck(check2); err != nil {
t.Fatalf("err: %v")
}
if err := store.DeleteNodeCheck("foo", "db"); err != nil {
t.Fatalf("err: %v", err)
}
checks := store.NodeChecks("foo")
if len(checks) != 1 {
t.Fatalf("bad: %v", checks)
}
if !reflect.DeepEqual(checks[0], check2) {
t.Fatalf("bad: %v", checks[0])
}
}