Merge branch 'collectd-5.1'
authorFlorian Forster <octo@collectd.org>
Fri, 7 Sep 2012 09:19:52 +0000 (11:19 +0200)
committerFlorian Forster <octo@collectd.org>
Fri, 7 Sep 2012 09:19:52 +0000 (11:19 +0200)
1  2 
src/Makefile.am
src/amqp.c
src/collectd.conf.pod
src/oracle.c
src/redis.c

diff --combined src/Makefile.am
@@@ -43,7 -43,7 +43,7 @@@ collectd_SOURCES = collectd.c collectd.
  collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
  collectd_CFLAGS = $(AM_CFLAGS)
  collectd_LDFLAGS = -export-dynamic
- collectd_LDADD =
+ collectd_LDADD = -lm
  collectd_DEPENDENCIES =
  
  # Link to these libraries..
@@@ -70,7 -70,6 +70,6 @@@ collectd_LDADD += -ldevinf
  endif
  if BUILD_AIX
  collectd_LDFLAGS += -Wl,-bexpall,-brtllib
- collectd_LDADD += -lm
  endif
  
  # The daemon needs to call sg_init, so we need to link it against libstatgrab,
@@@ -124,7 -123,6 +123,7 @@@ if BUILD_PLUGIN_AMQ
  pkglib_LTLIBRARIES += amqp.la
  amqp_la_SOURCES = amqp.c \
                  utils_cmd_putval.c utils_cmd_putval.h \
 +                utils_format_graphite.c utils_format_graphite.h \
                  utils_format_json.c utils_format_json.h
  amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
  amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
@@@ -1258,8 -1256,7 +1257,8 @@@ endi
  if BUILD_PLUGIN_WRITE_GRAPHITE
  pkglib_LTLIBRARIES += write_graphite.la
  write_graphite_la_SOURCES = write_graphite.c \
 -                      utils_format_json.c utils_format_json.h
 +                        utils_format_graphite.c utils_format_graphite.h \
 +                        utils_format_json.c utils_format_json.h
  write_graphite_la_LDFLAGS = -module -avoid-version
  collectd_LDADD += "-dlopen" write_graphite.la
  collectd_DEPENDENCIES += write_graphite.la
@@@ -1372,7 -1369,7 +1371,7 @@@ EXTRA_DIST +=   collectd.conf.pod 
        fi
  
  pinba.pb-c.c pinba.pb-c.h: pinba.proto
-       protoc-c --c_out $(builddir) pinba.proto
+       protoc-c --c_out . pinba.proto
  
  install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
diff --combined src/amqp.c
@@@ -31,7 -31,6 +31,7 @@@
  #include "plugin.h"
  #include "utils_cmd_putval.h"
  #include "utils_format_json.h"
 +#include "utils_format_graphite.h"
  
  #include <pthread.h>
  
@@@ -43,9 -42,8 +43,9 @@@
  #define CAMQP_DM_VOLATILE   1
  #define CAMQP_DM_PERSISTENT 2
  
 -#define CAMQP_FORMAT_COMMAND 1
 -#define CAMQP_FORMAT_JSON    2
 +#define CAMQP_FORMAT_COMMAND    1
 +#define CAMQP_FORMAT_JSON       2
 +#define CAMQP_FORMAT_GRAPHITE   3
  
  #define CAMQP_CHANNEL 1
  
@@@ -70,10 -68,6 +70,10 @@@ struct camqp_config_
      uint8_t delivery_mode;
      _Bool   store_rates;
      int     format;
 +    /* publish & graphite format only */
 +    char    *prefix;
 +    char    *postfix;
 +    char    escape_char;
  
      /* subscribe only */
      char   *exchange_type;
@@@ -135,9 -129,6 +135,9 @@@ static void camqp_config_free (void *pt
      sfree (conf->exchange_type);
      sfree (conf->queue);
      sfree (conf->routing_key);
 +    sfree (conf->prefix);
 +    sfree (conf->postfix);
 +
  
      sfree (conf);
  } /* }}} void camqp_config_free */
@@@ -650,6 -641,7 +650,7 @@@ static void *camqp_subscribe_thread (vo
  
      camqp_config_free (conf);
      pthread_exit (NULL);
+     return (NULL);
  } /* }}} void *camqp_subscribe_thread */
  
  static int camqp_subscribe_init (camqp_config_t *conf) /* {{{ */
@@@ -707,8 -699,6 +708,8 @@@ static int camqp_write_locked (camqp_co
          props.content_type = amqp_cstring_bytes("text/collectd");
      else if (conf->format == CAMQP_FORMAT_JSON)
          props.content_type = amqp_cstring_bytes("application/json");
 +    else if (conf->format == CAMQP_FORMAT_GRAPHITE)
 +        props.content_type = amqp_cstring_bytes("text/graphite");
      else
          assert (23 == 42);
      props.delivery_mode = conf->delivery_mode;
@@@ -787,17 -777,6 +788,17 @@@ static int camqp_write (const data_set_
          format_json_value_list (buffer, &bfill, &bfree, ds, vl, conf->store_rates);
          format_json_finalize (buffer, &bfill, &bfree);
      }
 +    else if (conf->format == CAMQP_FORMAT_GRAPHITE)
 +    {
 +        status = format_graphite (buffer, sizeof (buffer), ds, vl,
 +                    conf->prefix, conf->postfix, conf->escape_char);
 +        if (status != 0)
 +        {
 +            ERROR ("amqp plugin: format_graphite failed with status %i.",
 +                    status);
 +            return (status);
 +        }
 +    }
      else
      {
          ERROR ("amqp plugin: Invalid format (%i).", conf->format);
@@@ -830,8 -809,6 +831,8 @@@ static int camqp_config_set_format (oco
          conf->format = CAMQP_FORMAT_COMMAND;
      else if (strcasecmp ("JSON", string) == 0)
          conf->format = CAMQP_FORMAT_JSON;
 +    else if (strcasecmp ("Graphite", string) == 0)
 +        conf->format = CAMQP_FORMAT_GRAPHITE;
      else
      {
          WARNING ("amqp plugin: Invalid format string: %s",
@@@ -872,10 -849,6 +873,10 @@@ static int camqp_config_connection (oco
      /* publish only */
      conf->delivery_mode = CAMQP_DM_VOLATILE;
      conf->store_rates = 0;
 +    /* publish & graphite only */
 +    conf->prefix = NULL;
 +    conf->postfix = NULL;
 +    conf->escape_char = '_';
      /* subscribe only */
      conf->exchange_type = NULL;
      conf->queue = NULL;
              status = cf_util_get_boolean (child, &conf->store_rates);
          else if ((strcasecmp ("Format", child->key) == 0) && publish)
              status = camqp_config_set_format (child, conf);
 +        else if ((strcasecmp ("GraphitePrefix", child->key) == 0) && publish)
 +            status = cf_util_get_string (child, &conf->prefix);
 +        else if ((strcasecmp ("GraphitePostfix", child->key) == 0) && publish)
 +            status = cf_util_get_string (child, &conf->postfix);
 +        else if ((strcasecmp ("GraphiteEscapeChar", child->key) == 0) && publish)
 +        {
 +            char *tmp_buff = NULL;
 +            status = cf_util_get_string (child, &tmp_buff);
 +            if (strlen (tmp_buff) > 1)
 +                WARNING ("amqp plugin: The option \"GraphiteEscapeChar\" handles "
 +                        "only one character. Others will be ignored.");
 +            conf->escape_char = tmp_buff[0];
 +            sfree (tmp_buff);
 +        }
          else
              WARNING ("amqp plugin: Ignoring unknown "
                      "configuration option \"%s\".", child->key);
diff --combined src/collectd.conf.pod
@@@ -25,22 -25,32 +25,32 @@@ controls which plugins to load. These p
  behavior.
  
  The syntax of this config file is similar to the config file of the famous
- B<Apache Webserver>. Each line contains either a key-value-pair or a
- section-start or -end. Empty lines and everything after the hash-symbol `#' is
- ignored. Values are either string, enclosed in double-quotes,
- (floating-point-)numbers or a boolean expression, i.E<nbsp>e. either B<true> or
- B<false>. String containing of only alphanumeric characters and underscores do
- not need to be quoted. Lines may be wrapped by using `\' as the last character
- before the newline. This allows long lines to be split into multiple lines.
- Quoted strings may be wrapped as well. However, those are treated special in
- that whitespace at the beginning of the following lines will be ignored, which
- allows for nicely indenting the wrapped lines.
- The configuration is read and processed in order, i.E<nbsp>e. from top to
- bottom. So the plugins are loaded in the order listed in this config file. It
- is a good idea to load any logging plugins first in order to catch messages
- from plugins during configuration. Also, the C<LoadPlugin> option B<must> occur
- B<before> the C<E<lt>Plugin ...E<gt>> block.
+ I<Apache> webserver. Each line contains either an option (a key and a list of
+ one or more values) or a section-start or -end. Empty lines and everything
+ after a non-quoted hash-symbol (C<#>) is ignored. I<Keys> are unquoted
+ strings, consisting only of alphanumeric characters and the underscore (C<_>)
+ character. Keys are handled case insensitive by I<collectd> itself and all
+ plugins included with it. I<Values> can either be an I<unquoted string>, a
+ I<quoted string> (enclosed in double-quotes) a I<number> or a I<boolean>
+ expression. I<Unquoted strings> consist of only alphanumeric characters and
+ underscores (C<_>) and do not need to be quoted. I<Quoted strings> are
+ enclosed in double quotes (C<">). You can use the backslash character (C<\>)
+ to include double quotes as part of the string. I<Numbers> can be specified in
+ decimal and floating point format (using a dot C<.> as decimal separator),
+ hexadecimal when using the C<0x> prefix and octal with a leading zero (C<0>).
+ I<Boolean> values are either B<true> or B<false>.
+ Lines may be wrapped by using C<\> as the last character before the newline.
+ This allows long lines to be split into multiple lines. Quoted strings may be
+ wrapped as well. However, those are treated special in that whitespace at the
+ beginning of the following lines will be ignored, which allows for nicely
+ indenting the wrapped lines.
+ The configuration is read and processed in order, i.e. from top to bottom. So
+ the plugins are loaded in the order listed in this config file. It is a good
+ idea to load any logging plugins first in order to catch messages from plugins
+ during configuration. Also, the C<LoadPlugin> option B<must> occur B<before>
+ the appropriate C<E<lt>Plugin ...E<gt>> block.
  
  =head1 GLOBAL OPTIONS
  
@@@ -210,8 -220,6 +220,8 @@@ possibly filtering or messages
   #   Persistent false
   #   Format "command"
   #   StoreRates false
 + #   GraphitePrefix "collectd."
 + #   GraphiteEscapeChar "_"
     </Publish>
     
     # Receive values from an AMQP broker
@@@ -312,10 -320,6 +322,10 @@@ If set to B<JSON>, the values are encod
  an easy and straight forward exchange format. The C<Content-Type> header field
  will be set to C<application/json>.
  
 +If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
 +"<metric> <value> <timestamp>\n". The C<Content-Type> header field will be set to
 +C<text/graphite>.
 +
  A subscribing client I<should> use the C<Content-Type> header field to
  determine how to decode the values. Currently, the I<AMQP plugin> itself can
  only decode the B<Command> format.
@@@ -330,25 -334,6 +340,25 @@@ using the internal value cache
  Please note that currently this option is only used if the B<Format> option has
  been set to B<JSON>.
  
 +=item B<GraphitePrefix> (Publish and B<Format>=I<Graphite> only)
 +
 +A prefix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added before the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphitePostfix> (Publish and B<Format>=I<Graphite> only)
 +
 +A postfix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added after the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphiteEscapeChar> (Publish and B<Format>=I<Graphite> only)
 +
 +Specify a character to replace dots (.) in the host part of the metric name.
 +In I<Graphite> metric name, dots are used as separators between different
 +metric parts (host, plugin, type).
 +Default is "_" (I<Underscore>).
 +
  =back
  
  =head2 Plugin C<apache>
@@@ -1964,17 -1949,6 +1974,17 @@@ The C<memcached plugin> connects to a m
  about cache utilization, memory and bandwidth used.
  L<http://www.danga.com/memcached/>
  
 + <Plugin "memcached">
 +   <Instance "name">
 +     Host "memcache.example.com"
 +     Port 11211
 +   </Instance>
 + </Plugin>
 +
 +The plugin configuration consists of one or more B<Instance> blocks which
 +specify one I<memcached> connection each. Within the B<Instance> blocks, the
 +following options are allowed:
 +
  =over 4
  
  =item B<Host> I<Hostname>
@@@ -1985,11 -1959,6 +1995,11 @@@ Hostname to connect to. Defaults to B<1
  
  TCP-Port to connect to. Defaults to B<11211>.
  
 +=item B<Socket> I<Path>
 +
 +Connect to I<memcached> using the UNIX domain socket at I<Path>. If this
 +setting is given, the B<Host> and B<Port> settings are ignored.
 +
  =back
  
  =head2 Plugin C<modbus>
@@@ -3309,11 -3278,6 +3319,11 @@@ values submitted to the daemon. Other t
  Defines the "database alias" or "service name" to connect to. Usually, these
  names are defined in the file named C<$ORACLE_HOME/network/admin/tnsnames.ora>.
  
 +=item B<Host> I<Host>
 +
 +Hostname to use when dispatching values for this database. Defaults to using
 +the global hostname of the I<collectd> instance.
 +
  =item B<Username> I<Username>
  
  Username used for authentication.
@@@ -4102,10 -4066,6 +4112,10 @@@ The B<Port> option is the TCP port on w
  connections. Either a service name of a port number may be given. Please note
  that numerical port numbers must be given as a string, too.
  
 +=item B<Password> I<Password>
 +
 +Use I<Password> to authenticate when connecting to I<Redis>.
 +
  =item B<Timeout> I<Timeout in miliseconds>
  
  The B<Timeout> option set the socket timeout for node response. Since the Redis
@@@ -4965,7 -4925,7 +4975,7 @@@ number
  If set to B<true>, the plugin instance and type instance will be in their own
  path component, for example C<host.cpu.0.cpu.idle>. If set to B<false> (the
  default), the plugin and plugin instance (and likewise the type and type
- instance) are put into once component, for example C<host.cpu-0.cpu-idle>.
+ instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
  
  =item B<AlwaysAppendDS> B<false>|B<true>
  
diff --combined src/oracle.c
@@@ -59,7 -59,6 +59,7 @@@
  struct o_database_s
  {
    char *name;
 +  char *host;
    char *connect_id;
    char *username;
    char *password;
@@@ -87,6 -86,7 +87,7 @@@ OCIError *oci_error = NULL
   * Functions
   */
  static void o_report_error (const char *where, /* {{{ */
+     const char *db_name, const char *query_name,
      const char *what, OCIError *eh)
  {
    char buffer[2048];
    int status;
    unsigned int record_number;
  
+   if (db_name == NULL)
+     db_name = "(none)";
+   if (query_name == NULL)
+     query_name = "(none)";
    /* An operation may cause / return multiple errors. Loop until we have
     * handled all errors available (with a fail-save limit of 16). */
    for (record_number = 1; record_number <= 16; record_number++)
          buffer[buffer_length] = 0;
        }
  
-       ERROR ("oracle plugin: %s: %s failed: %s", where, what, buffer);
+       ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed: %s",
+           where, db_name, query_name, what, buffer);
      }
      else
      {
-       ERROR ("oracle plugin: %s: %s failed. Additionally, OCIErrorGet failed with status %i.",
-           where, what, status);
+       ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed. "
+           "Additionally, OCIErrorGet failed with status %i.",
+           where, db_name, query_name, what, status);
        return;
      }
    }
@@@ -176,6 -183,33 +184,6 @@@ static void o_database_free (o_database
   * </Plugin>
   */
  
 -static int o_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 ("oracle 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 ("oracle plugin: strdup failed.");
 -    return (-1);
 -  }
 -
 -  if (*ret_string != NULL)
 -    free (*ret_string);
 -  *ret_string = string;
 -
 -  return (0);
 -} /* }}} int o_config_set_string */
 -
  static int o_config_add_database (oconfig_item_t *ci) /* {{{ */
  {
    o_database_t *db;
      return (-1);
    }
    memset (db, 0, sizeof (*db));
 +  db->name = NULL;
 +  db->host = NULL;
 +  db->connect_id = NULL;
 +  db->username = NULL;
 +  db->password = NULL;
  
 -  status = o_config_set_string (&db->name, ci);
 +  status = cf_util_get_string (ci, &db->name);
    if (status != 0)
    {
      sfree (db);
      oconfig_item_t *child = ci->children + i;
  
      if (strcasecmp ("ConnectID", child->key) == 0)
 -      status = o_config_set_string (&db->connect_id, child);
 +      status = cf_util_get_string (child, &db->connect_id);
 +    else if (strcasecmp ("Host", child->key) == 0)
 +      status = cf_util_get_string (child, &db->host);
      else if (strcasecmp ("Username", child->key) == 0)
 -      status = o_config_set_string (&db->username, child);
 +      status = cf_util_get_string (child, &db->username);
      else if (strcasecmp ("Password", child->key) == 0)
 -      status = o_config_set_string (&db->password, child);
 +      status = cf_util_get_string (child, &db->password);
      else if (strcasecmp ("Query", child->key) == 0)
        status = udb_query_pick_from_list (child, queries, queries_num,
            &db->queries, &db->queries_num);
@@@ -408,7 -435,8 +416,8 @@@ static int o_read_database_query (o_dat
          OCI_HTYPE_STMT, /* user_data_size = */ 0, /* user_data = */ NULL);
      if (status != OCI_SUCCESS)
      {
-       o_report_error ("o_read_database_query", "OCIHandleAlloc", oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIHandleAlloc", oci_error);
        oci_statement = NULL;
        return (-1);
      }
          /* mode     = */ OCI_DEFAULT);
      if (status != OCI_SUCCESS)
      {
-       o_report_error ("o_read_database_query", "OCIStmtPrepare", oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIStmtPrepare", oci_error);
        OCIHandleFree (oci_statement, OCI_HTYPE_STMT);
        oci_statement = NULL;
        return (-1);
        /* mode = */ OCI_DEFAULT);
    if (status != OCI_SUCCESS)
    {
-     DEBUG ("oracle plugin: o_read_database_query: status = %i (%#x)", status, status);
-     o_report_error ("o_read_database_query", "OCIStmtExecute", oci_error);
-     ERROR ("oracle plugin: o_read_database_query: "
-         "Failing statement was: %s", udb_query_get_statement (q));
+     o_report_error ("o_read_database_query", db->name, udb_query_get_name (q),
+         "OCIStmtExecute", oci_error);
      return (-1);
    } /* }}} */
  
          OCI_ATTR_PARAM_COUNT, oci_error);
      if (status != OCI_SUCCESS)
      {
-       o_report_error ("o_read_database_query", "OCIAttrGet", oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIAttrGet", oci_error);
        return (-1);
      } /* }}} */
  
      if (status != OCI_SUCCESS)
      {
        /* This is probably alright */
-       DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);", status, status);
-       o_report_error ("o_read_database_query", "OCIParamGet", oci_error);
+       DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);",
+           status, status);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIParamGet", oci_error);
        status = OCI_SUCCESS;
        break;
      }
      if (status != OCI_SUCCESS)
      {
        OCIDescriptorFree (oci_param, OCI_DTYPE_PARAM);
-       o_report_error ("o_read_database_query", "OCIAttrGet (OCI_ATTR_NAME)",
-           oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIAttrGet (OCI_ATTR_NAME)", oci_error);
        continue;
      }
  
          NULL, NULL, NULL, OCI_DEFAULT);
      if (status != OCI_SUCCESS)
      {
-       o_report_error ("o_read_database_query", "OCIDefineByPos", oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIDefineByPos", oci_error);
        continue;
      }
    } /* for (j = 1; j <= param_counter; j++) */
    /* }}} End of the ``define'' stuff. */
  
 -  status = udb_query_prepare_result (q, prep_area, hostname_g,
 +  status = udb_query_prepare_result (q, prep_area,
 +      (db->host != NULL) ? db->host : hostname_g,
        /* plugin = */ "oracle", db->name, column_names, column_num,
        /* interval = */ 0);
    if (status != 0)
      }
      else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
      {
-       o_report_error ("o_read_database_query", "OCIStmtFetch2", oci_error);
+       o_report_error ("o_read_database_query", db->name,
+           udb_query_get_name (q), "OCIStmtFetch2", oci_error);
        break;
      }
  
@@@ -645,7 -676,8 +658,8 @@@ static int o_read_database (o_database_
          OCI_ATTR_SERVER, oci_error);
      if (status != OCI_SUCCESS)
      {
-       o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+       o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+           oci_error);
        return (-1);
      }
  
            OCI_ATTR_SERVER_STATUS, oci_error);
        if (status != OCI_SUCCESS)
        {
-         o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+         o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+             oci_error);
          return (-1);
        }
      }
          (OraText *) db->connect_id, (ub4) strlen (db->connect_id));
      if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
      {
-       o_report_error ("o_read_database", "OCILogon", oci_error);
+       char errfunc[256];
+       ssnprintf (errfunc, sizeof (errfunc), "OCILogon(\"%s\")", db->connect_id);
+       o_report_error ("o_read_database", db->name, NULL, errfunc, oci_error);
        DEBUG ("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
            db->connect_id, db->oci_service_context);
        db->oci_service_context = NULL;
diff --combined src/redis.c
  #include <pthread.h>
  #include <credis.h>
  
+ #ifndef HOST_NAME_MAX
+ # define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+ #endif
  #define REDIS_DEF_HOST   "localhost"
  #define REDIS_DEF_PORT    6379
  #define REDIS_DEF_TIMEOUT 2000
@@@ -50,7 -54,6 +54,7 @@@ struct redis_node_
  {
    char name[MAX_REDIS_NODE_NAME];
    char host[HOST_NAME_MAX];
 +  char passwd[HOST_NAME_MAX];
    int port;
    int timeout;
  
@@@ -133,8 -136,6 +137,8 @@@ static int redis_config_node (oconfig_i
      }
      else if (strcasecmp ("Timeout", option->key) == 0)
        status = cf_util_get_int (option, &rn.timeout);
 +    else if (strcasecmp ("Password", option->key) == 0)
 +      status = cf_util_get_string_buffer (option, rn.passwd, sizeof (rn.passwd));
      else
        WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
            "block. I'll ignore this option.", option->key);
@@@ -254,18 -255,6 +258,18 @@@ static int redis_read (void) /* {{{ *
        continue;
      }
  
 +    if (strlen (rn->passwd) > 0)
 +    {
 +      DEBUG ("redis plugin: authenticanting node `%s' passwd(%s).", rn->name, rn->passwd);
 +      status = credis_auth(rh, rn->passwd);
 +      if (status != 0)
 +      {
 +        WARNING ("redis plugin: unable to authenticate on node `%s'.", rn->name);
 +        credis_close (rh);
 +        continue;
 +      }
 +    }
 +
      memset (&info, 0, sizeof (info));
      status = credis_info (rh, &info);
      if (status != 0)