Port the OpenLDAP collector from Python to Go (#18625)
Co-authored-by: ilyam8 <ilya@netdata.cloud>
Fotis Voutsas committed
Sep 30, 2024 at 17:40 UTC
23067a7cb6ebfeade923a5c44abf6946266785fe
18 files changed
+1283
-1
src/go/go.mod
+3
@@ -19,6 +19,7 @@ require (
19
github.com/docker/docker v27.3.1+incompatible
20
github.com/facebook/time v0.0.0-20240626113945-18207c5d8ddc
21
github.com/fsnotify/fsnotify v1.7.0
22
+ github.com/go-ldap/ldap/v3 v3.4.8
23
github.com/go-sql-driver/mysql v1.8.1
24
github.com/godbus/dbus/v5 v5.1.0
25
github.com/gofrs/flock v0.12.1
@@ -62,6 +63,7 @@ require (
63
dario.cat/mergo v1.0.1 // indirect
64
filippo.io/edwards25519 v1.1.0 // indirect
65
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
66
+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
67
github.com/Masterminds/goutils v1.1.1 // indirect
68
github.com/Masterminds/semver/v3 v3.3.0 // indirect
69
github.com/Microsoft/go-winio v0.6.1 // indirect
@@ -75,6 +77,7 @@ require (
77
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
78
github.com/felixge/httpsnoop v1.0.4 // indirect
79
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
80
+ github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
81
github.com/go-logr/logr v1.4.2 // indirect
82
github.com/go-logr/stdr v1.2.2 // indirect
83
github.com/go-openapi/jsonpointer v0.20.0 // indirect
src/go/go.sum
+48
@@ -4,6 +4,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
4
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
5
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
6
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
7
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
8
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
9
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
10
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
11
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
@@ -18,6 +20,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
20
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
21
github.com/Wing924/ltsv v0.3.1 h1:hbjzQ6YuS/sOm7nQJG7ddT9ua1yYmcH25Q8lsuiQE0A=
22
github.com/Wing924/ltsv v0.3.1/go.mod h1:zl47wq7H23LocdDHg7yJAH/Qdc4MWHXu1Evx9Ahilmo=
23
+github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
24
+github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
25
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
26
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
27
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
@@ -83,7 +87,11 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
87
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
88
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
89
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
90
+github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
91
+github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
92
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
93
+github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
94
+github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
95
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
96
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
97
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -135,6 +143,8 @@ github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73
143
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
144
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
145
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
146
+github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
147
+github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
148
github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc=
149
github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY=
150
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
@@ -144,6 +154,9 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8
154
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
155
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
156
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
157
+github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
158
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
159
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
160
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
161
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
162
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@@ -202,6 +215,18 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
215
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
216
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
217
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
218
+github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
219
+github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
220
+github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
221
+github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
222
+github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
223
+github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
224
+github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
225
+github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
226
+github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
227
+github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
228
+github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
229
+github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
230
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
231
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
232
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -421,6 +446,9 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
446
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
447
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
448
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
449
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
450
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
451
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
452
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
453
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
454
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
@@ -432,6 +460,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
460
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
461
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
462
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
463
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
464
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
465
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
466
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -439,11 +468,17 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
468
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
469
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
470
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
471
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
472
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
473
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
474
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
475
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
476
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
477
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
478
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
479
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
480
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
481
+golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
482
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
483
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
484
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
@@ -454,6 +489,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
489
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
490
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
491
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
492
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
493
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
494
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
495
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -477,12 +513,20 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
513
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
514
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
515
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
516
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
517
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
518
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
519
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
520
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
521
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
522
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
523
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
524
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
525
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
526
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
527
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
528
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
529
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
530
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
531
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
532
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -492,6 +536,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
536
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
537
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
538
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
539
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
540
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
541
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
542
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
543
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
544
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@@ -509,6 +556,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
556
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
557
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
558
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
559
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
560
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
561
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
562
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
src/go/plugin/go.d/README.md
+2
@@ -111,7 +111,9 @@ see the appropriate collector readme.
111
| [nginxvts](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nginxvts) | NGINX VTS |
112
| [nsd](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nsd) | NSD (NLnet Labs) |
113
| [ntpd](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/ntpd) | NTP daemon |
114
+| [nvidia_smi](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nvidia_smi) | Nvidia SMI |
115
| [nvme](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nvme) | NVMe devices |
116
+| [openldap](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/openldap) | OpenLDAP |
117
| [openvpn](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/openvpn) | OpenVPN |
118
| [openvpn_status_log](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/openvpn_status_log) | OpenVPN |
119
| [pgbouncer](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/pgbouncer) | PgBouncer |
src/go/plugin/go.d/config/go.d.conf
+2
-1
@@ -75,8 +75,9 @@ modules:
75
# nginxvts: yes
76
# nsd: yes
77
# ntpd: yes
78
-# nvme: yes
78
# nvidia_smi: no
79
+# nvme: yes
80
+# openldap: yes
81
# openvpn: no
82
# openvpn_status_log: yes
83
# ping: yes
src/go/plugin/go.d/config/go.d/openldap.conf
new
+8
@@ -0,0 +1,8 @@
1
+## All available configuration options, their descriptions and default values:
2
+## https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/openldap#readme
3
+
4
+#jobs:
5
+# - name: local
6
+# url: ldap://127.0.0.1:389
7
+# username: cn=user,dc=example,dc=com
8
+# password: password
src/go/plugin/go.d/config/go.d/sd/net_listeners.conf
+7
@@ -96,6 +96,8 @@ classify:
96
expr: '{{ and (eq .Port "8000") (eq .Comm "unit") }}'
97
- tags: "ntpd"
98
expr: '{{ or (eq .Port "123") (eq .Comm "ntpd") }}'
99
+ - tags: "openldap"
100
+ expr: '{{ eq .Comm "slapd" }}'
101
- tags: "openvpn"
102
expr: '{{ and (eq .Port "7505") (eq .Comm "openvpn") }}'
103
- tags: "pgbouncer"
@@ -405,6 +407,11 @@ compose:
407
name: local
408
address: {{.Address}}
409
collect_peers: no
410
+ - selector: "openldap"
411
+ template: |
412
+ module: openldap
413
+ name: local
414
+ url: ldap://{{.Address}}
415
- selector: "openvpn"
416
template: |
417
module: openvpn
src/go/plugin/go.d/modules/init.go
+1
@@ -68,6 +68,7 @@ import (
68
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/ntpd"
69
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/nvidia_smi"
70
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/nvme"
71
+ _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/openldap"
72
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/openvpn"
73
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/openvpn_status_log"
74
_ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/pgbouncer"
src/go/plugin/go.d/modules/openldap/charts.go
new
+141
@@ -0,0 +1,141 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
7
+)
8
+
9
+const (
10
+ prioCurrentConnections = module.Priority + iota
11
+ prioTotalConnections
12
+ prioBytesSent
13
+ prioEntries
14
+ prioReferrals
15
+ prioOperations
16
+ prioOperationsByType
17
+ prioWaiters
18
+)
19
+
20
+var charts = module.Charts{
21
+ currentConnectionsChart.Copy(),
22
+ connectionsChart.Copy(),
23
+
24
+ bytesSentChart.Copy(),
25
+ referralsSentChart.Copy(),
26
+ entriesSentChart.Copy(),
27
+
28
+ operationsChart.Copy(),
29
+ operationsByTypeChart.Copy(),
30
+
31
+ waitersChart.Copy(),
32
+}
33
+
34
+var (
35
+ currentConnectionsChart = module.Chart{
36
+ ID: "current_connections",
37
+ Title: "Current Connections",
38
+ Units: "connections",
39
+ Fam: "connections",
40
+ Ctx: "openldap.current_connections",
41
+ Priority: prioCurrentConnections,
42
+ Type: module.Line,
43
+ Dims: module.Dims{
44
+ {ID: "current_connections", Name: "active"},
45
+ },
46
+ }
47
+ connectionsChart = module.Chart{
48
+ ID: "connections",
49
+ Title: "Connections",
50
+ Units: "connections/s",
51
+ Fam: "connections",
52
+ Ctx: "openldap.connections",
53
+ Priority: prioTotalConnections,
54
+ Type: module.Line,
55
+ Dims: module.Dims{
56
+ {ID: "total_connections", Name: "connections", Algo: module.Incremental},
57
+ },
58
+ }
59
+
60
+ bytesSentChart = module.Chart{
61
+ ID: "bytes_sent",
62
+ Title: "Traffic",
63
+ Units: "bytes/s",
64
+ Fam: "activity",
65
+ Ctx: "openldap.traffic",
66
+ Priority: prioBytesSent,
67
+ Type: module.Area,
68
+ Dims: module.Dims{
69
+ {ID: "bytes_sent", Name: "sent", Algo: module.Incremental},
70
+ },
71
+ }
72
+ entriesSentChart = module.Chart{
73
+ ID: "entries_sent",
74
+ Title: "Entries",
75
+ Units: "entries/s",
76
+ Fam: "activity",
77
+ Ctx: "openldap.entries",
78
+ Priority: prioEntries,
79
+ Type: module.Line,
80
+ Dims: module.Dims{
81
+ {ID: "entries_sent", Name: "sent", Algo: module.Incremental},
82
+ },
83
+ }
84
+ referralsSentChart = module.Chart{
85
+ ID: "referrals_sent",
86
+ Title: "Referrals",
87
+ Units: "referrals/s",
88
+ Fam: "activity",
89
+ Ctx: "openldap.referrals",
90
+ Priority: prioReferrals,
91
+ Type: module.Line,
92
+ Dims: module.Dims{
93
+ {ID: "referrals_sent", Name: "sent", Algo: module.Incremental},
94
+ },
95
+ }
96
+
97
+ operationsChart = module.Chart{
98
+ ID: "operations",
99
+ Title: "Operations",
100
+ Units: "operations/s",
101
+ Fam: "operations",
102
+ Ctx: "openldap.operations",
103
+ Priority: prioOperations,
104
+ Type: module.Line,
105
+ Dims: module.Dims{
106
+ {ID: "completed_operations", Name: "completed", Algo: module.Incremental},
107
+ {ID: "initiated_operations", Name: "initiated", Algo: module.Incremental},
108
+ },
109
+ }
110
+ operationsByTypeChart = module.Chart{
111
+ ID: "operations_by_type",
112
+ Title: "Operations by Type",
113
+ Units: "operations/s",
114
+ Fam: "operations",
115
+ Ctx: "openldap.operations_by_type",
116
+ Priority: prioOperationsByType,
117
+ Type: module.Stacked,
118
+ Dims: module.Dims{
119
+ {ID: "completed_bind_operations", Name: "bind", Algo: module.Incremental},
120
+ {ID: "completed_search_operations", Name: "search", Algo: module.Incremental},
121
+ {ID: "completed_unbind_operations", Name: "unbind", Algo: module.Incremental},
122
+ {ID: "completed_add_operations", Name: "add", Algo: module.Incremental},
123
+ {ID: "completed_delete_operations", Name: "delete", Algo: module.Incremental},
124
+ {ID: "completed_modify_operations", Name: "modify", Algo: module.Incremental},
125
+ {ID: "completed_compare_operations", Name: "compare", Algo: module.Incremental},
126
+ },
127
+ }
128
+ waitersChart = module.Chart{
129
+ ID: "waiters",
130
+ Title: "Waiters",
131
+ Units: "waiters/s",
132
+ Fam: "operations",
133
+ Ctx: "openldap.waiters",
134
+ Priority: prioWaiters,
135
+ Type: module.Line,
136
+ Dims: module.Dims{
137
+ {ID: "read_waiters", Name: "read", Algo: module.Incremental},
138
+ {ID: "write_waiters", Name: "write", Algo: module.Incremental},
139
+ },
140
+ }
141
+)
src/go/plugin/go.d/modules/openldap/client.go
new
+83
@@ -0,0 +1,83 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "net"
7
+
8
+ "github.com/go-ldap/ldap/v3"
9
+
10
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/tlscfg"
11
+)
12
+
13
+type ldapConn interface {
14
+ connect() error
15
+ disconnect() error
16
+ search(*ldap.SearchRequest) (*ldap.SearchResult, error)
17
+}
18
+
19
+func newLdapConn(cfg Config) ldapConn {
20
+ return &ldapClient{Config: cfg}
21
+}
22
+
23
+type ldapClient struct {
24
+ Config
25
+
26
+ conn *ldap.Conn
27
+}
28
+
29
+func (c *ldapClient) search(req *ldap.SearchRequest) (*ldap.SearchResult, error) {
30
+ return c.conn.Search(req)
31
+}
32
+
33
+func (c *ldapClient) connect() error {
34
+ opts, err := c.connectOpts()
35
+ if err != nil {
36
+ return err
37
+ }
38
+
39
+ conn, err := ldap.DialURL(c.URL, opts...)
40
+ if err != nil {
41
+ return err
42
+ }
43
+
44
+ if c.Password == "" {
45
+ err = conn.UnauthenticatedBind(c.Username)
46
+ } else {
47
+ err = conn.Bind(c.Username, c.Password)
48
+ }
49
+ if err != nil {
50
+ _ = conn.Close()
51
+ return err
52
+ }
53
+
54
+ c.conn = conn
55
+
56
+ return nil
57
+}
58
+
59
+func (c *ldapClient) connectOpts() ([]ldap.DialOpt, error) {
60
+ d := &net.Dialer{
61
+ Timeout: c.Timeout.Duration(),
62
+ }
63
+
64
+ opts := []ldap.DialOpt{ldap.DialWithDialer(d)}
65
+
66
+ tlsConf, err := tlscfg.NewTLSConfig(c.TLSConfig)
67
+ if err != nil {
68
+ return nil, err
69
+ }
70
+ if tlsConf != nil {
71
+ opts = append(opts, ldap.DialWithTLSConfig(tlsConf))
72
+ }
73
+
74
+ return opts, nil
75
+}
76
+
77
+func (c *ldapClient) disconnect() error {
78
+ defer func() { c.conn = nil }()
79
+ if c.conn != nil {
80
+ return c.conn.Close()
81
+ }
82
+ return nil
83
+}
src/go/plugin/go.d/modules/openldap/collect.go
new
+55
@@ -0,0 +1,55 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "github.com/go-ldap/ldap/v3"
7
+)
8
+
9
+func (l *OpenLDAP) collect() (map[string]int64, error) {
10
+ if l.conn == nil {
11
+ conn, err := l.establishConn()
12
+ if err != nil {
13
+ return nil, err
14
+ }
15
+ l.conn = conn
16
+ }
17
+
18
+ mx := make(map[string]int64)
19
+
20
+ if err := l.collectMonitorCounters(mx); err != nil {
21
+ l.Cleanup()
22
+ return nil, err
23
+ }
24
+ if err := l.collectOperations(mx); err != nil {
25
+ l.Cleanup()
26
+ return nil, err
27
+ }
28
+
29
+ return mx, nil
30
+}
31
+
32
+func (l *OpenLDAP) doSearchRequest(req *ldap.SearchRequest, fn func(*ldap.Entry)) error {
33
+ resp, err := l.conn.search(req)
34
+ if err != nil {
35
+ return err
36
+ }
37
+
38
+ for _, entry := range resp.Entries {
39
+ if len(entry.Attributes) != 0 {
40
+ fn(entry)
41
+ }
42
+ }
43
+
44
+ return nil
45
+}
46
+
47
+func (l *OpenLDAP) establishConn() (ldapConn, error) {
48
+ conn := l.newConn(l.Config)
49
+
50
+ if err := conn.connect(); err != nil {
51
+ return nil, err
52
+ }
53
+
54
+ return conn, nil
55
+}
src/go/plugin/go.d/modules/openldap/collect_mon_counters.go
new
+63
@@ -0,0 +1,63 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "strconv"
7
+
8
+ "github.com/go-ldap/ldap/v3"
9
+)
10
+
11
+const (
12
+ attrMonitorCounter = "monitorCounter"
13
+)
14
+
15
+func (l *OpenLDAP) collectMonitorCounters(mx map[string]int64) error {
16
+ req := newLdapMonitorCountersSearchRequest()
17
+
18
+ dnMetricMap := map[string]string{
19
+ "cn=Current,cn=Connections,cn=Monitor": "current_connections",
20
+ "cn=Total,cn=Connections,cn=Monitor": "total_connections",
21
+ "cn=Bytes,cn=Statistics,cn=Monitor": "bytes_sent",
22
+ "cn=Referrals,cn=Statistics,cn=Monitor": "referrals_sent",
23
+ "cn=Entries,cn=Statistics,cn=Monitor": "entries_sent",
24
+ "cn=Write,cn=Waiters,cn=Monitor": "write_waiters",
25
+ "cn=Read,cn=Waiters,cn=Monitor": "read_waiters",
26
+ }
27
+
28
+ return l.doSearchRequest(req, func(entry *ldap.Entry) {
29
+ metric := dnMetricMap[entry.DN]
30
+ if metric == "" {
31
+ l.Debugf("skipping entry '%s'", entry.DN)
32
+ return
33
+ }
34
+
35
+ s := entry.GetAttributeValue(attrMonitorCounter)
36
+ if s == "" {
37
+ l.Debugf("entry '%s' does not have attribute '%s'", entry.DN, attrMonitorCounter)
38
+ return
39
+ }
40
+
41
+ v, err := strconv.ParseInt(s, 10, 64)
42
+ if err != nil {
43
+ l.Debugf("failed to parse entry '%s' value '%s': %v", entry.DN, s, err)
44
+ return
45
+ }
46
+
47
+ mx[metric] = v
48
+ })
49
+}
50
+
51
+func newLdapMonitorCountersSearchRequest() *ldap.SearchRequest {
52
+ return ldap.NewSearchRequest(
53
+ "cn=Monitor",
54
+ ldap.ScopeWholeSubtree,
55
+ ldap.NeverDerefAliases,
56
+ 0,
57
+ 0,
58
+ false,
59
+ "(objectclass=monitorCounterObject)",
60
+ []string{attrMonitorCounter},
61
+ nil,
62
+ )
63
+}
src/go/plugin/go.d/modules/openldap/collect_operations.go
new
+71
@@ -0,0 +1,71 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "strconv"
7
+
8
+ "github.com/go-ldap/ldap/v3"
9
+)
10
+
11
+const (
12
+ attrMonitorOpInitiated = "monitorOpInitiated"
13
+ attrMonitorOpCompleted = "monitorOpCompleted"
14
+)
15
+
16
+func (l *OpenLDAP) collectOperations(mx map[string]int64) error {
17
+ req := newLdapOperationsSearchRequest()
18
+
19
+ dnMetricMap := map[string]string{
20
+ "cn=Bind,cn=Operations,cn=Monitor": "bind_operations",
21
+ "cn=Unbind,cn=Operations,cn=Monitor": "unbind_operations",
22
+ "cn=Add,cn=Operations,cn=Monitor": "add_operations",
23
+ "cn=Delete,cn=Operations,cn=Monitor": "delete_operations",
24
+ "cn=Modify,cn=Operations,cn=Monitor": "modify_operations",
25
+ "cn=Compare,cn=Operations,cn=Monitor": "compare_operations",
26
+ "cn=Search,cn=Operations,cn=Monitor": "search_operations",
27
+ }
28
+
29
+ return l.doSearchRequest(req, func(entry *ldap.Entry) {
30
+ metric := dnMetricMap[entry.DN]
31
+ if metric == "" {
32
+ l.Debugf("skipping entry '%s'", entry.DN)
33
+ return
34
+ }
35
+
36
+ attrs := map[string]string{
37
+ "initiated": attrMonitorOpInitiated,
38
+ "completed": attrMonitorOpCompleted,
39
+ }
40
+
41
+ for prefix, attr := range attrs {
42
+ s := entry.GetAttributeValue(attr)
43
+ if s == "" {
44
+ l.Debugf("entry '%s' does not have attribute '%s'", entry.DN, attr)
45
+ continue
46
+ }
47
+ v, err := strconv.ParseInt(s, 10, 64)
48
+ if err != nil {
49
+ l.Debugf("failed to parse entry '%s' value '%s': %v", entry.DN, s, err)
50
+ continue
51
+ }
52
+
53
+ mx[prefix+"_"+metric] = v
54
+ mx[prefix+"_operations"] += v
55
+ }
56
+ })
57
+}
58
+
59
+func newLdapOperationsSearchRequest() *ldap.SearchRequest {
60
+ return ldap.NewSearchRequest(
61
+ "cn=Operations,cn=Monitor",
62
+ ldap.ScopeWholeSubtree,
63
+ ldap.NeverDerefAliases,
64
+ 0,
65
+ 0,
66
+ false,
67
+ "(objectclass=monitorOperation)",
68
+ []string{attrMonitorOpInitiated, attrMonitorOpCompleted},
69
+ nil,
70
+ )
71
+}
src/go/plugin/go.d/modules/openldap/config_schema.json
new
+110
@@ -0,0 +1,110 @@
1
+{
2
+ "jsonSchema": {
3
+ "$schema": "http://json-schema.org/draft-07/schema#",
4
+ "title": "OpenLDAP collector configuration.",
5
+ "type": "object",
6
+ "properties": {
7
+ "update_every": {
8
+ "title": "Update every",
9
+ "description": "Data collection interval, measured in seconds.",
10
+ "type": "integer",
11
+ "minimum": 1,
12
+ "default": 1
13
+ },
14
+ "timeout": {
15
+ "title": "Timeout",
16
+ "description": "Timeout for establishing a connection and communication (reading and writing) in seconds.",
17
+ "type": "number",
18
+ "minimum": 0.5,
19
+ "default": 2
20
+ },
21
+ "url": {
22
+ "title": "URL",
23
+ "description": "LDAP server URL.",
24
+ "type": "string",
25
+ "default": "ldap://127.0.0.1:389"
26
+ },
27
+ "username": {
28
+ "title": "DN",
29
+ "description": "The distinguished name (DN) of the user authorized to view the monitor database.",
30
+ "type": "string",
31
+ "default": ""
32
+ },
33
+ "password": {
34
+ "title": "Password",
35
+ "description": "The password associated with the user identified by the DN.",
36
+ "type": "string",
37
+ "default": ""
38
+ },
39
+ "tls_skip_verify": {
40
+ "title": "Skip TLS verification",
41
+ "description": "If set, TLS certificate verification will be skipped.",
42
+ "type": "boolean"
43
+ },
44
+ "tls_ca": {
45
+ "title": "TLS CA",
46
+ "description": "The path to the CA certificate file for TLS verification.",
47
+ "type": "string",
48
+ "pattern": "^$|^/"
49
+ },
50
+ "tls_cert": {
51
+ "title": "TLS certificate",
52
+ "description": "The path to the client certificate file for TLS authentication.",
53
+ "type": "string",
54
+ "pattern": "^$|^/"
55
+ },
56
+ "tls_key": {
57
+ "title": "TLS key",
58
+ "description": "The path to the client key file for TLS authentication.",
59
+ "type": "string",
60
+ "pattern": "^$|^/"
61
+ }
62
+ },
63
+ "required": [
64
+ "url",
65
+ "username"
66
+ ],
67
+ "additionalProperties": false,
68
+ "patternProperties": {
69
+ "^name$": {}
70
+ }
71
+ },
72
+ "uiSchema": {
73
+ "uiOptions": {
74
+ "fullPage": true
75
+ },
76
+ "ui:flavour": "tabs",
77
+ "ui:options": {
78
+ "tabs": [
79
+ {
80
+ "title": "Base",
81
+ "fields": [
82
+ "update_every",
83
+ "url",
84
+ "timeout",
85
+ "username",
86
+ "password"
87
+ ]
88
+ },
89
+ {
90
+ "title": "TLS",
91
+ "fields": [
92
+ "tls_skip_verify",
93
+ "tls_ca",
94
+ "tls_cert",
95
+ "tls_key"
96
+ ]
97
+ }
98
+ ]
99
+ },
100
+ "timeout": {
101
+ "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
102
+ },
103
+ "username": {
104
+ "ui:placeholder": "cn=admin,dc=example,dc=com"
105
+ },
106
+ "password": {
107
+ "ui:widget": "password"
108
+ }
109
+ }
110
+}
src/go/plugin/go.d/modules/openldap/metadata.yaml
new
+192
@@ -0,0 +1,192 @@
1
+plugin_name: go.d.plugin
2
+modules:
3
+ - meta:
4
+ plugin_name: go.d.plugin
5
+ module_name: openldap
6
+ monitored_instance:
7
+ name: OpenLDAP
8
+ link: https://www.openldap.org/
9
+ categories:
10
+ - data-collection.authentication-and-authorization
11
+ icon_filename: openldap.svg
12
+ related_resources:
13
+ integrations:
14
+ list: []
15
+ info_provided_to_referring_integrations:
16
+ description: ""
17
+ keywords:
18
+ - openldap
19
+ - RBAC
20
+ - Directory access
21
+ most_popular: false
22
+ overview:
23
+ data_collection:
24
+ metrics_description: |
25
+ This collector monitors OpenLDAP metrics about connections, operations, referrals and more.
26
+ method_description: |
27
+ It gathers the metrics using the [go-ldap](https://github.com/go-ldap/ldap) module and the [Monitor backend](https://www.openldap.org/doc/admin24/monitoringslapd.html) of OpenLDAP.
28
+ supported_platforms:
29
+ include: ["Linux"]
30
+ exclude: []
31
+ multi_instance: true
32
+ additional_permissions:
33
+ description: ""
34
+ default_behavior:
35
+ auto_detection:
36
+ description: "The collector cannot auto-detect OpenLDAP instances, because credential configuration is required."
37
+ limits:
38
+ description: ""
39
+ performance_impact:
40
+ description: ""
41
+ setup:
42
+ prerequisites:
43
+ list:
44
+ - title: Enable the openLDAP Monitor Backend.
45
+ description: |
46
+ Follow instructions from https://www.openldap.org/doc/admin24/monitoringslapd.html to activate monitoring interface.
47
+ configuration:
48
+ file:
49
+ name: go.d/openldap.conf
50
+ options:
51
+ description: |
52
+ The following options can be defined globally: update_every.
53
+ folding:
54
+ title: Config options
55
+ enabled: true
56
+ list:
57
+ - name: update_every
58
+ description: Data collection frequency.
59
+ default_value: 1
60
+ required: false
61
+ - name: timeout
62
+ description: Timeout for establishing a connection and communication (reading and writing) in seconds.
63
+ default_value: 2
64
+ required: false
65
+ - name: url
66
+ description: LDAP server URL.
67
+ default_value: ldap://127.0.0.1:389
68
+ required: true
69
+ - name: username
70
+ description: The distinguished name (DN) of the user authorized to view the monitor database.
71
+ default_value: ""
72
+ required: true
73
+ - name: password
74
+ description: The password associated with the user identified by the DN.
75
+ default_value: ""
76
+ required: true
77
+ - name: tls_skip_verify
78
+ description: Server certificate chain and hostname validation policy. Controls whether the client performs this check.
79
+ default_value: false
80
+ required: false
81
+ - name: tls_ca
82
+ description: Certification authority that the client uses when verifying the server's certificates.
83
+ default_value: ""
84
+ required: false
85
+ - name: tls_cert
86
+ description: Client TLS certificate.
87
+ default_value: ""
88
+ required: false
89
+ - name: tls_key
90
+ description: Client TLS key.
91
+ default_value: ""
92
+ required: false
93
+ examples:
94
+ folding:
95
+ title: ""
96
+ enabled: false
97
+ list:
98
+ - name: Basic
99
+ description: A basic example configuration.
100
+ config: |
101
+ jobs:
102
+ - name: local
103
+ url: ldap://localhost:389
104
+ username: cn=netdata,dc=example,dc=com
105
+ password: secret
106
+ - name: Multi-instance
107
+ description: |
108
+ > **Note**: When you define multiple jobs, their names must be unique.
109
+
110
+ Collecting metrics from local and remote instances.
111
+ config: |
112
+ jobs:
113
+ - name: local
114
+ url: ldap://localhost:389
115
+ username: cn=netdata,dc=example,dc=com
116
+ password: secret
117
+
118
+ - name: remote
119
+ url: ldap://192.0.2.1:389
120
+ username: cn=netdata,dc=example,dc=com
121
+ password: secret
122
+ troubleshooting:
123
+ problems:
124
+ list: []
125
+ alerts: []
126
+ metrics:
127
+ folding:
128
+ title: Metrics
129
+ enabled: false
130
+ description: ""
131
+ availability: []
132
+ scopes:
133
+ - name: global
134
+ description: "These metrics refer to the entire monitored application."
135
+ labels: []
136
+ metrics:
137
+ - name: openldap.current_connections
138
+ description: Current Connections
139
+ unit: "connections"
140
+ chart_type: line
141
+ dimensions:
142
+ - name: active
143
+ - name: openldap.connections
144
+ description: Connections
145
+ unit: "connections/s"
146
+ chart_type: line
147
+ dimensions:
148
+ - name: connections
149
+ - name: openldap.traffic
150
+ description: Traffic
151
+ unit: "bytes/s"
152
+ chart_type: area
153
+ dimensions:
154
+ - name: sent
155
+ - name: openldap.entries
156
+ description: Entries
157
+ unit: "entries/s"
158
+ chart_type: line
159
+ dimensions:
160
+ - name: sent
161
+ - name: openldap.referrals
162
+ description: Referrals
163
+ unit: "referrals/s"
164
+ chart_type: line
165
+ dimensions:
166
+ - name: sent
167
+ - name: openldap.operations
168
+ description: Operations
169
+ unit: "operations/s"
170
+ chart_type: line
171
+ dimensions:
172
+ - name: completed
173
+ - name: initiated
174
+ - name: openldap.operations_by_type
175
+ description: Operations by Typ
176
+ unit: "operations/s"
177
+ chart_type: stacked
178
+ dimensions:
179
+ - name: bind
180
+ - name: search
181
+ - name: unbind
182
+ - name: add
183
+ - name: delete
184
+ - name: modify
185
+ - name: compare
186
+ - name: openldap.waiters
187
+ description: Waiters
188
+ unit: "waiters/s"
189
+ chart_type: line
190
+ dimensions:
191
+ - name: write
192
+ - name: read
src/go/plugin/go.d/modules/openldap/openldap.go
new
+115
@@ -0,0 +1,115 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ _ "embed"
7
+ "errors"
8
+ "time"
9
+
10
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
11
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/confopt"
12
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/tlscfg"
13
+)
14
+
15
+//go:embed "config_schema.json"
16
+var configSchema string
17
+
18
+func init() {
19
+ module.Register("openldap", module.Creator{
20
+ JobConfigSchema: configSchema,
21
+ Defaults: module.Defaults{
22
+ UpdateEvery: 1,
23
+ },
24
+ Create: func() module.Module { return New() },
25
+ Config: func() any { return &Config{} },
26
+ })
27
+}
28
+
29
+func New() *OpenLDAP {
30
+ return &OpenLDAP{
31
+ Config: Config{
32
+ URL: "ldap://127.0.0.1:389",
33
+ Timeout: confopt.Duration(time.Second * 2),
34
+ },
35
+
36
+ newConn: newLdapConn,
37
+
38
+ charts: charts.Copy(),
39
+ }
40
+
41
+}
42
+
43
+type Config struct {
44
+ UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
45
+ URL string `yaml:"url" json:"url"`
46
+ Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
47
+ Username string `yaml:"username" json:"username"`
48
+ Password string `yaml:"password" json:"password"`
49
+ tlscfg.TLSConfig `yaml:",inline" json:""`
50
+}
51
+
52
+type OpenLDAP struct {
53
+ module.Base
54
+ Config `yaml:",inline" json:""`
55
+
56
+ charts *module.Charts
57
+
58
+ conn ldapConn
59
+ newConn func(Config) ldapConn
60
+}
61
+
62
+func (l *OpenLDAP) Configuration() any {
63
+ return l.Config
64
+}
65
+
66
+func (l *OpenLDAP) Init() error {
67
+ if l.URL == "" {
68
+ return errors.New("empty LDAP server url")
69
+ }
70
+ if l.Username == "" {
71
+ return errors.New("empty LDAP username")
72
+ }
73
+
74
+ return nil
75
+}
76
+
77
+func (l *OpenLDAP) Check() error {
78
+ mx, err := l.collect()
79
+ if err != nil {
80
+ l.Error(err)
81
+ return err
82
+ }
83
+
84
+ if len(mx) == 0 {
85
+ return errors.New("no metrics collected")
86
+ }
87
+
88
+ return nil
89
+}
90
+
91
+func (l *OpenLDAP) Charts() *module.Charts {
92
+ return l.charts
93
+}
94
+
95
+func (l *OpenLDAP) Collect() map[string]int64 {
96
+ mx, err := l.collect()
97
+ if err != nil {
98
+ l.Error(err)
99
+ }
100
+
101
+ if len(mx) == 0 {
102
+ return nil
103
+ }
104
+
105
+ return mx
106
+}
107
+
108
+func (l *OpenLDAP) Cleanup() {
109
+ if l.conn != nil {
110
+ if err := l.conn.disconnect(); err != nil {
111
+ l.Warningf("error disconnecting ldap client: %v", err)
112
+ }
113
+ l.conn = nil
114
+ }
115
+}
src/go/plugin/go.d/modules/openldap/openldap_test.go
new
+363
@@ -0,0 +1,363 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package openldap
4
+
5
+import (
6
+ "errors"
7
+ "fmt"
8
+ "os"
9
+ "testing"
10
+
11
+ "github.com/go-ldap/ldap/v3"
12
+ "github.com/stretchr/testify/assert"
13
+ "github.com/stretchr/testify/require"
14
+
15
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
16
+)
17
+
18
+var (
19
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
20
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
21
+)
22
+
23
+func Test_testDataIsValid(t *testing.T) {
24
+ for name, data := range map[string][]byte{
25
+ "dataConfigJSON": dataConfigJSON,
26
+ "dataConfigYAML": dataConfigYAML,
27
+ } {
28
+ assert.NotNil(t, data, name)
29
+ }
30
+}
31
+
32
+func TestOpenLDAP_ConfigurationSerialize(t *testing.T) {
33
+ module.TestConfigurationSerialize(t, &OpenLDAP{}, dataConfigJSON, dataConfigYAML)
34
+}
35
+
36
+func TestOpenLDAP_Init(t *testing.T) {
37
+ tests := map[string]struct {
38
+ config Config
39
+ wantFail bool
40
+ }{
41
+ "fails with default config": {
42
+ wantFail: true,
43
+ config: New().Config,
44
+ },
45
+ "fails if URL not set": {
46
+ wantFail: true,
47
+ config: func() Config {
48
+ conf := New().Config
49
+ conf.URL = ""
50
+ return conf
51
+ }(),
52
+ },
53
+ }
54
+
55
+ for name, test := range tests {
56
+ t.Run(name, func(t *testing.T) {
57
+ oldap := New()
58
+ oldap.Config = test.config
59
+
60
+ if test.wantFail {
61
+ assert.Error(t, oldap.Init())
62
+ } else {
63
+ assert.NoError(t, oldap.Init())
64
+ }
65
+ })
66
+ }
67
+}
68
+
69
+func TestOpenLDAP_Cleanup(t *testing.T) {
70
+ tests := map[string]struct {
71
+ prepare func() *OpenLDAP
72
+ }{
73
+ "not initialized": {
74
+ prepare: func() *OpenLDAP {
75
+ return New()
76
+ },
77
+ },
78
+ "after check": {
79
+ prepare: func() *OpenLDAP {
80
+ oldap := New()
81
+ oldap.newConn = func(Config) ldapConn { return prepareMockOk() }
82
+ _ = oldap.Check()
83
+ return oldap
84
+ },
85
+ },
86
+ "after collect": {
87
+ prepare: func() *OpenLDAP {
88
+ oldap := New()
89
+ oldap.newConn = func(Config) ldapConn { return prepareMockOk() }
90
+ _ = oldap.Collect()
91
+ return oldap
92
+ },
93
+ },
94
+ }
95
+
96
+ for name, test := range tests {
97
+ t.Run(name, func(t *testing.T) {
98
+ oldap := test.prepare()
99
+
100
+ assert.NotPanics(t, oldap.Cleanup)
101
+ })
102
+ }
103
+}
104
+
105
+func TestOpenLDAP_Charts(t *testing.T) {
106
+ assert.NotNil(t, New().Charts())
107
+}
108
+
109
+func TestOpenLDAP_Check(t *testing.T) {
110
+ tests := map[string]struct {
111
+ prepareMock func() *mockOpenLDAPConn
112
+ wantFail bool
113
+ }{
114
+ "success case": {
115
+ wantFail: false,
116
+ prepareMock: prepareMockOk,
117
+ },
118
+ "err on connect": {
119
+ wantFail: true,
120
+ prepareMock: prepareMockErrOnConnect,
121
+ },
122
+ "err on search": {
123
+ wantFail: true,
124
+ prepareMock: prepareMockErrOnSearch,
125
+ },
126
+ }
127
+
128
+ for name, test := range tests {
129
+ t.Run(name, func(t *testing.T) {
130
+ oldap := New()
131
+ mock := test.prepareMock()
132
+ oldap.newConn = func(Config) ldapConn { return mock }
133
+
134
+ if test.wantFail {
135
+ assert.Error(t, oldap.Check())
136
+ } else {
137
+ assert.NoError(t, oldap.Check())
138
+ }
139
+ })
140
+ }
141
+}
142
+
143
+func TestOpenLDAP_Collect(t *testing.T) {
144
+ tests := map[string]struct {
145
+ prepareMock func() *mockOpenLDAPConn
146
+ wantMetrics map[string]int64
147
+ disconnectBeforeCleanup bool
148
+ disconnectAfterCleanup bool
149
+ }{
150
+ "success case": {
151
+ prepareMock: prepareMockOk,
152
+ disconnectBeforeCleanup: false,
153
+ disconnectAfterCleanup: true,
154
+ wantMetrics: map[string]int64{
155
+ "bytes_sent": 1,
156
+ "completed_add_operations": 1,
157
+ "completed_bind_operations": 1,
158
+ "completed_compare_operations": 1,
159
+ "completed_delete_operations": 1,
160
+ "completed_modify_operations": 1,
161
+ "completed_operations": 7,
162
+ "completed_search_operations": 1,
163
+ "completed_unbind_operations": 1,
164
+ "current_connections": 1,
165
+ "entries_sent": 1,
166
+ "initiated_add_operations": 1,
167
+ "initiated_bind_operations": 1,
168
+ "initiated_compare_operations": 1,
169
+ "initiated_delete_operations": 1,
170
+ "initiated_modify_operations": 1,
171
+ "initiated_operations": 7,
172
+ "initiated_search_operations": 1,
173
+ "initiated_unbind_operations": 1,
174
+ "read_waiters": 1,
175
+ "referrals_sent": 1,
176
+ "total_connections": 1,
177
+ "write_waiters": 1,
178
+ },
179
+ },
180
+ "err on connect": {
181
+ prepareMock: prepareMockErrOnConnect,
182
+ disconnectBeforeCleanup: false,
183
+ disconnectAfterCleanup: false,
184
+ },
185
+ "err on search": {
186
+ prepareMock: prepareMockErrOnSearch,
187
+ disconnectBeforeCleanup: true,
188
+ disconnectAfterCleanup: true,
189
+ },
190
+ }
191
+
192
+ for name, test := range tests {
193
+ t.Run(name, func(t *testing.T) {
194
+ oldap := New()
195
+ mock := test.prepareMock()
196
+ oldap.newConn = func(Config) ldapConn { return mock }
197
+
198
+ mx := oldap.Collect()
199
+
200
+ require.Equal(t, test.wantMetrics, mx)
201
+
202
+ if len(test.wantMetrics) > 0 {
203
+ module.TestMetricsHasAllChartsDims(t, oldap.Charts(), mx)
204
+ }
205
+
206
+ assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
207
+ oldap.Cleanup()
208
+ assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
209
+ })
210
+ }
211
+}
212
+
213
+func prepareMockOk() *mockOpenLDAPConn {
214
+ return &mockOpenLDAPConn{
215
+ dataSearchMonCounters: &ldap.SearchResult{
216
+ Entries: []*ldap.Entry{
217
+ {
218
+ DN: "cn=Current,cn=Connections,cn=Monitor",
219
+ Attributes: []*ldap.EntryAttribute{
220
+ {Name: attrMonitorCounter, Values: []string{"1"}},
221
+ },
222
+ },
223
+ {
224
+ DN: "cn=Total,cn=Connections,cn=Monitor",
225
+ Attributes: []*ldap.EntryAttribute{
226
+ {Name: attrMonitorCounter, Values: []string{"1"}},
227
+ },
228
+ },
229
+ {
230
+ DN: "cn=Bytes,cn=Statistics,cn=Monitor",
231
+ Attributes: []*ldap.EntryAttribute{
232
+ {Name: attrMonitorCounter, Values: []string{"1"}},
233
+ },
234
+ },
235
+ {
236
+ DN: "cn=Referrals,cn=Statistics,cn=Monitor",
237
+ Attributes: []*ldap.EntryAttribute{
238
+ {Name: attrMonitorCounter, Values: []string{"1"}},
239
+ },
240
+ },
241
+ {
242
+ DN: "cn=Entries,cn=Statistics,cn=Monitor",
243
+ Attributes: []*ldap.EntryAttribute{
244
+ {Name: attrMonitorCounter, Values: []string{"1"}},
245
+ },
246
+ },
247
+ {
248
+ DN: "cn=Write,cn=Waiters,cn=Monitor",
249
+ Attributes: []*ldap.EntryAttribute{
250
+ {Name: attrMonitorCounter, Values: []string{"1"}},
251
+ },
252
+ },
253
+ {
254
+ DN: "cn=Read,cn=Waiters,cn=Monitor",
255
+ Attributes: []*ldap.EntryAttribute{
256
+ {Name: attrMonitorCounter, Values: []string{"1"}},
257
+ },
258
+ },
259
+ },
260
+ },
261
+ dataSearchMonOperations: &ldap.SearchResult{
262
+ Entries: []*ldap.Entry{
263
+ {
264
+ DN: "cn=Bind,cn=Operations,cn=Monitor",
265
+ Attributes: []*ldap.EntryAttribute{
266
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
267
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
268
+ },
269
+ },
270
+ {
271
+ DN: "cn=Unbind,cn=Operations,cn=Monitor",
272
+ Attributes: []*ldap.EntryAttribute{
273
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
274
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
275
+ },
276
+ },
277
+ {
278
+ DN: "cn=Add,cn=Operations,cn=Monitor",
279
+ Attributes: []*ldap.EntryAttribute{
280
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
281
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
282
+ },
283
+ },
284
+ {
285
+ DN: "cn=Delete,cn=Operations,cn=Monitor",
286
+ Attributes: []*ldap.EntryAttribute{
287
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
288
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
289
+ },
290
+ },
291
+ {
292
+ DN: "cn=Modify,cn=Operations,cn=Monitor",
293
+ Attributes: []*ldap.EntryAttribute{
294
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
295
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
296
+ },
297
+ },
298
+ {
299
+ DN: "cn=Compare,cn=Operations,cn=Monitor",
300
+ Attributes: []*ldap.EntryAttribute{
301
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
302
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
303
+ },
304
+ },
305
+ {
306
+ DN: "cn=Search,cn=Operations,cn=Monitor",
307
+ Attributes: []*ldap.EntryAttribute{
308
+ {Name: attrMonitorOpInitiated, Values: []string{"1"}},
309
+ {Name: attrMonitorOpCompleted, Values: []string{"1"}},
310
+ },
311
+ },
312
+ },
313
+ },
314
+ }
315
+}
316
+
317
+func prepareMockErrOnConnect() *mockOpenLDAPConn {
318
+ return &mockOpenLDAPConn{
319
+ errOnConnect: true,
320
+ }
321
+}
322
+
323
+func prepareMockErrOnSearch() *mockOpenLDAPConn {
324
+ return &mockOpenLDAPConn{
325
+ errOnSearch: true,
326
+ }
327
+}
328
+
329
+type mockOpenLDAPConn struct {
330
+ errOnConnect bool
331
+ disconnectCalled bool
332
+
333
+ dataSearchMonCounters *ldap.SearchResult
334
+ dataSearchMonOperations *ldap.SearchResult
335
+ errOnSearch bool
336
+}
337
+
338
+func (m *mockOpenLDAPConn) connect() error {
339
+ if m.errOnConnect {
340
+ return errors.New("mock.connect() error")
341
+ }
342
+ return nil
343
+}
344
+
345
+func (m *mockOpenLDAPConn) disconnect() error {
346
+ m.disconnectCalled = true
347
+ return nil
348
+}
349
+
350
+func (m *mockOpenLDAPConn) search(req *ldap.SearchRequest) (*ldap.SearchResult, error) {
351
+ if m.errOnSearch {
352
+ return nil, errors.New("mock.search() error")
353
+ }
354
+
355
+ switch req.BaseDN {
356
+ case "cn=Monitor":
357
+ return m.dataSearchMonCounters, nil
358
+ case "cn=Operations,cn=Monitor":
359
+ return m.dataSearchMonOperations, nil
360
+ default:
361
+ return nil, fmt.Errorf("mock.search(): unknown BaseDSN: %s", req.BaseDN)
362
+ }
363
+}
src/go/plugin/go.d/modules/openldap/testdata/config.json
new
+11
@@ -0,0 +1,11 @@
1
+{
2
+ "update_every": 123,
3
+ "url": "ok",
4
+ "timeout": 123.123,
5
+ "username": "ok",
6
+ "password": "ok",
7
+ "tls_ca": "ok",
8
+ "tls_cert": "ok",
9
+ "tls_key": "ok",
10
+ "tls_skip_verify": false
11
+}
src/go/plugin/go.d/modules/openldap/testdata/config.yaml
new
+8
@@ -0,0 +1,8 @@
1
+update_every: 123
2
+url: "ok"
3
+timeout: 123.123
4
+username: "ok"
5
+password: "ok"
6
+tls_ca: "ok"
7
+tls_cert: "ok"
8
+tls_key: "ok"