github.com/netdata/go.d.plugin@v0.58.1/agent/setup.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package agent 4 5 import ( 6 "io" 7 "os" 8 "strings" 9 10 "github.com/netdata/go.d.plugin/agent/confgroup" 11 "github.com/netdata/go.d.plugin/agent/discovery" 12 "github.com/netdata/go.d.plugin/agent/discovery/dummy" 13 "github.com/netdata/go.d.plugin/agent/discovery/file" 14 "github.com/netdata/go.d.plugin/agent/hostinfo" 15 "github.com/netdata/go.d.plugin/agent/module" 16 "github.com/netdata/go.d.plugin/agent/vnodes" 17 18 "gopkg.in/yaml.v2" 19 ) 20 21 func (a *Agent) loadPluginConfig() config { 22 a.Info("loading config file") 23 24 if len(a.ConfDir) == 0 { 25 a.Info("config dir not provided, will use defaults") 26 return defaultConfig() 27 } 28 29 cfgPath := a.Name + ".conf" 30 a.Debugf("looking for '%s' in %v", cfgPath, a.ConfDir) 31 32 path, err := a.ConfDir.Find(cfgPath) 33 if err != nil || path == "" { 34 a.Warning("couldn't find config, will use defaults") 35 return defaultConfig() 36 } 37 a.Infof("found '%s", path) 38 39 cfg := defaultConfig() 40 if err := loadYAML(&cfg, path); err != nil { 41 a.Warningf("couldn't load config '%s': %v, will use defaults", path, err) 42 return defaultConfig() 43 } 44 a.Info("config successfully loaded") 45 return cfg 46 } 47 48 func (a *Agent) loadEnabledModules(cfg config) module.Registry { 49 a.Info("loading modules") 50 51 all := a.RunModule == "all" || a.RunModule == "" 52 enabled := module.Registry{} 53 54 for name, creator := range a.ModuleRegistry { 55 if !all && a.RunModule != name { 56 continue 57 } 58 if all { 59 // Known issue: go.d/logind high CPU usage on Alma Linux8 (https://github.com/netdata/netdata/issues/15930) 60 if !cfg.isExplicitlyEnabled(name) && (creator.Disabled || name == "logind" && hostinfo.SystemdVersion == 239) { 61 a.Infof("'%s' module disabled by default, should be explicitly enabled in the config", name) 62 continue 63 } 64 if !cfg.isImplicitlyEnabled(name) { 65 a.Infof("'%s' module disabled in the config file", name) 66 continue 67 } 68 } 69 enabled[name] = creator 70 } 71 72 a.Infof("enabled/registered modules: %d/%d", len(enabled), len(a.ModuleRegistry)) 73 74 return enabled 75 } 76 77 func (a *Agent) buildDiscoveryConf(enabled module.Registry) discovery.Config { 78 a.Info("building discovery config") 79 80 reg := confgroup.Registry{} 81 for name, creator := range enabled { 82 reg.Register(name, confgroup.Default{ 83 MinUpdateEvery: a.MinUpdateEvery, 84 UpdateEvery: creator.UpdateEvery, 85 AutoDetectionRetry: creator.AutoDetectionRetry, 86 Priority: creator.Priority, 87 }) 88 } 89 90 var readPaths, dummyPaths []string 91 92 if len(a.ModulesConfDir) == 0 { 93 if isInsideK8sCluster() { 94 return discovery.Config{Registry: reg} 95 } 96 a.Info("modules conf dir not provided, will use default config for all enabled modules") 97 for name := range enabled { 98 dummyPaths = append(dummyPaths, name) 99 } 100 return discovery.Config{ 101 Registry: reg, 102 Dummy: dummy.Config{Names: dummyPaths}, 103 } 104 } 105 106 for name := range enabled { 107 // TODO: properly handle module renaming 108 // We need to announce this change in Netdata v1.39.0 release notes and then remove this workaround. 109 // This is just a quick fix for wmi=>windows. We need to prefer user wmi.conf over windows.conf 110 // 2nd part of this fix is in /agent/job/discovery/file/parse.go parseStaticFormat() 111 if name == "windows" { 112 cfgName := "wmi.conf" 113 a.Debugf("looking for '%s' in %v", cfgName, a.ModulesConfDir) 114 115 path, err := a.ModulesConfDir.Find(cfgName) 116 117 if err == nil && strings.Contains(path, "etc/netdata") { 118 a.Infof("found '%s", path) 119 readPaths = append(readPaths, path) 120 continue 121 } 122 } 123 124 cfgName := name + ".conf" 125 a.Debugf("looking for '%s' in %v", cfgName, a.ModulesConfDir) 126 127 path, err := a.ModulesConfDir.Find(cfgName) 128 if isInsideK8sCluster() { 129 if err != nil { 130 a.Infof("not found '%s', won't use default (reading stock configs is disabled in k8s)", cfgName) 131 continue 132 } else if isStockConfig(path) { 133 a.Infof("found '%s', but won't load it (reading stock configs is disabled in k8s)", cfgName) 134 continue 135 } 136 } 137 if err != nil { 138 a.Infof("couldn't find '%s' module config, will use default config", name) 139 dummyPaths = append(dummyPaths, name) 140 } else { 141 a.Debugf("found '%s", path) 142 readPaths = append(readPaths, path) 143 } 144 } 145 146 a.Infof("dummy/read/watch paths: %d/%d/%d", len(dummyPaths), len(readPaths), len(a.ModulesSDConfPath)) 147 return discovery.Config{ 148 Registry: reg, 149 File: file.Config{ 150 Read: readPaths, 151 Watch: a.ModulesSDConfPath, 152 }, 153 Dummy: dummy.Config{ 154 Names: dummyPaths, 155 }, 156 } 157 } 158 159 func (a *Agent) setupVnodeRegistry() *vnodes.Vnodes { 160 a.Debugf("looking for 'vnodes/' in %v", a.VnodesConfDir) 161 162 if len(a.VnodesConfDir) == 0 { 163 return nil 164 } 165 166 dirPath, err := a.VnodesConfDir.Find("vnodes/") 167 if err != nil || dirPath == "" { 168 return nil 169 } 170 171 reg := vnodes.New(dirPath) 172 a.Infof("found '%s' (%d vhosts)", dirPath, reg.Len()) 173 174 return reg 175 } 176 177 func loadYAML(conf interface{}, path string) error { 178 f, err := os.Open(path) 179 if err != nil { 180 return err 181 } 182 defer func() { _ = f.Close() }() 183 184 if err = yaml.NewDecoder(f).Decode(conf); err != nil { 185 if err == io.EOF { 186 return nil 187 } 188 return err 189 } 190 return nil 191 } 192 193 var ( 194 envKubeHost = os.Getenv("KUBERNETES_SERVICE_HOST") 195 envKubePort = os.Getenv("KUBERNETES_SERVICE_PORT") 196 envNDStockConfigDir = os.Getenv("NETDATA_STOCK_CONFIG_DIR") 197 ) 198 199 func isInsideK8sCluster() bool { return envKubeHost != "" && envKubePort != "" } 200 201 func isStockConfig(path string) bool { 202 if envNDStockConfigDir == "" { 203 return false 204 } 205 return strings.HasPrefix(path, envNDStockConfigDir) 206 }