Skip to content

Instantly share code, notes, and snippets.

@kimor79
Created June 4, 2014 15:52
Show Gist options
  • Save kimor79/684e2e7777f4f48037e9 to your computer and use it in GitHub Desktop.
Save kimor79/684e2e7777f4f48037e9 to your computer and use it in GitHub Desktop.
openldap plugin collectd original email
Hi,
I've managed to cobble together an openldap plugin to monitor the various
counters from an openldap server. This is based mainly off of the apache and
mysql plugins. I am not a c programmer so apologies if the code is horrible.
Two things I need help on are:
1) Initializing the global ldap options. I don't know where this would go.
From ldap_open(3):
Note: the first call into the LDAP library also initializes the global
options for the library. As such the first call should be single-
threaded or otherwise protected to insure that only one call is active.
It is recommended that ldap_get_option() or ldap_set_option() be used
in the program's main thread before any additional threads are created.
See ldap_get_option(3).
2) Specifying a timeout. LDAP_OPT_TIMEOUT needs to be a struct timeval * but I
couldn't work out the proper way to define and use it.
The full diff is available in my githhub clone of collectd5 in the
kimor79/openldap branch:
https://github.com/kimor79/collectd/commit/e08947a62a7b48b8e6d82e742379709be1633a25
https://github.com/kimor79/collectd/commit/c871b9095d60c641dd2cb81323bac412fc1de5de
Thanks
Kimo
#include "collectd.h"
#include "common.h"
#include "plugin.h"
#include "configfile.h"
#include <lber.h>
#include <ldap.h>
struct ldap_s /* {{{ */
{
char *name;
char *cacert;
char *host;
int state;
int starttls;
int timeout;
char *url;
int verifyhost;
int version;
LDAP *ld;
char *dn;
};
typedef struct ldap_s ldap_t; /* }}} */
static int ldap_read_host (user_data_t *ud);
static void ldap_free (ldap_t *st) /* {{{ */
{
if(st == NULL)
return;
sfree (st->cacert);
sfree (st->host);
sfree (st->name);
sfree (st->url);
if(st->ld)
ldap_memfree(st->ld);
sfree (st);
} /* }}} void ldap_free */
/* Configuration handling functions {{{
*
* <Plugin ldap>
* <Instance "plugin_instance1">
* URL "ldap://localhost"
* ...
* </Instance>
* </Plugin>
*/
static int config_set_string (char **ret_string, /* {{{ */
oconfig_item_t *ci)
{
char *string;
if ((ci->values_num != 1)
|| (ci->values[0].type != OCONFIG_TYPE_STRING))
{
WARNING ("openldap plugin: The `%s' config option "
"needs exactly one string argument.", ci->key);
return (-1);
}
string = strdup (ci->values[0].value.string);
if (string == NULL)
{
ERROR ("openldap plugin: strdup failed.");
return (-1);
}
if (*ret_string != NULL)
free (*ret_string);
*ret_string = string;
return (0);
} /* }}} int config_set_string */
static int config_set_int (int *ret_int, /* {{{ */
oconfig_item_t *ci)
{
if ((ci->values_num != 1)
|| (ci->values[0].type != OCONFIG_TYPE_NUMBER))
{
WARNING ("openldap plugin: The `%s' config option "
"needs exactly one string argument.", ci->key);
return (-1);
}
*ret_int = ci->values[0].value.number;
return (0);
} /* }}} int config_set_int */
static int config_set_bool (int *ret_boolean, /* {{{ */
oconfig_item_t *ci)
{
int status = 0;
if (ci->values_num != 1)
status = -1;
if (status == 0)
{
if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
*ret_boolean = ci->values[0].value.boolean;
else if (ci->values[0].type == OCONFIG_TYPE_STRING)
{
if (IS_TRUE (ci->values[0].value.string))
*ret_boolean = 1;
else if (IS_FALSE (ci->values[0].value.string))
*ret_boolean = 0;
else
status = -1;
}
else
status = -1;
}
if (status != 0)
{
WARNING ("openldap plugin: The `%s' config option "
"needs exactly one boolean argument.", ci->key);
return (-1);
}
return (0);
} /* }}} config_set_bool */
static int config_add (oconfig_item_t *ci) /* {{{ */
{
ldap_t *st;
int i;
int status;
if ((ci->values_num != 1)
|| (ci->values[0].type != OCONFIG_TYPE_STRING))
{
WARNING ("openldap plugin: The `%s' config option "
"needs exactly one string argument.", ci->key);
return (-1);
}
st = (ldap_t *) malloc (sizeof (*st));
if (st == NULL)
{
ERROR ("openldap plugin: malloc failed.");
return (-1);
}
memset (st, 0, sizeof (*st));
status = config_set_string (&st->name, ci);
if (status != 0)
{
sfree (st);
return (status);
}
st->verifyhost = 1;
st->version = LDAP_VERSION3;
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("CACert", child->key) == 0)
status = config_set_string (&st->cacert, child);
else if (strcasecmp ("StartTLS", child->key) == 0)
status = config_set_bool (&st->starttls, child);
else if (strcasecmp ("Timeout", child->key) == 0)
status = config_set_int (&st->timeout, child);
else if (strcasecmp ("URL", child->key) == 0)
status = config_set_string (&st->url, child);
else if (strcasecmp ("VerifyHost", child->key) == 0)
status = config_set_bool (&st->verifyhost, child);
else if (strcasecmp ("Version", child->key) == 0)
status = config_set_int (&st->version, child);
else
{
WARNING ("openldap plugin: Option `%s' not allowed here.",
child->key);
status = -1;
}
if (status != 0)
break;
}
/* Check if struct is complete.. */
if ((status == 0) && (st->url == NULL))
{
ERROR ("openldap plugin: Instance `%s': "
"No URL has been configured.",
st->name);
status = -1;
}
/* Check if URL is valid */
if ((status == 0) && (st->url != NULL))
{
LDAPURLDesc *ludpp;
int rc;
if ((rc = ldap_url_parse( st->url, &ludpp)) != 0)
{
ERROR ("openldap plugin: Instance `%s': "
"Invalid URL: `%s'",
st->name, st->url);
status = -1;
}
else
{
st->host = strdup (ludpp->lud_host);
}
ldap_free_urldesc(ludpp);
}
if (status == 0)
{
user_data_t ud;
char callback_name[3*DATA_MAX_NAME_LEN];
memset (&ud, 0, sizeof (ud));
ud.data = st;
ud.free_func = (void *) ldap_free;
memset (callback_name, 0, sizeof (callback_name));
ssnprintf (callback_name, sizeof (callback_name),
"openldap/%s/%s",
(st->host != NULL) ? st->host : hostname_g,
(st->name != NULL) ? st->name : "default"),
status = plugin_register_complex_read (/* group = */ NULL,
/* name = */ callback_name,
/* callback = */ ldap_read_host,
/* interval = */ NULL,
/* user_data = */ &ud);
}
if (status != 0)
{
ldap_free (st);
return (-1);
}
return (0);
} /* }}} int config_add */
static int config (oconfig_item_t *ci)
{
int i;
int status = 0;
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Instance", child->key) == 0)
config_add (child);
else
WARNING ("openldap plugin: The configuration option "
"\"%s\" is not allowed here. Did you "
"forget to add an <Instance /> block "
"around the configuration?",
child->key);
} /* for (ci->children) */
return (status);
} /* int config */
/* }}} End of configuration handling functions */
/* initialize ldap for each host */
static int init_host (ldap_t *st)
{
LDAP *ld;
int rc;
rc = ldap_initialize (&ld, st->url);
if (rc != LDAP_SUCCESS)
{
char errbuf[1024];
sstrerror (errno, errbuf, sizeof (errbuf));
ERROR ("ldap_initialize failed: %s", errbuf);
st->state = 0;
return (-1);
}
st->ld = ld;
ldap_set_option (st->ld, LDAP_OPT_PROTOCOL_VERSION, &st->version);
if(st->cacert != NULL)
ldap_set_option (st->ld, LDAP_OPT_X_TLS_CACERTFILE, st->cacert);
if(st->verifyhost == 0)
{
int never = LDAP_OPT_X_TLS_NEVER;
ldap_set_option (st->ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &never);
}
if(st->starttls != 0)
{
rc = ldap_start_tls_s(ld, NULL, NULL);
if (rc != LDAP_SUCCESS)
{
ERROR ("openldap plugin: Failed to start tls on %s: %s",
st->url, ldap_err2string (rc));
st->state = 0;
return (-1);
}
}
struct berval cred;
cred.bv_val = "";
cred.bv_len = 0;
rc = ldap_sasl_bind_s(st->ld, NULL, NULL, &cred, NULL, NULL, NULL);
if (rc != LDAP_SUCCESS)
{
ERROR ("openldap plugin: Failed to bind to %s: %s",
st->url, ldap_err2string (rc));
st->state = 0;
return (-1);
}
else
{
DEBUG ("openldap plugin: Successfully connected to %s",
st->url);
st->state = 1;
return (0);
}
} /* static init_host (ldap_t *st) */
static void submit_value (const char *type, const char *type_instance,
value_t value, ldap_t *st)
{
value_list_t vl = VALUE_LIST_INIT;
vl.values = &value;
vl.values_len = 1;
if ((st->host == NULL)
|| (strcmp ("", st->host) == 0)
|| (strcmp ("localhost", st->host) == 0))
{
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
}
else
{
sstrncpy (vl.host, st->host, sizeof (vl.host));
}
sstrncpy (vl.plugin, "openldap", sizeof (vl.plugin));
if (st->name != NULL)
sstrncpy (vl.plugin_instance, st->name,
sizeof (vl.plugin_instance));
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
sstrncpy (vl.type_instance, type_instance,
sizeof (vl.type_instance));
plugin_dispatch_values (&vl);
} /* submit */
static void submit_derive (const char *type, const char *type_instance,
derive_t d, ldap_t *st)
{
value_t v;
v.derive = d;
submit_value (type, type_instance, v, st);
} /* void submit_derive */
static void submit_gauge (const char *type, const char *type_instance,
gauge_t g, ldap_t *st)
{
value_t v;
v.gauge = g;
submit_value (type, type_instance, v, st);
} /* void submit_gauge */
static int ldap_read_host (user_data_t *ud)
{
ldap_t *st;
LDAPMessage *e, *result;
char *dn;
int rc;
int status;
char *attrs[3] = { "monitorCounter",
"monitorOpCompleted",
"monitorOpInitiated" };
if ((ud == NULL) || (ud->data == NULL))
{
ERROR ("openldap plugin: ldap_read_host: Invalid user data.");
return (-1);
}
st = (ldap_t *) ud->data;
status = init_host (st);
if (status != 0)
return (-1);
rc = ldap_search_ext_s (st->ld, "cn=Monitor", LDAP_SCOPE_SUBTREE,
"(!(cn=* *))", attrs, 0,
NULL, NULL, NULL, 0, &result);
if (rc != LDAP_SUCCESS)
{
ERROR ("openldap plugin: Failed to execute search: %s",
ldap_err2string (rc));
ldap_msgfree (result);
return (-1);
}
for (e = ldap_first_entry (st->ld, result); e != NULL;
e = ldap_next_entry (st->ld, e))
{
if ((dn = ldap_get_dn (st->ld, e)) != NULL)
{
unsigned long long counter = 0;
unsigned long long opc = 0;
unsigned long long opi = 0;
struct berval counter_data;
struct berval opc_data;
struct berval opi_data;
struct berval **counter_list;
struct berval **opc_list;
struct berval **opi_list;
if ((counter_list = ldap_get_values_len (st->ld, e,
"monitorCounter")) != NULL)
{
counter_data = *counter_list[0];
counter = atoll (counter_data.bv_val);
}
if ((opc_list = ldap_get_values_len (st->ld, e,
"monitorOpCompleted")) != NULL)
{
opc_data = *opc_list[0];
opc = atoll (opc_data.bv_val);
}
if ((opi_list = ldap_get_values_len (st->ld, e,
"monitorOpInitiated")) != NULL)
{
opi_data = *opi_list[0];
opi = atoll (opi_data.bv_val);
}
if (strcmp (dn, "cn=Total,cn=Connections,cn=Monitor")
== 0)
{
submit_derive ("total_connections", NULL,
counter, st);
}
else if (strcmp (dn,
"cn=Current,cn=Connections,cn=Monitor")
== 0)
{
submit_gauge ("current_connections", NULL,
counter, st);
}
else if (strcmp (dn,
"cn=Operations,cn=Monitor") == 0)
{
submit_derive ("operations",
"completed", opc, st);
submit_derive ("operations",
"initiated", opi, st);
}
else if (strcmp (dn,
"cn=Bind,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"bind-completed", opc, st);
submit_derive ("operations",
"bind-initiated", opi, st);
}
else if (strcmp (dn,
"cn=UnBind,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"unbind-completed", opc, st);
submit_derive ("operations",
"unbind-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Search,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"search-completed", opc, st);
submit_derive ("operations",
"search-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Compare,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"compare-completed", opc, st);
submit_derive ("operations",
"compare-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Modify,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"modify-completed", opc, st);
submit_derive ("operations",
"modify-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Modrdn,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"modrdn-completed", opc, st);
submit_derive ("operations",
"modrdn-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Add,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"add-completed", opc, st);
submit_derive ("operations",
"add-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Delete,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"delete-completed", opc, st);
submit_derive ("operations",
"delete-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Abandon,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"abandon-completed", opc, st);
submit_derive ("operations",
"abandon-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Extended,cn=Operations,cn=Monitor")
== 0)
{
submit_derive ("operations",
"extended-completed", opc, st);
submit_derive ("operations",
"extended-initiated", opi, st);
}
else if (strcmp (dn,
"cn=Bytes,cn=Statistics,cn=Monitor")
== 0)
{
submit_derive ("derive", "statistics-bytes",
counter, st);
}
else if (strcmp (dn,
"cn=PUD,cn=Statistics,cn=Monitor")
== 0)
{
submit_derive ("derive", "statistics-pdu",
counter, st);
}
else if (strcmp (dn,
"cn=Entries,cn=Statistics,cn=Monitor")
== 0)
{
submit_derive ("derive", "statistics-entries",
counter, st);
}
else if (strcmp (dn,
"cn=Referrals,cn=Statistics,cn=Monitor")
== 0)
{
submit_derive ("derive", "statistics-referrals",
counter, st);
}
else if (strcmp (dn,
"cn=Read,cn=Waiters,cn=Monitor")
== 0)
{
submit_derive ("derive", "waiters-read",
counter, st);
}
else if (strcmp (dn,
"cn=Write,cn=Waiters,cn=Monitor")
== 0)
{
submit_derive ("derive", "waiters-write",
counter, st);
}
ldap_value_free_len (counter_list);
ldap_value_free_len (opc_list);
ldap_value_free_len (opi_list);
}
ldap_memfree (dn);
}
ldap_msgfree (result);
ldap_unbind_ext_s (st->ld, NULL, NULL);
return (0);
} /* int ldap_read_host */
void module_register (void)
{
plugin_register_complex_config ("openldap", config);
} /* void module_register */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment