Commit 20591354 authored by Chelsea Holland Komlo's avatar Chelsea Holland Komlo
Browse files

allow nomad to schedule based on the status of a client driver health check

parent afdade00
Showing with 90 additions and 13 deletions
+90 -13
...@@ -46,6 +46,7 @@ func Node() *structs.Node { ...@@ -46,6 +46,7 @@ func Node() *structs.Node {
}, },
}, },
}, },
Drivers: make(map[string]*structs.DriverInfo),
Links: map[string]string{ Links: map[string]string{
"consul": "foobar.dc1", "consul": "foobar.dc1",
}, },
......
...@@ -129,21 +129,37 @@ func (c *DriverChecker) Feasible(option *structs.Node) bool { ...@@ -129,21 +129,37 @@ func (c *DriverChecker) Feasible(option *structs.Node) bool {
func (c *DriverChecker) hasDrivers(option *structs.Node) bool { func (c *DriverChecker) hasDrivers(option *structs.Node) bool {
for driver := range c.drivers { for driver := range c.drivers {
driverStr := fmt.Sprintf("driver.%s", driver) driverStr := fmt.Sprintf("driver.%s", driver)
value, ok := option.Attributes[driverStr]
if !ok {
return false
}
enabled, err := strconv.ParseBool(value) // TODO this is a compatibility mechanism- as of Nomad 0.8, nodes have a
if err != nil { // DriverInfo that corresponds with every driver. As a Nomad server might
c.ctx.Logger(). // be on a later version than a Nomad client, we need to check for
Printf("[WARN] scheduler.DriverChecker: node %v has invalid driver setting %v: %v", // compatibility here to verify the client supports this.
option.ID, driverStr, value) if option.Drivers != nil {
return false driverInfo := option.Drivers[driverStr]
} if driverInfo == nil {
c.ctx.Logger().
Printf("[WARN] scheduler.DriverChecker: node %v has no driver info set for %v",
option.ID, driverStr)
return false
}
return driverInfo.Detected && driverInfo.Healthy
} else {
value, ok := option.Attributes[driverStr]
if !ok {
return false
}
if !enabled { enabled, err := strconv.ParseBool(value)
return false if err != nil {
c.ctx.Logger().
Printf("[WARN] scheduler.DriverChecker: node %v has invalid driver setting %v: %v",
option.ID, driverStr, value)
return false
}
if !enabled {
return false
}
} }
} }
return true return true
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"testing" "testing"
"time"
"github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/helper/uuid"
"github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/mock"
...@@ -125,6 +126,65 @@ func TestDriverChecker(t *testing.T) { ...@@ -125,6 +126,65 @@ func TestDriverChecker(t *testing.T) {
} }
} }
func TestDriverChecker_HealthChecks(t *testing.T) {
_, ctx := testContext(t)
nodes := []*structs.Node{
mock.Node(),
mock.Node(),
mock.Node(),
}
nodes[0].Attributes["driver.foo"] = "1"
nodes[0].Drivers["driver.foo"] = &structs.DriverInfo{
Detected: true,
Healthy: true,
HealthDescription: "running",
UpdateTime: time.Now(),
}
nodes[1].Attributes["driver.bar"] = "1"
nodes[1].Drivers["driver.bar"] = &structs.DriverInfo{
Detected: true,
Healthy: false,
HealthDescription: "not running",
UpdateTime: time.Now(),
}
nodes[2].Attributes["driver.baz"] = "0"
nodes[2].Drivers["driver.baz"] = &structs.DriverInfo{
Detected: false,
Healthy: false,
HealthDescription: "not running",
UpdateTime: time.Now(),
}
testDrivers := []string{"foo", "bar", "baz"}
cases := []struct {
Node *structs.Node
Result bool
}{
{
Node: nodes[0],
Result: true,
},
{
Node: nodes[1],
Result: false,
},
{
Node: nodes[2],
Result: false,
},
}
for i, c := range cases {
drivers := map[string]struct{}{
testDrivers[i]: {},
}
checker := NewDriverChecker(ctx, drivers)
if act := checker.Feasible(c.Node); act != c.Result {
t.Fatalf("case(%d) failed: got %v; want %v", i, act, c.Result)
}
}
}
func TestConstraintChecker(t *testing.T) { func TestConstraintChecker(t *testing.T) {
_, ctx := testContext(t) _, ctx := testContext(t)
nodes := []*structs.Node{ nodes := []*structs.Node{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment