diff --git a/client/client.go b/client/client.go index 744bad876..029ac3954 100644 --- a/client/client.go +++ b/client/client.go @@ -443,11 +443,33 @@ 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. +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: periodic fingerprinting for %v failed: %v", name, err) + } + case <-c.shutdownCh: + return + } + } +} + // setupDrivers is used to find the available drivers func (c *Client) setupDrivers() error { var avail []string diff --git a/client/driver/docker.go b/client/driver/docker.go index d5031d5d9..1708c6921 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 213bc574f..4de719c46 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 808bdfe5b..1aa2c6d3f 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 0eab4e659..b0d0afc62 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 856f2b7fc..c53e73a2b 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 456e4e02b..3f1912531 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 869c542eb..16d8c99a8 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 a03dfeec1..9ae81faf6 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)) @@ -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 true, 15 * time.Second +} diff --git a/client/fingerprint/cpu.go b/client/fingerprint/cpu.go index 3e809397e..5027c8e9a 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 575409bf8..f5e26e7cb 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 f721fc36a..faef7deab 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 4a42057b2..a0139d485 100644 --- a/client/fingerprint/fingerprint.go +++ b/client/fingerprint/fingerprint.go @@ -3,35 +3,41 @@ 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{ "arch", + "consul", "cpu", - "host", - "memory", - "storage", - "network", "env_aws", "env_gce", + "host", + "memory", + "network", + "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, - "host": NewHostFingerprint, - "memory": NewMemoryFingerprint, - "storage": NewStorageFingerprint, - "network": NewNetworkFingerprinter, "env_aws": NewEnvAWSFingerprint, "env_gce": NewEnvGCEFingerprint, + "host": NewHostFingerprint, + "memory": NewMemoryFingerprint, + "network": NewNetworkFingerprinter, + "storage": NewStorageFingerprint, } // NewFingerprint is used to instantiate and return a new fingerprint @@ -59,4 +65,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 ac7a347f2..87acac63c 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 5af097848..b249bebf5 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 4278384e9..9adb5f41b 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 99467bcc8..b438b7292 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 6abbe52e4..ead264845 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 }