From 8bbc16715bda6ba2cc32548e888e21c26e8299b1 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 28 Aug 2014 16:42:34 -0700 Subject: [PATCH] timeseries::rrdtool: Added support for RRDCacheD. After enabling RRDCacheD support, the plugin supports an additional time-series fetcher callback which may be used to flush outstanding updates to an RRD file before fetching data from it. --- configure.ac | 4 + doc/sysdbd-timeseries-rrdtool.5.txt | 11 ++- src/plugins/timeseries/rrdtool.c | 135 +++++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index ef6868e..37d77ff 100644 --- a/configure.ac +++ b/configure.ac @@ -422,6 +422,10 @@ else AC_MSG_ERROR([Invalid value for option --with-librrd=$with_librrd (expected "yes", "no", or "auto")]) fi; fi +if test "x$have_librrd" = "xyes"; then + AC_CHECK_HEADERS([rrd_client.h]) +fi + dnl Feature checks. build_documentation="yes" diff --git a/doc/sysdbd-timeseries-rrdtool.5.txt b/doc/sysdbd-timeseries-rrdtool.5.txt index 693caad..b36a177 100644 --- a/doc/sysdbd-timeseries-rrdtool.5.txt +++ b/doc/sysdbd-timeseries-rrdtool.5.txt @@ -17,8 +17,15 @@ data from RRD files. CONFIGURATION ------------- -*timeseries::rrdtool* does not currently accept any configuration options. It -registers a time-series fetcher callback called *rrdtool*. +*timeseries::rrdtool* accepts the following configuration options. In addition +to any configuration, the plugin always registers a time-series fetcher +callback called *rrdtool* which may be used to access RRD files on local disk. + +*RRDCacheD* '':: + Enable support for RRDCacheD. When using this option, an additional + time-series fetcher callback called *rrdcached* is made available. It will + flush cached updates for an RRD file before fetching data from it. + Currently, local connections through a UNIX socket are supported only. SEE ALSO -------- diff --git a/src/plugins/timeseries/rrdtool.c b/src/plugins/timeseries/rrdtool.c index 572c033..db24903 100644 --- a/src/plugins/timeseries/rrdtool.c +++ b/src/plugins/timeseries/rrdtool.c @@ -25,22 +25,37 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + #include "sysdb.h" #include "core/plugin.h" #include "utils/error.h" +#include "liboconfig/utils.h" + #include +#include #include +#ifdef HAVE_RRD_CLIENT_H +# include +#endif SDB_PLUGIN_MAGIC; +/* Current versions of RRDtool do not support multiple RRDCacheD client + * connections. Use this to guard against multiple configured RRDCacheD + * instances. */ +static _Bool rrdcached_in_use = 0; + /* * plugin API */ static sdb_timeseries_t * sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, - sdb_object_t __attribute__((unused)) *user_data) + sdb_object_t *user_data) { sdb_timeseries_t *ts; @@ -54,6 +69,34 @@ sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, char **ds_namv = NULL; rrd_value_t *data = NULL, *data_ptr; + if (user_data) { +#ifdef HAVE_RRD_CLIENT_H + /* -> use RRDCacheD */ + char *addr = SDB_OBJ_WRAPPER(user_data)->data; + + rrd_clear_error(); + if (! rrdc_is_connected(addr)) { + if (rrdc_connect(addr)) { + sdb_log(SDB_LOG_ERR, "timeseries::rrdtool: Failed to " + "connectd to RRDCacheD at %s: %s", + addr, rrd_get_error()); + return NULL; + } + } + + if (rrdc_flush(id)) { + sdb_log(SDB_LOG_ERR, "timeseries::rrdtool: Failed to flush " + "'%s' through RRDCacheD: %s", id, rrd_get_error()); + return NULL; + } +#else + sdb_log(SDB_LOG_ERR, "timeseries::rrdtool: Callback called with " + "RRDCacheD address but your build of SysDB does not support " + "that"); + return NULL; +#endif + } + #define FREE_RRD_DATA() \ do { \ size_t i; \ @@ -104,6 +147,95 @@ sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, return ts; } /* sdb_rrd_fetch */ +static int +sdb_rrdcached_shutdown(sdb_object_t __attribute__((unused)) *user_data) +{ +#ifdef HAVE_RRD_CLIENT_H + rrdc_disconnect(); +#endif + return 0; +} /* sdb_rrdcached_shutdown */ + +static int +sdb_rrd_config_rrdcached(oconfig_item_t *ci) +{ + sdb_object_t *ud; + char *addr = NULL; + + if (rrdcached_in_use) { + sdb_log(SDB_LOG_ERR, "timeseries::rrdtool: RRDCacheD does " + "not support multiple connections"); + return -1; + } + +#ifndef HAVE_RRD_CLIENT_H + sdb_log(SDB_LOG_ERR, "timeseries::rrdtool: RRDCacheD client " + "support not available in your SysDB build"); + return -1; +#else + if (oconfig_get_string(ci, &addr)) { + sdb_log(SDB_LOG_ERR, "timeseries::unixsock: RRDCacheD requires " + "a single string argument\n\tUsage "); + return -1; + } + if ((*addr != '/') && strncmp(addr, "unix:", strlen("unix:"))) { + /* XXX: add (optional) support for rrdc_fetch if available */ + sdb_log(SDB_LOG_ERR, "timeseries::unixsock: RRDCacheD only " + "supports local (UNIX socket) addresses"); + return -1; + } + + addr = strdup(addr); + if (! addr) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "timeseries::unixsock: Failed to duplicate " + "string: %s", sdb_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + if (ci->children_num) + sdb_log(SDB_LOG_WARNING, "timeseries::unixsock: RRDCacheD does " + "not support any child config options"); + + ud = sdb_object_create_wrapper("rrdcached-addr", addr, free); + if (! ud) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "timeseries::unixsock: Failed to create " + "user-data object: %s", + sdb_strerror(errno, errbuf, sizeof(errbuf))); + free(addr); + return -1; + } + + sdb_plugin_register_ts_fetcher("rrdcached", sdb_rrd_fetch, ud); + sdb_plugin_register_shutdown("rrdcached", sdb_rrdcached_shutdown, NULL); + sdb_object_deref(ud); + rrdcached_in_use = 1; + return 0; +#endif +} /* sdb_rrd_config_rrdcached */ + +static int +sdb_rrd_config(oconfig_item_t *ci) +{ + int i; + + if (! ci) { /* reconfigure */ + rrdcached_in_use = 0; + return 0; + } + + for (i = 0; i < ci->children_num; ++i) { + oconfig_item_t *child = ci->children + i; + + if (! strcasecmp(child->key, "RRDCacheD")) + sdb_rrd_config_rrdcached(child); + else + sdb_log(SDB_LOG_WARNING, "timeseries::rrdtool: Ignoring " + "unknown config option '%s'.", child->key); + } + return 0; +} /* sdb_rrd_config */ + int sdb_module_init(sdb_plugin_info_t *info) { @@ -116,6 +248,7 @@ sdb_module_init(sdb_plugin_info_t *info) sdb_plugin_set_info(info, SDB_PLUGIN_INFO_PLUGIN_VERSION, SDB_VERSION); sdb_plugin_register_ts_fetcher("rrdtool", sdb_rrd_fetch, NULL); + sdb_plugin_register_config(sdb_rrd_config); return 0; } /* sdb_module_init */ -- 2.30.2