github.com/influxdata/telegraf@v1.30.3/internal/snmp/mib_loader.go (about)

     1  package snmp
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"sync"
     8  
     9  	"github.com/sleepinggenius2/gosmi"
    10  
    11  	"github.com/influxdata/telegraf"
    12  )
    13  
    14  // must init, append path for each directory, load module for every file
    15  // or gosmi will fail without saying why
    16  var m sync.Mutex
    17  var once sync.Once
    18  var cache = make(map[string]bool)
    19  
    20  type MibLoader interface {
    21  	// appendPath takes the path of a directory
    22  	appendPath(path string)
    23  
    24  	// loadModule takes the name of a file in one of the
    25  	// directories. Basename only, no relative or absolute path
    26  	loadModule(path string) error
    27  }
    28  
    29  type GosmiMibLoader struct{}
    30  
    31  func (*GosmiMibLoader) appendPath(path string) {
    32  	m.Lock()
    33  	defer m.Unlock()
    34  
    35  	gosmi.AppendPath(path)
    36  }
    37  
    38  func (*GosmiMibLoader) loadModule(path string) error {
    39  	m.Lock()
    40  	defer m.Unlock()
    41  
    42  	_, err := gosmi.LoadModule(path)
    43  	return err
    44  }
    45  
    46  // will give all found folders to gosmi and load in all modules found in the folders
    47  func LoadMibsFromPath(paths []string, log telegraf.Logger, loader MibLoader) error {
    48  	folders, err := walkPaths(paths, log)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	for _, path := range folders {
    53  		loader.appendPath(path)
    54  		modules, err := os.ReadDir(path)
    55  		if err != nil {
    56  			log.Warnf("Can't read directory %v", modules)
    57  			continue
    58  		}
    59  
    60  		for _, entry := range modules {
    61  			info, err := entry.Info()
    62  			if err != nil {
    63  				log.Warnf("Couldn't get info for %v: %v", entry.Name(), err)
    64  				continue
    65  			}
    66  			if info.Mode()&os.ModeSymlink != 0 {
    67  				symlink := filepath.Join(path, info.Name())
    68  				target, err := filepath.EvalSymlinks(symlink)
    69  				if err != nil {
    70  					log.Warnf("Couldn't evaluate symbolic links for %v: %v", symlink, err)
    71  					continue
    72  				}
    73  				//replace symlink's info with the target's info
    74  				info, err = os.Lstat(target)
    75  				if err != nil {
    76  					log.Warnf("Couldn't stat target %v: %v", target, err)
    77  					continue
    78  				}
    79  			}
    80  			if info.Mode().IsRegular() {
    81  				err := loader.loadModule(info.Name())
    82  				if err != nil {
    83  					log.Warnf("Couldn't load module %v: %v", info.Name(), err)
    84  					continue
    85  				}
    86  			}
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  // should walk the paths given and find all folders
    93  func walkPaths(paths []string, log telegraf.Logger) ([]string, error) {
    94  	once.Do(gosmi.Init)
    95  	folders := []string{}
    96  
    97  	for _, mibPath := range paths {
    98  		// Check if we loaded that path already and skip it if so
    99  		m.Lock()
   100  		cached := cache[mibPath]
   101  		cache[mibPath] = true
   102  		m.Unlock()
   103  		if cached {
   104  			continue
   105  		}
   106  
   107  		err := filepath.Walk(mibPath, func(path string, info os.FileInfo, err error) error {
   108  			if info == nil {
   109  				log.Warnf("No mibs found")
   110  				if os.IsNotExist(err) {
   111  					log.Warnf("MIB path doesn't exist: %q", mibPath)
   112  				} else if err != nil {
   113  					return err
   114  				}
   115  				return nil
   116  			}
   117  
   118  			if info.Mode()&os.ModeSymlink != 0 {
   119  				target, err := filepath.EvalSymlinks(path)
   120  				if err != nil {
   121  					log.Warnf("Couldn't evaluate symbolic links for %v: %v", path, err)
   122  				}
   123  				info, err = os.Lstat(target)
   124  				if err != nil {
   125  					log.Warnf("Couldn't stat target %v: %v", target, err)
   126  				}
   127  				path = target
   128  			}
   129  			if info.IsDir() {
   130  				folders = append(folders, path)
   131  			}
   132  
   133  			return nil
   134  		})
   135  		if err != nil {
   136  			return folders, fmt.Errorf("couldn't walk path %q: %w", mibPath, err)
   137  		}
   138  	}
   139  	return folders, nil
   140  }