From 5b067a3e4fa2bee98096db0ba98155a585c2eb73 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Thu, 5 Nov 2015 13:46:02 -0800 Subject: [PATCH 1/4] Merge fix --- client/driver/docker.go | 4 +++- client/driver/exec.go | 4 +++- client/driver/java.go | 4 +++- client/driver/qemu.go | 4 +++- client/driver/raw_exec.go | 4 +++- client/driver/rkt.go | 4 +++- client/fingerprint/arch.go | 1 + client/fingerprint/consul.go | 4 ++++ client/fingerprint/cpu.go | 1 + client/fingerprint/env_aws.go | 1 + client/fingerprint/env_gce.go | 1 + client/fingerprint/fingerprint.go | 17 +++++++++++++++++ client/fingerprint/host.go | 1 + client/fingerprint/memory.go | 1 + client/fingerprint/network_unix.go | 1 + client/fingerprint/network_windows.go | 1 + client/fingerprint/storage.go | 1 + 17 files changed, 48 insertions(+), 6 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index d5031d5d97a..1708c692116 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -13,11 +13,13 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/args" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/nomad/structs" ) type DockerDriver struct { DriverContext + fingerprint.StaticFingerprinter } type dockerPID struct { @@ -37,7 +39,7 @@ type dockerHandle struct { } func NewDockerDriver(ctx *DriverContext) Driver { - return &DockerDriver{*ctx} + return &DockerDriver{DriverContext: *ctx} } // dockerClient creates *docker.Client. In test / dev mode we can use ENV vars diff --git a/client/driver/exec.go b/client/driver/exec.go index 213bc574f51..4de719c465a 100644 --- a/client/driver/exec.go +++ b/client/driver/exec.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/executor" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/client/getter" "github.com/hashicorp/nomad/nomad/structs" ) @@ -18,6 +19,7 @@ import ( // features. type ExecDriver struct { DriverContext + fingerprint.StaticFingerprinter } // execHandle is returned from Start/Open as a handle to the PID @@ -29,7 +31,7 @@ type execHandle struct { // NewExecDriver is used to create a new exec driver func NewExecDriver(ctx *DriverContext) Driver { - return &ExecDriver{*ctx} + return &ExecDriver{DriverContext: *ctx} } func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { diff --git a/client/driver/java.go b/client/driver/java.go index 808bdfe5b90..1aa2c6d3f94 100644 --- a/client/driver/java.go +++ b/client/driver/java.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/executor" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/client/getter" "github.com/hashicorp/nomad/nomad/structs" ) @@ -21,6 +22,7 @@ import ( // It literally just fork/execs tasks with the java command. type JavaDriver struct { DriverContext + fingerprint.StaticFingerprinter } // javaHandle is returned from Start/Open as a handle to the PID @@ -32,7 +34,7 @@ type javaHandle struct { // NewJavaDriver is used to create a new exec driver func NewJavaDriver(ctx *DriverContext) Driver { - return &JavaDriver{*ctx} + return &JavaDriver{DriverContext: *ctx} } func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { diff --git a/client/driver/qemu.go b/client/driver/qemu.go index 0eab4e659ec..b0d0afc6294 100644 --- a/client/driver/qemu.go +++ b/client/driver/qemu.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/client/getter" "github.com/hashicorp/nomad/nomad/structs" ) @@ -29,6 +30,7 @@ var ( // planned in the future type QemuDriver struct { DriverContext + fingerprint.StaticFingerprinter } // qemuHandle is returned from Start/Open as a handle to the PID @@ -48,7 +50,7 @@ type qemuPID struct { // NewQemuDriver is used to create a new exec driver func NewQemuDriver(ctx *DriverContext) Driver { - return &QemuDriver{*ctx} + return &QemuDriver{DriverContext: *ctx} } func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { diff --git a/client/driver/raw_exec.go b/client/driver/raw_exec.go index 856f2b7fc65..c53e73a2b4f 100644 --- a/client/driver/raw_exec.go +++ b/client/driver/raw_exec.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/args" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/client/getter" "github.com/hashicorp/nomad/nomad/structs" ) @@ -31,6 +32,7 @@ const ( // and this should only be used when explicitly needed. type RawExecDriver struct { DriverContext + fingerprint.StaticFingerprinter } // rawExecHandle is returned from Start/Open as a handle to the PID @@ -42,7 +44,7 @@ type rawExecHandle struct { // NewRawExecDriver is used to create a new raw exec driver func NewRawExecDriver(ctx *DriverContext) Driver { - return &RawExecDriver{*ctx} + return &RawExecDriver{DriverContext: *ctx} } func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { diff --git a/client/driver/rkt.go b/client/driver/rkt.go index 456e4e02bfe..3f191253174 100644 --- a/client/driver/rkt.go +++ b/client/driver/rkt.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/args" + "github.com/hashicorp/nomad/client/fingerprint" "github.com/hashicorp/nomad/nomad/structs" ) @@ -30,6 +31,7 @@ var ( // planned in the future type RktDriver struct { DriverContext + fingerprint.StaticFingerprinter } // rktHandle is returned from Start/Open as a handle to the PID @@ -50,7 +52,7 @@ type rktPID struct { // NewRktDriver is used to create a new exec driver func NewRktDriver(ctx *DriverContext) Driver { - return &RktDriver{*ctx} + return &RktDriver{DriverContext: *ctx} } func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) { diff --git a/client/fingerprint/arch.go b/client/fingerprint/arch.go index 869c542ebbb..16d8c99a878 100644 --- a/client/fingerprint/arch.go +++ b/client/fingerprint/arch.go @@ -10,6 +10,7 @@ import ( // ArchFingerprint is used to fingerprint the architecture type ArchFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/consul.go b/client/fingerprint/consul.go index a03dfeec1fa..a8c054e21ab 100644 --- a/client/fingerprint/consul.go +++ b/client/fingerprint/consul.go @@ -63,3 +63,7 @@ func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Nod return true, nil } + +func (f *ConsulFingerprint) Periodic() (bool, time.Duration) { + return false, 15 * time.Second +} diff --git a/client/fingerprint/cpu.go b/client/fingerprint/cpu.go index 3e809397e41..5027c8e9ae7 100644 --- a/client/fingerprint/cpu.go +++ b/client/fingerprint/cpu.go @@ -11,6 +11,7 @@ import ( // CPUFingerprint is used to fingerprint the CPU type CPUFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/env_aws.go b/client/fingerprint/env_aws.go index 575409bf8ca..f5e26e7cbb6 100644 --- a/client/fingerprint/env_aws.go +++ b/client/fingerprint/env_aws.go @@ -69,6 +69,7 @@ var ec2InstanceSpeedMap = map[string]int{ // EnvAWSFingerprint is used to fingerprint AWS metadata type EnvAWSFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/env_gce.go b/client/fingerprint/env_gce.go index f721fc36abd..faef7deabca 100644 --- a/client/fingerprint/env_gce.go +++ b/client/fingerprint/env_gce.go @@ -46,6 +46,7 @@ func lastToken(s string) string { // EnvGCEFingerprint is used to fingerprint GCE metadata type EnvGCEFingerprint struct { + StaticFingerprinter client *http.Client logger *log.Logger metadataURL string diff --git a/client/fingerprint/fingerprint.go b/client/fingerprint/fingerprint.go index 4a42057b297..3154aad2bcf 100644 --- a/client/fingerprint/fingerprint.go +++ b/client/fingerprint/fingerprint.go @@ -3,11 +3,15 @@ package fingerprint import ( "fmt" "log" + "time" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/nomad/structs" ) +// EmptyDuration is to be used by fingerprinters that are not periodic. +const EmptyDuration = time.Duration(0) + // BuiltinFingerprints is a slice containing the key names of all regestered // fingerprints available, to provided an ordered iteration var BuiltinFingerprints = []string{ @@ -59,4 +63,17 @@ type Fingerprint interface { // Fingerprint is used to update properties of the Node, // and returns if the fingerprint was applicable and a potential error. Fingerprint(*config.Config, *structs.Node) (bool, error) + + // Periodic is a mechanism for the fingerprinter to indicate that it should + // be run periodically. The return value is a boolean indicating if it + // should be periodic, and if true, a duration. + Periodic() (bool, time.Duration) +} + +// StaticFingerprinter can be embeded in a struct that has a Fingerprint method +// to make it non-periodic. +type StaticFingerprinter struct{} + +func (s *StaticFingerprinter) Periodic() (bool, time.Duration) { + return false, EmptyDuration } diff --git a/client/fingerprint/host.go b/client/fingerprint/host.go index ac7a347f2ba..87acac63c97 100644 --- a/client/fingerprint/host.go +++ b/client/fingerprint/host.go @@ -14,6 +14,7 @@ import ( // HostFingerprint is used to fingerprint the host type HostFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/memory.go b/client/fingerprint/memory.go index 5af097848c9..b249bebf575 100644 --- a/client/fingerprint/memory.go +++ b/client/fingerprint/memory.go @@ -11,6 +11,7 @@ import ( // MemoryFingerprint is used to fingerprint the available memory on the node type MemoryFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/network_unix.go b/client/fingerprint/network_unix.go index 4278384e9a9..9adb5f41b0e 100644 --- a/client/fingerprint/network_unix.go +++ b/client/fingerprint/network_unix.go @@ -19,6 +19,7 @@ import ( // NetworkFingerprint is used to fingerprint the Network capabilities of a node type NetworkFingerprint struct { + StaticFingerprinter logger *log.Logger interfaceDetector NetworkInterfaceDetector } diff --git a/client/fingerprint/network_windows.go b/client/fingerprint/network_windows.go index 99467bcc8c9..b438b72920e 100644 --- a/client/fingerprint/network_windows.go +++ b/client/fingerprint/network_windows.go @@ -11,6 +11,7 @@ import ( // NetworkFingerprint is used to fingerprint the Network capabilities of a node type NetworkFingerprint struct { + StaticFingerprinter logger *log.Logger } diff --git a/client/fingerprint/storage.go b/client/fingerprint/storage.go index 6abbe52e492..ead264845a8 100644 --- a/client/fingerprint/storage.go +++ b/client/fingerprint/storage.go @@ -18,6 +18,7 @@ import ( // StorageFingerprint is used to measure the amount of storage free for // applications that the Nomad agent will run on this machine. type StorageFingerprint struct { + StaticFingerprinter logger *log.Logger } From 8e0ab77b1042525cd231d729917da0442aaa2240 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Thu, 5 Nov 2015 10:39:52 -0800 Subject: [PATCH 2/4] Add consul fingerprinter to builtin list; sort list; fix bad error in consul fingerprinter --- client/fingerprint/consul.go | 2 +- client/fingerprint/fingerprint.go | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/fingerprint/consul.go b/client/fingerprint/consul.go index a8c054e21ab..01e3a658b60 100644 --- a/client/fingerprint/consul.go +++ b/client/fingerprint/consul.go @@ -48,7 +48,7 @@ func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Nod // If we can't hit this URL consul is probably not running on this machine. info, err := consulClient.Agent().Self() if err != nil { - return false, fmt.Errorf("Failed to query consul for agent status: %s", err) + return false, nil } node.Attributes["consul.server"] = strconv.FormatBool(info["Config"]["Server"].(bool)) diff --git a/client/fingerprint/fingerprint.go b/client/fingerprint/fingerprint.go index 3154aad2bcf..a0139d485cb 100644 --- a/client/fingerprint/fingerprint.go +++ b/client/fingerprint/fingerprint.go @@ -16,26 +16,28 @@ const EmptyDuration = time.Duration(0) // fingerprints available, to provided an ordered iteration var BuiltinFingerprints = []string{ "arch", + "consul", "cpu", + "env_aws", + "env_gce", "host", "memory", - "storage", "network", - "env_aws", - "env_gce", + "storage", } // builtinFingerprintMap contains the built in registered fingerprints // which are available, corresponding to a key found in BuiltinFingerprints var builtinFingerprintMap = map[string]Factory{ "arch": NewArchFingerprint, + "consul": NewConsulFingerprint, "cpu": NewCPUFingerprint, + "env_aws": NewEnvAWSFingerprint, + "env_gce": NewEnvGCEFingerprint, "host": NewHostFingerprint, "memory": NewMemoryFingerprint, - "storage": NewStorageFingerprint, "network": NewNetworkFingerprinter, - "env_aws": NewEnvAWSFingerprint, - "env_gce": NewEnvGCEFingerprint, + "storage": NewStorageFingerprint, } // NewFingerprint is used to instantiate and return a new fingerprint From f43c067b3e62c98afeb7314302f1b3db03669db2 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Thu, 5 Nov 2015 13:41:41 -0800 Subject: [PATCH 3/4] Client handles periodic fingerprinters --- client/client.go | 24 ++++++++++++++++++++++++ client/fingerprint/consul.go | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/client/client.go b/client/client.go index 744bad87691..2d466a7841b 100644 --- a/client/client.go +++ b/client/client.go @@ -443,11 +443,35 @@ func (c *Client) fingerprint() error { if applies { applied = append(applied, name) } + p, period := 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) + } } c.logger.Printf("[DEBUG] client: applied fingerprints %v", applied) return nil } +// fingerprintPeriodic runs a fingerprinter at the specified duration. If the +// fingerprinter returns an error, the function exits. +func (c *Client) fingerprintPeriodic(name string, f fingerprint.Fingerprint, d time.Duration) { + c.logger.Printf("[DEBUG] client: periodically fingerprinting %v at duration %v", name, d) + for { + select { + case <-time.After(d): + if _, err := f.Fingerprint(c.config, c.config.Node); err != nil { + c.logger.Printf("[DEBUG] client: disabling periodic fingerprinting for %v: %v", name, err) + return + } + case <-c.shutdownCh: + return + } + } +} + // setupDrivers is used to find the available drivers func (c *Client) setupDrivers() error { var avail []string diff --git a/client/fingerprint/consul.go b/client/fingerprint/consul.go index 01e3a658b60..9ae81faf6a0 100644 --- a/client/fingerprint/consul.go +++ b/client/fingerprint/consul.go @@ -65,5 +65,5 @@ func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Nod } func (f *ConsulFingerprint) Periodic() (bool, time.Duration) { - return false, 15 * time.Second + return true, 15 * time.Second } From 10e19064d947c6cc2345821ec72ebbec6e989a22 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Thu, 5 Nov 2015 18:47:16 -0800 Subject: [PATCH 4/4] Make periodic fingerprinting log the error --- client/client.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/client.go b/client/client.go index 2d466a7841b..029ac395401 100644 --- a/client/client.go +++ b/client/client.go @@ -455,16 +455,14 @@ func (c *Client) fingerprint() error { return nil } -// fingerprintPeriodic runs a fingerprinter at the specified duration. If the -// fingerprinter returns an error, the function exits. +// 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: periodically fingerprinting %v at duration %v", name, d) for { select { case <-time.After(d): if _, err := f.Fingerprint(c.config, c.config.Node); err != nil { - c.logger.Printf("[DEBUG] client: disabling periodic fingerprinting for %v: %v", name, err) - return + c.logger.Printf("[DEBUG] client: periodic fingerprinting for %v failed: %v", name, err) } case <-c.shutdownCh: return