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

Peter Stamfest <[email protected]>
Newsgroups gmane.comp.db.rrdtool.devel
Message-ID <[email protected]>
# HG changeset patch
# User Peter Stamfest <[email protected]>
# 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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.