forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0f55d9e
commit b0f1292
Showing
4 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Openldap Input Plugin | ||
|
||
This plugin gathers metrics from OpenLDAP's cn=Monitor backend. | ||
|
||
### Configuration: | ||
|
||
To use this plugin you must enable the [monitoring](https://www.openldap.org/devel/admin/monitoringslapd.html) backend. | ||
|
||
```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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
package ldap_response | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"gopkg.in/ldap.v2" | ||
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/internal" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
) | ||
|
||
type Ldap struct { | ||
Host string | ||
Port int | ||
Ssl string | ||
InsecureSkipVerify bool | ||
SslCa string | ||
BindDn string | ||
BindPassword string | ||
SearchBase string | ||
SearchFilter string | ||
SearchAttributes []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 = "" | ||
# base entry for searches | ||
search_base = "" | ||
# ldap search to perform. If search_filter is empty, the bind_dn is used. | ||
search_filter = "" | ||
# the attributes to return as fields | ||
search_attributes = [ | ||
"attribute1", | ||
"attribute2", | ||
] | ||
` | ||
|
||
var DefaultSearchFilter = "(objectClass=*)" | ||
var DefaultSearchAttributes = []string{"objectclass"} | ||
|
||
func (l *Ldap) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
func (l *Ldap) Description() string { | ||
return "LDAP Response Input Plugin" | ||
} | ||
|
||
// return an initialized Ldap | ||
func NewLdap() *Ldap { | ||
return &Ldap{ | ||
Host: "localhost", | ||
Port: 389, | ||
} | ||
} | ||
|
||
// gather metrics | ||
func (l *Ldap) Gather(acc telegraf.Accumulator) error { | ||
var err error | ||
var server *ldap.Conn | ||
beforeConnect := time.Now() | ||
if l.Ssl != "" { | ||
// build tls config | ||
tlsConfig, err := internal.GetTLSConfig("", "", l.SslCa, l.InsecureSkipVerify) | ||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
if l.Ssl == "ldaps" { | ||
server, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", l.Host, l.Port), tlsConfig) | ||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
} else if l.Ssl == "starttls" { | ||
server, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", l.Host, l.Port)) | ||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
err = server.StartTLS(tlsConfig) | ||
} else { | ||
acc.AddError(fmt.Errorf("Invalid setting for ssl: %s", l.Ssl)) | ||
return nil | ||
} | ||
} else { | ||
server, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", l.Host, l.Port)) | ||
} | ||
afterConnect := time.Now() | ||
|
||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
defer server.Close() | ||
|
||
// username/password bind | ||
beforeBind := time.Now() | ||
if l.BindDn != "" && l.BindPassword != "" { | ||
err = server.Bind(l.BindDn, l.BindPassword) | ||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
} | ||
afterBind := time.Now() | ||
|
||
if l.SearchFilter == "" { | ||
l.SearchFilter = DefaultSearchFilter | ||
} | ||
if len(l.SearchAttributes) == 0 { | ||
l.SearchAttributes = DefaultSearchAttributes | ||
} | ||
|
||
searchRequest := ldap.NewSearchRequest( | ||
l.SearchBase, | ||
ldap.ScopeSingleLevel, | ||
ldap.NeverDerefAliases, | ||
1000, | ||
60, | ||
false, | ||
l.SearchFilter, | ||
l.SearchAttributes, | ||
nil, | ||
) | ||
|
||
beforeSearch := time.Now() | ||
sr, err := server.Search(searchRequest) | ||
afterSearch := time.Now() | ||
if err != nil { | ||
acc.AddError(err) | ||
return nil | ||
} | ||
|
||
fields := map[string]interface{}{ | ||
"connect_time_ms": float64(afterConnect.Sub(beforeConnect).Nanoseconds()) / 1000 / 1000, | ||
"bind_time_ms": float64(afterBind.Sub(beforeBind).Nanoseconds()) / 1000 / 1000, | ||
"query_time_ms": float64(afterSearch.Sub(beforeSearch).Nanoseconds()) / 1000 / 1000, | ||
"total_time_ms": float64(afterSearch.Sub(beforeConnect).Nanoseconds()) / 1000 / 1000, | ||
} | ||
|
||
gatherSearchResult(fields, sr, l, acc) | ||
|
||
return nil | ||
} | ||
|
||
func gatherSearchResult(fields map[string]interface{}, sr *ldap.SearchResult, l *Ldap, acc telegraf.Accumulator) { | ||
tags := map[string]string{ | ||
"server": l.Host, | ||
"port": strconv.Itoa(l.Port), | ||
} | ||
for _, entry := range sr.Entries { | ||
metricName := dnToMetric(entry.DN, l.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+attr.Name] = v | ||
} | ||
} | ||
} | ||
} | ||
acc.AddFields("ldap_response", 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("ldap_response", func() telegraf.Input { return NewLdap() }) | ||
} |
Oops, something went wrong.