powerdns plugin: Replace the `Command' option with the `Collect' option.
authorFlorian Forster <octo@crystal.wlan.home.verplant.org>
Sat, 3 May 2008 21:17:10 +0000 (23:17 +0200)
committerFlorian Forster <octo@crystal.wlan.home.verplant.org>
Sat, 3 May 2008 21:17:10 +0000 (23:17 +0200)
The original code let the user define the command to use when querying the
server. This commit changes that and lets the user select the _values_ he's
interested in. Depending on whether an authorative server or a recursor is
collected this
- issues a `SHOW *' and manually greps the interesting pieces, or
- builds a command that requests only the interesting values.

Code compiles but it untested. Manpage not yet updated.

src/powerdns.c

index 5a4ccf8..d91ce5b 100644 (file)
@@ -65,9 +65,18 @@ typedef struct list_item_s list_item_t;
 
 struct list_item_s
 {
+  enum
+  {
+    SRV_AUTHORATIVE,
+    SRV_RECURSOR
+  } server_type;
   int (*func) (list_item_t *item);
   char *instance;
+
+  char **fields;
+  int fields_num;
   char *command;
+
   struct sockaddr_un sockaddr;
   int socktype;
 };
@@ -190,13 +199,9 @@ static llist_t *list = NULL;
 static char *local_sockpath = NULL;
 
 /* TODO: Do this before 4.4:
- * - Make list of ``interesting values'' configurable
- * - Authorative server:
- *   - Store each element in a list or an array
- *   - Check values returned by `SHOW *' against that list.
  * - Recursor:
- *   - Use the list to build a command to request the given values
  *   - Complete list of known pdns -> collectd mappings.
+ * - Update the collectd.conf(5) manpage.
  *
  * -octo
  */
@@ -493,6 +498,14 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
   char *key;
   char *value;
 
+  if (item->command == NULL)
+    item->command = strdup ("SHOW *");
+  if (item->command == NULL)
+  {
+    ERROR ("powerdns plugin: strdup failed.");
+    return (-1);
+  }
+
   status = powerdns_get_data (item, &buffer, &buffer_size);
   if (status != 0)
     return (-1);
@@ -502,6 +515,8 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
   saveptr = NULL;
   while ((key = strtok_r (dummy, ",", &saveptr)) != NULL)
   {
+    int i;
+
     dummy = NULL;
 
     value = strchr (key, '=');
@@ -514,6 +529,13 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
     if (value[0] == '\0')
       continue;
 
+    /* Check if this item was requested. */
+    for (i = 0; i < item->fields_num; i++)
+      if (strcasecmp (key, item->fields[i]) == 0)
+       break;
+    if (i >= item->fields_num)
+      continue;
+
     submit (item->instance, key, value);
   } /* while (strtok_r) */
 
@@ -522,6 +544,41 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
   return (0);
 } /* }}} int powerdns_read_server */
 
+/*
+ * powerdns_update_recursor_command
+ *
+ * Creates a string that holds the command to be sent to the recursor. This
+ * string is stores in the `command' member of the `list_item_t' passed to the
+ * function. This function is called by `powerdns_read_recursor'.
+ */
+static int powerdns_update_recursor_command (list_item_t *li) /* {{{ */
+{
+  char buffer[4096];
+  int status;
+
+  if (li != NULL)
+    return (0);
+
+  strcpy (buffer, "get ");
+  status = strjoin (&buffer[4], sizeof (buffer) - strlen ("get "),
+      li->fields, li->fields_num,
+      /* seperator = */ " ");
+  if (status < 0)
+  {
+    ERROR ("powerdns plugin: strjoin failed.");
+    return (-1);
+  }
+
+  li->command = strdup (buffer);
+  if (li->command == NULL)
+  {
+    ERROR ("powerdns plugin: strdup failed.");
+    return (-1);
+  }
+
+  return (0);
+} /* }}} int powerdns_update_recursor_command */
+
 static int powerdns_read_recursor (list_item_t *item) /* {{{ */
 {
   char *buffer = NULL;
@@ -536,6 +593,17 @@ static int powerdns_read_recursor (list_item_t *item) /* {{{ */
   char *value;
   char *value_saveptr;
 
+  if (item->command == NULL)
+  {
+    status = powerdns_update_recursor_command (item);
+    if (status != 0)
+    {
+      ERROR ("powerdns plugin: powerdns_update_recursor_command failed.");
+      return (-1);
+    }
+  }
+  assert (item->command != NULL);
+
   status = powerdns_get_data (item, &buffer, &buffer_size);
   if (status != 0)
     return (-1);
@@ -589,7 +657,54 @@ static int powerdns_config_add_string (const char *name, /* {{{ */
     return (-1);
 
   return (0);
-} /* }}} int ctail_config_add_string */
+} /* }}} int powerdns_config_add_string */
+
+static int powerdns_config_add_collect (list_item_t *li, /* {{{ */
+    oconfig_item_t *ci)
+{
+  int i;
+  char **temp;
+
+  if (ci->values_num < 1)
+  {
+    WARNING ("powerdns plugin: The `Collect' option needs "
+       "at least one argument.");
+    return (-1);
+  }
+
+  for (i = 0; i < ci->values_num; i++)
+    if (ci->values[i].type != OCONFIG_TYPE_STRING)
+    {
+      WARNING ("powerdns plugin: Only string arguments are allowed to "
+         "the `Collect' option.");
+      return (-1);
+    }
+
+  temp = (char **) realloc (li->fields,
+      sizeof (char *) * (li->fields_num + ci->values_num));
+  if (temp == NULL)
+  {
+    WARNING ("powerdns plugin: realloc failed.");
+    return (-1);
+  }
+  li->fields = temp;
+
+  for (i = 0; i < ci->values_num; i++)
+  {
+    li->fields[li->fields_num] = strdup (ci->values[i].value.string);
+    if (li->fields[li->fields_num] == NULL)
+    {
+      WARNING ("powerdns plugin: strdup failed.");
+      continue;
+    }
+    li->fields_num++;
+  }
+
+  /* Invalidate a previously computed command */
+  sfree (li->command);
+
+  return (0);
+} /* }}} int powerdns_config_add_collect */
 
 static int powerdns_config_add_server (oconfig_item_t *ci) /* {{{ */
 {
@@ -627,26 +742,32 @@ static int powerdns_config_add_server (oconfig_item_t *ci) /* {{{ */
    */
   if (strcasecmp ("Server", ci->key) == 0)
   {
+    item->server_type = SRV_AUTHORATIVE;
     item->func = powerdns_read_server;
-    item->command = strdup (SERVER_COMMAND);
     item->socktype = SOCK_STREAM;
     socket_temp = strdup (SERVER_SOCKET);
   }
   else if (strcasecmp ("Recursor", ci->key) == 0)
   {
+    item->server_type = SRV_RECURSOR;
     item->func = powerdns_read_recursor;
-    item->command = strdup (RECURSOR_COMMAND);
     item->socktype = SOCK_DGRAM;
     socket_temp = strdup (RECURSOR_SOCKET);
   }
+  else
+  {
+    /* We must never get here.. */
+    assert (0);
+    return (-1);
+  }
 
   status = 0;
   for (i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *option = ci->children + i;
 
-    if (strcasecmp ("Command", option->key) == 0)
-      status = powerdns_config_add_string ("Command", &item->command, option);
+    if (strcasecmp ("Collect", option->key) == 0)
+      status = powerdns_config_add_collect (item, option);
     else if (strcasecmp ("Socket", option->key) == 0)
       status = powerdns_config_add_string ("Socket", &socket_temp, option);
     else