From c39c72e87febf6bec0c128ee4aa92f4011cd7735 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 20 Aug 2015 16:41:29 -0700 Subject: [PATCH] client: attempt fingerprint of host --- client/client.go | 60 +++++++++++++++++++++++++++++++++++++++++++ client/client_test.go | 14 ++++++++++ 2 files changed, 74 insertions(+) diff --git a/client/client.go b/client/client.go index d59340967..6971896f9 100644 --- a/client/client.go +++ b/client/client.go @@ -10,7 +10,9 @@ import ( "sync" "time" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/nomad" + "github.com/hashicorp/nomad/nomad/structs" ) const ( @@ -44,6 +46,9 @@ type Config struct { // RPCHandler can be provided to avoid network traffic if the // server is running locally. RPCHandler RPCHandler + + // Node provides the base node + Node *structs.Node } // DefaultConfig returns the default configuration @@ -77,12 +82,23 @@ func NewClient(config *Config) (*Client, error) { // Create a logger logger := log.New(config.LogOutput, "", log.LstdFlags) + // Create the client c := &Client{ config: config, connPool: nomad.NewPool(config.LogOutput, clientRPCCache, clientMaxStreams, nil), logger: logger, shutdownCh: make(chan struct{}), } + + // Setup the node + if err := c.setupNode(); err != nil { + return nil, fmt.Errorf("node setup failed: %v", err) + } + + // Fingerprint the node + if err := c.fingerprint(); err != nil { + return nil, fmt.Errorf("fingerprinting failed: %v", err) + } return c, nil } @@ -179,3 +195,47 @@ func (c *Client) Stats() map[string]map[string]string { } return stats } + +// Node returns the locally registered node +func (c *Client) Node() *structs.Node { + return c.config.Node +} + +// setupNode is used to setup the initial node +func (c *Client) setupNode() error { + node := c.config.Node + if node == nil { + node = &structs.Node{} + c.config.Node = node + } + if node.Attributes == nil { + node.Attributes = make(map[string]string) + } + if node.Links == nil { + node.Links = make(map[string]string) + } + if node.Meta == nil { + node.Meta = make(map[string]string) + } + return nil +} + +// fingerprint is used to fingerprint the client and setup the node +func (c *Client) fingerprint() error { + var applied []string + for name := range fingerprint.BuiltinFingerprints { + f, err := fingerprint.NewFingerprint(name, c.logger) + if err != nil { + return err + } + applies, err := f.Fingerprint(c.config.Node) + if err != nil { + return err + } + if applies { + applied = append(applied, name) + } + } + c.logger.Printf("[DEBUG] client: applied fingerprints %v", applied) + return nil +} diff --git a/client/client_test.go b/client/client_test.go index 09694530e..20c4c8ede 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -112,3 +112,17 @@ func TestClient_RPC_Passthrough(t *testing.T) { t.Fatalf("err: %v", err) }) } + +func TestClient_Fingerprint(t *testing.T) { + c := testClient(t, nil) + defer c.Shutdown() + + // Ensure os and arch are always present + node := c.Node() + if node.Attributes["os"] == "" { + t.Fatalf("missing OS") + } + if node.Attributes["arch"] == "" { + t.Fatalf("missing arch") + } +}