[rrd-developers] [PATCH 7 of 7] * Add new UDEF definition style to rrd_graph

Peter Stamfest peter at stamfest.at
Mon Mar 7 20:28:09 CET 2011


# HG changeset patch
# User Peter Stamfest <peter at stamfest.at>
# Date 1299524877 -3600
# Node ID 2c4dd24dac78c2f41f7fc564be569001e012c5c1
# Parent  ca194c6734f0c3251b389c4603919f9687588691
* Add new UDEF definition style to rrd_graph
  - syntax:
    UDEF:x=file:///<FILE>?cf=<CF>&step=<STEP>....
  - allowed query parameters:
    cf, ds, step, start, end, reduce, cache
  - file:///  indicates a relative path (as per the URL definition)
  - file://// indicates an absolute path
* This is in preparation for possible other URL style RRD access methods

diff --git a/src/rrd_graph.c b/src/rrd_graph.c
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
@@ -239,6 +239,7 @@
     conv_if(TICK, GF_TICK);
     conv_if(TEXTALIGN, GF_TEXTALIGN);
     conv_if(DEF, GF_DEF);
+    conv_if(UDEF, GF_UDEF);
     conv_if(CDEF, GF_CDEF);
     conv_if(VDEF, GF_VDEF);
     conv_if(XPORT, GF_XPORT);
@@ -822,16 +823,16 @@
 
     /* pull the data from the rrd files ... */
     for (i = 0; i < (int) im->gdes_c; i++) {
-        /* only GF_DEF elements fetch data */
-        if (im->gdes[i].gf != GF_DEF)
+        /* only GF_DEF and GF_UDEF elements fetch data */
+        if (im->gdes[i].gf != GF_DEF && im->gdes[i].gf != GF_UDEF )
             continue;
 
         skip = 0;
         /* do we have it already ? */
         for (ii = 0; ii < i; ii++) {
-            if (im->gdes[ii].gf != GF_DEF)
+            if (im->gdes[ii].gf != GF_DEF && im->gdes[ii].gf != GF_UDEF)
                 continue;
-            if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
+            if (call(im->gdes[i].source, compare_m, im->gdes[ii].source) == 0
                 && (im->gdes[i].cf == im->gdes[ii].cf)
                 && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
                 && (im->gdes[i].start_orig == im->gdes[ii].start_orig)
@@ -853,47 +854,18 @@
         }
         if (!skip) {
             unsigned long ft_step = im->gdes[i].step;   /* ft_step will record what we got from fetch */
-            const char *rrd_daemon;
             int status;
 
-            if (im->gdes[i].daemon[0] != 0)
-                rrd_daemon = im->gdes[i].daemon;
-            else
-                rrd_daemon = im->daemon_addr;
-
-            const char *addr = want_rrdc_connection(rrd_daemon);
-            if (addr != NULL) {
-                rrdc_connection_t *conn = new_rrdc_connection(addr);
-                if (conn != NULL) {
-                    status = rrdc_fetch (conn, im->gdes[i].rrd,
-                                         cf_to_string (im->gdes[i].cf),
-                                         &im->gdes[i].start,
-                                         &im->gdes[i].end,
-                                         &ft_step,
-                                         &im->gdes[i].ds_cnt,
-                                         &im->gdes[i].ds_namv,
-                                         &im->gdes[i].data);
-
-                    delete_rrdc_connection(conn);
-
-                    if (status != 0)
-                        return (status);
-
-                } else {
-                    // try to read data locally
-                }
-            }
-
-            if ((rrd_fetch_fn(im->gdes[i].rrd,
-                              im->gdes[i].cf,
-                              &im->gdes[i].start,
-                              &im->gdes[i].end,
-                              &ft_step,
-                              &im->gdes[i].ds_cnt,
-                              &im->gdes[i].ds_namv,
-                              &im->gdes[i].data)) == -1) {
-                return -1;
-            }
+            status = call(im->gdes[i].source, fetch_m,
+                          cf_to_string (im->gdes[i].cf),
+                          &im->gdes[i].start,
+                          &im->gdes[i].end,
+                          &ft_step,
+                          &im->gdes[i].ds_cnt,
+                          &im->gdes[i].ds_namv,
+                          &im->gdes[i].data);
+
+            if (status != 0) return -1;
 
             im->gdes[i].data_first = 1;
 
@@ -916,8 +888,10 @@
             }
         }
         if (im->gdes[i].ds == -1) {
+            char *rrd = call0(im->gdes[i].source, to_string_m);
             rrd_set_error("No DS called '%s' in '%s'",
-                          im->gdes[i].ds_nam, im->gdes[i].rrd);
+                          im->gdes[i].ds_nam, rrd);
+            if (rrd != NULL) free(rrd);
             return -1;
         }
 
@@ -946,7 +920,7 @@
     long      ii;
 
     for (ii = 0; ii < im->gdes_c - 1; ii++) {
-        if ((im->gdes[ii].gf == GF_DEF
+        if ((im->gdes[ii].gf == GF_DEF || im->gdes[ii].gf == GF_UDEF
              || im->gdes[ii].gf == GF_VDEF || im->gdes[ii].gf == GF_CDEF)
             && (strcmp(im->gdes[ii].vname, key) == 0)) {
             return ii;
@@ -1678,6 +1652,7 @@
         case GF_COMMENT:
         case GF_TEXTALIGN:
         case GF_DEF:
+        case GF_UDEF:
         case GF_CDEF:
         case GF_VDEF:
 #ifdef WITH_PIECHART
@@ -3415,6 +3390,7 @@
         case GF_CDEF:
         case GF_VDEF:
         case GF_DEF:
+        case GF_UDEF:
         case GF_PRINT:
         case GF_GPRINT:
         case GF_COMMENT:
@@ -3879,13 +3855,12 @@
     im->gdes[im->gdes_c - 1].legend[0] = '\0';
     im->gdes[im->gdes_c - 1].format[0] = '\0';
     im->gdes[im->gdes_c - 1].strftm = 0;
-    im->gdes[im->gdes_c - 1].rrd[0] = '\0';
+    im->gdes[im->gdes_c - 1].source = NULL;
     im->gdes[im->gdes_c - 1].ds = -1;
     im->gdes[im->gdes_c - 1].cf_reduce = CF_AVERAGE;
     im->gdes[im->gdes_c - 1].cf = CF_AVERAGE;
     im->gdes[im->gdes_c - 1].yrule = DNAN;
     im->gdes[im->gdes_c - 1].xrule = 0;
-    im->gdes[im->gdes_c - 1].daemon[0] = 0;
     return 0;
 }
 
diff --git a/src/rrd_graph.h b/src/rrd_graph.h
--- a/src/rrd_graph.h
+++ b/src/rrd_graph.h
@@ -22,6 +22,7 @@
 
 
 #include "rrd_tool.h"
+#include "rrd_source.h"
 #include "rrd_rpncalc.h"
 
 #ifdef WIN32
@@ -57,7 +58,7 @@
 
 enum gf_en { GF_PRINT = 0, GF_GPRINT, GF_COMMENT, GF_HRULE, GF_VRULE, GF_LINE,
     GF_AREA,GF_GRAD, GF_STACK, GF_TICK, GF_TEXTALIGN,
-    GF_DEF, GF_CDEF, GF_VDEF, GF_SHIFT,
+    GF_DEF, GF_UDEF, GF_CDEF, GF_VDEF, GF_SHIFT,
     GF_XPORT
 };
 
@@ -160,10 +161,9 @@
     int       debug;    /* boolean */
     char      vname[MAX_VNAME_LEN + 1]; /* name of the variable */
     long      vidx;     /* gdes reference */
-    char      rrd[1024];    /* name of the rrd_file containing data */
+    rrd_base_source_t *source; /* the RRD source to fetch the data from */
     char      ds_nam[DS_NAM_SIZE];  /* data source name */
     long      ds;       /* data source number */
-    char      daemon[256];
     enum cf_en cf;      /* consolidation function */
     enum cf_en cf_reduce;   /* consolidation function for reduce_data() */
     struct gfx_color_t col, col2; /* graph color */
diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c
--- a/src/rrd_graph_helper.c
+++ b/src/rrd_graph_helper.c
@@ -6,6 +6,7 @@
  ****************************************************************************/
 
 #include "rrd_graph.h"
+#include "rrd_source.h"
 
 #define dprintf if (gdp->debug) printf
 
@@ -116,6 +117,12 @@
     graph_desc_t *const,
     image_desc_t *const);
 
+int       rrd_parse_udef(
+    const char *const,
+    unsigned int *const,
+    graph_desc_t *const,
+    image_desc_t *const);
+
 int       rrd_parse_vdef(
     const char *const,
     unsigned int *const,
@@ -371,8 +378,9 @@
 
     switch (im->gdes[gdp->vidx].gf) {
     case GF_DEF:
+    case GF_UDEF:
     case GF_CDEF:
-        dprintf("- vname is of type DEF or CDEF, looking for CF\n");
+        dprintf("- vname is of type DEF, UDEF or CDEF, looking for CF\n");
         if (rrd_parse_CF(line, eaten, gdp, &gdp->cf))
             return 1;
         break;
@@ -415,8 +423,9 @@
 
     switch (im->gdes[gdp->vidx].gf) {
     case GF_DEF:
+    case GF_UDEF:
     case GF_CDEF:
-        dprintf("- vname is of type DEF or CDEF, OK\n");
+        dprintf("- vname is of type DEF, UDEF or CDEF, OK\n");
         break;
     case GF_VDEF:
         rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
@@ -431,8 +440,9 @@
     if ((gdp->shidx = rrd_parse_find_vname(line, eaten, gdp, im)) >= 0) {
         switch (im->gdes[gdp->shidx].gf) {
         case GF_DEF:
+        case GF_UDEF:
         case GF_CDEF:
-            rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",
+            rrd_set_error("Offset cannot be a ([CU])DEF: '%s' in line '%s'\n",
                           im->gdes[gdp->shidx].vname, line);
             return 1;
         case GF_VDEF:
@@ -476,8 +486,9 @@
 
     switch (im->gdes[gdp->vidx].gf) {
     case GF_DEF:
+    case GF_UDEF:
     case GF_CDEF:
-        dprintf("- vname is of type DEF or CDEF, OK\n");
+        dprintf("- vname is of type DEF, UDEF or CDEF, OK\n");
         break;
     case GF_VDEF:
         rrd_set_error("Cannot xport a VDEF: '%s' in line '%s'\n",
@@ -931,7 +942,10 @@
     rrd_time_value_t start_tv, end_tv;
     time_t    start_tmp = 0, end_tmp = 0;
     char     *parsetime_error = NULL;
+    char      rrd[1024];
+    char      using_daemon[256];
 
+    rrd[0] = using_daemon[0] = 0;
     start_tv.type = end_tv.type = ABSOLUTE_TIME;
     start_tv.offset = end_tv.offset = 0;
     localtime_r(&gdp->start, &start_tv.tm);
@@ -942,13 +956,13 @@
 
     if (rrd_parse_make_vname(line, eaten, gdp, im))
         return 1;
-    i = scan_for_col(&line[*eaten], sizeof(gdp->rrd) - 1, gdp->rrd);
+    i = scan_for_col(&line[*eaten], sizeof(rrd) - 1, rrd);
     if (line[*eaten + i] != ':') {
         rrd_set_error("Problems reading database name");
         return 1;
     }
     (*eaten) += ++i;
-    dprintf("- using file '%s'\n", gdp->rrd);
+    dprintf("- using file '%s'\n", rrd);
 
     i = 0;
     sscanf(&line[*eaten], DS_NAM_FMT ":%n", gdp->ds_nam, &i);
@@ -963,8 +977,14 @@
         return 1;
     gdp->cf_reduce = gdp->cf;
 
-    if (line[*eaten] == '\0')
+    if (line[*eaten] == '\0') {
+        gdp->source = (rrd_base_source_t *) new_file_source(rrd, NULL);
+        if (gdp->source == NULL) {
+            rrd_set_error("Out of memory");
+            return 1;
+        }
         return 0;
+    }
 
     while (1) {
         dprintf("- optional parameter follows: %s\n", &line[*eaten]);
@@ -1005,9 +1025,9 @@
             dprintf("- done parsing:  '%s'\n", &line[*eaten]);
         } else if (!strcmp("daemon", command)) {
             i = scan_for_col(&line[*eaten],
-                    sizeof (gdp->daemon), gdp->daemon);
+                    sizeof (using_daemon), using_daemon);
             (*eaten) += i;
-            dprintf("- using daemon '%s'\n", gdp->daemon);
+            dprintf("- using daemon '%s'\n", using_daemon);
         } else {
             rrd_set_error("Parse error in '%s'", line);
             return 1;
@@ -1038,6 +1058,13 @@
         return 1;
     }
 
+
+    gdp->source = (rrd_base_source_t *) new_file_source(rrd, using_daemon);
+    if (gdp->source == NULL) {
+        rrd_set_error("Out of memory");
+        return 1;
+    }
+
     gdp->start = start_tmp;
     gdp->end = end_tmp;
     gdp->start_orig = start_tmp;
@@ -1049,6 +1076,149 @@
     return 0;
 }
 
+int rrd_parse_udef(
+    const char *const line,
+    unsigned int *const eaten,
+    graph_desc_t *const gdp,
+    image_desc_t *const im)
+{
+    int       i = 0, queryLen = 0;
+    rrd_time_value_t start_tv, end_tv;
+    time_t    start_tmp = 0, end_tmp = 0;
+    char     *parsetime_error = NULL;
+    rrd_base_source_t *source = NULL;
+    int       rc = 0;
+    UriQueryListA *queryList = NULL, *p;
+    int       itemCount;
+    int       cfSetFlag = 0;
+    int       cfReduceSetFlag = 0;
+    int       dsSetFlag = 0;
+
+
+    start_tv.type = end_tv.type = ABSOLUTE_TIME;
+    start_tv.offset = end_tv.offset = 0;
+    localtime_r(&gdp->start, &start_tv.tm);
+    localtime_r(&gdp->end, &end_tv.tm);
+
+    dprintf("- parsing '%s'\n", &line[*eaten]);
+    dprintf("- from line '%s'\n", line);
+
+    if (rrd_parse_make_vname(line, eaten, gdp, im))
+        return 1;
+
+    source = parse_source_string(&line[*eaten]);
+    if (source == NULL) {
+        rrd_set_error("Problem parsing uri into rrd source");
+        rc = 1;
+        goto out;
+    }
+    *eaten += strlen(&line[*eaten]);
+
+    if (source->uri == NULL) {
+        rrd_set_error("Hm, uri expected, but not available after parsing");
+        rc = 1;
+        goto out;
+    }
+
+    queryLen = source->uri->query.afterLast - source->uri->query.first;
+
+    if (queryLen > 0 &&
+            uriDissectQueryMallocA(&queryList, &itemCount, source->uri->query.first,
+                                   source->uri->query.afterLast) != URI_SUCCESS) {
+        rrd_set_error("Cannot parse URL query string");
+        rc = 1;
+        goto out;
+    }
+
+    gdp->cf = gdp->cf_reduce = CF_AVERAGE;
+    for (p = queryList ; p ; p = p->next) {
+        if (strcmp(p->key, "ds") == 0) {
+            strncpy(gdp->ds_nam, p->value, sizeof(gdp->ds_nam));
+            dsSetFlag = 1;
+            dprintf("- using DS '%s'\n", gdp->ds_nam);
+            continue;
+        } else if (strcmp(p->key, "cf") == 0) {
+            gdp->cf = cf_conv(p->value);
+            cfSetFlag = 1;
+            continue;
+        } else if (strcmp(p->key, "step") == 0) {
+            sscanf(p->value, "%lu%n", &gdp->step, &i);
+            gdp->step_orig = gdp->step;
+            dprintf("- using step %lu\n", gdp->step);
+
+            continue;
+        } else if (strcmp(p->key, "start") == 0) {
+            if ((parsetime_error = rrd_parsetime(p->value, &start_tv))) {
+                rrd_set_error("start time: %s", parsetime_error);
+                rc = 1;
+                goto out;
+            }
+            dprintf("- done parsing:  '%s'\n", p->value);
+            continue;
+        } else if (strcmp(p->key, "end") == 0) {
+            if ((parsetime_error = rrd_parsetime(p->value, &end_tv))) {
+                rrd_set_error("end time: %s", parsetime_error);
+                rc = 1;
+                goto out;
+            }
+            dprintf("- done parsing:  '%s'\n", p->value);
+            continue;
+        } else if (strcmp(p->key, "reduce") == 0) {
+            gdp->cf_reduce = cf_conv(p->value);
+            cfReduceSetFlag = 1;
+            continue;
+        }
+    }
+
+    if (!dsSetFlag) {
+        rrd_set_error("Missing DS name. Use 'ds=' query parameter");
+        rc = 1;
+        goto out;
+    }
+
+    if (!cfReduceSetFlag && cfSetFlag)
+        gdp->cf_reduce = gdp->cf;
+
+    uriFreeQueryListA(queryList);
+
+    if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+        /* error string is set in rrd_parsetime.c */
+        goto out;
+    }
+    if (start_tmp < 3600 * 24 * 365 * 10) {
+        rrd_set_error("the first entry to fetch should be "
+                      "after 1980 (%ld)", start_tmp);
+        rc = 1;
+        goto out;
+    }
+
+    if (end_tmp < start_tmp) {
+        rrd_set_error("start (%ld) should be less than end (%ld)",
+                      start_tmp, end_tmp);
+        rc = 1;
+        goto out;
+    }
+
+
+
+    gdp->start = start_tmp;
+    gdp->end = end_tmp;
+    gdp->start_orig = start_tmp;
+    gdp->end_orig = end_tmp;
+
+    dprintf("- start time %lu\n", gdp->start);
+    dprintf("- end   time %lu\n", gdp->end);
+    rc = 0;
+out:
+    if (rc != 0 && source != NULL) {
+        delete_source_obj(source);
+        source = NULL;
+    }
+
+    gdp->source = source;
+    return rc;
+}
+
 int rrd_parse_vdef(
     const char *const line,
     unsigned int *const eaten,
@@ -1071,8 +1241,8 @@
         rrd_set_error("Not a valid vname: %s in line %s", tmpstr, line);
         return 1;
     }
-    if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
-        rrd_set_error("variable '%s' not DEF nor "
+    if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_UDEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
+        rrd_set_error("variable '%s' not DEF, UDEF nor "
                       "CDEF in VDEF '%s'", tmpstr, gdp->vname);
         return 1;
     }
@@ -1183,6 +1353,10 @@
             if (rrd_parse_def(argv[i], &eaten, gdp, im))
                 return;
             break;
+        case GF_UDEF:   /* vname=URL?ds=DS&cf=CF[&step=#][&start=#][&end=#] */
+            if (rrd_parse_udef(argv[i], &eaten, gdp, im))
+                return;
+            break;
         case GF_CDEF:  /* vname=rpn-expression */
             if (rrd_parse_cdef(argv[i], &eaten, gdp, im))
                 return;



More information about the rrd-developers mailing list