github.com/bigcommerce/nomad@v0.9.3-bc/client/fingerprint/network_linux.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os/exec"
     7  	"regexp"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  // linkSpeedSys parses link speed in Mb/s from /sys.
    13  func (f *NetworkFingerprint) linkSpeedSys(device string) int {
    14  	path := fmt.Sprintf("/sys/class/net/%s/speed", device)
    15  
    16  	// Read contents of the device/speed file
    17  	content, err := ioutil.ReadFile(path)
    18  	if err != nil {
    19  		f.logger.Debug("unable to read link speed", "path", path)
    20  		return 0
    21  	}
    22  
    23  	lines := strings.Split(string(content), "\n")
    24  	mbs, err := strconv.Atoi(lines[0])
    25  	if err != nil || mbs <= 0 {
    26  		f.logger.Debug("unable to parse link speed", "path", path)
    27  		return 0
    28  	}
    29  
    30  	return mbs
    31  }
    32  
    33  // linkSpeed returns link speed in Mb/s, or 0 when unable to determine it.
    34  func (f *NetworkFingerprint) linkSpeed(device string) int {
    35  	// Use LookPath to find the ethtool in the systems $PATH
    36  	// If it's not found or otherwise errors, LookPath returns and empty string
    37  	// and an error we can ignore for our purposes
    38  	ethtoolPath, _ := exec.LookPath("ethtool")
    39  	if ethtoolPath != "" {
    40  		if speed := f.linkSpeedEthtool(ethtoolPath, device); speed > 0 {
    41  			return speed
    42  		}
    43  	}
    44  
    45  	// Fall back on checking a system file for link speed.
    46  	return f.linkSpeedSys(device)
    47  }
    48  
    49  // linkSpeedEthtool determines link speed in Mb/s with 'ethtool'.
    50  func (f *NetworkFingerprint) linkSpeedEthtool(path, device string) int {
    51  	outBytes, err := exec.Command(path, device).Output()
    52  	if err != nil {
    53  		f.logger.Warn("error calling ethtool", "error", err, "path", path, "device", device)
    54  		return 0
    55  	}
    56  
    57  	output := strings.TrimSpace(string(outBytes))
    58  	re := regexp.MustCompile("Speed: [0-9]+[a-zA-Z]+/s")
    59  	m := re.FindString(output)
    60  	if m == "" {
    61  		// no matches found, output may be in a different format
    62  		f.logger.Warn("unable to parse speed", "path", path, "device", device)
    63  		return 0
    64  	}
    65  
    66  	// Split and trim the Mb/s unit from the string output
    67  	args := strings.Split(m, ": ")
    68  	raw := strings.TrimSuffix(args[1], "Mb/s")
    69  
    70  	// convert to Mb/s
    71  	mbs, err := strconv.Atoi(raw)
    72  	if err != nil || mbs <= 0 {
    73  		f.logger.Warn("unable to parse Mb/s", "path", path, "device", device)
    74  		return 0
    75  	}
    76  
    77  	return mbs
    78  }