fix scheduler driver name; create node structs file

This commit is contained in:
Chelsea Holland Komlo
2018-02-27 14:57:10 -05:00
parent a340baddf1
commit 9ec5a93bc1
8 changed files with 130 additions and 61 deletions

View File

@@ -1008,12 +1008,9 @@ func (c *Client) updateNodeFromFingerprint(response *cstructs.FingerprintRespons
for name, newVal := range response.Drivers {
oldVal := c.config.Node.Drivers[name]
if newVal.Equals(oldVal) {
continue
}
if oldVal == nil {
if oldVal == nil && newVal != nil {
c.config.Node.Drivers[name] = newVal
} else {
} else if newVal != nil && newVal.Detected != oldVal.Detected {
c.config.Node.Drivers[name].MergeFingerprintInfo(newVal)
}
}
@@ -1032,8 +1029,11 @@ func (c *Client) updateNodeFromHealthCheck(response *cstructs.HealthCheckRespons
// update the node with the latest driver health information
for name, newVal := range response.Drivers {
if newVal == nil {
continue
}
oldVal := c.config.Node.Drivers[name]
if newVal.Equals(oldVal) {
if newVal.HealthCheckEquals(oldVal) {
continue
}
nodeHasChanged = true
@@ -1675,6 +1675,7 @@ func (c *Client) watchNodeUpdates() {
c.retryRegisterNode()
hasChanged = false
timer.Reset(c.retryIntv(nodeUpdateRetryIntv))
case <-c.triggerNodeUpdate:
if hasChanged {
continue

View File

@@ -560,7 +560,14 @@ func (d *DockerDriver) HealthCheck(req *cstructs.HealthCheckRequest, resp *cstru
UpdateTime: time.Now(),
}
_, _, err := d.dockerClients()
client, _, err := d.dockerClients()
if err != nil {
d.logger.Printf("[WARN] driver.docker: docker driver is available but is unresponsive to `docker ps`")
resp.AddDriverInfo("docker", unhealthy)
return err
}
_, err = client.ListContainers(docker.ListContainersOptions{All: false})
if err != nil {
d.logger.Printf("[WARN] driver.docker: docker driver is available but is unresponsive to `docker ps`")
resp.AddDriverInfo("docker", unhealthy)
@@ -582,7 +589,7 @@ func (d *DockerDriver) HealthCheck(req *cstructs.HealthCheckRequest, resp *cstru
// interval at which to do them.
func (d *DockerDriver) GetHealthCheckInterval(req *cstructs.HealthCheckIntervalRequest, resp *cstructs.HealthCheckIntervalResponse) error {
resp.Eligible = true
resp.Period = 1 * time.Minute
resp.Period = 3 * time.Second
return nil
}

View File

@@ -206,9 +206,7 @@ func (fm *FingerprintManager) fingerprint(name string, f fingerprint.Fingerprint
func (fm *FingerprintManager) healthCheck(name string, hc fingerprint.HealthCheck) error {
request := &cstructs.HealthCheckRequest{}
var response cstructs.HealthCheckResponse
if err := hc.HealthCheck(request, &response); err != nil {
return err
}
err := hc.HealthCheck(request, &response)
if node := fm.updateHealthCheck(&response); node != nil {
fm.nodeLock.Lock()
@@ -216,7 +214,7 @@ func (fm *FingerprintManager) healthCheck(name string, hc fingerprint.HealthChec
fm.nodeLock.Unlock()
}
return nil
return err
}
// setupFingerprints is used to fingerprint the node to see if these attributes are

46
nomad/structs/node.go Normal file
View File

@@ -0,0 +1,46 @@
package structs
import (
"strings"
"time"
)
// DriverInfo is the current state of a single driver. This is updated
// regularly as driver health changes on the node.
type DriverInfo struct {
Attributes map[string]string
Detected bool
Healthy bool
HealthDescription string
UpdateTime time.Time
}
func (di *DriverInfo) MergeHealthCheck(other *DriverInfo) {
di.Healthy = other.Healthy
di.HealthDescription = other.HealthDescription
di.UpdateTime = other.UpdateTime
}
func (di *DriverInfo) MergeFingerprintInfo(other *DriverInfo) {
di.Detected = other.Detected
di.Attributes = other.Attributes
}
// DriverInfo determines if two driver info objects are equal..As this is used
// in the process of health checking, we only check the fields that are
// computed by the health checker. In the future, this will be merged.
func (di *DriverInfo) HealthCheckEquals(other *DriverInfo) bool {
if di == nil && other != nil || di != nil && other == nil {
return false
}
if di.Healthy != other.Healthy {
return false
}
if strings.Compare(di.HealthDescription, other.HealthDescription) != 0 {
return false
}
return true
}

View File

@@ -0,0 +1,60 @@
package structs
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestDriverInfoEquals(t *testing.T) {
require := require.New(t)
var driverInfoTest = []struct {
input []*DriverInfo
expected bool
errorMsg string
}{
{
[]*DriverInfo{
&DriverInfo{
Healthy: true,
},
&DriverInfo{
Healthy: false,
},
},
false,
"Different healthy values should not be equal.",
},
{
[]*DriverInfo{
&DriverInfo{
HealthDescription: "not running",
},
&DriverInfo{
HealthDescription: "running",
},
},
false,
"Different health description values should not be equal.",
},
{
[]*DriverInfo{
&DriverInfo{
Healthy: true,
HealthDescription: "running",
},
&DriverInfo{
Healthy: true,
HealthDescription: "running",
},
},
true,
"Different health description values should not be equal.",
},
}
for _, testCase := range driverInfoTest {
first := testCase.input[0]
second := testCase.input[1]
require.Equal(testCase.expected, first.HealthCheckEquals(second), testCase.errorMsg)
}
}

View File

@@ -1163,50 +1163,6 @@ func ValidNodeStatus(status string) bool {
}
}
// DriverInfo is the current state of a single driver. This is updated
// regularly as driver health changes on the node.
type DriverInfo struct {
Attributes map[string]string
Detected bool
Healthy bool
HealthDescription string
UpdateTime time.Time
}
func (di *DriverInfo) MergeHealthCheck(other *DriverInfo) {
di.Healthy = other.Healthy
di.HealthDescription = other.HealthDescription
di.UpdateTime = other.UpdateTime
}
func (di *DriverInfo) MergeFingerprintInfo(other *DriverInfo) {
di.Detected = other.Detected
di.Attributes = other.Attributes
}
func (di *DriverInfo) Equals(other *DriverInfo) bool {
if di == nil && other == nil {
return true
}
if di == nil && other != nil || di != nil && other == nil {
return false
}
if !di.Detected == other.Detected {
return false
}
if !di.Healthy == other.Healthy {
return false
}
if strings.Compare(di.HealthDescription, other.HealthDescription) != 0 {
return false
}
return true
}
// Node is a representation of a schedulable client node
type Node struct {
// ID is a unique identifier for the node. It can be constructed

View File

@@ -135,13 +135,14 @@ func (c *DriverChecker) hasDrivers(option *structs.Node) bool {
// be on a later version than a Nomad client, we need to check for
// compatibility here to verify the client supports this.
if option.Drivers != nil {
driverInfo := option.Drivers[driverStr]
driverInfo := option.Drivers[driver]
if driverInfo == nil {
c.ctx.Logger().
Printf("[WARN] scheduler.DriverChecker: node %v has no driver info set for %v",
option.ID, driverStr)
option.ID, driver)
return false
}
return driverInfo.Detected && driverInfo.Healthy
} else {
value, ok := option.Attributes[driverStr]

View File

@@ -134,21 +134,21 @@ func TestDriverChecker_HealthChecks(t *testing.T) {
mock.Node(),
}
nodes[0].Attributes["driver.foo"] = "1"
nodes[0].Drivers["driver.foo"] = &structs.DriverInfo{
nodes[0].Drivers["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{
nodes[1].Drivers["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{
nodes[2].Drivers["baz"] = &structs.DriverInfo{
Detected: false,
Healthy: false,
HealthDescription: "not running",