Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add input plugin for OpenLDAP #2612

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0c2f633
Add input plugin for OpenLDAP
acobaugh Apr 3, 2017
2106ed0
Run go fmt for the openldap plugin
acobaugh Apr 3, 2017
0728537
Forgot to run gdm restore/save.
acobaugh Apr 3, 2017
0a2ff9d
openldap: cannot close a connection that isn't open
acobaugh Apr 5, 2017
8c95bb0
openldap: initial stab at some simple unit tests
acobaugh Apr 5, 2017
507e338
openldap: get TestOpenldapNoConnection() working
acobaugh Apr 5, 2017
9f58b37
openldap: add ldif file for the openldap docker container
acobaugh Apr 6, 2017
069be71
openldap: split out the code that parses the search result into its o…
acobaugh Apr 6, 2017
3f78c5c
openldap: add TestOpenldapMockResult(), put our common tests in runTe…
acobaugh Apr 6, 2017
61a38f3
openldap: get the rest of the test functions working
acobaugh Apr 7, 2017
8965523
openldap: go fmt
acobaugh Apr 7, 2017
5c812b8
openldap: monitor backend is now part of the image
acobaugh Apr 7, 2017
b778d8f
Makefile: add openldap docker commands
acobaugh Apr 7, 2017
de0692f
Add openldap container to docker-run-circle make target
acobaugh Apr 7, 2017
5c30a1e
Merge branch 'master' of https://github.com/influxdata/telegraf
acobaugh Apr 13, 2017
845a0c1
openldap: gatherSearchResults() always returns nil, so remove the ret…
acobaugh Apr 13, 2017
feb8ff3
openldap: all field values should be ints, not floats
acobaugh Apr 13, 2017
de99556
openldap: add tls_cacertificate option
acobaugh Apr 24, 2017
df187bf
openlda: set tls.Config{ServerName} to Host, add toml tags to our str…
acobaugh Apr 24, 2017
fc5eb36
openldap: merge local openldap branch
acobaugh Apr 24, 2017
bb4340b
openldap: go fmt
acobaugh Apr 24, 2017
1a5f908
openldap: switch over to internal.GetTLSConfig
acobaugh Apr 30, 2017
ac2f2d0
openldap: update the sample config and readme
acobaugh Apr 30, 2017
4a47c60
openldap: expose port 636 for the openldap container
acobaugh Jun 28, 2017
1a29eef
openldap: make ssl option a string, support ldaps
acobaugh Jun 28, 2017
a9fb95f
openldap: update README.md per recent changes to the config
acobaugh Jun 28, 2017
1451064
Merge branch 'master' of https://github.com/influxdata/telegraf
acobaugh Jun 28, 2017
80759b0
openldap: re-run gdm save
acobaugh Jun 28, 2017
0e6230c
openldap: add messages to the common tests
acobaugh Jun 28, 2017
80dd38b
openldap: need to switch to HasInt64Field because of changes in #2813
acobaugh Jun 28, 2017
49a27d1
openldap: fix capitalization of InsecureSkipVerify and SslCa
acobaugh Jul 14, 2017
acb4392
openldap: update sample config
acobaugh Jul 14, 2017
a31e5f6
openldap: update README sample config and sample output
acobaugh Jul 14, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Godeps
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ github.com/aerospike/aerospike-client-go 95e1ad7791bdbca44707fedbb29be42024900d9
github.com/amir/raidman c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985
github.com/aws/aws-sdk-go c861d27d0304a79f727e9a8a4e2ac1e74602fdc0
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
github.com/bsm/sarama-cluster ccdc0803695fbce22f1706d04ded46cd518fd832
github.com/cenkalti/backoff b02f2bbce11d7ea6b97f282ef1771b0fe2f65ef3
github.com/couchbase/go-couchbase bfe555a140d53dc1adf390f1a1d4b0fd4ceadb28
github.com/couchbase/gomemcached 4a25d2f4e1dea9ea7dd76dfd943407abf9b07d29
Expand All @@ -29,7 +30,6 @@ github.com/jackc/pgx b84338d7d62598f75859b2b146d830b22f1b9ec8
github.com/kardianos/osext c2c54e542fb797ad986b31721e1baedf214ca413
github.com/kardianos/service 6d3a0ee7d3425d9d835debc51a0ca1ffa28f4893
github.com/kballard/go-shellquote d8ec1a69a250a17bb0e419c386eac1f3711dc142
github.com/klauspost/crc32 cb6bfca970f6908083f26f39a79009d608efd5cd
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c
github.com/miekg/dns 99f84ae56e75126dd77e5de4fae2ea034a468ca1
github.com/naoina/go-stringutil 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b
Expand All @@ -52,15 +52,16 @@ github.com/streadway/amqp 63795daa9a446c920826655f26ba31c81c860fd6
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
github.com/vjeantet/grok d73e972b60935c7fec0b4ffbc904ed39ecaf7efe
github.com/wvanbergen/kafka bc265fedb9ff5b5c5d3c0fdcef4a819b3523d3ee
github.com/bsm/sarama-cluster ccdc0803695fbce22f1706d04ded46cd518fd832
github.com/wvanbergen/kazoo-go 968957352185472eacb69215fa3dbfcfdbac1096
github.com/yuin/gopher-lua 66c871e454fcf10251c61bf8eff02d0978cae75a
github.com/zensqlmonitor/go-mssqldb ffe5510c6fa5e15e6d983210ab501c815b56b363
golang.org/x/crypto dc137beb6cce2043eb6b5f223ab8bf51c32459f4
golang.org/x/net f2499483f923065a842d38eb4c7f1927e6fc6e6d
golang.org/x/text 506f9d5c962f284575e88337e7d9296d27e729d3
gopkg.in/asn1-ber.v1 4e86f4367175e39f69d9358a5f17b4dda270378d
gopkg.in/fatih/pool.v2 6e328e67893eb46323ad06f0e92cb9536babbabc
gopkg.in/gorethink/gorethink.v3 7ab832f7b65573104a555d84a27992ae9ea1f659
gopkg.in/ldap.v2 8168ee085ee43257585e50c6441aadf54ecb2c9f
gopkg.in/mgo.v2 3f83fa5005286a7fe593b055f0d7771a7dce4655
gopkg.in/olivere/elastic.v5 ee3ebceab960cf68ab9a89ee6d78c031ef5b4a4e
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ docker-run:
docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann
docker run --name nats -p "4222:4222" -d nats
docker run --name openldap \
-e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \
-e SLAPD_CONFIG_ROOTPW="secret" \
-p "389:389" -p "636:636" \
-d cobaugh/openldap-alpine

# Run docker containers necessary for CircleCI unit tests
docker-run-circle:
Expand All @@ -88,11 +93,16 @@ docker-run-circle:
docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann
docker run --name nats -p "4222:4222" -d nats
docker run --name openldap \
-e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \
-e SLAPD_CONFIG_ROOTPW="secret" \
-p "389:389" -p "636:636" \
-d cobaugh/openldap-alpine

# Kill all docker containers, ignore errors
docker-kill:
-docker kill nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch
-docker rm nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch
-docker kill nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch openldap
-docker rm nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch openldap

# Run full unit tests using docker containers (includes setup and teardown)
test: vet docker-kill docker-run
Expand Down
1 change: 1 addition & 0 deletions plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer"
_ "github.com/influxdata/telegraf/plugins/inputs/nstat"
_ "github.com/influxdata/telegraf/plugins/inputs/ntpq"
_ "github.com/influxdata/telegraf/plugins/inputs/openldap"
_ "github.com/influxdata/telegraf/plugins/inputs/passenger"
_ "github.com/influxdata/telegraf/plugins/inputs/phpfpm"
_ "github.com/influxdata/telegraf/plugins/inputs/ping"
Expand Down
82 changes: 82 additions & 0 deletions plugins/inputs/openldap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Openldap Input Plugin

This plugin gathers metrics from OpenLDAP's cn=Monitor backend.

### Configuration:

```toml
[[inputs.openldap]]
host = "localhost"
port = 389

# ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.
# note that port will likely need to be changed to 636 for ldaps
# valid options: "" | "starttls" | "ldaps"
ssl = ""

# skip peer certificate verification. Default is false.
insecure_skip_verify = false

# Path to PEM-encoded Root certificate to use to verify server certificate
ssl_ca = "/etc/ssl/certs.pem"

# dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.
bind_dn = ""
bind_password = ""
```

### Measurements & Fields:

All **monitorCounter**, **monitorOpInitiated**, and **monitorOpCompleted** attributes are gathered based on this LDAP query:

```(|(objectClass=monitorCounterObject)(objectClass=monitorOperation))```

Metric names are based on their entry DN.

Metrics for the **monitorOp*** attributes have **_initiated** and **_completed** added to the base name.

An OpenLDAP 2.4 server will provide these metrics:

- openldap
- max_file_descriptors_connections
- current_connections
- total_connections
- abandon_operations_completed
- abandon_operations_initiated
- add_operations_completed
- add_operations_initiated
- bind_operations_completed
- bind_operations_initiated
- compare_operations_completed
- compare_operations_initiated
- delete_operations_completed
- delete_operations_initiated
- extended_operations_completed
- extended_operations_initiated
- modify_operations_completed
- modify_operations_initiated
- modrdn_operations_completed
- modrdn_operations_initiated
- search_operations_completed
- search_operations_initiated
- unbind_operations_completed
- unbind_operations_initiated
- bytes_statistics
- entries_statistics
- pdu_statistics
- referrals_statistics
- read_waiters
- write_waiters

### Tags:

- server= # value from config
- port= # value from config

### Example Output:

```
$ telegraf -config telegraf.conf -input-filter openldap -test --debug
* Plugin: inputs.openldap, Collection 1
> openldap,server=localhost,port=389,host=zirzla search_operations_completed=2i,delete_operations_completed=0i,read_waiters=1i,total_connections=1004i,bind_operations_completed=3i,unbind_operations_completed=3i,referrals_statistics=0i,current_connections=1i,bind_operations_initiated=3i,compare_operations_completed=0i,add_operations_completed=2i,delete_operations_initiated=0i,unbind_operations_initiated=3i,search_operations_initiated=3i,add_operations_initiated=2i,max_file_descriptors_connections=4096i,abandon_operations_initiated=0i,write_waiters=0i,modrdn_operations_completed=0i,abandon_operations_completed=0i,pdu_statistics=23i,modify_operations_initiated=0i,bytes_statistics=1660i,entries_statistics=17i,compare_operations_initiated=0i,modrdn_operations_initiated=0i,extended_operations_completed=0i,modify_operations_completed=0i,extended_operations_initiated=0i 1499990455000000000
```
177 changes: 177 additions & 0 deletions plugins/inputs/openldap/openldap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package openldap

import (
"fmt"
"gopkg.in/ldap.v2"
"strconv"
"strings"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
)

type Openldap struct {
Host string
Port int
Ssl string
InsecureSkipVerify bool
SslCa string
BindDn string
BindPassword string
}

const sampleConfig string = `
host = "localhost"
port = 389

# ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.
# note that port will likely need to be changed to 636 for ldaps
# valid options: "" | "starttls" | "ldaps"
ssl = ""

# skip peer certificate verification. Default is false.
insecure_skip_verify = false

# Path to PEM-encoded Root certificate to use to verify server certificate
ssl_ca = "/etc/ssl/certs.pem"

# dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.
bind_dn = ""
bind_password = ""
`

var searchBase = "cn=Monitor"
var searchFilter = "(|(objectClass=monitorCounterObject)(objectClass=monitorOperation))"
var searchAttrs = []string{"monitorCounter", "monitorOpInitiated", "monitorOpCompleted"}
var attrTranslate = map[string]string{
"monitorCounter": "",
"monitorOpInitiated": "_initiated",
"monitorOpCompleted": "_completed",
}

func (o *Openldap) SampleConfig() string {
return sampleConfig
}

func (o *Openldap) Description() string {
return "OpenLDAP cn=Monitor plugin"
}

// return an initialized Openldap
func NewOpenldap() *Openldap {
return &Openldap{
Host: "localhost",
Port: 389,
Ssl: "",
InsecureSkipVerify: false,
SslCa: "",
BindDn: "",
BindPassword: "",
}
}

// gather metrics
func (o *Openldap) Gather(acc telegraf.Accumulator) error {
var err error
var l *ldap.Conn
if o.Ssl != "" {
// build tls config
tlsConfig, err := internal.GetTLSConfig("", "", o.SslCa, o.InsecureSkipVerify)
if err != nil {
acc.AddError(err)
return nil
}
if o.Ssl == "ldaps" {
l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port), tlsConfig)
if err != nil {
acc.AddError(err)
return nil
}
} else if o.Ssl == "starttls" {
l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port))
if err != nil {
acc.AddError(err)
return nil
}
err = l.StartTLS(tlsConfig)
} else {
acc.AddError(fmt.Errorf("Invalid setting for ssl: %s", o.Ssl))
return nil
}
} else {
l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port))
}

if err != nil {
acc.AddError(err)
return nil
}
defer l.Close()

// username/password bind
if o.BindDn != "" && o.BindPassword != "" {
err = l.Bind(o.BindDn, o.BindPassword)
if err != nil {
acc.AddError(err)
return nil
}
}

searchRequest := ldap.NewSearchRequest(
searchBase,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
searchFilter,
searchAttrs,
nil,
)

sr, err := l.Search(searchRequest)
if err != nil {
acc.AddError(err)
return nil
}

gatherSearchResult(sr, o, acc)

return nil
}

func gatherSearchResult(sr *ldap.SearchResult, o *Openldap, acc telegraf.Accumulator) {
fields := map[string]interface{}{}
tags := map[string]string{
"server": o.Host,
"port": strconv.Itoa(o.Port),
}
for _, entry := range sr.Entries {
metricName := dnToMetric(entry.DN, searchBase)
for _, attr := range entry.Attributes {
if len(attr.Values[0]) >= 1 {
if v, err := strconv.ParseInt(attr.Values[0], 10, 64); err == nil {
fields[metricName+attrTranslate[attr.Name]] = v
}
}
}
}
acc.AddFields("openldap", fields, tags)
return
}

// Convert a DN to metric name, eg cn=Read,cn=Waiters,cn=Monitor to read_waiters
func dnToMetric(dn, searchBase string) string {
metricName := strings.Trim(dn, " ")
metricName = strings.Replace(metricName, " ", "_", -1)
metricName = strings.ToLower(metricName)
metricName = strings.TrimPrefix(metricName, "cn=")
metricName = strings.Replace(metricName, strings.ToLower(searchBase), "", -1)
metricName = strings.Replace(metricName, "cn=", "_", -1)
return strings.Replace(metricName, ",", "", -1)
}

func init() {
inputs.Add("openldap", func() telegraf.Input { return NewOpenldap() })
}
Loading