github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/client/fingerprint/bridge_linux.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"os"
     7  	"regexp"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  	"github.com/shirou/gopsutil/host"
    12  )
    13  
    14  const bridgeKernelModuleName = "bridge"
    15  
    16  const (
    17  	dynamicModuleRe = `%s\s+.*$`
    18  	builtinModuleRe = `.+/%s.ko$`
    19  	dependsModuleRe = `.+/%s.ko(\.xz)?:.*$`
    20  )
    21  
    22  func (f *BridgeFingerprint) Fingerprint(req *FingerprintRequest, resp *FingerprintResponse) error {
    23  	if err := f.detect(bridgeKernelModuleName); err != nil {
    24  		f.logger.Warn("failed to detect bridge kernel module, bridge network mode disabled", "error", err)
    25  		return nil
    26  	}
    27  
    28  	resp.NodeResources = &structs.NodeResources{
    29  		Networks: []*structs.NetworkResource{{
    30  			Mode: "bridge",
    31  		}},
    32  		NodeNetworks: []*structs.NodeNetworkResource{{
    33  			Mode:   "bridge",
    34  			Device: req.Config.BridgeNetworkName,
    35  		}},
    36  	}
    37  
    38  	resp.Detected = true
    39  	return nil
    40  }
    41  
    42  func (f *BridgeFingerprint) regexp(pattern, module string) *regexp.Regexp {
    43  	return regexp.MustCompile(fmt.Sprintf(pattern, module))
    44  }
    45  
    46  func (f *BridgeFingerprint) detect(module string) error {
    47  	// accumulate errors from every place we might find the module
    48  	var errs error
    49  
    50  	// check if the module has been dynamically loaded
    51  	dynamicPath := "/proc/modules"
    52  	if err := f.searchFile(module, dynamicPath, f.regexp(dynamicModuleRe, module)); err != nil {
    53  		errs = multierror.Append(errs, err)
    54  	} else {
    55  		return nil
    56  	}
    57  
    58  	// will need kernel info to look for builtin and unloaded modules
    59  	hostInfo, err := host.Info()
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	// check if the module is builtin to the kernel
    65  	builtinPath := fmt.Sprintf("/lib/modules/%s/modules.builtin", hostInfo.KernelVersion)
    66  	if err := f.searchFile(module, builtinPath, f.regexp(builtinModuleRe, module)); err != nil {
    67  		errs = multierror.Append(errs, err)
    68  	} else {
    69  		return nil
    70  	}
    71  
    72  	// check if the module is dynamic but unloaded (will have a dep entry)
    73  	dependsPath := fmt.Sprintf("/lib/modules/%s/modules.dep", hostInfo.KernelVersion)
    74  	if err := f.searchFile(module, dependsPath, f.regexp(dependsModuleRe, module)); err != nil {
    75  		errs = multierror.Append(errs, err)
    76  	} else {
    77  		return nil
    78  	}
    79  
    80  	return errs
    81  }
    82  
    83  func (f *BridgeFingerprint) searchFile(module, filename string, re *regexp.Regexp) error {
    84  	file, err := os.Open(filename)
    85  	if err != nil {
    86  		return fmt.Errorf("failed to open %s: %v", filename, err)
    87  	}
    88  	defer func() {
    89  		_ = file.Close()
    90  	}()
    91  
    92  	scanner := bufio.NewScanner(file)
    93  	for scanner.Scan() {
    94  		if re.MatchString(scanner.Text()) {
    95  			return nil // found the module!
    96  		}
    97  	}
    98  	if err := scanner.Err(); err != nil {
    99  		return fmt.Errorf("failed to scan %s: %v", filename, err)
   100  	}
   101  
   102  	return fmt.Errorf("module %s not in %s", module, filename)
   103  }