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  }