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 }