Skip to content

Commit

Permalink
Merge pull request #2337 from hashicorp/f-driver-errors
Browse files Browse the repository at this point in the history
Drivers log during fingerprinting
  • Loading branch information
dadgar committed Feb 21, 2017
2 parents c441f50 + 4ba4987 commit e49f672
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 84 deletions.
90 changes: 47 additions & 43 deletions client/driver/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/hashicorp/nomad/client/driver/executor"
dstructs "github.com/hashicorp/nomad/client/driver/structs"
cstructs "github.com/hashicorp/nomad/client/structs"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/helper/fields"
shelpers "github.com/hashicorp/nomad/helper/stats"
"github.com/hashicorp/nomad/nomad/structs"
Expand Down Expand Up @@ -108,6 +109,10 @@ type DockerDriver struct {

driverConfig *DockerDriverConfig
imageID string

// A tri-state boolean to know if the fingerprinting has happened and
// whether it has been successful
fingerprintSuccess *bool
}

type DockerDriverAuth struct {
Expand Down Expand Up @@ -262,6 +267,48 @@ func NewDockerDriver(ctx *DriverContext) Driver {
return &DockerDriver{DriverContext: *ctx}
}

func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Initialize docker API clients
client, _, err := d.dockerClients()
if err != nil {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[INFO] driver.docker: failed to initialize client: %s", err)
}
delete(node.Attributes, dockerDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

// This is the first operation taken on the client so we'll try to
// establish a connection to the Docker daemon. If this fails it means
// Docker isn't available so we'll simply disable the docker driver.
env, err := client.Version()
if err != nil {
delete(node.Attributes, dockerDriverAttr)
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.docker: could not connect to docker daemon at %s: %s", client.Endpoint(), err)
}
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

node.Attributes[dockerDriverAttr] = "1"
node.Attributes["driver.docker.version"] = env.Get("Version")

privileged := d.config.ReadBoolDefault(dockerPrivilegedConfigOption, false)
if privileged {
node.Attributes[dockerPrivilegedConfigOption] = "1"
}

// Advertise if this node supports Docker volumes
if d.config.ReadBoolDefault(dockerVolumesConfigOption, dockerVolumesConfigDefault) {
node.Attributes["driver."+dockerVolumesConfigOption] = "1"
}

d.fingerprintSuccess = helper.BoolToPtr(true)
return true, nil
}

// Validate is used to validate the driver configuration
func (d *DockerDriver) Validate(config map[string]interface{}) error {
fd := &fields.FieldData{
Expand Down Expand Up @@ -618,49 +665,6 @@ func (d *DockerDriver) dockerClients() (*docker.Client, *docker.Client, error) {
return client, waitClient, merr.ErrorOrNil()
}

func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[dockerDriverAttr]

// Initialize docker API clients
client, _, err := d.dockerClients()
if err != nil {
delete(node.Attributes, dockerDriverAttr)
if currentlyEnabled {
d.logger.Printf("[INFO] driver.docker: failed to initialize client: %s", err)
}
return false, nil
}

privileged := d.config.ReadBoolDefault(dockerPrivilegedConfigOption, false)
if privileged {
node.Attributes[dockerPrivilegedConfigOption] = "1"
}

// This is the first operation taken on the client so we'll try to
// establish a connection to the Docker daemon. If this fails it means
// Docker isn't available so we'll simply disable the docker driver.
env, err := client.Version()
if err != nil {
if currentlyEnabled {
d.logger.Printf("[DEBUG] driver.docker: could not connect to docker daemon at %s: %s", client.Endpoint(), err)
}
delete(node.Attributes, dockerDriverAttr)
return false, nil
}

node.Attributes[dockerDriverAttr] = "1"
node.Attributes["driver.docker.version"] = env.Get("Version")

// Advertise if this node supports Docker volumes
if d.config.ReadBoolDefault(dockerVolumesConfigOption, dockerVolumesConfigDefault) {
node.Attributes["driver."+dockerVolumesConfigOption] = "1"
}

return true, nil
}

func (d *DockerDriver) containerBinds(driverConfig *DockerDriverConfig, taskDir *allocdir.TaskDir,
task *structs.Task) ([]string, error) {

Expand Down
4 changes: 4 additions & 0 deletions client/driver/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const (
// features.
type ExecDriver struct {
DriverContext

// A tri-state boolean to know if the fingerprinting has happened and
// whether it has been successful
fingerprintSuccess *bool
}

type ExecDriverConfig struct {
Expand Down
2 changes: 2 additions & 0 deletions client/driver/exec_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ package driver

import (
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/nomad/structs"
)

func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}
16 changes: 8 additions & 8 deletions client/driver/exec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@ package driver

import (
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/nomad/structs"
"golang.org/x/sys/unix"
)

func (d *ExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[execDriverAttr]

// Only enable if cgroups are available and we are root
if _, ok := node.Attributes["unique.cgroup.mountpoint"]; !ok {
if currentlyEnabled {
if !cgroupsMounted(node) {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.exec: cgroups unavailable, disabling")
}
d.fingerprintSuccess = helper.BoolToPtr(false)
delete(node.Attributes, execDriverAttr)
return false, nil
} else if unix.Geteuid() != 0 {
if currentlyEnabled {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.exec: must run as root user, disabling")
}
delete(node.Attributes, execDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

if !currentlyEnabled {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.exec: exec driver is enabled")
}
node.Attributes[execDriverAttr] = "1"
d.fingerprintSuccess = helper.BoolToPtr(true)
return true, nil
}
26 changes: 12 additions & 14 deletions client/driver/java.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
dstructs "github.com/hashicorp/nomad/client/driver/structs"
"github.com/hashicorp/nomad/client/fingerprint"
cstructs "github.com/hashicorp/nomad/client/structs"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/helper/fields"
"github.com/hashicorp/nomad/nomad/structs"
)
Expand All @@ -38,6 +39,10 @@ const (
type JavaDriver struct {
DriverContext
fingerprint.StaticFingerprinter

// A tri-state boolean to know if the fingerprinting has happened and
// whether it has been successful
fingerprintSuccess *bool
}

type JavaDriverConfig struct {
Expand Down Expand Up @@ -105,16 +110,13 @@ func (d *JavaDriver) Abilities() DriverAbilities {
}

func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[javaDriverAttr]

// Only enable if we are root and cgroups are mounted when running on linux systems.
if runtime.GOOS == "linux" && (syscall.Geteuid() != 0 || !d.cgroupsMounted(node)) {
if currentlyEnabled {
if runtime.GOOS == "linux" && (syscall.Geteuid() != 0 || !cgroupsMounted(node)) {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.java: root priviledges and mounted cgroups required on linux, disabling")
}
delete(node.Attributes, "driver.java")
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

Expand All @@ -128,6 +130,7 @@ func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
if err != nil {
// assume Java wasn't found
delete(node.Attributes, javaDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

Expand All @@ -143,10 +146,11 @@ func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
}

if infoString == "" {
if currentlyEnabled {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Println("[WARN] driver.java: error parsing Java version information, aborting")
}
delete(node.Attributes, javaDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

Expand All @@ -163,6 +167,7 @@ func (d *JavaDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
node.Attributes["driver.java.version"] = versionString
node.Attributes["driver.java.runtime"] = info[1]
node.Attributes["driver.java.vm"] = info[2]
d.fingerprintSuccess = helper.BoolToPtr(true)

return true, nil
}
Expand Down Expand Up @@ -295,13 +300,6 @@ func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,

func (d *JavaDriver) Cleanup(*ExecContext, *CreatedResources) error { return nil }

// cgroupsMounted returns true if the cgroups are mounted on a system otherwise
// returns false
func (d *JavaDriver) cgroupsMounted(node *structs.Node) bool {
_, ok := node.Attributes["unique.cgroup.mountpoint"]
return ok
}

type javaId struct {
Version string
KillTimeout time.Duration
Expand Down
7 changes: 0 additions & 7 deletions client/driver/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ func (d *QemuDriver) FSIsolation() cstructs.FSIsolation {
}

func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[qemuDriverAttr]

bin := "qemu-system-x86_64"
if runtime.GOOS == "windows" {
// On windows, the "qemu-system-x86_64" command does not respond to the
Expand All @@ -128,9 +124,6 @@ func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool,
return false, fmt.Errorf("Unable to parse Qemu version string: %#v", matches)
}

if !currentlyEnabled {
d.logger.Printf("[DEBUG] driver.qemu: enabling driver")
}
node.Attributes[qemuDriverAttr] = "1"
node.Attributes["driver.qemu.version"] = matches[1]
return true, nil
Expand Down
8 changes: 1 addition & 7 deletions client/driver/raw_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,11 @@ func (d *RawExecDriver) FSIsolation() cstructs.FSIsolation {
}

func (d *RawExecDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[rawExecDriverAttr]

// Check that the user has explicitly enabled this executor.
enabled := cfg.ReadBoolDefault(rawExecConfigOption, false)

if enabled || cfg.DevMode {
if currentlyEnabled {
d.logger.Printf("[WARN] driver.raw_exec: raw exec is enabled. Only enable if needed")
}
d.logger.Printf("[WARN] driver.raw_exec: raw exec is enabled. Only enable if needed")
node.Attributes[rawExecDriverAttr] = "1"
return true, nil
}
Expand Down
15 changes: 10 additions & 5 deletions client/driver/rkt.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/hashicorp/nomad/client/driver/executor"
dstructs "github.com/hashicorp/nomad/client/driver/structs"
cstructs "github.com/hashicorp/nomad/client/structs"
"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/helper/fields"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/mitchellh/mapstructure"
Expand Down Expand Up @@ -57,6 +58,10 @@ const (
// planned in the future
type RktDriver struct {
DriverContext

// A tri-state boolean to know if the fingerprinting has happened and
// whether it has been successful
fingerprintSuccess *bool
}

type RktDriverConfig struct {
Expand Down Expand Up @@ -157,22 +162,20 @@ func (d *RktDriver) Abilities() DriverAbilities {
}

func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// Get the current status so that we can log any debug messages only if the
// state changes
_, currentlyEnabled := node.Attributes[rktDriverAttr]

// Only enable if we are root when running on non-windows systems.
if runtime.GOOS != "windows" && syscall.Geteuid() != 0 {
if currentlyEnabled {
if d.fingerprintSuccess == nil || *d.fingerprintSuccess {
d.logger.Printf("[DEBUG] driver.rkt: must run as root user, disabling")
}
delete(node.Attributes, rktDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}

outBytes, err := exec.Command(rktCmd, "version").Output()
if err != nil {
delete(node.Attributes, rktDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, nil
}
out := strings.TrimSpace(string(outBytes))
Expand All @@ -181,6 +184,7 @@ func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, e
appcMatches := reAppcVersion.FindStringSubmatch(out)
if len(rktMatches) != 2 || len(appcMatches) != 2 {
delete(node.Attributes, rktDriverAttr)
d.fingerprintSuccess = helper.BoolToPtr(false)
return false, fmt.Errorf("Unable to parse Rkt version string: %#v", rktMatches)
}

Expand All @@ -200,6 +204,7 @@ func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, e
if d.config.ReadBoolDefault(rktVolumesConfigOption, rktVolumesConfigDefault) {
node.Attributes["driver."+rktVolumesConfigOption] = "1"
}
d.fingerprintSuccess = helper.BoolToPtr(true)
return true, nil
}

Expand Down
7 changes: 7 additions & 0 deletions client/driver/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ import (
"github.com/hashicorp/nomad/nomad/structs"
)

// cgroupsMounted returns true if the cgroups are mounted on a system otherwise
// returns false
func cgroupsMounted(node *structs.Node) bool {
_, ok := node.Attributes["unique.cgroup.mountpoint"]
return ok
}

// createExecutor launches an executor plugin and returns an instance of the
// Executor interface
func createExecutor(w io.Writer, clientConfig *config.Config,
Expand Down

0 comments on commit e49f672

Please sign in to comment.