Skip to content

Commit

Permalink
add driver manager
Browse files Browse the repository at this point in the history
  • Loading branch information
chelseakomlo committed Jan 25, 2018
1 parent 5e8151d commit 2e2bf74
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 35 deletions.
59 changes: 24 additions & 35 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,12 @@ func (c *Client) fingerprint() error {
whitelistEnabled := len(whitelist) > 0
blacklist := c.config.ReadStringListToMap("fingerprint.blacklist")

driverManager := &DriverManager{
fingerprinters: make(map[string]fingerprint.Fingerprint, 0),
client: c,
logger: c.logger,
}

c.logger.Printf("[DEBUG] client: built-in fingerprints: %v", fingerprint.BuiltinFingerprints())

var applied []string
Expand All @@ -946,6 +952,7 @@ func (c *Client) fingerprint() error {
continue
}
f, err := fingerprint.NewFingerprint(name, c.logger)

if err != nil {
return err
}
Expand Down Expand Up @@ -975,13 +982,14 @@ func (c *Client) fingerprint() error {
// add the diff found from each fingerprinter
c.updateNodeFromFingerprint(response)

p, period := f.Periodic()
p, _ := f.Periodic()
if p {
// TODO: If more periodic fingerprinters are added, then
// fingerprintPeriodic should be used to handle all the periodic
// fingerprinters by using a priority queue.
go c.fingerprintPeriodic(name, f, period)
// append the fingerprinter to the client's driver manager
// TODO this should handle the period before assigning it?
driverManager.fingerprinters[name] = f
}

driverManager.Fingerprint()
}

c.logger.Printf("[DEBUG] client: applied fingerprints %v", applied)
Expand All @@ -991,40 +999,19 @@ func (c *Client) fingerprint() error {
return nil
}

// fingerprintPeriodic runs a fingerprinter at the specified duration.
func (c *Client) fingerprintPeriodic(name string, f fingerprint.Fingerprint, d time.Duration) {
c.logger.Printf("[DEBUG] client: fingerprinting %v every %v", name, d)
for {
select {
case <-time.After(d):
request := &cstructs.FingerprintRequest{Config: c.config, Node: c.config.Node}
response := &cstructs.FingerprintResponse{
Attributes: make(map[string]string, 0),
Links: make(map[string]string, 0),
Resources: &structs.Resources{},
}

err := f.Fingerprint(request, response)

if err != nil {
c.logger.Printf("[DEBUG] client: periodic fingerprinting for %v failed: %v", name, err)
} else {
c.updateNodeFromFingerprint(response)
}

case <-c.shutdownCh:
return
}
}
}

// setupDrivers is used to find the available drivers
func (c *Client) setupDrivers() error {
// Build the white/blacklists of drivers.
whitelist := c.config.ReadStringListToMap("driver.whitelist")
whitelistEnabled := len(whitelist) > 0
blacklist := c.config.ReadStringListToMap("driver.blacklist")

driverManager := &DriverManager{
fingerprinters: make(map[string]fingerprint.Fingerprint, 0),
client: c,
logger: c.logger,
}

var avail []string
var skipped []string
driverCtx := driver.NewDriverContext("", "", c.config, c.config.Node, c.logger, nil)
Expand Down Expand Up @@ -1069,15 +1056,17 @@ func (c *Client) setupDrivers() error {

c.updateNodeFromFingerprint(response)

p, period := d.Periodic()
p, _ := d.Periodic()
if p {
go c.fingerprintPeriodic(name, d, period)
// append the fingerprinter to the client's driver manager
// TODO this should handle the period before assigning it?
driverManager.fingerprinters[name] = d
}

driverManager.Fingerprint()
}

c.logger.Printf("[DEBUG] client: available drivers %v", avail)
c.logger.Printf("[DEBUG] client: skipped attributes %v", skipped)

if len(skipped) != 0 {
c.logger.Printf("[DEBUG] client: drivers skipped due to white/blacklist: %v", skipped)
Expand Down
56 changes: 56 additions & 0 deletions client/driver_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package client

import (
"log"
"time"

"github.com/hashicorp/nomad/client/fingerprint"
cstructs "github.com/hashicorp/nomad/client/structs"
"github.com/hashicorp/nomad/nomad/structs"
)

// DriverManager runs a client fingerprinters on a continuous basis, and
// updates the client when the node has changed
type DriverManager struct {
fingerprinters map[string]fingerprint.Fingerprint
client *Client
logger *log.Logger
}

// Fingerprint starts the ongoing process of running a client's fingerprinters
// and continuously updating its attributes
func (dm *DriverManager) Fingerprint() {
for name, f := range dm.fingerprinters {
go dm.runFingerprint(f, name)
}
}

// runFingerprint is an interfal function which runs each fingerprinter
// individually on an ongoing basis
func (dm *DriverManager) runFingerprint(f fingerprint.Fingerprint, name string) {
_, period := f.Periodic()
dm.logger.Printf("[DEBUG] driver_manager: fingerprinting %s every %v", name, period)

for {
select {
case <-time.After(period):
request := &cstructs.FingerprintRequest{Config: dm.client.config, Node: dm.client.config.Node}
response := &cstructs.FingerprintResponse{
Attributes: make(map[string]string, 0),
Links: make(map[string]string, 0),
Resources: &structs.Resources{},
}

err := f.Fingerprint(request, response)
if err != nil {
dm.logger.Printf("[DEBUG] driver_manager: periodic fingerprinting for %v failed: %+v", name, err)
continue
}

dm.client.updateNodeFromFingerprint(response)

case <-dm.client.shutdownCh:
return
}
}
}
25 changes: 25 additions & 0 deletions client/driver_manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package client

import (
"testing"

"github.com/hashicorp/nomad/client/testutil"
)

// test that the driver manager updates a node when its attributes change
func TestDriverManager_Fingerprint(t *testing.T) {
testutil.RequireRoot(t)
t.Parallel()

c := testClient(t, nil)
defer c.Shutdown()

// Ensure kernel and arch are always present
node := c.Node()
if node.Attributes["kernel.name"] == "" {
t.Fatalf("missing kernel.name")
}
if node.Attributes["cpu.arch"] == "" {
t.Fatalf("missing cpu arch")
}
}

0 comments on commit 2e2bf74

Please sign in to comment.