src/go/plugin/go.d/agent/setup.go
// SPDX-License-Identifier: GPL-3.0-or-later
package agent
import (
"io"
"os"
"strings"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/dummy"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/file"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/hostinfo"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/vnodes"
"gopkg.in/yaml.v2"
)
func (a *Agent) loadPluginConfig() config {
a.Info("loading config file")
if len(a.ConfDir) == 0 {
a.Info("config dir not provided, will use defaults")
return defaultConfig()
}
cfgPath := a.Name + ".conf"
a.Debugf("looking for '%s' in %v", cfgPath, a.ConfDir)
path, err := a.ConfDir.Find(cfgPath)
if err != nil || path == "" {
a.Warning("couldn't find config, will use defaults")
return defaultConfig()
}
a.Infof("found '%s", path)
cfg := defaultConfig()
if err := loadYAML(&cfg, path); err != nil {
a.Warningf("couldn't load config '%s': %v, will use defaults", path, err)
return defaultConfig()
}
a.Info("config successfully loaded")
return cfg
}
func (a *Agent) loadEnabledModules(cfg config) module.Registry {
a.Info("loading modules")
all := a.RunModule == "all" || a.RunModule == ""
enabled := module.Registry{}
for name, creator := range a.ModuleRegistry {
if !all && a.RunModule != name {
continue
}
if all {
// Known issue: go.d/logind high CPU usage on Alma Linux8 (https://github.com/netdata/netdata/issues/15930)
if !cfg.isExplicitlyEnabled(name) && (creator.Disabled || name == "logind" && hostinfo.SystemdVersion == 239) {
a.Infof("'%s' module disabled by default, should be explicitly enabled in the config", name)
continue
}
if !cfg.isImplicitlyEnabled(name) {
a.Infof("'%s' module disabled in the config file", name)
continue
}
}
enabled[name] = creator
}
a.Infof("enabled/registered modules: %d/%d", len(enabled), len(a.ModuleRegistry))
return enabled
}
func (a *Agent) buildDiscoveryConf(enabled module.Registry) discovery.Config {
a.Info("building discovery config")
reg := confgroup.Registry{}
for name, creator := range enabled {
reg.Register(name, confgroup.Default{
MinUpdateEvery: a.MinUpdateEvery,
UpdateEvery: creator.UpdateEvery,
AutoDetectionRetry: creator.AutoDetectionRetry,
Priority: creator.Priority,
})
}
var readPaths, dummyPaths []string
if len(a.ModulesConfDir) == 0 {
if hostinfo.IsInsideK8sCluster() {
return discovery.Config{Registry: reg}
}
a.Info("modules conf dir not provided, will use default config for all enabled modules")
for name := range enabled {
dummyPaths = append(dummyPaths, name)
}
return discovery.Config{
Registry: reg,
Dummy: dummy.Config{Names: dummyPaths},
}
}
for name := range enabled {
// TODO: properly handle module renaming
// We need to announce this change in Netdata v1.39.0 release notes and then remove this workaround.
// This is just a quick fix for wmi=>windows. We need to prefer user wmi.conf over windows.conf
// 2nd part of this fix is in /agent/job/discovery/file/parse.go parseStaticFormat()
if name == "windows" {
cfgName := "wmi.conf"
a.Debugf("looking for '%s' in %v", cfgName, a.ModulesConfDir)
path, err := a.ModulesConfDir.Find(cfgName)
if err == nil && strings.Contains(path, "etc/netdata") {
a.Infof("found '%s", path)
readPaths = append(readPaths, path)
continue
}
}
cfgName := name + ".conf"
a.Debugf("looking for '%s' in %v", cfgName, a.ModulesConfDir)
path, err := a.ModulesConfDir.Find(cfgName)
if hostinfo.IsInsideK8sCluster() {
if err != nil {
a.Infof("not found '%s', won't use default (reading stock configs is disabled in k8s)", cfgName)
continue
} else if isStockConfig(path) {
a.Infof("found '%s', but won't load it (reading stock configs is disabled in k8s)", cfgName)
continue
}
}
if err != nil {
a.Infof("couldn't find '%s' module config, will use default config", name)
dummyPaths = append(dummyPaths, name)
} else {
a.Debugf("found '%s", path)
readPaths = append(readPaths, path)
}
}
a.Infof("dummy/read/watch paths: %d/%d/%d", len(dummyPaths), len(readPaths), len(a.ModulesSDConfPath))
return discovery.Config{
Registry: reg,
File: file.Config{
Read: readPaths,
Watch: a.ModulesSDConfPath,
},
Dummy: dummy.Config{
Names: dummyPaths,
},
SD: sd.Config{
ConfDir: a.ModulesConfSDDir,
},
}
}
func (a *Agent) setupVnodeRegistry() *vnodes.Vnodes {
a.Debugf("looking for 'vnodes/' in %v", a.VnodesConfDir)
if len(a.VnodesConfDir) == 0 {
return nil
}
dirPath, err := a.VnodesConfDir.Find("vnodes/")
if err != nil || dirPath == "" {
return nil
}
reg := vnodes.New(dirPath)
a.Infof("found '%s' (%d vhosts)", dirPath, reg.Len())
return reg
}
func loadYAML(conf any, path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer func() { _ = f.Close() }()
if err = yaml.NewDecoder(f).Decode(conf); err != nil {
if err == io.EOF {
return nil
}
return err
}
return nil
}
var (
envNDStockConfigDir = os.Getenv("NETDATA_STOCK_CONFIG_DIR")
)
func isStockConfig(path string) bool {
if envNDStockConfigDir == "" {
return false
}
return strings.HasPrefix(path, envNDStockConfigDir)
}