]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
cmds: Fix the PUTVAL command.
authorFlorian Forster <octo@google.com>
Wed, 15 Jul 2020 14:18:42 +0000 (16:18 +0200)
committerFlorian Forster <octo@google.com>
Wed, 29 Jul 2020 11:40:54 +0000 (13:40 +0200)
This is a partial roll-back of previous code that tried to convert PUTVAL
to use metric_t. This role is now filled by PUTMETRIC instead.

Modifications to the "common" plugin (particularly "parse_identifier" and
"parse_identifier_vl" fix the "cmds" unit tests.

The "cmd_create_putval" function has been removed because output will use
the new metric format instead.

src/utils/cmds/cmds.h
src/utils/cmds/cmds_test.c
src/utils/cmds/putval.c
src/utils/cmds/putval.h

index b6c9a54ece303343b1f924bfa0ccd10db8f5ad52..3e30a56bb96d74af6f3c374ffeea574f79fb50b4 100644 (file)
@@ -67,16 +67,10 @@ typedef struct {
   /* The raw identifier as provided by the user. */
   char *raw_identifier;
 
-  /* Depending on the function, this is an input or output field:
-   *
-   * cmd_parse_putval:
-   *   OUTPUT  Receives parsed metric information. The metric family will
-   *           contain a single metric.
-   * cmd_create_putval:
-   *   INPUT   Holds the metrics for which to format the PUTVAL command. The
-   *           metric family may contain multiple metrics.
-   */
-  metric_family_t *family;
+  /* An array of the fully parsed identifier and all value lists, and their
+   * options as provided by the user. */
+  value_list_t *vl;
+  size_t vl_num;
 } cmd_putval_t;
 
 typedef struct {
index d95fd59ab0e45292a8c6228834d2f03292f37517..7b26b570bf5af6ea3ec8154f3488443a2c8c8dfb 100644 (file)
@@ -52,7 +52,7 @@ static void error_cb(void *ud, cmd_status_t status, const char *format,
   int size = vsnprintf(NULL, 0, format, ap_copy);
   assert(size > 0);
 
-  char buffer[size];
+  char buffer[size+1];
   vsnprintf(buffer, sizeof(buffer), format, ap);
 
   strbuf_print(buf, buffer);
@@ -181,12 +181,6 @@ static struct {
     },
 
     /* Valid PUTVAL commands. */
-    {
-        "PUTVAL unit_test N:42",
-        &default_host_opts,
-        CMD_OK,
-        CMD_PUTVAL,
-    },
     {
         "PUTVAL magic/MAGIC N:42",
         &default_host_opts,
@@ -386,7 +380,7 @@ DEF_TEST(parse) {
 
     char description[1024];
     ssnprintf(description, sizeof(description),
-              "cmd_parse (\"%s\", opts=%p) = "
+              "cmd_parse(\"%s\", opts=%p) = "
               "%d (type=%d [%s]); want %d "
               "(type=%d [%s])",
               parse_data[i].input, parse_data[i].opts, status, cmd.type,
index 61dc8fda584815912a4dfec41f15a046aa35a968..a287d0ed14cd6c0c9a308068c4a6e65f7301af45 100644 (file)
  * private helper functions
  */
 
-static int is_quoted(char const *str, size_t len) {
-  if (len < 2) {
-    return 0;
+static int set_option(value_list_t *vl, char const *key, char const *value,
+                      cmd_error_handler_t *errhndl) {
+  if ((vl == NULL) || (key == NULL) || (value == NULL)) {
+    return EINVAL;
   }
 
-  return (str[0] == '"' && str[len - 1] == '"');
-}
-
-/* TODO(octo): add an option to set metric->value_type */
-static int set_option(metric_t *m, char const *key, char const *value,
-                      cmd_error_handler_t *err) {
-  if ((m == NULL) || (key == NULL) || (value == NULL))
-    return -1;
-
   if (strcasecmp("interval", key) == 0) {
     double tmp;
     char *endptr;
@@ -58,35 +50,19 @@ static int set_option(metric_t *m, char const *key, char const *value,
     tmp = strtod(value, &endptr);
 
     if ((errno == 0) && (endptr != NULL) && (endptr != value) && (tmp > 0.0))
-      m->interval = DOUBLE_TO_CDTIME_T(tmp);
+      vl->interval = DOUBLE_TO_CDTIME_T(tmp);
   } else if (strncasecmp("meta:", key, 5) == 0) {
     char const *meta_key = key + 5;
-    size_t value_len = strlen(value);
 
-    if (m->meta == NULL) {
-      m->meta = meta_data_create();
-      if (m->meta == NULL) {
+    if (vl->meta == NULL) {
+      vl->meta = meta_data_create();
+      if (vl->meta == NULL) {
         return CMD_ERROR;
       }
     }
 
-    /* TODO(octo): this should deal with escaped characters. */
-    if (is_quoted(value, value_len)) {
-      int metadata_err;
-      char const *value_str = sstrndup(value + 1, value_len - 2);
-      if (value_str == NULL) {
-        return CMD_ERROR;
-      }
-      metadata_err = meta_data_add_string(m->meta, meta_key, value_str);
-      free((void *)value_str);
-      if (metadata_err != 0) {
-        return CMD_ERROR;
-      }
-      return CMD_OK;
-    }
-
-    cmd_error(CMD_NO_OPTION, err, "Non-string metadata not supported yet");
-    return CMD_NO_OPTION;
+    int status = meta_data_add_string(vl->meta, meta_key, value);
+    return (status == 0) ? CMD_OK : CMD_ERROR;
   } else {
     return CMD_ERROR;
   }
@@ -99,7 +75,7 @@ static int set_option(metric_t *m, char const *key, char const *value,
 
 cmd_status_t cmd_parse_putval(size_t argc, char **argv,
                               cmd_putval_t *ret_putval,
-                              cmd_options_t const *opts,
+                              const cmd_options_t *opts,
                               cmd_error_handler_t *errhndl) {
   if ((ret_putval == NULL) || (opts == NULL)) {
     errno = EINVAL;
@@ -113,41 +89,48 @@ cmd_status_t cmd_parse_putval(size_t argc, char **argv,
     return CMD_PARSE_ERROR;
   }
 
-  char *identifier = strdup(argv[0]);
-  if (identifier == NULL) {
-    cmd_error(CMD_ERROR, errhndl, "malloc failed.");
-    return CMD_ERROR;
+  value_list_t vl = VALUE_LIST_INIT;
+  if ((opts != NULL) && (opts->identifier_default_host != NULL)) {
+         sstrncpy(vl.host, opts->identifier_default_host, sizeof(vl.host));
   }
 
-  metric_family_t *fam =
-      metric_family_unmarshal_text(identifier, METRIC_TYPE_UNTYPED);
-  if (fam == NULL) {
-    int err = errno;
-    DEBUG("cmd_handle_putval: Parsing identifier \"%s\" failed: %s.",
-          identifier, STRERROR(err));
-    cmd_error(CMD_PARSE_ERROR, errhndl, "Parsing identifier \"%s\" failed: %s.",
-              identifier, STRERROR(err));
-    free(identifier);
+  char const *identifier = argv[0];
+  int status = parse_identifier_vl(identifier, &vl);
+  if (status != 0) {
+    DEBUG("cmd_handle_putval: Cannot parse identifier `%s'.", identifier);
+    cmd_error(CMD_PARSE_ERROR, errhndl, "parse_identifier_vl(\"%s\"): %s", identifier, STRERROR(status));
     return CMD_PARSE_ERROR;
   }
 
-  (*ret_putval) = (cmd_putval_t){
-      .raw_identifier = identifier,
-      .family = fam,
-  };
+  data_set_t const *ds = plugin_get_ds(vl.type);
+  if (ds == NULL) {
+    cmd_error(CMD_PARSE_ERROR, errhndl, "1 Type `%s' isn't defined.", vl.type);
+    return CMD_PARSE_ERROR;
+  }
+
+  ret_putval->raw_identifier = strdup(identifier);
+  if (ret_putval->raw_identifier == NULL) {
+    cmd_error(CMD_ERROR, errhndl, "malloc failed.");
+    cmd_destroy_putval(ret_putval);
+    sfree(vl.values);
+    return CMD_ERROR;
+  }
 
   /* All the remaining fields are part of the option list. */
   cmd_status_t result = CMD_OK;
-  metric_t m = {0};
   for (size_t i = 1; i < argc; ++i) {
+    value_list_t *tmp;
+
     char *key = NULL;
     char *value = NULL;
 
-    int status = cmd_parse_option(argv[i], &key, &value, errhndl);
+    status = cmd_parse_option(argv[i], &key, &value, errhndl);
     if (status == CMD_OK) {
+      int option_err;
+
       assert(key != NULL);
       assert(value != NULL);
-      int option_err = set_option(&m, key, value, errhndl);
+      option_err = set_option(&vl, key, value, errhndl);
       if (option_err != CMD_OK && option_err != CMD_NO_OPTION) {
         result = option_err;
         break;
@@ -160,21 +143,43 @@ cmd_status_t cmd_parse_putval(size_t argc, char **argv,
       break;
     }
     /* else: cmd_parse_option did not find an option; treat this as a
-     * value. */
+     * value list. */
+
+    vl.values_len = ds->ds_num;
+    vl.values = calloc(vl.values_len, sizeof(*vl.values));
+    if (vl.values == NULL) {
+      cmd_error(CMD_ERROR, errhndl, "malloc failed.");
+      result = CMD_ERROR;
+      break;
+    }
 
-    status = parse_value(argv[i], &m.value, fam->type);
+    status = parse_values(argv[i], &vl, ds);
     if (status != 0) {
       cmd_error(CMD_PARSE_ERROR, errhndl, "Parsing the values string failed.");
       result = CMD_PARSE_ERROR;
+      vl.values_len = 0;
+      sfree(vl.values);
       break;
     }
 
-    status = metric_family_metric_append(fam, m);
-    if (status != 0) {
-      cmd_error(CMD_ERROR, errhndl, "metric_family_metric_append failed.");
+    tmp = realloc(ret_putval->vl,
+                  (ret_putval->vl_num + 1) * sizeof(*ret_putval->vl));
+    if (tmp == NULL) {
+      cmd_error(CMD_ERROR, errhndl, "realloc failed.");
+      cmd_destroy_putval(ret_putval);
       result = CMD_ERROR;
+      vl.values_len = 0;
+      sfree(vl.values);
       break;
     }
+
+    ret_putval->vl = tmp;
+    ret_putval->vl_num++;
+    memcpy(&ret_putval->vl[ret_putval->vl_num - 1], &vl, sizeof(vl));
+
+    /* pointer is now owned by ret_putval->vl[] */
+    vl.values_len = 0;
+    vl.values = NULL;
   } /* while (*buffer != 0) */
   /* Done parsing the options. */
 
@@ -189,73 +194,44 @@ void cmd_destroy_putval(cmd_putval_t *putval) {
   if (putval == NULL)
     return;
 
-  free(putval->raw_identifier);
-  metric_family_free(putval->family);
+  sfree(putval->raw_identifier);
 
-  (*putval) = (cmd_putval_t){0};
+  for (size_t i = 0; i < putval->vl_num; ++i) {
+    sfree(putval->vl[i].values);
+    meta_data_destroy(putval->vl[i].meta);
+    putval->vl[i].meta = NULL;
+  }
+  sfree(putval->vl);
+  putval->vl = NULL;
+  putval->vl_num = 0;
 } /* void cmd_destroy_putval */
 
 cmd_status_t cmd_handle_putval(FILE *fh, char *buffer) {
-  cmd_error_handler_t err = {cmd_error_fh, fh};
+  cmd_error_handler_t errhndl = {cmd_error_fh, fh};
+  cmd_t cmd;
+
+  int status;
 
   DEBUG("utils_cmd_putval: cmd_handle_putval (fh = %p, buffer = %s);",
         (void *)fh, buffer);
 
-  cmd_t cmd = {0};
-  int status;
-  if ((status = cmd_parse(buffer, &cmd, NULL, &err)) != CMD_OK)
+  if ((status = cmd_parse(buffer, &cmd, NULL, &errhndl)) != CMD_OK)
     return status;
   if (cmd.type != CMD_PUTVAL) {
-    cmd_error(CMD_UNKNOWN_COMMAND, &err, "Unexpected command: `%s'.",
+    cmd_error(CMD_UNKNOWN_COMMAND, &errhndl, "Unexpected command: `%s'.",
               CMD_TO_STRING(cmd.type));
     cmd_destroy(&cmd);
     return CMD_UNKNOWN_COMMAND;
   }
 
-  status = plugin_dispatch_metric_family(cmd.cmd.putval.family);
-  if (status != 0) {
-    cmd_error(CMD_ERROR, &err,
-              "plugin_dispatch_metric_list failed with status %d.", status);
-    cmd_destroy(&cmd);
-    return CMD_ERROR;
-  }
+  for (size_t i = 0; i < cmd.cmd.putval.vl_num; ++i)
+    plugin_dispatch_values(&cmd.cmd.putval.vl[i]);
 
-  if (fh != stdout) {
-    cmd_putval_t *putval = &cmd.cmd.putval;
-    size_t n = putval->family->metric.num;
-    cmd_error(CMD_OK, &err, "Success: %zu %s been dispatched.", n,
-              (n == 1) ? "metric has" : "metrics have");
-  }
+  if (fh != stdout)
+    cmd_error(CMD_OK, &errhndl, "Success: %i %s been dispatched.",
+              (int)cmd.cmd.putval.vl_num,
+              (cmd.cmd.putval.vl_num == 1) ? "value has" : "values have");
 
   cmd_destroy(&cmd);
   return CMD_OK;
 } /* int cmd_handle_putval */
-
-/* TODO(octo): Improve the readability of the command.
- *
- * Currently, this assumes lines similar to:
- *
- *   PUTVAL "metric_name{key=\"value\"}" interval=10.000 42
- *
- * Encoding the labels in this way generates a lot of escaped quotes, which is
- * not ideal. An alternative representation would be:
- *
- *   PUTVAL metric_name label:key="value" interval=10.000 42
- */
-int cmd_create_putval(strbuf_t *buf, metric_t const *m) { /* {{{ */
-  if ((buf == NULL) || (m == NULL)) {
-    return EINVAL;
-  }
-
-  strbuf_t id_buf = STRBUF_CREATE;
-  int status = metric_identity(&id_buf, m);
-  if (status != 0) {
-    return status;
-  }
-
-  strbuf_print(buf, "PUTVAL \"");
-  strbuf_print_escaped(buf, id_buf.ptr, "\\\"\n\r\t", '\\');
-  strbuf_printf(buf, "\" interval=%.3f", CDTIME_T_TO_DOUBLE(m->interval));
-  /* TODO(octo): print option to set the value type. */
-  return value_marshal_text(buf, m->value, m->family->type);
-} /* }}} int cmd_create_putval */
index 9985d3e0516759052a41c6d16aa910d6889e9324..b4d736da3b6f2798c56bd2762364cc6cc678ffa5 100644 (file)
@@ -41,6 +41,4 @@ cmd_status_t cmd_handle_putval(FILE *fh, char *buffer);
 
 void cmd_destroy_putval(cmd_putval_t *putval);
 
-int cmd_create_putval(strbuf_t *buf, metric_t const *m);
-
 #endif /* UTILS_CMD_PUTVAL_H */