go.d: sd local-listeners: discover /proc/net/tcp6 only apps (#17252)
Ilya Mashchenko committed
Mar 25, 2024 at 21:34 UTC
288d311afdf3b9f7e4c0fcc5eb82d4031a4b609c
4 files changed
+78
-68
src/go/collectors/go.d.plugin/agent/discovery/sd/discoverer/netlisteners/netlisteners.go
+50
-26
@@ -13,6 +13,8 @@ import (
13
"os"
14
"os/exec"
15
"path/filepath"
16
+ "sort"
17
+ "strconv"
18
"strings"
19
"time"
20
@@ -183,8 +185,12 @@ func (d *Discoverer) processTargets(tgts []model.Target) []model.TargetGroup {
185
}
186
187
func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
186
- var tgts []model.Target
187
- set := make(map[string]bool)
188
+ const (
189
+ local4 = "127.0.0.1"
190
+ local6 = "::1"
191
+ )
192
+
193
+ var targets []target
194
sc := bufio.NewScanner(bytes.NewReader(bs))
195
196
for sc.Scan() {
@@ -207,11 +213,6 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
213
Cmdline: parts[3],
214
}
215
210
- const (
211
- local4 = "127.0.0.1"
212
- local6 = "::1"
213
- )
214
-
216
if tgt.IPAddress == "0.0.0.0" || strings.HasPrefix(tgt.IPAddress, "127") {
217
tgt.IPAddress = local4
218
} else if tgt.IPAddress == "::" {
@@ -220,21 +221,6 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
221
222
tgt.Address = net.JoinHostPort(tgt.IPAddress, tgt.Port)
223
223
- key := fmt.Sprintf("%s:%s", tgt.Protocol, tgt.Address)
224
- var keyLocal string
225
- if strings.HasSuffix(tgt.Protocol, "6") {
226
- keyLocal = fmt.Sprintf("%s:%s", tgt.Protocol, net.JoinHostPort(local6, tgt.Port))
227
- } else {
228
- keyLocal = fmt.Sprintf("%s:%s", tgt.Protocol, net.JoinHostPort(local4, tgt.Port))
229
- }
230
-
231
- // Filter targets that accept conns on any (0.0.0.0) and additionally on each individual network interface (a.b.c.d).
232
- // Create a target only for localhost. Assumption: any address always goes first.
233
- if set[key] || set[keyLocal] {
234
- continue
235
- }
236
- set[key] = true
237
-
224
hash, err := calcHash(tgt)
225
if err != nil {
226
continue
@@ -243,10 +229,49 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
229
tgt.hash = hash
230
tgt.Tags().Merge(d.Tags())
231
246
- tgts = append(tgts, &tgt)
232
+ targets = append(targets, tgt)
233
+ }
234
+
235
+ // order: TCP, TCP6, UDP, UDP6
236
+ sort.Slice(targets, func(i, j int) bool {
237
+ tgt1, tgt2 := targets[i], targets[j]
238
+ if tgt1.Protocol != tgt2.Protocol {
239
+ return tgt1.Protocol < tgt2.Protocol
240
+ }
241
+
242
+ p1, _ := strconv.Atoi(targets[i].Port)
243
+ p2, _ := strconv.Atoi(targets[j].Port)
244
+ if p1 != p2 {
245
+ return p1 < p2
246
+ }
247
+
248
+ return tgt1.IPAddress == local4 || tgt1.IPAddress == local6
249
+ })
250
+
251
+ seen := make(map[string]bool)
252
+ tgts := make([]model.Target, len(targets))
253
+ var n int
254
+
255
+ for _, tgt := range targets {
256
+ tgt := tgt
257
+
258
+ proto := strings.TrimSuffix(tgt.Protocol, "6")
259
+ key := tgt.Protocol + ":" + tgt.Address
260
+ keyLocal4 := proto + ":" + net.JoinHostPort(local4, tgt.Port)
261
+ keyLocal6 := proto + "6:" + net.JoinHostPort(local6, tgt.Port)
262
+
263
+ // Filter targets that accept conns on any (0.0.0.0) and additionally on each individual network interface (a.b.c.d).
264
+ // Create a target only for localhost. Assumption: any address always goes first.
265
+ if seen[key] || seen[keyLocal4] || seen[keyLocal6] {
266
+ continue
267
+ }
268
+ seen[key] = true
269
+
270
+ tgts[n] = &tgt
271
+ n++
272
}
273
249
- return tgts, nil
274
+ return tgts[:n], nil
275
}
276
277
type localListenersExec struct {
@@ -258,11 +283,10 @@ func (e *localListenersExec) discover(ctx context.Context) ([]byte, error) {
283
execCtx, cancel := context.WithTimeout(ctx, e.timeout)
284
defer cancel()
285
261
- // TCPv4 and UPDv4 sockets in LISTEN state
286
+ // TCPv4/6 and UPDv4 sockets in LISTEN state
287
// https://github.com/netdata/netdata/blob/master/src/collectors/plugins.d/local_listeners.c
288
args := []string{
289
"no-udp6",
265
- "no-tcp6",
290
"no-local",
291
"no-inbound",
292
"no-outbound",
src/go/collectors/go.d.plugin/agent/discovery/sd/discoverer/netlisteners/netlisteners_test.go
+16
-30
@@ -21,6 +21,8 @@ func TestDiscoverer_Discover(t *testing.T) {
21
cli.addListener("TCP|0.0.0.0|8125|/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D")
22
cli.addListener("TCP|192.0.2.1|8125|/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D")
23
cli.addListener("UDP|127.0.0.1|53768|/opt/netdata/usr/libexec/netdata/plugins.d/go.d.plugin 1")
24
+ cli.addListener("TCP6|::|80|/usr/sbin/apache2 -k start")
25
+ cli.addListener("TCP|0.0.0.0|80|/usr/sbin/apache2 -k start")
26
time.Sleep(interval * 2)
27
},
28
wantGroups: []model.TargetGroup{&targetGroup{
@@ -28,20 +30,12 @@ func TestDiscoverer_Discover(t *testing.T) {
30
source: "discoverer=net_listeners,host=localhost",
31
targets: []model.Target{
32
withHash(&target{
31
- Protocol: "UDP6",
32
- IPAddress: "::1",
33
- Port: "8125",
34
- Address: "[::1]:8125",
35
- Comm: "netdata",
36
- Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
37
- }),
38
- withHash(&target{
39
- Protocol: "TCP6",
40
- IPAddress: "::1",
41
- Port: "8125",
42
- Address: "[::1]:8125",
43
- Comm: "netdata",
44
- Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
33
+ Protocol: "TCP",
34
+ IPAddress: "127.0.0.1",
35
+ Port: "80",
36
+ Address: "127.0.0.1:80",
37
+ Comm: "apache2",
38
+ Cmdline: "/usr/sbin/apache2 -k start",
39
}),
40
withHash(&target{
41
Protocol: "TCP",
@@ -59,6 +53,14 @@ func TestDiscoverer_Discover(t *testing.T) {
53
Comm: "go.d.plugin",
54
Cmdline: "/opt/netdata/usr/libexec/netdata/plugins.d/go.d.plugin 1",
55
}),
56
+ withHash(&target{
57
+ Protocol: "UDP6",
58
+ IPAddress: "::1",
59
+ Port: "8125",
60
+ Address: "[::1]:8125",
61
+ Comm: "netdata",
62
+ Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
63
+ }),
64
},
65
}},
66
},
@@ -85,14 +87,6 @@ func TestDiscoverer_Discover(t *testing.T) {
87
Comm: "netdata",
88
Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
89
}),
88
- withHash(&target{
89
- Protocol: "TCP6",
90
- IPAddress: "::1",
91
- Port: "8125",
92
- Address: "[::1]:8125",
93
- Comm: "netdata",
94
- Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
95
- }),
90
withHash(&target{
91
Protocol: "TCP",
92
IPAddress: "127.0.0.1",
@@ -127,14 +121,6 @@ func TestDiscoverer_Discover(t *testing.T) {
121
provider: "sd:net_listeners",
122
source: "discoverer=net_listeners,host=localhost",
123
targets: []model.Target{
130
- withHash(&target{
131
- Protocol: "TCP6",
132
- IPAddress: "::1",
133
- Port: "8125",
134
- Address: "[::1]:8125",
135
- Comm: "netdata",
136
- Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
137
- }),
124
withHash(&target{
125
Protocol: "TCP",
126
IPAddress: "127.0.0.1",
src/go/collectors/go.d.plugin/config/go.d/sd/docker.conf
+6
-6
@@ -129,7 +129,7 @@ compose:
129
template: |
130
module: mysql
131
name: docker_{{.Name}}
132
- dsn: netdata@tcp({{.IPAddress}}:{{.PrivatePort}})/
132
+ dsn: netdata@tcp({{.Address}})/
133
- selector: "nginx"
134
template: |
135
module: nginx
@@ -139,22 +139,22 @@ compose:
139
template: |
140
module: pgbouncer
141
name: docker_{{.Name}}
142
- dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.PrivatePort}}/pgbouncer
142
+ dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
143
- selector: "pika"
144
template: |
145
module: pika
146
name: docker_{{.Name}}
147
- address: redis://@{{.IPAddress}}:{{.PrivatePort}}
147
+ address: redis://@{{.Address}}
148
- selector: "postgres"
149
template: |
150
module: postgres
151
name: docker_{{.Name}}
152
- dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.PrivatePort}}/postgres
152
+ dsn: postgres://netdata:postgres@{{.Address}}/postgres
153
- selector: "proxysql"
154
template: |
155
module: proxysql
156
name: docker_{{.Name}}
157
- dsn: stats:stats@tcp({{.IPAddress}}:{{.PrivatePort}})/
157
+ dsn: stats:stats@tcp({{.Address}})/
158
- selector: "rabbitmq"
159
template: |
160
module: rabbitmq
@@ -164,7 +164,7 @@ compose:
164
template: |
165
module: redis
166
name: docker_{{.Name}}
167
- address: redis://@{{.IPAddress}}:{{.PrivatePort}}
167
+ address: redis://@{{.Address}}
168
- selector: "tengine"
169
template: |
170
module: tengine
src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf
+6
-6
@@ -15,7 +15,7 @@ classify:
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" "httpd") }}'
18
+ expr: '{{ and (eq .Port "80" "8080") (eq .Comm "apache" "apache2" "httpd") }}'
19
- tags: "bind"
20
expr: '{{ and (eq .Port "8653") (eq .Comm "bind" "named") }}'
21
- tags: "cassandra"
@@ -270,7 +270,7 @@ compose:
270
template: |
271
module: mysql
272
name: local
273
- dsn: netdata@tcp({{.IPAddress}}:{{.Port}})/
273
+ dsn: netdata@tcp({{.Address}})/
274
- selector: "nginx"
275
template: |
276
- module: nginx
@@ -300,7 +300,7 @@ compose:
300
template: |
301
module: pgbouncer
302
name: local
303
- dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.Port}}/pgbouncer
303
+ dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
304
- selector: "pihole"
305
template: |
306
module: pihole
@@ -315,7 +315,7 @@ compose:
315
template: |
316
module: postgres
317
name: local
318
- dsn: postgresql://netdata@{{.IPAddress}}:{{.Port}}/postgres
318
+ dsn: postgresql://netdata@{{.Address}}/postgres
319
- selector: "powerdns"
320
template: |
321
module: powerdns
@@ -334,7 +334,7 @@ compose:
334
template: |
335
module: proxysql
336
name: local
337
- dsn: stats:stats@tcp({{.IPAddress}}:{{.Port}})/
337
+ dsn: stats:stats@tcp({{.Address}})/
338
- selector: "rabbitmq"
339
template: |
340
module: rabbitmq
@@ -347,7 +347,7 @@ compose:
347
template: |
348
module: redis
349
name: local
350
- address: redis://@{{.IPAddress}}:{{.Port}}
350
+ address: redis://@{{.Address}}
351
- selector: "supervisord"
352
template: |
353
module: supervisord