improve(go.d/sd/pipeline): add `services` config (#21269)
Ilya Mashchenko committed
Nov 6, 2025 at 15:29 UTC
9e729508770c4bbe7c221bae882611938c9834f2
10 files changed
+1573
-1037
src/go/plugin/go.d/agent/discovery/sd/pipeline/compose.go
+1
-33
@@ -4,15 +4,12 @@ package pipeline
4
5
import (
6
"bytes"
7
- "errors"
7
"fmt"
8
"text/template"
9
10
"github.com/netdata/netdata/go/plugins/logger"
11
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
12
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
14
-
15
- "gopkg.in/yaml.v2"
13
)
14
15
func newConfigComposer(cfg []ComposeRuleConfig) (*configComposer, error) {
@@ -71,7 +68,7 @@ func (c *configComposer) compose(tgt model.Target) []confgroup.Config {
68
continue
69
}
70
74
- cfgs, err := c.parseTemplateData(c.buf.Bytes())
71
+ cfgs, err := parseConfigTemplateData(c.buf.Bytes())
72
if err != nil {
73
c.Warningf("failed to parse template data: %v", err)
74
continue
@@ -87,35 +84,6 @@ func (c *configComposer) compose(tgt model.Target) []confgroup.Config {
84
return configs
85
}
86
90
-func (c *configComposer) parseTemplateData(bs []byte) ([]confgroup.Config, error) {
91
- var data any
92
- if err := yaml.Unmarshal(bs, &data); err != nil {
93
- return nil, err
94
- }
95
-
96
- type (
97
- single = map[any]any
98
- multi = []any
99
- )
100
-
101
- switch data.(type) {
102
- case single:
103
- var cfg confgroup.Config
104
- if err := yaml.Unmarshal(bs, &cfg); err != nil {
105
- return nil, err
106
- }
107
- return []confgroup.Config{cfg}, nil
108
- case multi:
109
- var cfgs []confgroup.Config
110
- if err := yaml.Unmarshal(bs, &cfgs); err != nil {
111
- return nil, err
112
- }
113
- return cfgs, nil
114
- default:
115
- return nil, errors.New("unknown config format")
116
- }
117
-}
118
-
87
func newComposeRules(cfg []ComposeRuleConfig) ([]*composeRule, error) {
88
var rules []*composeRule
89
src/go/plugin/go.d/agent/discovery/sd/pipeline/config.go
+96
-8
@@ -5,21 +5,29 @@ package pipeline
5
import (
6
"errors"
7
"fmt"
8
+ "strings"
9
10
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
11
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/discoverer/dockersd"
12
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/discoverer/k8ssd"
13
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/discoverer/netlistensd"
14
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/discoverer/snmpsd"
15
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
16
)
17
18
type Config struct {
19
Source string `yaml:"-"`
20
ConfigDefaults confgroup.Registry `yaml:"-"`
21
20
- Disabled bool `yaml:"disabled"`
21
- Name string `yaml:"name"`
22
- Discover []DiscoveryConfig `yaml:"discover"`
22
+ Disabled bool `yaml:"disabled"`
23
+ Name string `yaml:"name"`
24
+
25
+ Discover []DiscoveryConfig `yaml:"discover"`
26
+
27
+ // New single-step format:
28
+ Services []ServiceRuleConfig `yaml:"services"`
29
+
30
+ // Legacy two-step:
31
Classify []ClassifyRuleConfig `yaml:"classify"`
32
Compose []ComposeRuleConfig `yaml:"compose"`
33
}
@@ -32,6 +40,12 @@ type DiscoveryConfig struct {
40
SNMP snmpsd.Config `yaml:"snmp"`
41
}
42
43
+type ServiceRuleConfig struct {
44
+ ID string `yaml:"id"` // mandatory (for logging/diagnostics)
45
+ Match string `yaml:"match"` // mandatory
46
+ ConfigTemplate string `yaml:"config_template"` // optional (drop if empty)
47
+}
48
+
49
type ClassifyRuleConfig struct {
50
Name string `yaml:"name"`
51
Selector string `yaml:"selector"` // mandatory
@@ -58,11 +72,20 @@ func validateConfig(cfg Config) error {
72
if err := validateDiscoveryConfig(cfg.Discover); err != nil {
73
return fmt.Errorf("discover config: %v", err)
74
}
61
- if err := validateClassifyConfig(cfg.Classify); err != nil {
62
- return fmt.Errorf("classify rules: %v", err)
63
- }
64
- if err := validateComposeConfig(cfg.Compose); err != nil {
65
- return fmt.Errorf("compose rules: %v", err)
75
+
76
+ switch {
77
+ case len(cfg.Services) > 0:
78
+ if err := validateServicesConfig(cfg.Services); err != nil {
79
+ return fmt.Errorf("services rules: %v", err)
80
+ }
81
+ default:
82
+ // Legacy path
83
+ if err := validateClassifyConfig(cfg.Classify); err != nil {
84
+ return fmt.Errorf("classify rules: %v", err)
85
+ }
86
+ if err := validateComposeConfig(cfg.Compose); err != nil {
87
+ return fmt.Errorf("compose rules: %v", err)
88
+ }
89
}
90
return nil
91
}
@@ -81,6 +104,23 @@ func validateDiscoveryConfig(config []DiscoveryConfig) error {
104
return nil
105
}
106
107
+func validateServicesConfig(rules []ServiceRuleConfig) error {
108
+ if len(rules) == 0 {
109
+ return errors.New("empty config, need at least 1 service rule")
110
+ }
111
+ for i, r := range rules {
112
+ i++
113
+ if r.ID == "" {
114
+ return fmt.Errorf("'service[%d]->id' not set", i)
115
+ }
116
+ if r.Match == "" {
117
+ return fmt.Errorf("'service[%s][%d]->match' not set", r.ID, i)
118
+ }
119
+ // config_template is optional
120
+ }
121
+ return nil
122
+}
123
+
124
func validateClassifyConfig(rules []ClassifyRuleConfig) error {
125
if len(rules) == 0 {
126
return errors.New("empty config, need least 1 rule")
@@ -136,3 +176,51 @@ func validateComposeConfig(rules []ComposeRuleConfig) error {
176
}
177
return nil
178
}
179
+
180
+func ConvertOldToServices(cls []ClassifyRuleConfig, cmp []ComposeRuleConfig) ([]ServiceRuleConfig, error) {
181
+ var out []ServiceRuleConfig
182
+
183
+ // Build quick lookups for tag -> list of match exprs that add this tag.
184
+ tagToExprs := map[string][]string{}
185
+ for _, r := range cls {
186
+ for _, m := range r.Match {
187
+ // split tags line into tokens:
188
+ tags, _ := model.ParseTags(m.Tags) // reuse existing parser if accessible
189
+ for tag := range tags {
190
+ if strings.HasPrefix(tag, "-") { // ignore deletions
191
+ continue
192
+ }
193
+ tagToExprs[tag] = append(tagToExprs[tag], m.Expr)
194
+ }
195
+ }
196
+ // also include rule-level tags
197
+ rtags, _ := model.ParseTags(r.Tags)
198
+ for tag := range rtags {
199
+ if strings.HasPrefix(tag, "-") {
200
+ continue
201
+ }
202
+ // no expr here; this is too generic to build a service rule from.
203
+ }
204
+ }
205
+
206
+ // For each compose rule config entry, create services for its selector tags.
207
+ for _, r := range cmp {
208
+ for _, c := range r.Config {
209
+ sel := strings.TrimSpace(c.Selector)
210
+ exprs := tagToExprs[sel]
211
+ for i, expr := range exprs {
212
+ id := sel
213
+ if i > 0 {
214
+ id = fmt.Sprintf("%s_%d", sel, i+1)
215
+ }
216
+ out = append(out, ServiceRuleConfig{
217
+ ID: id,
218
+ Match: expr,
219
+ ConfigTemplate: c.Template,
220
+ })
221
+ }
222
+ }
223
+ }
224
+
225
+ return out, nil
226
+}
src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline.go
+50
-15
@@ -24,30 +24,41 @@ func New(cfg Config) (*Pipeline, error) {
24
return nil, err
25
}
26
27
- clr, err := newTargetClassificator(cfg.Classify)
28
- if err != nil {
29
- return nil, fmt.Errorf("classify rules: %v", err)
30
- }
31
-
32
- cmr, err := newConfigComposer(cfg.Compose)
33
- if err != nil {
34
- return nil, fmt.Errorf("compose rules: %v", err)
35
- }
36
-
27
p := &Pipeline{
28
Logger: logger.New().With(
29
slog.String("component", "service discovery"),
30
slog.String("pipeline", cfg.Name),
31
),
32
configDefaults: cfg.ConfigDefaults,
43
- clr: clr,
44
- cmr: cmr,
33
accum: newAccumulator(),
34
discoverers: make([]model.Discoverer, 0),
35
configs: make(map[string]map[uint64][]confgroup.Config),
36
}
37
+
38
p.accum.Logger = p.Logger
39
40
+ if len(cfg.Services) > 0 {
41
+ svr, err := newServiceEngine(cfg.Services)
42
+ if err != nil {
43
+ return nil, fmt.Errorf("services rules: %v", err)
44
+ }
45
+ p.svr = svr
46
+ svr.Logger = p.Logger
47
+ } else {
48
+ // Legacy path
49
+ clr, err := newTargetClassificator(cfg.Classify)
50
+ if err != nil {
51
+ return nil, fmt.Errorf("classify rules: %v", err)
52
+ }
53
+ cmr, err := newConfigComposer(cfg.Compose)
54
+ if err != nil {
55
+ return nil, fmt.Errorf("compose rules: %v", err)
56
+ }
57
+ p.clr, p.cmr = clr, cmr
58
+ clr.Logger = p.Logger
59
+ cmr.Logger = p.Logger
60
+ }
61
+
62
if err := p.registerDiscoverers(cfg); err != nil {
63
return nil, err
64
}
@@ -62,9 +73,15 @@ type (
73
configDefaults confgroup.Registry
74
discoverers []model.Discoverer
75
accum *accumulator
65
- clr classificator
66
- cmr composer
67
- configs map[string]map[uint64][]confgroup.Config // [targetSource][targetHash]
76
+
77
+ configs map[string]map[uint64][]confgroup.Config // [targetSource][targetHash]
78
+
79
+ // new
80
+ svr composer
81
+
82
+ // legacy
83
+ clr classificator
84
+ cmr composer
85
}
86
classificator interface {
87
classify(model.Target) model.Tags
@@ -201,6 +218,23 @@ func (p *Pipeline) processGroup(tgg model.TargetGroup) *confgroup.Group {
218
219
targetsCache[hash] = nil
220
221
+ if p.svr != nil {
222
+ if cfgs := p.svr.compose(tgt); len(cfgs) > 0 {
223
+ targetsCache[hash] = cfgs
224
+ changed = true
225
+ for _, cfg := range cfgs {
226
+ cfg.SetProvider(tgg.Provider())
227
+ cfg.SetSource(tgg.Source())
228
+ cfg.SetSourceType(confgroup.TypeDiscovered)
229
+ if def, ok := p.configDefaults.Lookup(cfg.Module()); ok {
230
+ cfg.ApplyDefaults(def)
231
+ }
232
+ }
233
+ }
234
+ continue
235
+ }
236
+
237
+ // Legacy:
238
if tags := p.clr.classify(tgt); len(tags) > 0 {
239
tgt.Tags().Merge(tags)
240
@@ -218,6 +252,7 @@ func (p *Pipeline) processGroup(tgg model.TargetGroup) *confgroup.Group {
252
}
253
}
254
}
255
+
256
}
257
258
for hash := range targetsCache {
src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go
+209
@@ -94,6 +94,18 @@ compose:
94
template: |
95
name: {{ .Name }}-foobar2
96
`
97
+
98
+ const servicesConfig = `
99
+services:
100
+ - id: "svc-foobar1"
101
+ match: '{{ glob .Name "mock*1*" }}'
102
+ config_template: |
103
+ name: {{ .Name }}-foobar1
104
+ - id: "svc-foobar2"
105
+ match: '{{ glob .Name "mock*2*" }}'
106
+ config_template: |
107
+ name: {{ .Name }}-foobar2
108
+`
109
tests := map[string]discoverySim{
110
"new group with no targets": {
111
config: config,
@@ -186,6 +198,21 @@ compose:
198
prepareDiscoveredGroup("mock11-foobar1", "mock22-foobar2"),
199
},
200
},
201
+ "services-only: new group with targets": {
202
+ config: servicesConfig,
203
+ discoverers: []model.Discoverer{
204
+ newMockDiscoverer("rule1",
205
+ newMockTargetGroup("test", "mock1", "mock2"),
206
+ ),
207
+ },
208
+ useServices: true, // tell the simulator to wire svr-only
209
+ wantClassifyCalls: 0, // no classify in services mode
210
+ wantComposeCalls: 2, // compose called per target (2 targets)
211
+ wantConfGroups: []*confgroup.Group{
212
+ // same expected configs as the legacy "new group with targets"
213
+ prepareDiscoveredGroup("mock1-foobar1", "mock2-foobar2"),
214
+ },
215
+ },
216
}
217
218
for name, sim := range tests {
@@ -301,3 +328,185 @@ func mustCalcHash(obj any) uint64 {
328
}
329
return hash
330
}
331
+
332
+func TestConvertOldToServices(t *testing.T) {
333
+ type inYAML struct {
334
+ Classify string
335
+ Compose string
336
+ }
337
+
338
+ tests := map[string]struct {
339
+ in inYAML
340
+ want []ServiceRuleConfig
341
+ }{
342
+ "basic 1:1 mapping": {
343
+ in: inYAML{
344
+ Classify: `
345
+- name: "Applications"
346
+ selector: "unknown"
347
+ tags: "-unknown app"
348
+ match:
349
+ - tags: "activemq"
350
+ expr: '{{ and (eq .Port "8161") (eq .Comm "activemq") }}'
351
+`,
352
+ Compose: `
353
+- name: "Applications"
354
+ selector: "app"
355
+ config:
356
+ - selector: "activemq"
357
+ template: |
358
+ module: activemq
359
+ name: local
360
+ url: http://{{.Address}}
361
+ webadmin: admin
362
+`,
363
+ },
364
+ want: []ServiceRuleConfig{
365
+ {
366
+ ID: "activemq",
367
+ Match: `{{ and (eq .Port "8161") (eq .Comm "activemq") }}`,
368
+ ConfigTemplate: "module: activemq\nname: local\nurl: http://{{.Address}}\nwebadmin: admin\n",
369
+ },
370
+ },
371
+ },
372
+
373
+ "multiple classify exprs for same tag -> multiple service rules": {
374
+ in: inYAML{
375
+ Classify: `
376
+- name: "Databases"
377
+ selector: "unknown"
378
+ match:
379
+ - tags: "redis"
380
+ expr: '{{ eq .Port "6379" }}'
381
+ - tags: "redis"
382
+ expr: '{{ and (eq .Comm "redis-server") (eq .Address "127.0.0.1") }}'
383
+`,
384
+ Compose: `
385
+- name: "Databases"
386
+ selector: "app"
387
+ config:
388
+ - selector: "redis"
389
+ template: |
390
+ module: redis
391
+ name: {{ .Name }}
392
+`,
393
+ },
394
+ // NOTE: Order should follow classify expr encounter order:
395
+ // 1) Port-based, 2) Comm+Address-based. IDs redis, redis_2 accordingly.
396
+ want: []ServiceRuleConfig{
397
+ {
398
+ ID: "redis",
399
+ Match: `{{ eq .Port "6379" }}`,
400
+ ConfigTemplate: "module: redis\nname: {{ .Name }}\n",
401
+ },
402
+ {
403
+ ID: "redis_2",
404
+ Match: `{{ and (eq .Comm "redis-server") (eq .Address "127.0.0.1") }}`,
405
+ ConfigTemplate: "module: redis\nname: {{ .Name }}\n",
406
+ },
407
+ },
408
+ },
409
+
410
+ "ignore deletions and rule-level tags without expr": {
411
+ in: inYAML{
412
+ Classify: `
413
+- name: "NoExpr"
414
+ selector: "unknown"
415
+ tags: "nginx" # rule-level tag: no expr -> cannot produce a service rule
416
+ match: []
417
+- name: "Deletions"
418
+ selector: "unknown"
419
+ match:
420
+ - tags: "-nginx" # deletion: ignore
421
+ expr: '{{ eq .Port "80" }}' # has expr but tag is a deletion, ignore
422
+`,
423
+ Compose: `
424
+- name: "Web"
425
+ selector: "app"
426
+ config:
427
+ - selector: "nginx"
428
+ template: |
429
+ module: nginx
430
+ name: web
431
+`,
432
+ },
433
+ want: nil, // nothing to map
434
+ },
435
+
436
+ "compose selector without classify producer -> empty": {
437
+ in: inYAML{
438
+ Classify: `
439
+- name: "App"
440
+ selector: "unknown"
441
+ match:
442
+ - tags: "foo"
443
+ expr: '{{ eq .Port "1234" }}'
444
+`,
445
+ Compose: `
446
+- name: "App"
447
+ selector: "app"
448
+ config:
449
+ - selector: "bar"
450
+ template: |
451
+ module: bar
452
+`,
453
+ },
454
+ want: nil,
455
+ },
456
+
457
+ "multiple compose selectors map to different classify tags": {
458
+ in: inYAML{
459
+ Classify: `
460
+- name: "Mixed"
461
+ selector: "unknown"
462
+ match:
463
+ - tags: "kafka"
464
+ expr: '{{ eq .Port "9092" }}'
465
+ - tags: "zookeeper"
466
+ expr: '{{ eq .Port "2181" }}'
467
+`,
468
+ Compose: `
469
+- name: "Stream"
470
+ selector: "app"
471
+ config:
472
+ - selector: "zookeeper"
473
+ template: |
474
+ module: zookeeper
475
+ name: zk
476
+ - selector: "kafka"
477
+ template: |
478
+ module: kafka
479
+ name: broker
480
+`,
481
+ },
482
+ // Order follows compose config order; for each selector, classify exprs order is preserved.
483
+ want: []ServiceRuleConfig{
484
+ {
485
+ ID: "zookeeper",
486
+ Match: `{{ eq .Port "2181" }}`,
487
+ ConfigTemplate: "module: zookeeper\nname: zk\n",
488
+ },
489
+ {
490
+ ID: "kafka",
491
+ Match: `{{ eq .Port "9092" }}`,
492
+ ConfigTemplate: "module: kafka\nname: broker\n",
493
+ },
494
+ },
495
+ },
496
+ }
497
+
498
+ for name, tc := range tests {
499
+ t.Run(name, func(t *testing.T) {
500
+ var cls []ClassifyRuleConfig
501
+ var cmp []ComposeRuleConfig
502
+
503
+ require.NoError(t, yaml.Unmarshal([]byte(tc.in.Classify), &cls), "classify YAML")
504
+ require.NoError(t, yaml.Unmarshal([]byte(tc.in.Compose), &cmp), "compose YAML")
505
+
506
+ got, err := ConvertOldToServices(cls, cmp)
507
+ require.NoError(t, err)
508
+
509
+ assert.Equal(t, tc.want, got)
510
+ })
511
+ }
512
+}
src/go/plugin/go.d/agent/discovery/sd/pipeline/services.go
new
+137
@@ -0,0 +1,137 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package pipeline
4
+
5
+import (
6
+ "bytes"
7
+ "errors"
8
+ "fmt"
9
+ "strings"
10
+ "text/template"
11
+
12
+ "github.com/netdata/netdata/go/plugins/logger"
13
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
14
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
15
+
16
+ "gopkg.in/yaml.v2"
17
+)
18
+
19
+func newServiceEngine(cfg []ServiceRuleConfig) (*serviceEngine, error) {
20
+ rules, err := newServiceRules(cfg)
21
+ if err != nil {
22
+ return nil, err
23
+ }
24
+ return &serviceEngine{rules: rules}, nil
25
+}
26
+
27
+type serviceEngine struct {
28
+ *logger.Logger
29
+ rules []*serviceRule
30
+ buf bytes.Buffer
31
+}
32
+
33
+type serviceRule struct {
34
+ id string
35
+ match *template.Template
36
+ tmpl *template.Template // optional
37
+}
38
+
39
+func newServiceRules(cfg []ServiceRuleConfig) ([]*serviceRule, error) {
40
+ fmap := newFuncMap()
41
+ var rules []*serviceRule
42
+
43
+ for i, rc := range cfg {
44
+ i++
45
+
46
+ m, err := parseTemplate(rc.Match, fmap)
47
+ if err != nil {
48
+ return nil, fmt.Errorf("service '%s'[%d]: match: %v", rc.ID, i, err)
49
+ }
50
+
51
+ var tmpl *template.Template
52
+ if strings.TrimSpace(rc.ConfigTemplate) != "" {
53
+ tmpl, err = parseTemplate(rc.ConfigTemplate, fmap)
54
+ if err != nil {
55
+ return nil, fmt.Errorf("service '%s'[%d]: config_template: %v", rc.ID, i, err)
56
+ }
57
+ }
58
+
59
+ rules = append(rules, &serviceRule{
60
+ id: rc.ID, match: m, tmpl: tmpl,
61
+ })
62
+ }
63
+ return rules, nil
64
+}
65
+
66
+func (s *serviceEngine) compose(tgt model.Target) []confgroup.Config {
67
+ var out []confgroup.Config
68
+
69
+ for i, r := range s.rules {
70
+ s.buf.Reset()
71
+
72
+ if err := r.match.Execute(&s.buf, tgt); err != nil {
73
+ s.Warningf("failed to execute services[%d]->match on target '%s'", i+1, tgt.TUID())
74
+ continue
75
+ }
76
+ if strings.TrimSpace(s.buf.String()) != "true" {
77
+ continue
78
+ }
79
+
80
+ // No config_template => drop
81
+ if r.tmpl == nil {
82
+ break
83
+ }
84
+
85
+ s.buf.Reset()
86
+ if err := r.tmpl.Execute(&s.buf, tgt); err != nil {
87
+ s.Warningf("failed to execute services[%d]->config_template on target '%s': %v", i+1, tgt.TUID(), err)
88
+ continue
89
+ }
90
+ if s.buf.Len() == 0 {
91
+ continue
92
+ }
93
+
94
+ cfgs, err := parseConfigTemplateData(s.buf.Bytes())
95
+ if err != nil {
96
+ s.Warningf("failed to parse services[%d] template data: %v", i+1, err)
97
+ continue
98
+ }
99
+
100
+ out = append(out, cfgs...)
101
+ }
102
+
103
+ if len(out) > 0 {
104
+ s.Debugf("created %d config(s) for target '%s'", len(out), tgt.TUID())
105
+ }
106
+
107
+ return out
108
+}
109
+
110
+func parseConfigTemplateData(bs []byte) ([]confgroup.Config, error) {
111
+ var data any
112
+ if err := yaml.Unmarshal(bs, &data); err != nil {
113
+ return nil, err
114
+ }
115
+
116
+ type (
117
+ single = map[any]any
118
+ multi = []any
119
+ )
120
+
121
+ switch data.(type) {
122
+ case single:
123
+ var cfg confgroup.Config
124
+ if err := yaml.Unmarshal(bs, &cfg); err != nil {
125
+ return nil, err
126
+ }
127
+ return []confgroup.Config{cfg}, nil
128
+ case multi:
129
+ var cfgs []confgroup.Config
130
+ if err := yaml.Unmarshal(bs, &cfgs); err != nil {
131
+ return nil, err
132
+ }
133
+ return cfgs, nil
134
+ default:
135
+ return nil, errors.New("unknown config format")
136
+ }
137
+}
src/go/plugin/go.d/agent/discovery/sd/pipeline/services_test.go
new
+121
@@ -0,0 +1,121 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package pipeline
4
+
5
+import (
6
+ "testing"
7
+
8
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
9
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
10
+
11
+ "github.com/stretchr/testify/assert"
12
+ "github.com/stretchr/testify/require"
13
+ "gopkg.in/yaml.v2"
14
+)
15
+
16
+func TestServiceEngine_compose(t *testing.T) {
17
+ // Config A:
18
+ // - rule1: matches exactly Name == "mock1" and yields 1 config
19
+ // - rule2: matches Name == "mock2" or "mock3" and yields 2 configs (YAML list)
20
+ // - drop1: matches Name == "dropme" but has no config_template => hard drop (break)
21
+ // - rule3: another rule matching Name == "mock3" to validate multi-rule aggregation
22
+ configA := `
23
+- id: "rule1"
24
+ match: '{{ eq .Name "mock1" }}'
25
+ config_template: |
26
+ name: {{ .Name }}-1
27
+- id: "rule2"
28
+ match: '{{ or (eq .Name "mock2") (eq .Name "mock3") }}'
29
+ config_template: |
30
+ - name: {{ .Name }}-2
31
+ - name: {{ .Name }}-3
32
+- id: "drop1"
33
+ match: '{{ eq .Name "dropme" }}'
34
+- id: "rule3"
35
+ match: '{{ eq .Name "mock3" }}'
36
+ config_template: |
37
+ - name: {{ .Name }}-4
38
+`
39
+
40
+ // Config B:
41
+ // - drop3: matches Name == "mock3" with no template => hard drop (break)
42
+ // - rule2/rule3 exist but must NOT be evaluated if drop3 matches
43
+ configB := `
44
+- id: "rule1"
45
+ match: '{{ eq .Name "mock1" }}'
46
+ config_template: |
47
+ name: {{ .Name }}-1
48
+- id: "drop3"
49
+ match: '{{ eq .Name "mock3" }}'
50
+- id: "rule2"
51
+ match: '{{ or (eq .Name "mock2") (eq .Name "mock3") }}'
52
+ config_template: |
53
+ - name: {{ .Name }}-2
54
+ - name: {{ .Name }}-3
55
+- id: "rule3"
56
+ match: '{{ eq .Name "mock3" }}'
57
+ config_template: |
58
+ - name: {{ .Name }}-4
59
+`
60
+
61
+ type tc struct {
62
+ configYAML string
63
+ target model.Target
64
+ wantConfigs []confgroup.Config
65
+ }
66
+
67
+ tests := map[string]tc{
68
+ "no rules match": {
69
+ configYAML: configA,
70
+ target: newMockTarget("nothing"),
71
+ wantConfigs: nil,
72
+ },
73
+ "drop rule hit (no config_template)": {
74
+ configYAML: configA,
75
+ target: newMockTarget("dropme"),
76
+ wantConfigs: nil,
77
+ },
78
+ "one rule -> one config": {
79
+ configYAML: configA,
80
+ target: newMockTarget("mock1"),
81
+ wantConfigs: []confgroup.Config{
82
+ {"name": "mock1-1"},
83
+ },
84
+ },
85
+ "one rule -> two configs (YAML list)": {
86
+ configYAML: configA,
87
+ target: newMockTarget("mock2"),
88
+ wantConfigs: []confgroup.Config{
89
+ {"name": "mock2-2"},
90
+ {"name": "mock2-3"},
91
+ },
92
+ },
93
+ "multiple rules aggregated (no drop before)": {
94
+ configYAML: configA,
95
+ target: newMockTarget("mock3"),
96
+ wantConfigs: []confgroup.Config{
97
+ {"name": "mock3-2"},
98
+ {"name": "mock3-3"},
99
+ {"name": "mock3-4"},
100
+ },
101
+ },
102
+ "hard drop stops further evaluation": {
103
+ configYAML: configB,
104
+ target: newMockTarget("mock3"),
105
+ wantConfigs: nil, // drop3 matches first => break => rule2/rule3 ignored
106
+ },
107
+ }
108
+
109
+ for name, test := range tests {
110
+ t.Run(name, func(t *testing.T) {
111
+ var cfg []ServiceRuleConfig
112
+ err := yaml.Unmarshal([]byte(test.configYAML), &cfg)
113
+ require.NoErrorf(t, err, "yaml unmarshalling of services config")
114
+
115
+ svr, err := newServiceEngine(cfg)
116
+ require.NoErrorf(t, err, "service engine creation")
117
+
118
+ assert.Equal(t, test.wantConfigs, svr.compose(test.target))
119
+ })
120
+ }
121
+}
src/go/plugin/go.d/agent/discovery/sd/pipeline/sim_test.go
+39
-13
@@ -23,6 +23,9 @@ type discoverySim struct {
23
wantClassifyCalls int
24
wantComposeCalls int
25
wantConfGroups []*confgroup.Group
26
+
27
+ // New: when true (or when cfg.Services is non-empty), run with services engine only.
28
+ useServices bool
29
}
30
31
func (sim discoverySim) run(t *testing.T) {
@@ -32,15 +35,6 @@ func (sim discoverySim) run(t *testing.T) {
35
err := yaml.Unmarshal([]byte(sim.config), &cfg)
36
require.Nilf(t, err, "cfg unmarshal")
37
35
- clr, err := newTargetClassificator(cfg.Classify)
36
- require.Nil(t, err, "newTargetClassificator")
37
-
38
- cmr, err := newConfigComposer(cfg.Compose)
39
- require.Nil(t, err, "newConfigComposer")
40
-
41
- mockClr := &mockClassificator{clr: clr}
42
- mockCmr := &mockComposer{cmr: cmr}
43
-
38
accum := newAccumulator()
39
accum.sendEvery = time.Second * 2
40
@@ -48,12 +42,44 @@ func (sim discoverySim) run(t *testing.T) {
42
Logger: logger.New(),
43
discoverers: sim.discoverers,
44
accum: accum,
51
- clr: mockClr,
52
- cmr: mockCmr,
45
configs: make(map[string]map[uint64][]confgroup.Config),
46
}
55
-
47
pl.accum.Logger = pl.Logger
48
+
49
+ // Prefer services when either explicitly requested or present in config.
50
+ if sim.useServices || len(cfg.Services) > 0 {
51
+ // --- services-only path ---
52
+ svr, err := newServiceEngine(cfg.Services)
53
+ require.Nil(t, err, "newServiceEngine")
54
+
55
+ mockSvr := &mockComposer{cmr: svr} // reuse mock to count compose()
56
+ pl.svr = mockSvr // set services engine
57
+ svr.Logger = pl.Logger
58
+
59
+ groups := sim.collectGroups(t, pl)
60
+ sortConfigGroups(groups)
61
+ sortConfigGroups(sim.wantConfGroups)
62
+
63
+ assert.Equal(t, sim.wantConfGroups, groups)
64
+ // When services is used, classify is not called.
65
+ assert.Equalf(t, 0, sim.wantClassifyCalls, "classify calls should be zero in services mode")
66
+ assert.Equalf(t, sim.wantComposeCalls, mockSvr.calls, "compose (services) calls")
67
+ return
68
+ }
69
+
70
+ // --- legacy path ---
71
+ clr, err := newTargetClassificator(cfg.Classify)
72
+ require.Nil(t, err, "newTargetClassificator")
73
+
74
+ cmr, err := newConfigComposer(cfg.Compose)
75
+ require.Nil(t, err, "newConfigComposer")
76
+
77
+ mockClr := &mockClassificator{clr: clr}
78
+ mockCmr := &mockComposer{cmr: cmr}
79
+
80
+ pl.clr = mockClr
81
+ pl.cmr = mockCmr
82
+
83
clr.Logger = pl.Logger
84
cmr.Logger = pl.Logger
85
@@ -109,7 +135,7 @@ func (m *mockClassificator) classify(tgt model.Target) model.Tags {
135
136
type mockComposer struct {
137
calls int
112
- cmr *configComposer
138
+ cmr composer
139
}
140
141
func (m *mockComposer) compose(tgt model.Target) []confgroup.Config {
src/go/plugin/go.d/config/go.d/sd/docker.conf
+290
-306
@@ -8,309 +8,293 @@ discover:
8
tags: "unknown"
9
address: "unix:///var/run/docker.sock"
10
11
-classify:
12
- - name: "Skip"
13
- selector: "unknown"
14
- tags: "skip"
15
- match:
16
- - tags: "skip"
17
- expr: |
18
- {{ $netNOK := eq .NetworkMode "host" -}}
19
- {{ $protoNOK := not (eq .PortProtocol "tcp") -}}
20
- {{ $portNOK := empty .PrivatePort -}}
21
- {{ $addrNOK := or (empty .IPAddress) (glob .PublicPortIP "*:*") -}}
22
- {{ or $netNOK $protoNOK $portNOK $addrNOK }}
23
- - name: "Applications"
24
- selector: "!skip unknown"
25
- tags: "-unknown app"
26
- match:
27
- - tags: "apache"
28
- expr: '{{ match "sp" .Image "httpd httpd:* */apache */apache:* */apache2 */apache2:*" }}'
29
- - tags: "beanstalk"
30
- expr: '{{ match "sp" .Image "*/beanstalkd */beanstalkd:*" }}'
31
- - tags: "boinc"
32
- expr: '{{ match "sp" .Image "boinc/client boinc/client:* */boinc */boinc:*" }}'
33
- - tags: "cockroachdb"
34
- expr: '{{ match "sp" .Image "cockroachdb/cockroach cockroachdb/cockroach:*" }}'
35
- - tags: "consul"
36
- expr: '{{ match "sp" .Image "consul consul:* */consul */consul:*" }}'
37
- - tags: "coredns"
38
- expr: '{{ match "sp" .Image "*/coredns */coredns:*" }}'
39
- - tags: "couchbase"
40
- expr: '{{ or (eq .PrivatePort "8091") (match "sp" .Image "couchbase couchbase:*") }}'
41
- - tags: "couchdb"
42
- expr: '{{ or (eq .PrivatePort "5984") (match "sp" .Image "couchdb couchdb:*") }}'
43
- - tags: "dovecot"
44
- expr: '{{ or (eq .PrivatePort "24242") (match "sp" .Image "*/dovecot */dovecot:*") }}'
45
- - tags: "elasticsearch"
46
- expr: '{{ or (eq .PrivatePort "9200") (match "sp" .Image "elasticsearch elasticsearch:* */elasticsearch */elasticsearch:* */opensearch */opensearch:*") }}'
47
- - tags: "gearman"
48
- expr: '{{ and (eq .PrivatePort "4730") (match "sp" .Image "*/gearmand */gearmand:*") }}'
49
- - tags: "ipfs"
50
- expr: '{{ and (eq .PrivatePort "5001") (match "sp" .Image "ipfs/kubo ipfs/kubo:*") }}'
51
- - tags: "lighttpd"
52
- expr: '{{ match "sp" .Image "*/lighttpd */lighttpd:*" }}'
53
- - tags: "maxscale"
54
- expr: '{{ or (eq .PrivatePort "8989") (match "sp" .Image "mariadb/maxscale mariadb/maxscale:*") }}'
55
- - tags: "memcached"
56
- expr: '{{ or (eq .PrivatePort "11211") (match "sp" .Image "memcached memcached:* */memcached */memcached:*") }}'
57
- - tags: "mongodb"
58
- expr: '{{ or (eq .PrivatePort "27017") (match "sp" .Image "mongo mongo:* */mongodb */mongodb:* */mongodb-community-server */mongodb-community-server:*") }}'
59
- - tags: "mysql"
60
- expr: '{{ or (eq .PrivatePort "3306") (match "sp" .Image "mysql mysql:* */mysql */mysql:* mariadb mariadb:* */mariadb */mariadb:* percona percona:* */percona-mysql */percona-mysql:*") }}'
61
- - tags: "nats"
62
- expr: '{{ and (eq .PrivatePort "8222") (match "sp" .Image "nats nats:*") }}'
63
- - tags: "nginx"
64
- expr: '{{ match "sp" .Image "nginx nginx:*" }}'
65
- - tags: "nginxunit"
66
- expr: '{{ match "sp" .Image "nginx/unit nginx/unit:*" }}'
67
- - tags: "oracledb"
68
- expr: '{{ and (eq .PrivatePort "1521" "2484") (match "sp" .Image "oracle/database oracle/database:*") }}'
69
- - tags: "pgbouncer"
70
- expr: '{{ or (eq .PrivatePort "6432") (match "sp" .Image "*/pgbouncer */pgbouncer:*") }}'
71
- - tags: "pika"
72
- expr: '{{ match "sp" .Image "pikadb/pika pikadb/pika:*" }}'
73
- - tags: "postgres"
74
- expr: '{{ or (eq .PrivatePort "5432") (match "sp" .Image "postgres postgres:* */postgres */postgres:* */postgresql */postgresql:*") }}'
75
- - tags: "proxysql"
76
- expr: '{{ or (eq .PrivatePort "6032") (match "sp" .Image "*/proxysql */proxysql:*") }}'
77
- - tags: "puppet"
78
- expr: '{{ or (eq .PrivatePort "8140") (match "sp" .Image "puppet/puppetserver puppet/puppetserver:*") }}'
79
- - tags: "rabbitmq"
80
- expr: '{{ or (eq .PrivatePort "15672") (match "sp" .Image "rabbitmq rabbitmq:* */rabbitmq */rabbitmq:*") }}'
81
- - tags: "redis"
82
- expr: '{{ or (eq .PrivatePort "6379") (match "sp" .Image "redis redis:* */redis */redis:*") }}'
83
- - tags: "rethinkdb"
84
- expr: '{{ and (eq .PrivatePort "28015") (match "sp" .Image "rethinkdb rethinkdb:* */rethinkdb */rethinkdb:*") }}'
85
- - tags: "squid"
86
- expr: '{{ match "sp" .Image "*/squid */squid:*" }}'
87
- - tags: "tengine"
88
- expr: '{{ match "sp" .Image "*/tengine */tengine:*" }}'
89
- - tags: "tor"
90
- expr: '{{ and (eq .PrivatePort "9051") (match "sp" .Image "*/tor */tor:*") }}'
91
- - tags: "tomcat"
92
- expr: '{{ match "sp" .Image "tomcat tomcat:* */tomcat */tomcat:*" }}'
93
- - tags: "typesense"
94
- expr: '{{ match "sp" .Image "typesense/typesense typesense/typesense:*" }}'
95
- - tags: "varnish"
96
- expr: '{{ match "sp" .Image "varnish varnish:*" }}'
97
- - tags: "vernemq"
98
- expr: '{{ match "sp" .Image "*/vernemq */vernemq:*" }}'
99
- - tags: "zookeeper"
100
- expr: '{{ or (eq .PrivatePort "2181") (match "sp" .Image "*/zookeeper */zookeeper:*") }}'
101
-compose:
102
- - name: "Applications"
103
- selector: "app"
104
- config:
105
- - selector: "apache"
106
- template: |
107
- module: apache
108
- name: docker_{{.Name}}
109
- url: http://{{.Address}}/server-status?auto
110
- - selector: "beanstalk"
111
- template: |
112
- module: beanstalk
113
- name: docker_{{.Name}}
114
- address: {{.Address}}
115
- - selector: "boinc"
116
- template: |
117
- module: boinc
118
- name: docker_{{.Name}}
119
- address: {{.Address}}
120
- - selector: "cockroachdb"
121
- template: |
122
- module: cockroachdb
123
- name: docker_{{.Name}}
124
- url: http://{{.Address}}/_status/vars
125
- - selector: "consul"
126
- template: |
127
- module: consul
128
- name: docker_{{.Name}}
129
- url: http://{{.Address}}
130
- - selector: "coredns"
131
- template: |
132
- module: coredns
133
- name: docker_{{.Name}}
134
- url: http://{{.Address}}/metrics
135
- - selector: "coredns"
136
- template: |
137
- module: coredns
138
- name: docker_{{.Name}}
139
- url: http://{{.Address}}/metrics
140
- - selector: "couchbase"
141
- template: |
142
- module: couchbase
143
- name: docker_{{.Name}}
144
- url: http://{{.Address}}
145
- - selector: "couchdb"
146
- template: |
147
- module: couchdb
148
- name: docker_{{.Name}}
149
- url: http://{{.Address}}
150
- - selector: "dovecot"
151
- template: |
152
- module: dovecot
153
- name: docker_{{.Name}}
154
- address: {{.Address}}
155
- - selector: "elasticsearch"
156
- template: |
157
- module: elasticsearch
158
- name: docker_{{.Name}}
159
- {{ if glob .Image "*elastic*" -}}
160
- url: http://{{.Address}}
161
- {{ else -}}
162
- url: https://{{.Address}}
163
- tls_skip_verify: yes
164
- username: admin
165
- password: admin
166
- {{ end -}}
167
- - selector: "gearman"
168
- template: |
169
- module: gearman
170
- name: docker_{{.Name}}
171
- address: {{.Address}}
172
- - selector: "ipfs"
173
- template: |
174
- module: ipfs
175
- name: docker_{{.Name}}
176
- url: http://{{.Address}}
177
- - selector: "lighttpd"
178
- template: |
179
- module: lighttpd
180
- name: docker_{{.Name}}
181
- url: http://{{.Address}}/server-status?auto
182
- - selector: "maxscale"
183
- template: |
184
- module: maxscale
185
- name: docker_{{.Name}}
186
- url: http://{{.Address}}
187
- - selector: "memcached"
188
- template: |
189
- module: memcached
190
- name: docker_{{.Name}}
191
- address: {{.Address}}
192
- - selector: "mongodb"
193
- template: |
194
- module: mongodb
195
- name: docker_{{.Name}}
196
- uri: mongodb://{{.Address}}
197
- - selector: "mysql"
198
- template: |
199
- module: mysql
200
- name: docker_{{.Name}}
201
- dsn: netdata@tcp({{.Address}})/
202
- - selector: "nats"
203
- template: |
204
- - module: nats
205
- name: docker_{{.Name}}
206
- url: http://{{.Address}}
207
- - selector: "nginx"
208
- template: |
209
- - module: nginx
210
- name: docker_{{.Name}}
211
- url: http://{{.Address}}/stub_status
212
- - module: nginx
213
- name: docker_{{.Name}}
214
- url: http://{{.Address}}/basic_status
215
- - module: nginx
216
- name: docker_{{.Name}}
217
- url: http://{{.Address}}/nginx_status
218
- - module: nginx
219
- name: docker_{{.Name}}
220
- url: http://{{.Address}}/status
221
- - selector: "nginxunit"
222
- template: |
223
- - module: nginxunit
224
- name: docker_{{.Name}}
225
- url: http://{{.Address}}
226
- - selector: "oracledb"
227
- template: |
228
- module: oracledb
229
- name: docker_{{.Name}}
230
- {{ if eq .PrivatePort "1521" -}}
231
- dsn: 'oracle://username:password@{{.Address}}/XE'
232
- {{ else -}}
233
- dsn: 'oracle://username:password@{{.Address}}/XE?ssl=true&ssl verify=false'
234
- {{ end -}}
235
- - selector: "pgbouncer"
236
- template: |
237
- module: pgbouncer
238
- name: docker_{{.Name}}
239
- dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
240
- - selector: "pika"
241
- template: |
242
- module: pika
243
- name: docker_{{.Name}}
244
- address: redis://@{{.Address}}
245
- - selector: "rethinkdb"
246
- template: |
247
- module: rethinkdb
248
- name: docker_{{.Name}}
249
- address: {{.Address}}
250
- - selector: "postgres"
251
- template: |
252
- module: postgres
253
- name: docker_{{.Name}}
254
- dsn: postgres://netdata:postgres@{{.Address}}/postgres
255
- - selector: "proxysql"
256
- template: |
257
- module: proxysql
258
- name: docker_{{.Name}}
259
- dsn: stats:stats@tcp({{.Address}})/
260
- - selector: "puppet"
261
- template: |
262
- module: puppet
263
- name: docker_{{.Name}}
264
- url: https://{{.Address}}
265
- tls_skip_verify: yes
266
- - selector: "rabbitmq"
267
- template: |
268
- module: rabbitmq
269
- name: docker_{{.Name}}
270
- url: http://{{.Address}}
271
- - selector: "redis"
272
- template: |
273
- module: redis
274
- name: docker_{{.Name}}
275
- address: redis://@{{.Address}}
276
- - selector: "squid"
277
- template: |
278
- module: squid
279
- name: docker_{{.Name}}
280
- url: http://{{.Address}}
281
- - selector: "tengine"
282
- template: |
283
- module: tengine
284
- name: docker_{{.Name}}
285
- url: http://{{.Address}}/us
286
- - selector: "tomcat"
287
- template: |
288
- module: tomcat
289
- name: docker_{{.Name}}
290
- url: http://{{.Address}}
291
- - selector: "typesense"
292
- template: |
293
- module: typesense
294
- name: docker_{{.Name}}
295
- url: http://{{.Address}}
296
- api_key: {{ trimPrefix "--api-key=" (regexFind "--api-key=[^ ]+" .Command) -}}
297
- - selector: "tor"
298
- template: |
299
- module: tor
300
- name: docker_{{.Name}}
301
- address: {{.Address}}
302
- - selector: "varnish"
303
- template: |
304
- module: varnish
305
- name: docker_{{.Name}}
306
- docker_container: {{.Name}}
307
- - selector: "vernemq"
308
- template: |
309
- module: vernemq
310
- name: docker_{{.Name}}
311
- url: http://{{.Address}}/metrics
312
- - selector: "zookeeper"
313
- template: |
314
- module: zookeeper
315
- name: docker_{{.Name}}
316
- address: {{.Address}}
11
+services:
12
+ - id: "skip"
13
+ match: |
14
+ {{ $netNOK := eq .NetworkMode "host" -}}
15
+ {{ $protoNOK := not (eq .PortProtocol "tcp") -}}
16
+ {{ $portNOK := empty .PrivatePort -}}
17
+ {{ $addrNOK := or (empty .IPAddress) (glob .PublicPortIP "*:*") -}}
18
+ {{ or $netNOK $protoNOK $portNOK $addrNOK }}
19
+
20
+ - id: "apache"
21
+ match: '{{ match "sp" .Image "httpd httpd:* */apache */apache:* */apache2 */apache2:*" }}'
22
+ config_template: |
23
+ module: apache
24
+ name: docker_{{.Name}}
25
+ url: http://{{.Address}}/server-status?auto
26
+
27
+ - id: "beanstalk"
28
+ match: '{{ match "sp" .Image "*/beanstalkd */beanstalkd:*" }}'
29
+ config_template: |
30
+ module: beanstalk
31
+ name: docker_{{.Name}}
32
+ address: {{.Address}}
33
+
34
+ - id: "boinc"
35
+ match: '{{ match "sp" .Image "boinc/client boinc/client:* */boinc */boinc:*" }}'
36
+ config_template: |
37
+ module: boinc
38
+ name: docker_{{.Name}}
39
+ address: {{.Address}}
40
+
41
+ - id: "cockroachdb"
42
+ match: '{{ match "sp" .Image "cockroachdb/cockroach cockroachdb/cockroach:*" }}'
43
+ config_template: |
44
+ module: cockroachdb
45
+ name: docker_{{.Name}}
46
+ url: http://{{.Address}}/_status/vars
47
+
48
+ - id: "consul"
49
+ match: '{{ match "sp" .Image "consul consul:* */consul */consul:*" }}'
50
+ config_template: |
51
+ module: consul
52
+ name: docker_{{.Name}}
53
+ url: http://{{.Address}}
54
+
55
+ - id: "coredns"
56
+ match: '{{ match "sp" .Image "*/coredns */coredns:*" }}'
57
+ config_template: |
58
+ module: coredns
59
+ name: docker_{{.Name}}
60
+ url: http://{{.Address}}/metrics
61
+
62
+ - id: "couchbase"
63
+ match: '{{ or (eq .PrivatePort "8091") (match "sp" .Image "couchbase couchbase:*") }}'
64
+ config_template: |
65
+ module: couchbase
66
+ name: docker_{{.Name}}
67
+ url: http://{{.Address}}
68
+
69
+ - id: "couchdb"
70
+ match: '{{ or (eq .PrivatePort "5984") (match "sp" .Image "couchdb couchdb:*") }}'
71
+ config_template: |
72
+ module: couchdb
73
+ name: docker_{{.Name}}
74
+ url: http://{{.Address}}
75
+
76
+ - id: "dovecot"
77
+ match: '{{ or (eq .PrivatePort "24242") (match "sp" .Image "*/dovecot */dovecot:*") }}'
78
+ config_template: |
79
+ module: dovecot
80
+ name: docker_{{.Name}}
81
+ address: {{.Address}}
82
+
83
+ - id: "elasticsearch"
84
+ match: '{{ or (eq .PrivatePort "9200") (match "sp" .Image "elasticsearch elasticsearch:* */elasticsearch */elasticsearch:* */opensearch */opensearch:*") }}'
85
+ config_template: |
86
+ module: elasticsearch
87
+ name: docker_{{.Name}}
88
+ {{ if glob .Image "*elastic*" -}}
89
+ url: http://{{.Address}}
90
+ {{ else -}}
91
+ url: https://{{.Address}}
92
+ tls_skip_verify: yes
93
+ username: admin
94
+ password: admin
95
+ {{ end -}}
96
+
97
+ - id: "gearman"
98
+ match: '{{ and (eq .PrivatePort "4730") (match "sp" .Image "*/gearmand */gearmand:*") }}'
99
+ config_template: |
100
+ module: gearman
101
+ name: docker_{{.Name}}
102
+ address: {{.Address}}
103
+
104
+ - id: "ipfs"
105
+ match: '{{ and (eq .PrivatePort "5001") (match "sp" .Image "ipfs/kubo ipfs/kubo:*") }}'
106
+ config_template: |
107
+ module: ipfs
108
+ name: docker_{{.Name}}
109
+ url: http://{{.Address}}
110
+
111
+ - id: "lighttpd"
112
+ match: '{{ match "sp" .Image "*/lighttpd */lighttpd:*" }}'
113
+ config_template: |
114
+ module: lighttpd
115
+ name: docker_{{.Name}}
116
+ url: http://{{.Address}}/server-status?auto
117
+
118
+ - id: "maxscale"
119
+ match: '{{ or (eq .PrivatePort "8989") (match "sp" .Image "mariadb/maxscale mariadb/maxscale:*") }}'
120
+ config_template: |
121
+ module: maxscale
122
+ name: docker_{{.Name}}
123
+ url: http://{{.Address}}
124
+
125
+ - id: "memcached"
126
+ match: '{{ or (eq .PrivatePort "11211") (match "sp" .Image "memcached memcached:* */memcached */memcached:*") }}'
127
+ config_template: |
128
+ module: memcached
129
+ name: docker_{{.Name}}
130
+ address: {{.Address}}
131
+
132
+ - id: "mongodb"
133
+ match: '{{ or (eq .PrivatePort "27017") (match "sp" .Image "mongo mongo:* */mongodb */mongodb:* */mongodb-community-server */mongodb-community-server:*") }}'
134
+ config_template: |
135
+ module: mongodb
136
+ name: docker_{{.Name}}
137
+ uri: mongodb://{{.Address}}
138
+
139
+ - id: "mysql"
140
+ match: '{{ or (eq .PrivatePort "3306") (match "sp" .Image "mysql mysql:* */mysql */mysql:* mariadb mariadb:* */mariadb */mariadb:* percona percona:* */percona-mysql */percona-mysql:*") }}'
141
+ config_template: |
142
+ module: mysql
143
+ name: docker_{{.Name}}
144
+ dsn: netdata@tcp({{.Address}})/
145
+
146
+ - id: "nats"
147
+ match: '{{ and (eq .PrivatePort "8222") (match "sp" .Image "nats nats:*") }}'
148
+ config_template: |
149
+ - module: nats
150
+ name: docker_{{.Name}}
151
+ url: http://{{.Address}}
152
+
153
+ - id: "nginx"
154
+ match: '{{ match "sp" .Image "nginx nginx:*" }}'
155
+ config_template: |
156
+ - module: nginx
157
+ name: docker_{{.Name}}
158
+ url: http://{{.Address}}/stub_status
159
+ - module: nginx
160
+ name: docker_{{.Name}}
161
+ url: http://{{.Address}}/basic_status
162
+ - module: nginx
163
+ name: docker_{{.Name}}
164
+ url: http://{{.Address}}/nginx_status
165
+ - module: nginx
166
+ name: docker_{{.Name}}
167
+ url: http://{{.Address}}/status
168
+
169
+ - id: "nginxunit"
170
+ match: '{{ match "sp" .Image "nginx/unit nginx/unit:*" }}'
171
+ config_template: |
172
+ - module: nginxunit
173
+ name: docker_{{.Name}}
174
+ url: http://{{.Address}}
175
+
176
+ - id: "oracledb"
177
+ match: '{{ and (eq .PrivatePort "1521" "2484") (match "sp" .Image "oracle/database oracle/database:*") }}'
178
+ config_template: |
179
+ module: oracledb
180
+ name: docker_{{.Name}}
181
+ {{ if eq .PrivatePort "1521" -}}
182
+ dsn: 'oracle://username:password@{{.Address}}/XE'
183
+ {{ else -}}
184
+ dsn: 'oracle://username:password@{{.Address}}/XE?ssl=true&ssl verify=false'
185
+ {{ end -}}
186
+
187
+ - id: "pgbouncer"
188
+ match: '{{ or (eq .PrivatePort "6432") (match "sp" .Image "*/pgbouncer */pgbouncer:*") }}'
189
+ config_template: |
190
+ module: pgbouncer
191
+ name: docker_{{.Name}}
192
+ dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
193
+
194
+ - id: "pika"
195
+ match: '{{ match "sp" .Image "pikadb/pika pikadb/pika:*" }}'
196
+ config_template: |
197
+ module: pika
198
+ name: docker_{{.Name}}
199
+ address: redis://@{{.Address}}
200
+
201
+ - id: "postgres"
202
+ match: '{{ or (eq .PrivatePort "5432") (match "sp" .Image "postgres postgres:* */postgres */postgres:* */postgresql */postgresql:*") }}'
203
+ config_template: |
204
+ module: postgres
205
+ name: docker_{{.Name}}
206
+ dsn: postgres://netdata:postgres@{{.Address}}/postgres
207
+
208
+ - id: "proxysql"
209
+ match: '{{ or (eq .PrivatePort "6032") (match "sp" .Image "*/proxysql */proxysql:*") }}'
210
+ config_template: |
211
+ module: proxysql
212
+ name: docker_{{.Name}}
213
+ dsn: stats:stats@tcp({{.Address}})/
214
+
215
+ - id: "puppet"
216
+ match: '{{ or (eq .PrivatePort "8140") (match "sp" .Image "puppet/puppetserver puppet/puppetserver:*") }}'
217
+ config_template: |
218
+ module: puppet
219
+ name: docker_{{.Name}}
220
+ url: https://{{.Address}}
221
+ tls_skip_verify: yes
222
+
223
+ - id: "rabbitmq"
224
+ match: '{{ or (eq .PrivatePort "15672") (match "sp" .Image "rabbitmq rabbitmq:* */rabbitmq */rabbitmq:*") }}'
225
+ config_template: |
226
+ module: rabbitmq
227
+ name: docker_{{.Name}}
228
+ url: http://{{.Address}}
229
+
230
+ - id: "redis"
231
+ match: '{{ or (eq .PrivatePort "6379") (match "sp" .Image "redis redis:* */redis */redis:*") }}'
232
+ config_template: |
233
+ module: redis
234
+ name: docker_{{.Name}}
235
+ address: redis://@{{.Address}}
236
+
237
+ - id: "rethinkdb"
238
+ match: '{{ and (eq .PrivatePort "28015") (match "sp" .Image "rethinkdb rethinkdb:* */rethinkdb */rethinkdb:*") }}'
239
+ config_template: |
240
+ module: rethinkdb
241
+ name: docker_{{.Name}}
242
+ address: {{.Address}}
243
+
244
+ - id: "squid"
245
+ match: '{{ match "sp" .Image "*/squid */squid:*" }}'
246
+ config_template: |
247
+ module: squid
248
+ name: docker_{{.Name}}
249
+ url: http://{{.Address}}
250
+
251
+ - id: "tengine"
252
+ match: '{{ match "sp" .Image "*/tengine */tengine:*" }}'
253
+ config_template: |
254
+ module: tengine
255
+ name: docker_{{.Name}}
256
+ url: http://{{.Address}}/us
257
+
258
+ - id: "tor"
259
+ match: '{{ and (eq .PrivatePort "9051") (match "sp" .Image "*/tor */tor:*") }}'
260
+ config_template: |
261
+ module: tor
262
+ name: docker_{{.Name}}
263
+ address: {{.Address}}
264
+
265
+ - id: "tomcat"
266
+ match: '{{ match "sp" .Image "tomcat tomcat:* */tomcat */tomcat:*" }}'
267
+ config_template: |
268
+ module: tomcat
269
+ name: docker_{{.Name}}
270
+ url: http://{{.Address}}
271
+
272
+ - id: "typesense"
273
+ match: '{{ match "sp" .Image "typesense/typesense typesense/typesense:*" }}'
274
+ config_template: |
275
+ module: typesense
276
+ name: docker_{{.Name}}
277
+ url: http://{{.Address}}
278
+ api_key: {{ trimPrefix "--api-key=" (regexFind "--api-key=[^ ]+" .Command) -}}
279
+
280
+ - id: "varnish"
281
+ match: '{{ match "sp" .Image "varnish varnish:*" }}'
282
+ config_template: |
283
+ module: varnish
284
+ name: docker_{{.Name}}
285
+ docker_container: {{.Name}}
286
+
287
+ - id: "vernemq"
288
+ match: '{{ match "sp" .Image "*/vernemq */vernemq:*" }}'
289
+ config_template: |
290
+ module: vernemq
291
+ name: docker_{{.Name}}
292
+ url: http://{{.Address}}/metrics
293
+
294
+ - id: "zookeeper"
295
+ match: '{{ or (eq .PrivatePort "2181") (match "sp" .Image "*/zookeeper */zookeeper:*") }}'
296
+ config_template: |
297
+ module: zookeeper
298
+ name: docker_{{.Name}}
299
+ address: {{.Address}}
300
+
src/go/plugin/go.d/config/go.d/sd/net_listeners.conf
+605
-627
@@ -7,630 +7,608 @@ discover:
7
net_listeners:
8
tags: "unknown"
9
10
-classify:
11
- - name: "Applications"
12
- selector: "unknown"
13
- tags: "-unknown app"
14
- match:
15
- - tags: "activemq"
16
- expr: '{{ and (eq .Port "8161") (eq .Comm "activemq") }}'
17
- - tags: "apache"
18
- expr: '{{ and (eq .Port "80" "8080") (eq .Comm "apache" "apache2" "httpd") }}'
19
- - tags: "apcupsd"
20
- expr: '{{ or (eq .Port "3551") (eq .Comm "apcupsd") }}'
21
- - tags: "beanstalk"
22
- expr: '{{ or (eq .Port "11300") (eq .Comm "beanstalkd") }}'
23
- - tags: "boinc"
24
- expr: '{{ and (eq .Port "31416") (eq .Comm "boinc") }}'
25
- - tags: "bind"
26
- expr: '{{ and (eq .Port "8653") (eq .Comm "bind" "named") }}'
27
- - tags: "cassandra"
28
- expr: '{{ and (eq .Port "7072") (glob .Cmdline "*cassandra*") }}'
29
- - tags: "ceph"
30
- expr: '{{ and (eq .Port "8443") (eq .Comm "ceph-mgr") }}'
31
- - tags: "chrony"
32
- expr: '{{ and (eq .Port "323") (eq .Comm "chronyd") }}'
33
- - tags: "clickhouse"
34
- expr: '{{ and (eq .Port "8123") (eq .Comm "clickhouse-server") }}'
35
- - tags: "cockroachdb"
36
- expr: '{{ and (eq .Port "8080") (eq .Comm "cockroach") }}'
37
- - tags: "consul"
38
- expr: '{{ and (eq .Port "8500") (eq .Comm "consul") }}'
39
- - tags: "coredns"
40
- expr: '{{ and (eq .Port "9153") (eq .Comm "coredns") }}'
41
- - tags: "couchbase"
42
- expr: '{{ or (eq .Port "8091") (glob .Cmdline "*couchbase*") }}'
43
- - tags: "couchdb"
44
- expr: '{{ or (eq .Port "5984") (glob .Cmdline "*couchdb*") }}'
45
- - tags: "dnsdist"
46
- expr: '{{ and (eq .Port "8083") (eq .Comm "dnsdist") }}'
47
- - tags: "dnsmasq"
48
- expr: '{{ and (eq .Protocol "UDP") (eq .Port "53") (eq .Comm "dnsmasq") }}'
49
- - tags: "docker_engine"
50
- expr: '{{ and (eq .Port "9323") (eq .Comm "dockerd") }}'
51
- - tags: "dovecot"
52
- expr: '{{ and (eq .Port "24242") (eq .Comm "dovecot") }}'
53
- - tags: "elasticsearch"
54
- expr: '{{ or (eq .Port "9200") (glob .Cmdline "*elasticsearch*" "*opensearch*") }}'
55
- - tags: "envoy"
56
- expr: '{{ and (eq .Port "9901") (eq .Comm "envoy") }}'
57
- - tags: "fluentd"
58
- expr: '{{ and (eq .Port "24220") (glob .Cmdline "*fluentd*") }}'
59
- - tags: "freeradius"
60
- expr: '{{ and (eq .Port "18121") (eq .Comm "freeradius") }}'
61
- - tags: "gearman"
62
- expr: '{{ or (eq .Port "4730") (eq .Comm "gearmand") }}'
63
- - tags: "geth"
64
- expr: '{{ and (eq .Port "6060") (eq .Comm "geth") }}'
65
- - tags: "haproxy"
66
- expr: '{{ and (eq .Port "8404") (eq .Comm "haproxy") }}'
67
- - tags: "hddtemp"
68
- expr: '{{ and (eq .Port "7634") (eq .Comm "hddtemp") }}'
69
- - tags: "hdfs_namenode"
70
- expr: '{{ and (eq .Port "9870") (eq .Comm "hadoop") }}'
71
- - tags: "hdfs_datanode"
72
- expr: '{{ and (eq .Port "9864") (eq .Comm "hadoop") }}'
73
- - tags: "icecast"
74
- expr: '{{ and (eq .Port "8000") (eq .Comm "icecast") }}'
75
- - tags: "ipfs"
76
- expr: '{{ and (eq .Port "5001") (eq .Comm "ipfs") }}'
77
- - tags: "kubelet"
78
- expr: '{{ and (eq .Port "10250" "10255") (eq .Comm "kubelet") }}'
79
- - tags: "kubeproxy"
80
- expr: '{{ and (eq .Port "10249") (eq .Comm "kube-proxy") }}'
81
- - tags: "lighttpd"
82
- expr: '{{ and (eq .Port "80" "8080") (eq .Comm "lighttpd") }}'
83
- - tags: "logstash"
84
- expr: '{{ and (eq .Port "9600") (glob .Cmdline "*logstash*") }}'
85
- - tags: "maxscale"
86
- expr: '{{ or (eq .Port "8989") (eq .Comm "maxscale") }}'
87
- - tags: "memcached"
88
- expr: '{{ or (eq .Port "11211") (eq .Comm "memcached") }}'
89
- - tags: "mongodb"
90
- expr: '{{ or (eq .Port "27017") (eq .Comm "mongod") }}'
91
- - tags: "monit"
92
- expr: '{{ or (eq .Port "2812") (eq .Comm "monit") }}'
93
- - tags: "mysql"
94
- expr: '{{ or (eq .Port "3306") (eq .Comm "mysqld" "mariadbd") }}'
95
- - tags: "nats"
96
- expr: '{{ and (eq .Port "8222") (eq .Comm "nats-server") }}'
97
- - tags: "nginx"
98
- expr: '{{ and (eq .Port "80" "8080") (eq .Comm "nginx") }}'
99
- - tags: "nginxunit"
100
- expr: '{{ and (eq .Port "8000") (eq .Comm "unit") }}'
101
- - tags: "ntpd"
102
- expr: '{{ or (eq .Port "123") (eq .Comm "ntpd") }}'
103
- - tags: "openldap"
104
- expr: '{{ eq .Comm "slapd" }}'
105
- - tags: "openvpn"
106
- expr: '{{ and (eq .Port "7505") (eq .Comm "openvpn") }}'
107
- - tags: "oracledb"
108
- expr: '{{ and (eq .Port "1521" "2484") (eq .Comm "tnslsnr") }}'
109
- - tags: "pgbouncer"
110
- expr: '{{ or (eq .Port "6432") (eq .Comm "pgbouncer") }}'
111
- - tags: "pihole"
112
- expr: '{{ and (eq .Port "80") (eq .Comm "pihole-FTL") }}'
113
- - tags: "pika"
114
- expr: '{{ and (eq .Port "9221") (eq .Comm "pika") }}'
115
- - tags: "postgres"
116
- expr: '{{ or (eq .Port "5432") (eq .Comm "postgres") }}'
117
- - tags: "powerdns"
118
- expr: '{{ and (eq .Port "8081") (eq .Comm "pdns_server") }}'
119
- - tags: "powerdns_recursor"
120
- expr: '{{ and (eq .Port "8081") (eq .Comm "pdns_recursor") }}'
121
- - tags: "proxysql"
122
- expr: '{{ or (eq .Port "6032") (eq .Comm "proxysql") }}'
123
- - tags: "puppet"
124
- expr: '{{ or (eq .Port "8140") (glob .Cmdline "*puppet-server*") }}'
125
- - tags: "rabbitmq"
126
- expr: '{{ or (eq .Port "15672") (glob .Cmdline "*rabbitmq*") }}'
127
- - tags: "redis"
128
- expr: '{{ or (eq .Port "6379") (eq .Comm "redis-server") }}'
129
- - tags: "rethinkdb"
130
- expr: '{{ and (eq .Port "28015") (eq .Comm "rethinkdb") }}'
131
- - tags: "riak"
132
- expr: '{{ and (eq .Port "8098") (glob .Cmdline "*riak*") }}'
133
- - tags: "rspamd"
134
- expr: '{{ and (eq .Port "11334") (eq .Comm "rspamd") }}'
135
- - tags: "squid"
136
- expr: '{{ and (eq .Port "3128") (eq .Comm "squid") }}'
137
- - tags: "spigotmc"
138
- expr: '{{ and (eq .Port "25575") (glob .Cmdline "*spigot*") }}'
139
- - tags: "supervisord"
140
- expr: '{{ and (eq .Port "9001") (eq .Comm "supervisord") }}'
141
- - tags: "tomcat"
142
- expr: '{{ and (eq .Port "8080") (glob .Cmdline "*tomcat*") }}'
143
- - tags: "tor"
144
- expr: '{{ and (eq .Port "9051") (eq .Comm "tor") }}'
145
- - tags: "traefik"
146
- expr: '{{ and (eq .Port "80" "8080") (eq .Comm "traefik") }}'
147
- - tags: "typesense"
148
- expr: '{{ and (eq .Port "8108") (eq .Comm "typesense-server") }}'
149
- - tags: "unbound"
150
- expr: '{{ and (eq .Port "8953") (eq .Comm "unbound") }}'
151
- - tags: "upsd"
152
- expr: '{{ or (eq .Port "3493") (eq .Comm "upsd") }}'
153
- - tags: "uwsgi"
154
- expr: '{{ and (eq .Port "1717") (eq .Comm "uwsgi") }}'
155
- - tags: "vernemq"
156
- expr: '{{ and (eq .Port "8888") (glob .Cmdline "*vernemq*") }}'
157
- - tags: "yugabytedb"
158
- expr: '{{ and (eq .Port "7000" "9000" "12000" "13000") (or (glob .Cmdline "*YSQL*") (eq .Comm "yb-master" "yb-tserver")) }}'
159
- - tags: "zookeeper"
160
- expr: '{{ or (eq .Port "2181" "2182") (glob .Cmdline "*zookeeper*") }}'
161
- - name: "Prometheus exporters"
162
- selector: "unknown"
163
- tags: "-unknown exporter"
164
- match:
165
- - tags: "exporter"
166
- expr: '{{ or (and (not (empty (promPort .Port))) (not (eq .Comm "docker-proxy"))) (glob .Comm "*exporter*") }}'
167
-compose:
168
- - name: "Applications"
169
- selector: "app"
170
- config:
171
- - selector: "activemq"
172
- template: |
173
- module: activemq
174
- name: local
175
- url: http://{{.Address}}
176
- webadmin: admin
177
- - selector: "apache"
178
- template: |
179
- module: apache
180
- name: local
181
- url: http://{{.Address}}/server-status?auto
182
- - selector: "apcupsd"
183
- template: |
184
- module: apcupsd
185
- name: local_{{.Port}}
186
- address: {{.Address}}
187
- - selector: "beanstalk"
188
- template: |
189
- module: beanstalk
190
- name: local
191
- address: {{.Address}}
192
- - selector: "bind"
193
- template: |
194
- module: bind
195
- name: local
196
- url: http://{{.Address}}/json/v1
197
- - selector: "boinc"
198
- template: |
199
- module: boinc
200
- name: local
201
- address: {{.Address}}
202
- - selector: "cassandra"
203
- template: |
204
- module: cassandra
205
- name: local
206
- url: http://{{.Address}}/metrics
207
- - selector: "ceph"
208
- template: |
209
- module: ceph
210
- name: local
211
- url: https://{{.Address}}
212
- - selector: "chrony"
213
- template: |
214
- module: chrony
215
- name: local
216
- address: {{.Address}}
217
- - selector: "clickhouse"
218
- template: |
219
- module: clickhouse
220
- name: local
221
- url: http://{{.Address}}
222
- - selector: "cockroachdb"
223
- template: |
224
- module: cockroachdb
225
- name: local
226
- url: http://{{.Address}}/_status/vars
227
- - selector: "consul"
228
- template: |
229
- module: consul
230
- name: local
231
- url: http://{{.Address}}
232
- - selector: "coredns"
233
- template: |
234
- module: coredns
235
- name: local
236
- url: http://{{.Address}}/metrics
237
- - selector: "couchbase"
238
- template: |
239
- module: couchbase
240
- name: local
241
- url: http://{{.Address}}
242
- - selector: "couchdb"
243
- template: |
244
- module: couchdb
245
- name: local
246
- url: http://{{.Address}}
247
- node: '_local'
248
- - selector: "dnsdist"
249
- template: |
250
- module: dnsdist
251
- name: local
252
- url: http://{{.Address}}
253
- headers:
254
- X-API-Key: 'dnsdist-api-key'
255
- - selector: "dnsmasq"
256
- template: |
257
- module: dnsmasq
258
- name: local
259
- protocol: udp
260
- address: {{.Address}}
261
- - selector: "docker_engine"
262
- template: |
263
- module: docker_engine
264
- name: local
265
- url: http://{{.Address}}/metrics
266
- - selector: "dovecot"
267
- template: |
268
- module: dovecot
269
- name: local
270
- address: {{.Address}}
271
- - selector: "elasticsearch"
272
- template: |
273
- module: elasticsearch
274
- name: local
275
- {{ if glob .Cmdline "*elastic*" -}}
276
- url: http://{{.Address}}
277
- {{ else -}}
278
- url: https://{{.Address}}
279
- tls_skip_verify: yes
280
- username: admin
281
- password: admin
282
- {{ end -}}
283
- - selector: "envoy"
284
- template: |
285
- module: envoy
286
- name: local
287
- url: http://{{.Address}}/stats/prometheus
288
- - selector: "envoy"
289
- template: |
290
- module: envoy
291
- name: local
292
- url: http://{{.Address}}/stats/prometheus
293
- - selector: "fluentd"
294
- template: |
295
- module: fluentd
296
- name: local
297
- url: http://{{.Address}}
298
- - selector: "freeradius"
299
- template: |
300
- module: freeradius
301
- name: local
302
- address: {{.IPAddress}}
303
- port: {{.Port}}
304
- secret: adminsecret
305
- - selector: "gearman"
306
- template: |
307
- module: gearman
308
- name: local
309
- address: {{.Address}}
310
- - selector: "geth"
311
- template: |
312
- module: geth
313
- name: local
314
- url: http://{{.Address}}/debug/metrics/prometheus
315
- - selector: "haproxy"
316
- template: |
317
- module: haproxy
318
- name: local
319
- url: http://{{.Address}}/metrics
320
- - selector: "hddtemp"
321
- template: |
322
- module: hddtemp
323
- name: local
324
- address: {{.Address}}
325
- - selector: "hdfs_namenode"
326
- template: |
327
- module: hdfs
328
- name: namenode_local
329
- url: http://{{.Address}}/jmx
330
- - selector: "hdfs_datanode"
331
- template: |
332
- module: hdfs
333
- name: datanode_local
334
- url: http://{{.Address}}/jmx
335
- - selector: "icecast"
336
- template: |
337
- module: icecast
338
- name: local
339
- url: http://{{.Address}}
340
- - selector: "ipfs"
341
- template: |
342
- module: ipfs
343
- name: local
344
- url: http://{{.Address}}
345
- - selector: "kubelet"
346
- template: |
347
- module: k8s_kubelet
348
- name: local
349
- {{- if eq .Port "10255" }}
350
- url: http://{{.Address}}/metrics
351
- {{- else }}
352
- url: https://{{.Address}}/metrics
353
- tls_skip_verify: yes
354
- {{- end }}
355
- - selector: "kubeproxy"
356
- template: |
357
- module: k8s_kubeproxy
358
- name: local
359
- url: http://{{.Address}}/metrics
360
- - selector: "lighttpd"
361
- template: |
362
- module: lighttpd
363
- name: local
364
- url: http://{{.Address}}/server-status?auto
365
- - selector: "logstash"
366
- template: |
367
- module: logstash
368
- name: local
369
- url: http://{{.Address}}
370
- - selector: "maxscale"
371
- template: |
372
- module: maxscale
373
- name: local
374
- url: http://{{.Address}}
375
- - selector: "memcached"
376
- template: |
377
- module: memcached
378
- name: local
379
- address: {{.Address}}
380
- - selector: "mongodb"
381
- template: |
382
- module: mongodb
383
- name: local
384
- uri: mongodb://{{.Address}}
385
- - selector: "monit"
386
- template: |
387
- module: monit
388
- name: local
389
- url: http://{{.Address}}
390
- username: admin
391
- password: monit
392
- - selector: "mysql"
393
- template: |
394
- - module: mysql
395
- name: local
396
- dsn: netdata@unix(/var/run/mysqld/mysqld.sock)/
397
- - module: mysql
398
- name: local
399
- dsn: netdata@tcp({{.Address}})/
400
- - selector: "nats"
401
- template: |
402
- - module: nats
403
- name: local
404
- url: http://{{.Address}}
405
- - selector: "nginx"
406
- template: |
407
- - module: nginx
408
- name: local
409
- url: http://{{.Address}}/stub_status
410
- - module: nginx
411
- name: local
412
- url: http://{{.Address}}/basic_status
413
- - module: nginx
414
- name: local
415
- url: http://{{.Address}}/nginx_status
416
- - module: nginx
417
- name: local
418
- url: http://{{.Address}}/status
419
- - selector: "nginxunit"
420
- template: |
421
- - module: nginxunit
422
- name: local
423
- url: http://{{.Address}}
424
- - selector: "ntpd"
425
- template: |
426
- module: ntpd
427
- name: local
428
- address: {{.Address}}
429
- collect_peers: no
430
- - selector: "openldap"
431
- template: |
432
- module: openldap
433
- name: local
434
- url: ldap://{{.Address}}
435
- - selector: "openvpn"
436
- template: |
437
- module: openvpn
438
- name: local
439
- address: {{.Address}}
440
- - selector: "oracledb"
441
- template: |
442
- module: oracledb
443
- name: local
444
- {{ if eq .Port "1521" -}}
445
- dsn: 'oracle://username:password@{{.Address}}/XE'
446
- {{ else -}}
447
- dsn: 'oracle://username:password@{{.Address}}/XE?ssl=true&ssl verify=false'
448
- {{ end -}}
449
- - selector: "pgbouncer"
450
- template: |
451
- module: pgbouncer
452
- name: local
453
- dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
454
- - selector: "pihole"
455
- template: |
456
- module: pihole
457
- name: local
458
- url: http://{{.Address}}
459
- - selector: "pika"
460
- template: |
461
- module: pika
462
- name: local
463
- address: redis://@{{.IPAddress}}:{{.Port}}
464
- - selector: "rethinkdb"
465
- template: |
466
- module: rethinkdb
467
- name: local
468
- address: {{.Address}}
469
- - selector: "riak"
470
- template: |
471
- module: riakkv
472
- name: local
473
- url: http://{{.Address}}/stats
474
- - selector: "rspamd"
475
- template: |
476
- module: rspamd
477
- name: local
478
- url: http://{{.Address}}
479
- - selector: "postgres"
480
- template: |
481
- - module: postgres
482
- name: local
483
- dsn: 'host=/var/run/postgresql dbname=postgres user=postgres'
484
- - module: postgres
485
- name: local
486
- dsn: 'host=/var/run/postgresql dbname=postgres user=netdata'
487
- - module: postgres
488
- name: local
489
- dsn: postgresql://netdata@{{.Address}}/postgres
490
- - selector: "powerdns"
491
- template: |
492
- module: powerdns
493
- name: local
494
- url: http://{{.Address}}
495
- headers:
496
- X-API-KEY: secret
497
- - selector: "powerdns_recursor"
498
- template: |
499
- module: powerdns_recursor
500
- name: local
501
- url: http://{{.Address}}
502
- headers:
503
- X-API-KEY: secret
504
- - selector: "proxysql"
505
- template: |
506
- module: proxysql
507
- name: local
508
- dsn: stats:stats@tcp({{.Address}})/
509
- - selector: "puppet"
510
- template: |
511
- module: puppet
512
- name: local
513
- url: https://{{.Address}}
514
- tls_skip_verify: yes
515
- - selector: "rabbitmq"
516
- template: |
517
- module: rabbitmq
518
- name: local
519
- url: http://{{.Address}}
520
- username: guest
521
- password: guest
522
- collect_queues_metrics: no
523
- - selector: "redis"
524
- template: |
525
- module: redis
526
- name: local
527
- address: redis://@{{.Address}}
528
- - selector: "squid"
529
- template: |
530
- module: squid
531
- name: local
532
- url: http://{{.Address}}
533
- - selector: "spigotmc"
534
- template: |
535
- module: spigotmc
536
- name: local
537
- address: {{.Address}}
538
- - selector: "supervisord"
539
- template: |
540
- module: supervisord
541
- name: local
542
- url: http://{{.Address}}/RPC2
543
- - selector: "traefik"
544
- template: |
545
- module: traefik
546
- name: local
547
- url: http://{{.Address}}/metrics
548
- - selector: "typesense"
549
- template: |
550
- module: typesense
551
- name: local
552
- url: http://{{.Address}}
553
- api_key: {{ trimPrefix "--api-key=" (regexFind "--api-key=[^ ]+" .Cmdline) -}}
554
- - selector: "tomcat"
555
- template: |
556
- module: tomcat
557
- name: local
558
- url: http://{{.Address}}
559
- - selector: "tor"
560
- template: |
561
- module: tor
562
- name: local
563
- address: {{.Address}}
564
- - selector: "unbound"
565
- template: |
566
- module: unbound
567
- name: local
568
- address: {{.Address}}
569
- - selector: "upsd"
570
- template: |
571
- module: upsd
572
- name: local
573
- address: {{.Address}}
574
- - selector: "uwsgi"
575
- template: |
576
- module: uwsgi
577
- name: local
578
- address: {{.Address}}
579
- - selector: "vernemq"
580
- template: |
581
- module: vernemq
582
- name: local
583
- url: http://{{.Address}}/metrics
584
- - selector: "yugabytedb"
585
- template: |
586
- - module: yugabytedb
587
- {{ if eq .Port "7000" -}}
588
- name: local_master
589
- {{ else if eq .Port "9000" -}}
590
- name: local_tserver
591
- {{ else if eq .Port "12000" -}}
592
- name: local_ycql
593
- {{ else if eq .Port "13000" -}}
594
- name: local_ysql
595
- {{ else -}}
596
- name: local
597
- {{ end }}
598
- url: http://{{.Address}}/prometheus-metrics
599
- - selector: "zookeeper"
600
- template: |
601
- module: zookeeper
602
- name: local
603
- address: {{.Address}}
604
-
605
- - name: "Prometheus exporters generic"
606
- selector: "exporter"
607
- config:
608
- - selector: "exporter"
609
- template: |
610
- {{ $name := promPort .Port -}}
611
- {{ if empty $name -}}
612
- {{ $name = printf "%s_%s" .Comm .Port -}}
613
- {{ end -}}
614
- module: prometheus
615
- name: {{$name}}_local
616
- url: http://{{.Address}}/metrics
617
- {{ if eq $name "caddy" -}}
618
- expected_prefix: 'caddy_'
619
- {{ else if eq $name "openethereum" -}}
620
- expected_prefix: 'blockchaincache_'
621
- {{ else if eq $name "crowdsec" -}}
622
- expected_prefix: 'cs_'
623
- {{ else if eq $name "netbox" -}}
624
- expected_prefix: 'django_'
625
- {{ else if eq $name "traefik" -}}
626
- expected_prefix: 'traefik_'
627
- {{ else if eq $name "pushgateway" -}}
628
- expected_prefix: 'pushgateway_'
629
- selector:
630
- allow:
631
- - pushgateway_*
632
- {{ else if eq $name "wireguard_exporter" -}}
633
- expected_prefix: 'wireguard_exporter'
634
- {{ else if eq $name "clickhouse" -}}
635
- max_time_series: 3000
636
- {{ end -}}
10
+services:
11
+ - id: "activemq"
12
+ match: '{{ and (eq .Port "8161") (eq .Comm "activemq") }}'
13
+ config_template: |
14
+ module: activemq
15
+ name: local
16
+ url: http://{{.Address}}
17
+ webadmin: admin
18
+
19
+ - id: "apache"
20
+ match: '{{ and (eq .Port "80" "8080") (eq .Comm "apache" "apache2" "httpd") }}'
21
+ config_template: |
22
+ module: apache
23
+ name: local
24
+ url: http://{{.Address}}/server-status?auto
25
+
26
+ - id: "apcupsd"
27
+ match: '{{ or (eq .Port "3551") (eq .Comm "apcupsd") }}'
28
+ config_template: |
29
+ module: apcupsd
30
+ name: local_{{.Port}}
31
+ address: {{.Address}}
32
+
33
+ - id: "beanstalk"
34
+ match: '{{ or (eq .Port "11300") (eq .Comm "beanstalkd") }}'
35
+ config_template: |
36
+ module: beanstalk
37
+ name: local
38
+ address: {{.Address}}
39
+
40
+ - id: "bind"
41
+ match: '{{ and (eq .Port "8653") (eq .Comm "bind" "named") }}'
42
+ config_template: |
43
+ module: bind
44
+ name: local
45
+ url: http://{{.Address}}/json/v1
46
+
47
+ - id: "boinc"
48
+ match: '{{ and (eq .Port "31416") (eq .Comm "boinc") }}'
49
+ config_template: |
50
+ module: boinc
51
+ name: local
52
+ address: {{.Address}}
53
+
54
+ - id: "cassandra"
55
+ match: '{{ and (eq .Port "7072") (glob .Cmdline "*cassandra*") }}'
56
+ config_template: |
57
+ module: cassandra
58
+ name: local
59
+ url: http://{{.Address}}/metrics
60
+
61
+ - id: "ceph"
62
+ match: '{{ and (eq .Port "8443") (eq .Comm "ceph-mgr") }}'
63
+ config_template: |
64
+ module: ceph
65
+ name: local
66
+ url: https://{{.Address}}
67
+
68
+ - id: "chrony"
69
+ match: '{{ and (eq .Port "323") (eq .Comm "chronyd") }}'
70
+ config_template: |
71
+ module: chrony
72
+ name: local
73
+ address: {{.Address}}
74
+
75
+ - id: "clickhouse"
76
+ match: '{{ and (eq .Port "8123") (eq .Comm "clickhouse-server") }}'
77
+ config_template: |
78
+ module: clickhouse
79
+ name: local
80
+ url: http://{{.Address}}
81
+
82
+ - id: "cockroachdb"
83
+ match: '{{ and (eq .Port "8080") (eq .Comm "cockroach") }}'
84
+ config_template: |
85
+ module: cockroachdb
86
+ name: local
87
+ url: http://{{.Address}}/_status/vars
88
+
89
+ - id: "consul"
90
+ match: '{{ and (eq .Port "8500") (eq .Comm "consul") }}'
91
+ config_template: |
92
+ module: consul
93
+ name: local
94
+ url: http://{{.Address}}
95
+
96
+ - id: "coredns"
97
+ match: '{{ and (eq .Port "9153") (eq .Comm "coredns") }}'
98
+ config_template: |
99
+ module: coredns
100
+ name: local
101
+ url: http://{{.Address}}/metrics
102
+
103
+ - id: "couchbase"
104
+ match: '{{ or (eq .Port "8091") (glob .Cmdline "*couchbase*") }}'
105
+ config_template: |
106
+ module: couchbase
107
+ name: local
108
+ url: http://{{.Address}}
109
+
110
+ - id: "couchdb"
111
+ match: '{{ or (eq .Port "5984") (glob .Cmdline "*couchdb*") }}'
112
+ config_template: |
113
+ module: couchdb
114
+ name: local
115
+ url: http://{{.Address}}
116
+ node: '_local'
117
+
118
+ - id: "dnsdist"
119
+ match: '{{ and (eq .Port "8083") (eq .Comm "dnsdist") }}'
120
+ config_template: |
121
+ module: dnsdist
122
+ name: local
123
+ url: http://{{.Address}}
124
+ headers:
125
+ X-API-Key: 'dnsdist-api-key'
126
+
127
+ - id: "dnsmasq"
128
+ match: '{{ and (eq .Protocol "UDP") (eq .Port "53") (eq .Comm "dnsmasq") }}'
129
+ config_template: |
130
+ module: dnsmasq
131
+ name: local
132
+ protocol: udp
133
+ address: {{.Address}}
134
+
135
+ - id: "docker_engine"
136
+ match: '{{ and (eq .Port "9323") (eq .Comm "dockerd") }}'
137
+ config_template: |
138
+ module: docker_engine
139
+ name: local
140
+ url: http://{{.Address}}/metrics
141
+
142
+ - id: "dovecot"
143
+ match: '{{ and (eq .Port "24242") (eq .Comm "dovecot") }}'
144
+ config_template: |
145
+ module: dovecot
146
+ name: local
147
+ address: {{.Address}}
148
+
149
+ - id: "elasticsearch"
150
+ match: '{{ or (eq .Port "9200") (glob .Cmdline "*elasticsearch*" "*opensearch*") }}'
151
+ config_template: |
152
+ module: elasticsearch
153
+ name: local
154
+ {{ if glob .Cmdline "*elastic*" -}}
155
+ url: http://{{.Address}}
156
+ {{ else -}}
157
+ url: https://{{.Address}}
158
+ tls_skip_verify: yes
159
+ username: admin
160
+ password: admin
161
+ {{ end -}}
162
+
163
+ - id: "envoy"
164
+ match: '{{ and (eq .Port "9901") (eq .Comm "envoy") }}'
165
+ config_template: |
166
+ module: envoy
167
+ name: local
168
+ url: http://{{.Address}}/stats/prometheus
169
+
170
+ - id: "fluentd"
171
+ match: '{{ and (eq .Port "24220") (glob .Cmdline "*fluentd*") }}'
172
+ config_template: |
173
+ module: fluentd
174
+ name: local
175
+ url: http://{{.Address}}
176
+
177
+ - id: "freeradius"
178
+ match: '{{ and (eq .Port "18121") (eq .Comm "freeradius") }}'
179
+ config_template: |
180
+ module: freeradius
181
+ name: local
182
+ address: {{.IPAddress}}
183
+ port: {{.Port}}
184
+ secret: adminsecret
185
+
186
+ - id: "gearman"
187
+ match: '{{ or (eq .Port "4730") (eq .Comm "gearmand") }}'
188
+ config_template: |
189
+ module: gearman
190
+ name: local
191
+ address: {{.Address}}
192
+
193
+ - id: "geth"
194
+ match: '{{ and (eq .Port "6060") (eq .Comm "geth") }}'
195
+ config_template: |
196
+ module: geth
197
+ name: local
198
+ url: http://{{.Address}}/debug/metrics/prometheus
199
+
200
+ - id: "haproxy"
201
+ match: '{{ and (eq .Port "8404") (eq .Comm "haproxy") }}'
202
+ config_template: |
203
+ module: haproxy
204
+ name: local
205
+ url: http://{{.Address}}/metrics
206
+
207
+ - id: "hddtemp"
208
+ match: '{{ and (eq .Port "7634") (eq .Comm "hddtemp") }}'
209
+ config_template: |
210
+ module: hddtemp
211
+ name: local
212
+ address: {{.Address}}
213
+
214
+ - id: "hdfs_namenode"
215
+ match: '{{ and (eq .Port "9870") (eq .Comm "hadoop") }}'
216
+ config_template: |
217
+ module: hdfs
218
+ name: namenode_local
219
+ url: http://{{.Address}}/jmx
220
+
221
+ - id: "hdfs_datanode"
222
+ match: '{{ and (eq .Port "9864") (eq .Comm "hadoop") }}'
223
+ config_template: |
224
+ module: hdfs
225
+ name: datanode_local
226
+ url: http://{{.Address}}/jmx
227
+
228
+ - id: "icecast"
229
+ match: '{{ and (eq .Port "8000") (eq .Comm "icecast") }}'
230
+ config_template: |
231
+ module: icecast
232
+ name: local
233
+ url: http://{{.Address}}
234
+
235
+ - id: "ipfs"
236
+ match: '{{ and (eq .Port "5001") (eq .Comm "ipfs") }}'
237
+ config_template: |
238
+ module: ipfs
239
+ name: local
240
+ url: http://{{.Address}}
241
+
242
+ - id: "kubelet"
243
+ match: '{{ and (eq .Port "10250" "10255") (eq .Comm "kubelet") }}'
244
+ config_template: |
245
+ module: k8s_kubelet
246
+ name: local
247
+ {{- if eq .Port "10255" }}
248
+ url: http://{{.Address}}/metrics
249
+ {{- else }}
250
+ url: https://{{.Address}}/metrics
251
+ tls_skip_verify: yes
252
+ {{- end }}
253
+
254
+ - id: "kubeproxy"
255
+ match: '{{ and (eq .Port "10249") (eq .Comm "kube-proxy") }}'
256
+ config_template: |
257
+ module: k8s_kubeproxy
258
+ name: local
259
+ url: http://{{.Address}}/metrics
260
+
261
+ - id: "lighttpd"
262
+ match: '{{ and (eq .Port "80" "8080") (eq .Comm "lighttpd") }}'
263
+ config_template: |
264
+ module: lighttpd
265
+ name: local
266
+ url: http://{{.Address}}/server-status?auto
267
+
268
+ - id: "logstash"
269
+ match: '{{ and (eq .Port "9600") (glob .Cmdline "*logstash*") }}'
270
+ config_template: |
271
+ module: logstash
272
+ name: local
273
+ url: http://{{.Address}}
274
+
275
+ - id: "maxscale"
276
+ match: '{{ or (eq .Port "8989") (eq .Comm "maxscale") }}'
277
+ config_template: |
278
+ module: maxscale
279
+ name: local
280
+ url: http://{{.Address}}
281
+
282
+ - id: "memcached"
283
+ match: '{{ or (eq .Port "11211") (eq .Comm "memcached") }}'
284
+ config_template: |
285
+ module: memcached
286
+ name: local
287
+ address: {{.Address}}
288
+
289
+ - id: "mongodb"
290
+ match: '{{ or (eq .Port "27017") (eq .Comm "mongod") }}'
291
+ config_template: |
292
+ module: mongodb
293
+ name: local
294
+ uri: mongodb://{{.Address}}
295
+
296
+ - id: "monit"
297
+ match: '{{ or (eq .Port "2812") (eq .Comm "monit") }}'
298
+ config_template: |
299
+ module: monit
300
+ name: local
301
+ url: http://{{.Address}}
302
+ username: admin
303
+ password: monit
304
+
305
+ - id: "mysql"
306
+ match: '{{ or (eq .Port "3306") (eq .Comm "mysqld" "mariadbd") }}'
307
+ config_template: |
308
+ - module: mysql
309
+ name: local
310
+ dsn: netdata@unix(/var/run/mysqld/mysqld.sock)/
311
+ - module: mysql
312
+ name: local
313
+ dsn: netdata@tcp({{.Address}})/
314
+
315
+ - id: "nats"
316
+ match: '{{ and (eq .Port "8222") (eq .Comm "nats-server") }}'
317
+ config_template: |
318
+ - module: nats
319
+ name: local
320
+ url: http://{{.Address}}
321
+
322
+ - id: "nginx"
323
+ match: '{{ and (eq .Port "80" "8080") (eq .Comm "nginx") }}'
324
+ config_template: |
325
+ - module: nginx
326
+ name: local
327
+ url: http://{{.Address}}/stub_status
328
+ - module: nginx
329
+ name: local
330
+ url: http://{{.Address}}/basic_status
331
+ - module: nginx
332
+ name: local
333
+ url: http://{{.Address}}/nginx_status
334
+ - module: nginx
335
+ name: local
336
+ url: http://{{.Address}}/status
337
+
338
+ - id: "nginxunit"
339
+ match: '{{ and (eq .Port "8000") (eq .Comm "unit") }}'
340
+ config_template: |
341
+ - module: nginxunit
342
+ name: local
343
+ url: http://{{.Address}}
344
+
345
+ - id: "ntpd"
346
+ match: '{{ or (eq .Port "123") (eq .Comm "ntpd") }}'
347
+ config_template: |
348
+ module: ntpd
349
+ name: local
350
+ address: {{.Address}}
351
+ collect_peers: no
352
+
353
+ - id: "openldap"
354
+ match: '{{ eq .Comm "slapd" }}'
355
+ config_template: |
356
+ module: openldap
357
+ name: local
358
+ url: ldap://{{.Address}}
359
+
360
+ - id: "openvpn"
361
+ match: '{{ and (eq .Port "7505") (eq .Comm "openvpn") }}'
362
+ config_template: |
363
+ module: openvpn
364
+ name: local
365
+ address: {{.Address}}
366
+
367
+ - id: "oracledb"
368
+ match: '{{ and (eq .Port "1521" "2484") (eq .Comm "tnslsnr") }}'
369
+ config_template: |
370
+ module: oracledb
371
+ name: local
372
+ {{ if eq .Port "1521" -}}
373
+ dsn: 'oracle://username:password@{{.Address}}/XE'
374
+ {{ else -}}
375
+ dsn: 'oracle://username:password@{{.Address}}/XE?ssl=true&ssl verify=false'
376
+ {{ end -}}
377
+
378
+ - id: "pgbouncer"
379
+ match: '{{ or (eq .Port "6432") (eq .Comm "pgbouncer") }}'
380
+ config_template: |
381
+ module: pgbouncer
382
+ name: local
383
+ dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
384
+
385
+ - id: "pihole"
386
+ match: '{{ and (eq .Port "80") (eq .Comm "pihole-FTL") }}'
387
+ config_template: |
388
+ module: pihole
389
+ name: local
390
+ url: http://{{.Address}}
391
+
392
+ - id: "pika"
393
+ match: '{{ and (eq .Port "9221") (eq .Comm "pika") }}'
394
+ config_template: |
395
+ module: pika
396
+ name: local
397
+ address: redis://@{{.IPAddress}}:{{.Port}}
398
+
399
+ - id: "postgres"
400
+ match: '{{ or (eq .Port "5432") (eq .Comm "postgres") }}'
401
+ config_template: |
402
+ - module: postgres
403
+ name: local
404
+ dsn: 'host=/var/run/postgresql dbname=postgres user=postgres'
405
+ - module: postgres
406
+ name: local
407
+ dsn: 'host=/var/run/postgresql dbname=postgres user=netdata'
408
+ - module: postgres
409
+ name: local
410
+ dsn: postgresql://netdata@{{.Address}}/postgres
411
+
412
+ - id: "powerdns"
413
+ match: '{{ and (eq .Port "8081") (eq .Comm "pdns_server") }}'
414
+ config_template: |
415
+ module: powerdns
416
+ name: local
417
+ url: http://{{.Address}}
418
+ headers:
419
+ X-API-KEY: secret
420
+
421
+ - id: "powerdns_recursor"
422
+ match: '{{ and (eq .Port "8081") (eq .Comm "pdns_recursor") }}'
423
+ config_template: |
424
+ module: powerdns_recursor
425
+ name: local
426
+ url: http://{{.Address}}
427
+ headers:
428
+ X-API-KEY: secret
429
+
430
+ - id: "proxysql"
431
+ match: '{{ or (eq .Port "6032") (eq .Comm "proxysql") }}'
432
+ config_template: |
433
+ module: proxysql
434
+ name: local
435
+ dsn: stats:stats@tcp({{.Address}})/
436
+
437
+ - id: "puppet"
438
+ match: '{{ or (eq .Port "8140") (glob .Cmdline "*puppet-server*") }}'
439
+ config_template: |
440
+ module: puppet
441
+ name: local
442
+ url: https://{{.Address}}
443
+ tls_skip_verify: yes
444
+
445
+ - id: "rabbitmq"
446
+ match: '{{ or (eq .Port "15672") (glob .Cmdline "*rabbitmq*") }}'
447
+ config_template: |
448
+ module: rabbitmq
449
+ name: local
450
+ url: http://{{.Address}}
451
+ username: guest
452
+ password: guest
453
+ collect_queues_metrics: no
454
+
455
+ - id: "redis"
456
+ match: '{{ or (eq .Port "6379") (eq .Comm "redis-server") }}'
457
+ config_template: |
458
+ module: redis
459
+ name: local
460
+ address: redis://@{{.Address}}
461
+
462
+ - id: "rethinkdb"
463
+ match: '{{ and (eq .Port "28015") (eq .Comm "rethinkdb") }}'
464
+ config_template: |
465
+ module: rethinkdb
466
+ name: local
467
+ address: {{.Address}}
468
+
469
+ - id: "riak"
470
+ match: '{{ and (eq .Port "8098") (glob .Cmdline "*riak*") }}'
471
+ config_template: |
472
+ module: riakkv
473
+ name: local
474
+ url: http://{{.Address}}/stats
475
+
476
+ - id: "rspamd"
477
+ match: '{{ and (eq .Port "11334") (eq .Comm "rspamd") }}'
478
+ config_template: |
479
+ module: rspamd
480
+ name: local
481
+ url: http://{{.Address}}
482
+
483
+ - id: "squid"
484
+ match: '{{ and (eq .Port "3128") (eq .Comm "squid") }}'
485
+ config_template: |
486
+ module: squid
487
+ name: local
488
+ url: http://{{.Address}}
489
+
490
+ - id: "spigotmc"
491
+ match: '{{ and (eq .Port "25575") (glob .Cmdline "*spigot*") }}'
492
+ config_template: |
493
+ module: spigotmc
494
+ name: local
495
+ address: {{.Address}}
496
+
497
+ - id: "supervisord"
498
+ match: '{{ and (eq .Port "9001") (eq .Comm "supervisord") }}'
499
+ config_template: |
500
+ module: supervisord
501
+ name: local
502
+ url: http://{{.Address}}/RPC2
503
+
504
+ - id: "tomcat"
505
+ match: '{{ and (eq .Port "8080") (glob .Cmdline "*tomcat*") }}'
506
+ config_template: |
507
+ module: tomcat
508
+ name: local
509
+ url: http://{{.Address}}
510
+
511
+ - id: "tor"
512
+ match: '{{ and (eq .Port "9051") (eq .Comm "tor") }}'
513
+ config_template: |
514
+ module: tor
515
+ name: local
516
+ address: {{.Address}}
517
+
518
+ - id: "traefik"
519
+ match: '{{ and (eq .Port "80" "8080") (eq .Comm "traefik") }}'
520
+ config_template: |
521
+ module: traefik
522
+ name: local
523
+ url: http://{{.Address}}/metrics
524
+
525
+ - id: "typesense"
526
+ match: '{{ and (eq .Port "8108") (eq .Comm "typesense-server") }}'
527
+ config_template: |
528
+ module: typesense
529
+ name: local
530
+ url: http://{{.Address}}
531
+ api_key: {{ trimPrefix "--api-key=" (regexFind "--api-key=[^ ]+" .Cmdline) -}}
532
+
533
+ - id: "unbound"
534
+ match: '{{ and (eq .Port "8953") (eq .Comm "unbound") }}'
535
+ config_template: |
536
+ module: unbound
537
+ name: local
538
+ address: {{.Address}}
539
+
540
+ - id: "upsd"
541
+ match: '{{ or (eq .Port "3493") (eq .Comm "upsd") }}'
542
+ config_template: |
543
+ module: upsd
544
+ name: local
545
+ address: {{.Address}}
546
+
547
+ - id: "uwsgi"
548
+ match: '{{ and (eq .Port "1717") (eq .Comm "uwsgi") }}'
549
+ config_template: |
550
+ module: uwsgi
551
+ name: local
552
+ address: {{.Address}}
553
+
554
+ - id: "vernemq"
555
+ match: '{{ and (eq .Port "8888") (glob .Cmdline "*vernemq*") }}'
556
+ config_template: |
557
+ module: vernemq
558
+ name: local
559
+ url: http://{{.Address}}/metrics
560
+
561
+ - id: "yugabytedb"
562
+ match: '{{ and (eq .Port "7000" "9000" "12000" "13000") (or (glob .Cmdline "*YSQL*") (eq .Comm "yb-master" "yb-tserver")) }}'
563
+ config_template: |
564
+ - module: yugabytedb
565
+ {{ if eq .Port "7000" -}}
566
+ name: local_master
567
+ {{ else if eq .Port "9000" -}}
568
+ name: local_tserver
569
+ {{ else if eq .Port "12000" -}}
570
+ name: local_ycql
571
+ {{ else if eq .Port "13000" -}}
572
+ name: local_ysql
573
+ {{ else -}}
574
+ name: local
575
+ {{ end }}
576
+ url: http://{{.Address}}/prometheus-metrics
577
+
578
+ - id: "zookeeper"
579
+ match: '{{ or (eq .Port "2181" "2182") (glob .Cmdline "*zookeeper*") }}'
580
+ config_template: |
581
+ module: zookeeper
582
+ name: local
583
+ address: {{.Address}}
584
+
585
+ - id: "exporter"
586
+ match: '{{ or (and (not (empty (promPort .Port))) (not (eq .Comm "docker-proxy"))) (glob .Comm "*exporter*") }}'
587
+ config_template: |
588
+ {{ $name := promPort .Port -}}
589
+ {{ if empty $name -}}
590
+ {{ $name = printf "%s_%s" .Comm .Port -}}
591
+ {{ end -}}
592
+ module: prometheus
593
+ name: {{$name}}_local
594
+ url: http://{{.Address}}/metrics
595
+ {{ if eq $name "caddy" -}}
596
+ expected_prefix: 'caddy_'
597
+ {{ else if eq $name "openethereum" -}}
598
+ expected_prefix: 'blockchaincache_'
599
+ {{ else if eq $name "crowdsec" -}}
600
+ expected_prefix: 'cs_'
601
+ {{ else if eq $name "netbox" -}}
602
+ expected_prefix: 'django_'
603
+ {{ else if eq $name "traefik" -}}
604
+ expected_prefix: 'traefik_'
605
+ {{ else if eq $name "pushgateway" -}}
606
+ expected_prefix: 'pushgateway_'
607
+ selector:
608
+ allow:
609
+ - pushgateway_*
610
+ {{ else if eq $name "wireguard_exporter" -}}
611
+ expected_prefix: 'wireguard_exporter'
612
+ {{ else if eq $name "clickhouse" -}}
613
+ max_time_series: 3000
614
+ {{ end -}}
src/go/plugin/go.d/config/go.d/sd/snmp.conf
+25
-35
@@ -58,38 +58,28 @@ discover:
58
## Credential is the name of a credential from the Credentials list
59
credential: "public-v2c"
60
61
-classify:
62
- - name: "SNMP Devices"
63
- selector: "*"
64
- tags: "snmp"
65
- match:
66
- - tags: "snmp"
67
- expr: '{{ true }}'
68
-
69
-compose:
70
- - name: "SNMP Devices"
71
- selector: "snmp"
72
- config:
73
- - selector: "snmp"
74
- template: |
75
- module: snmp
76
- update_every: 5
77
- {{- if .SysInfo.Name }}
78
- name: {{ .SysInfo.Name }}-ip-{{ .IPAddress }}
79
- {{- else }}
80
- name: ip-{{ .IPAddress }}
81
- {{- end }}
82
- hostname: {{ .IPAddress }}
83
- options:
84
- version: {{ .Credential.Version }}
85
- {{- if eq .Credential.Version "1" "2" }}
86
- community: {{ .Credential.Community }}
87
- {{- else }}
88
- user:
89
- name: {{ .Credential.UserName }}
90
- level: {{ .Credential.SecurityLevel }}
91
- auth_proto: {{ .Credential.AuthProtocol }}
92
- auth_key: {{ .Credential.AuthPassphrase }}
93
- priv_proto: {{ .Credential.PrivacyProtocol }}
94
- priv_key: {{ .Credential.PrivacyPassphrase }}
95
- {{- end }}
61
+services:
62
+ - id: "snmp"
63
+ match: '{{ true }}'
64
+ config_template: |
65
+ module: snmp
66
+ update_every: 5
67
+ {{- if .SysInfo.Name }}
68
+ name: {{ .SysInfo.Name }}-ip-{{ .IPAddress }}
69
+ {{- else }}
70
+ name: ip-{{ .IPAddress }}
71
+ {{- end }}
72
+ hostname: {{ .IPAddress }}
73
+ options:
74
+ version: {{ .Credential.Version }}
75
+ {{- if eq .Credential.Version "1" "2" }}
76
+ community: {{ .Credential.Community }}
77
+ {{- else }}
78
+ user:
79
+ name: {{ .Credential.UserName }}
80
+ level: {{ .Credential.SecurityLevel }}
81
+ auth_proto: {{ .Credential.AuthProtocol }}
82
+ auth_key: {{ .Credential.AuthPassphrase }}
83
+ priv_proto: {{ .Credential.PrivacyProtocol }}
84
+ priv_key: {{ .Credential.PrivacyPassphrase }}
85
+ {{- end }}