1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// SPDX-License-Identifier: GPL-3.0-or-later
package vnodes
import (
"io"
"io/fs"
"log/slog"
"os"
"path/filepath"
"github.com/netdata/netdata/go/go.d.plugin/logger"
"gopkg.in/yaml.v2"
)
var Disabled = false // TODO: remove after Netdata v1.39.0. Fix for "from source" stable-channel installations.
func New(confDir string) *Vnodes {
vn := &Vnodes{
Logger: logger.New().With(
slog.String("component", "vnodes"),
),
confDir: confDir,
vnodes: make(map[string]*VirtualNode),
}
vn.readConfDir()
return vn
}
type (
Vnodes struct {
*logger.Logger
confDir string
vnodes map[string]*VirtualNode
}
VirtualNode struct {
GUID string `yaml:"guid"`
Hostname string `yaml:"hostname"`
Labels map[string]string `yaml:"labels"`
}
)
func (vn *Vnodes) Lookup(key string) (*VirtualNode, bool) {
v, ok := vn.vnodes[key]
return v, ok
}
func (vn *Vnodes) Len() int {
return len(vn.vnodes)
}
func (vn *Vnodes) readConfDir() {
_ = filepath.WalkDir(vn.confDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
vn.Warning(err)
return nil
}
if !d.Type().IsRegular() || !isConfigFile(path) {
return nil
}
var cfg []VirtualNode
if err := loadConfigFile(&cfg, path); err != nil {
vn.Warning(err)
return nil
}
for _, v := range cfg {
if v.Hostname == "" || v.GUID == "" {
vn.Warningf("skipping virtual node '%+v': some required fields are missing (%s)", v, path)
continue
}
if _, ok := vn.vnodes[v.Hostname]; ok {
vn.Warningf("skipping virtual node '%+v': duplicate node (%s)", v, path)
continue
}
v := v
vn.Debugf("adding virtual node'%+v' (%s)", v, path)
vn.vnodes[v.Hostname] = &v
}
return nil
})
}
func isConfigFile(path string) bool {
switch filepath.Ext(path) {
case ".yaml", ".yml", ".conf":
return true
default:
return false
}
}
func loadConfigFile(conf interface{}, 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 && err != io.EOF {
return err
}
return nil
}
|