diff --git a/client/allocdir/alloc_dir_freebsd.go b/client/allocdir/alloc_dir_freebsd.go new file mode 100644 index 000000000..a4d3801db --- /dev/null +++ b/client/allocdir/alloc_dir_freebsd.go @@ -0,0 +1,26 @@ +package allocdir + +import ( + "syscall" +) + +// Hardlinks the shared directory. As a side-effect the shared directory and +// task directory must be on the same filesystem. +func (d *AllocDir) mountSharedDir(dir string) error { + return syscall.Link(d.SharedDir, dir) +} + +func (d *AllocDir) unmountSharedDir(dir string) error { + return syscall.Unlink(dir) +} + +// MountSpecialDirs mounts the dev and proc file system on the chroot of the +// task. It's a no-op on FreeBSD right now. +func (d *AllocDir) MountSpecialDirs(taskDir string) error { + return nil +} + +// unmountSpecialDirs unmounts the dev and proc file system from the chroot +func (d *AllocDir) unmountSpecialDirs(taskDir string) error { + return nil +} diff --git a/client/client.go b/client/client.go index 50a070e67..bd6a20216 100644 --- a/client/client.go +++ b/client/client.go @@ -582,6 +582,7 @@ func (c *Client) reservePorts() { func (c *Client) fingerprint() error { whitelist := c.config.ReadStringListToMap("fingerprint.whitelist") whitelistEnabled := len(whitelist) > 0 + c.logger.Printf("[DEBUG] client: built-in fingerprints: %v", fingerprint.BuiltinFingerprints) var applied []string var skipped []string diff --git a/client/fingerprint/cgroup.go b/client/fingerprint/cgroup.go index 3fb14a2f3..c0ec7c674 100644 --- a/client/fingerprint/cgroup.go +++ b/client/fingerprint/cgroup.go @@ -1,11 +1,9 @@ package fingerprint import ( - "fmt" "log" "time" - client "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/nomad/structs" ) @@ -47,35 +45,6 @@ func NewCGroupFingerprint(logger *log.Logger) Fingerprint { return f } -// Fingerprint tries to find a valid cgroup moint point -func (f *CGroupFingerprint) Fingerprint(cfg *client.Config, node *structs.Node) (bool, error) { - mount, err := f.mountPointDetector.MountPoint() - if err != nil { - f.clearCGroupAttributes(node) - return false, fmt.Errorf("Failed to discover cgroup mount point: %s", err) - } - - // Check if a cgroup mount point was found - if mount == "" { - // Clear any attributes from the previous fingerprint. - f.clearCGroupAttributes(node) - - if f.lastState == cgroupAvailable { - f.logger.Printf("[INFO] fingerprint.cgroups: cgroups are unavailable") - } - f.lastState = cgroupUnavailable - return true, nil - } - - node.Attributes["unique.cgroup.mountpoint"] = mount - - if f.lastState == cgroupUnavailable { - f.logger.Printf("[INFO] fingerprint.cgroups: cgroups are available") - } - f.lastState = cgroupAvailable - return true, nil -} - // clearCGroupAttributes clears any node attributes related to cgroups that might // have been set in a previous fingerprint run. func (f *CGroupFingerprint) clearCGroupAttributes(n *structs.Node) { diff --git a/client/fingerprint/cgroup_default.go b/client/fingerprint/cgroup_default.go new file mode 100644 index 000000000..43c55fd85 --- /dev/null +++ b/client/fingerprint/cgroup_default.go @@ -0,0 +1,18 @@ +// +build !linux + +package fingerprint + +import ( + client "github.com/hashicorp/nomad/client/config" + "github.com/hashicorp/nomad/nomad/structs" +) + +// FindCgroupMountpointDir returns an empty path on non-Linux systems +func FindCgroupMountpointDir() (string, error) { + return "", nil +} + +// Fingerprint tries to find a valid cgroup moint point +func (f *CGroupFingerprint) Fingerprint(cfg *client.Config, node *structs.Node) (bool, error) { + return false, nil +} diff --git a/client/fingerprint/cgroup_linux.go b/client/fingerprint/cgroup_linux.go index 25171c1f4..9abb959b5 100644 --- a/client/fingerprint/cgroup_linux.go +++ b/client/fingerprint/cgroup_linux.go @@ -3,6 +3,10 @@ package fingerprint import ( + "fmt" + + client "github.com/hashicorp/nomad/client/config" + "github.com/hashicorp/nomad/nomad/structs" "github.com/opencontainers/runc/libcontainer/cgroups" ) @@ -22,3 +26,32 @@ func FindCgroupMountpointDir() (string, error) { } return mount, nil } + +// Fingerprint tries to find a valid cgroup moint point +func (f *CGroupFingerprint) Fingerprint(cfg *client.Config, node *structs.Node) (bool, error) { + mount, err := f.mountPointDetector.MountPoint() + if err != nil { + f.clearCGroupAttributes(node) + return false, fmt.Errorf("Failed to discover cgroup mount point: %s", err) + } + + // Check if a cgroup mount point was found + if mount == "" { + // Clear any attributes from the previous fingerprint. + f.clearCGroupAttributes(node) + + if f.lastState == cgroupAvailable { + f.logger.Printf("[INFO] fingerprint.cgroups: cgroups are unavailable") + } + f.lastState = cgroupUnavailable + return true, nil + } + + node.Attributes["unique.cgroup.mountpoint"] = mount + + if f.lastState == cgroupUnavailable { + f.logger.Printf("[INFO] fingerprint.cgroups: cgroups are available") + } + f.lastState = cgroupAvailable + return true, nil +} diff --git a/client/fingerprint/cgroup_universal.go b/client/fingerprint/cgroup_universal.go deleted file mode 100644 index eeeade435..000000000 --- a/client/fingerprint/cgroup_universal.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !linux - -package fingerprint - -// FindCgroupMountpointDir returns an empty path on non-Linux systems -func FindCgroupMountpointDir() (string, error) { - return "", nil -} diff --git a/client/fingerprint/cpu.go b/client/fingerprint/cpu.go index 5027c8e9a..bcd09f507 100644 --- a/client/fingerprint/cpu.go +++ b/client/fingerprint/cpu.go @@ -48,10 +48,18 @@ func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bo if mhz > 0 { node.Attributes["cpu.frequency"] = fmt.Sprintf("%.6f", mhz) + f.logger.Printf("[DEBUG] fingerprint.cpu: frequency: %02.1fMHz", mhz) + } + + if numCores <= 0 { + const defaultCPUCoreCount = 1 + f.logger.Printf("[DEBUG] fingerprint.cpu: unable to find core count, defaulting to %d", defaultCPUCoreCount) + numCores = defaultCPUCoreCount } if numCores > 0 { node.Attributes["cpu.numcores"] = fmt.Sprintf("%d", numCores) + f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores) } if mhz > 0 && numCores > 0 { diff --git a/client/fingerprint/env_gce.go b/client/fingerprint/env_gce.go index 68f74d035..fa74d6a96 100644 --- a/client/fingerprint/env_gce.go +++ b/client/fingerprint/env_gce.go @@ -96,7 +96,7 @@ func (f *EnvGCEFingerprint) Get(attribute string, recursive bool) (string, error res, err := f.client.Do(req) if err != nil || res.StatusCode != http.StatusOK { - f.logger.Printf("[WARN] fingerprint.env_gce: Could not read value for attribute %q", attribute) + f.logger.Printf("[DEBUG] fingerprint.env_gce: Could not read value for attribute %q", attribute) return "", err } diff --git a/client/fingerprint/network.go b/client/fingerprint/network.go index 19b4ec5a4..f2fec805e 100644 --- a/client/fingerprint/network.go +++ b/client/fingerprint/network.go @@ -3,13 +3,8 @@ package fingerprint import ( "errors" "fmt" - "io/ioutil" "log" "net" - "os/exec" - "regexp" - "strconv" - "strings" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/nomad/structs" @@ -78,10 +73,11 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) newNetwork.IP = ip newNetwork.CIDR = newNetwork.IP + "/32" - f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip) + f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip) if throughput := f.linkSpeed(intf.Name); throughput > 0 { newNetwork.MBits = throughput + f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits) } else { f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed) newNetwork.MBits = cfg.NetworkSpeed @@ -97,74 +93,6 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) return true, nil } -// linkSpeed returns link speed in Mb/s, or 0 when unable to determine it. -func (f *NetworkFingerprint) linkSpeed(device string) int { - // Use LookPath to find the ethtool in the systems $PATH - // If it's not found or otherwise errors, LookPath returns and empty string - // and an error we can ignore for our purposes - ethtoolPath, _ := exec.LookPath("ethtool") - if ethtoolPath != "" { - if speed := f.linkSpeedEthtool(ethtoolPath, device); speed > 0 { - return speed - } - } - - // Fall back on checking a system file for link speed. - return f.linkSpeedSys(device) -} - -// linkSpeedSys parses link speed in Mb/s from /sys. -func (f *NetworkFingerprint) linkSpeedSys(device string) int { - path := fmt.Sprintf("/sys/class/net/%s/speed", device) - - // Read contents of the device/speed file - content, err := ioutil.ReadFile(path) - if err != nil { - f.logger.Printf("[WARN] fingerprint.network: Unable to read link speed from %s", path) - return 0 - } - - lines := strings.Split(string(content), "\n") - mbs, err := strconv.Atoi(lines[0]) - if err != nil || mbs <= 0 { - f.logger.Printf("[WARN] fingerprint.network: Unable to parse link speed from %s", path) - return 0 - } - - return mbs -} - -// linkSpeedEthtool determines link speed in Mb/s with 'ethtool'. -func (f *NetworkFingerprint) linkSpeedEthtool(path, device string) int { - outBytes, err := exec.Command(path, device).Output() - if err != nil { - f.logger.Printf("[WARN] fingerprint.network: Error calling ethtool (%s %s): %v", path, device, err) - return 0 - } - - output := strings.TrimSpace(string(outBytes)) - re := regexp.MustCompile("Speed: [0-9]+[a-zA-Z]+/s") - m := re.FindString(output) - if m == "" { - // no matches found, output may be in a different format - f.logger.Printf("[WARN] fingerprint.network: Unable to parse Speed in output of '%s %s'", path, device) - return 0 - } - - // Split and trim the Mb/s unit from the string output - args := strings.Split(m, ": ") - raw := strings.TrimSuffix(args[1], "Mb/s") - - // convert to Mb/s - mbs, err := strconv.Atoi(raw) - if err != nil || mbs <= 0 { - f.logger.Printf("[WARN] fingerprint.network: Unable to parse Mb/s in output of '%s %s'", path, device) - return 0 - } - - return mbs -} - // Gets the ipv4 addr for a network interface func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) { var addrs []net.Addr diff --git a/client/fingerprint/network_default.go b/client/fingerprint/network_default.go new file mode 100644 index 000000000..f24479b85 --- /dev/null +++ b/client/fingerprint/network_default.go @@ -0,0 +1,8 @@ +// +build !linux + +package fingerprint + +// linkSpeed returns the default link speed +func (f *NetworkFingerprint) linkSpeed(device string) int { + return 0 +} diff --git a/client/fingerprint/network_linux.go b/client/fingerprint/network_linux.go new file mode 100644 index 000000000..5a1ba001f --- /dev/null +++ b/client/fingerprint/network_linux.go @@ -0,0 +1,78 @@ +package fingerprint + +import ( + "fmt" + "io/ioutil" + "os/exec" + "regexp" + "strconv" + "strings" +) + +// linkSpeedSys parses link speed in Mb/s from /sys. +func (f *NetworkFingerprint) linkSpeedSys(device string) int { + path := fmt.Sprintf("/sys/class/net/%s/speed", device) + + // Read contents of the device/speed file + content, err := ioutil.ReadFile(path) + if err != nil { + f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed from %s", path) + return 0 + } + + lines := strings.Split(string(content), "\n") + mbs, err := strconv.Atoi(lines[0]) + if err != nil || mbs <= 0 { + f.logger.Printf("[DEBUG] fingerprint.network: Unable to parse link speed from %s", path) + return 0 + } + + return mbs +} + +// linkSpeed returns link speed in Mb/s, or 0 when unable to determine it. +func (f *NetworkFingerprint) linkSpeed(device string) int { + // Use LookPath to find the ethtool in the systems $PATH + // If it's not found or otherwise errors, LookPath returns and empty string + // and an error we can ignore for our purposes + ethtoolPath, _ := exec.LookPath("ethtool") + if ethtoolPath != "" { + if speed := f.linkSpeedEthtool(ethtoolPath, device); speed > 0 { + return speed + } + } + + // Fall back on checking a system file for link speed. + return f.linkSpeedSys(device) +} + +// linkSpeedEthtool determines link speed in Mb/s with 'ethtool'. +func (f *NetworkFingerprint) linkSpeedEthtool(path, device string) int { + outBytes, err := exec.Command(path, device).Output() + if err != nil { + f.logger.Printf("[WARN] fingerprint.network: Error calling ethtool (%s %s): %v", path, device, err) + return 0 + } + + output := strings.TrimSpace(string(outBytes)) + re := regexp.MustCompile("Speed: [0-9]+[a-zA-Z]+/s") + m := re.FindString(output) + if m == "" { + // no matches found, output may be in a different format + f.logger.Printf("[WARN] fingerprint.network: Unable to parse Speed in output of '%s %s'", path, device) + return 0 + } + + // Split and trim the Mb/s unit from the string output + args := strings.Split(m, ": ") + raw := strings.TrimSuffix(args[1], "Mb/s") + + // convert to Mb/s + mbs, err := strconv.Atoi(raw) + if err != nil || mbs <= 0 { + f.logger.Printf("[WARN] fingerprint.network: Unable to parse Mb/s in output of '%s %s'", path, device) + return 0 + } + + return mbs +} diff --git a/client/fingerprint/storage_unix.go b/client/fingerprint/storage_unix.go index a4e42f757..ada8f4bea 100644 --- a/client/fingerprint/storage_unix.go +++ b/client/fingerprint/storage_unix.go @@ -1,4 +1,4 @@ -// +build darwin linux +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package fingerprint