Uhm, lots of stuff changed. Forgot to check in to be honest ;)
authorFlorian Forster <ff@octo.it>
Thu, 27 May 2010 09:27:09 +0000 (11:27 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Thu, 27 May 2010 09:27:09 +0000 (11:27 +0200)
Makefile
action_graph.c
action_list_graphs.c
test.fcgi.c

index 7bc84aa..a8dc092 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,8 @@ common.o: common.c common.h
 
 graph_list.o: graph_list.c graph_list.h
 
+utils_array.o: utils_array.c utils_array.h
+
 utils_params.o: utils_params.c utils_params.h
 
 action_graph.o: action_graph.c action_graph.h
@@ -22,7 +24,7 @@ action_list_graphs.o: action_list_graphs.c action_list_graphs.h
 test: test.c utils_params.o
 
 test.fcgi: LDLIBS = -lfcgi -lrrd
-test.fcgi: test.fcgi.c common.o graph_list.o utils_params.o action_graph.o action_list_graphs.o
+test.fcgi: test.fcgi.c common.o graph_list.o utils_array.o utils_params.o action_graph.o action_list_graphs.o
 
 .PHONY: clean
 
index f517b5c..ea5e3d5 100644 (file)
@@ -6,9 +6,7 @@
 #include <inttypes.h>
 #include <dirent.h> /* for PATH_MAX */
 #include <assert.h>
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
+#include <math.h>
 
 #include <rrd.h>
 
 #include "action_graph.h"
 #include "graph_list.h"
 #include "utils_params.h"
+#include "utils_array.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
 
 struct data_source_s
 {
@@ -35,10 +37,12 @@ struct graph_def_s
   size_t data_sources_num;
 
   _Bool stack;
+
+  int def_num;
 };
 typedef struct graph_def_s graph_def_t;
 
-static void graph_def_free (graph_def_t *gd)
+static void graph_def_free (graph_def_t *gd) /* {{{ */
 {
   size_t i;
 
@@ -55,6 +59,58 @@ static void graph_def_free (graph_def_t *gd)
   free (gd);
 } /* }}} void graph_def_free */
 
+static int hsv_to_rgb (double *hsv, double *rgb) /* {{{ */
+{
+  double c = hsv[2] * hsv[1];
+  double h = hsv[0] / 60.0;
+  double x = c * (1.0 - fabs (fmod (h, 2.0) - 1));
+  double m = hsv[2] - c;
+
+  rgb[0] = 0.0;
+  rgb[1] = 0.0;
+  rgb[2] = 0.0;
+
+       if ((0.0 <= h) && (h < 1.0)) { rgb[0] = 1.0; rgb[1] = x; rgb[2] = 0.0; }
+  else if ((1.0 <= h) && (h < 2.0)) { rgb[0] = x; rgb[1] = 1.0; rgb[2] = 0.0; }
+  else if ((2.0 <= h) && (h < 3.0)) { rgb[0] = 0.0; rgb[1] = 1.0; rgb[2] = x; }
+  else if ((3.0 <= h) && (h < 4.0)) { rgb[0] = 0.0; rgb[1] = x; rgb[2] = 1.0; }
+  else if ((4.0 <= h) && (h < 5.0)) { rgb[0] = x; rgb[1] = 0.0; rgb[2] = 1.0; }
+  else if ((5.0 <= h) && (h < 6.0)) { rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = x; }
+
+  rgb[0] += m;
+  rgb[1] += m;
+  rgb[2] += m;
+
+  return (0);
+} /* }}} int hsv_to_rgb */
+
+static uint32_t rgb_to_uint32 (double *rgb) /* {{{ */
+{
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+
+  r = (uint8_t) (255.0 * rgb[0]);
+  g = (uint8_t) (255.0 * rgb[1]);
+  b = (uint8_t) (255.0 * rgb[2]);
+
+  return ((((uint32_t) r) << 16)
+      | (((uint32_t) g) << 8)
+      | ((uint32_t) b));
+} /* }}} uint32_t rgb_to_uint32 */
+
+static uint32_t get_random_color (void) /* {{{ */
+{
+  double hsv[3] = { 0.0, 1.0, 1.0 };
+  double rgb[3] = { 0.0, 0.0, 0.0 };
+
+  hsv[0] = 360.0 * ((double) rand ()) / (((double) RAND_MAX) + 1.0);
+
+  hsv_to_rgb (hsv, rgb);
+
+  return (rgb_to_uint32 (rgb));
+} /* }}} uint32_t get_random_color */
+
 static int graph_def_add_ds (graph_def_t *gd, /* {{{ */
     const char *file,
     const char *in_ds_name, size_t ds_name_len)
@@ -85,7 +141,7 @@ static int graph_def_add_ds (graph_def_t *gd, /* {{{ */
   }
 
   ds->legend = NULL;
-  ds->color = 0xff0000;
+  ds->color = get_random_color ();
 
   gd->data_sources_num++;
 
@@ -160,11 +216,153 @@ static graph_def_t *graph_def_from_gl (const graph_list_t *gl) /* {{{ */
         gl->type, gl->type_instance);
   rrd_file[sizeof (rrd_file) - 1] = 0;
 
-  printf ("rrd_file = %s;\n", rrd_file);
-
   return (graph_def_from_rrd_file (rrd_file));
 } /* }}} graph_def_t *graph_def_from_gl */
 
+static int draw_graph_ds (graph_def_t *gd, /* {{{ */
+    size_t index, str_array_t *args)
+{
+  data_source_t *ds;
+
+  assert (index < gd->data_sources_num);
+
+  ds = gd->data_sources + index;
+
+  /* CDEFs */
+  array_append_format (args, "DEF:def_%04zu_min=%s:%s:MIN",
+      index, ds->file, ds->name);
+  array_append_format (args, "DEF:def_%04zu_avg=%s:%s:AVERAGE",
+      index, ds->file, ds->name);
+  array_append_format (args, "DEF:def_%04zu_max=%s:%s:MAX",
+      index, ds->file, ds->name);
+  /* VDEFs */
+  array_append_format (args, "VDEF:vdef_%04zu_min=def_%04zu_min,MINIMUM",
+      index, index);
+  array_append_format (args, "VDEF:vdef_%04zu_avg=def_%04zu_avg,AVERAGE",
+      index, index);
+  array_append_format (args, "VDEF:vdef_%04zu_max=def_%04zu_max,MAXIMUM",
+      index, index);
+  array_append_format (args, "VDEF:vdef_%04zu_lst=def_%04zu_avg,LAST",
+      index, index);
+
+  /* Graph part */
+  array_append_format (args, "LINE1:def_%04zu_avg#%06x:%s", index, ds->color,
+      (ds->legend != NULL) ? ds->legend : ds->name);
+  array_append_format (args, "GPRINT:vdef_%04zu_min:%%lg min,", index);
+  array_append_format (args, "GPRINT:vdef_%04zu_avg:%%lg avg,", index);
+  array_append_format (args, "GPRINT:vdef_%04zu_max:%%lg max,", index);
+  array_append_format (args, "GPRINT:vdef_%04zu_lst:%%lg last\\l", index);
+
+  return (0);
+} /* }}} int draw_graph_ds */
+
+static void emulate_graph (int argc, char **argv) /* {{{ */
+{
+  int i;
+
+  printf ("rrdtool \\\n");
+  for (i = 0; i < argc; i++)
+  {
+    if (i < (argc - 1))
+      printf ("  \"%s\" \\\n", argv[i]);
+    else
+      printf ("  \"%s\"\n", argv[i]);
+  }
+} /* }}} void emulate_graph */
+
+static int ag_info_print (rrd_info_t *info)
+{
+  if (info->type == RD_I_VAL)
+    printf ("[info] %s = %g;\n", info->key, info->value.u_val);
+  else if (info->type == RD_I_CNT)
+    printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
+  else if (info->type == RD_I_STR)
+    printf ("[info] %s = %s;\n", info->key, info->value.u_str);
+  else if (info->type == RD_I_INT)
+    printf ("[info] %s = %i;\n", info->key, info->value.u_int);
+  else if (info->type == RD_I_BLO)
+    printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
+  else
+    printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
+
+  return (0);
+} /* }}} int ag_info_print */
+
+static int output_graph (rrd_info_t *info)
+{
+  rrd_info_t *img;
+
+  for (img = info; img != NULL; img = img->next)
+    if ((strcmp ("image", img->key) == 0)
+        && (img->type == RD_I_BLO))
+      break;
+
+  if (img == NULL)
+    return (ENOENT);
+
+  printf ("Content-Type: image/png\n"
+      "Content-Length: %lu\n"
+      "\n",
+      img->value.u_blo.size);
+  fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
+      /* nmemb = */ 1, stdout);
+
+  return (0);
+} /* }}} int output_graph */
+
+static int draw_graph (graph_def_t *gd) /* {{{ */
+{
+  str_array_t *args;
+  rrd_info_t *info;
+  size_t i;
+
+  args = array_create ();
+  if (args == NULL)
+    return (ENOMEM);
+
+  array_append (args, "graph");
+  array_append (args, "-");
+  array_append (args, "--imgformat");
+  array_append (args, "PNG");
+
+  for (i = 0; i < gd->data_sources_num; i++)
+    draw_graph_ds (gd, i, args);
+
+  rrd_clear_error ();
+  info = rrd_graph_v (array_argc (args), array_argv (args));
+  if ((info == NULL) || rrd_test_error ())
+  {
+    printf ("Content-Type: text/plain\n\n");
+    printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
+    emulate_graph (array_argc (args), array_argv (args));
+  }
+  else
+  {
+    int status;
+
+    status = output_graph (info);
+    if (status != 0)
+    {
+      rrd_info_t *ptr;
+
+      printf ("Content-Type: text/plain\n\n");
+      printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
+
+      for (ptr = info; ptr != NULL; ptr = ptr->next)
+      {
+        ag_info_print (ptr);
+      }
+    }
+  }
+
+  if (info != NULL)
+    rrd_info_free (info);
+
+  array_destroy (args);
+
+  return (0);
+} /* }}} int draw_graph */
+
 static int init_gl (graph_list_t *gl) /* {{{ */
 {
   gl->host = param ("host");
@@ -203,7 +401,6 @@ int action_graph (void) /* {{{ */
   graph_list_t gl;
   graph_def_t *gd;
   int status;
-  size_t i;
 
   memset (&gl, 0, sizeof (gl));
   status = init_gl (&gl);
@@ -214,8 +411,6 @@ int action_graph (void) /* {{{ */
     return (status);
   }
 
-  printf ("Content-Type: text/plain\n\n"
-      "Hello, this is %s\n", __func__);
   gd = graph_def_from_gl (&gl);
   if (gd == NULL)
   {
@@ -223,12 +418,7 @@ int action_graph (void) /* {{{ */
     return (0);
   }
 
-  for (i = 0; i < gd->data_sources_num; i++)
-  {
-    printf ("data source %lu: %s @ %s\n",
-        (unsigned long) i, gd->data_sources[i].name, gd->data_sources[i].file);
-  }
-
+  draw_graph (gd);
   graph_def_free (gd);
 
   return (0);
index 9fc8f45..14a13bb 100644 (file)
@@ -6,6 +6,7 @@
 #include <fcgiapp.h>
 #include <fcgi_stdio.h>
 
+#include "action_list_graphs.h"
 #include "graph_list.h"
 #include "utils_params.h"
 
@@ -48,13 +49,24 @@ static int print_graph_html (const graph_list_t *gl,
   if (gl == NULL)
     return (EINVAL);
 
-  printf ("<li>%s/%s", gl->host, gl->plugin);
+  printf ("<li>");
+
+  printf ("<a href=\"%s?action=graph;", getenv ("SCRIPT_NAME"));
+  printf ("host=%s;plugin=%s;", gl->host, gl->plugin);
+  if (gl->plugin_instance != NULL)
+    printf ("plugin_instance=%s;", gl->plugin_instance);
+  printf ("type=%s;", gl->type);
+  if (gl->type_instance != NULL)
+    printf ("type_instance=%s;", gl->type_instance);
+  printf ("\">");
+
+  printf ("%s/%s", gl->host, gl->plugin);
   if (gl->plugin_instance != NULL)
     printf ("-%s", gl->plugin_instance);
   printf ("/%s", gl->type);
   if (gl->type_instance != NULL)
     printf ("-%s", gl->type_instance);
-  printf ("</li>\n");
+  printf ("</a></li>\n");
 
   return (0);
 }
index e8d9bcb..f566965 100644 (file)
@@ -26,15 +26,6 @@ struct action_s
 };
 typedef struct action_s action_t;
 
-#if 0
-struct str_array_s
-{
-  char **ptr;
-  size_t size;
-};
-typedef struct str_array_s str_array_t;
-#endif
-
 static int action_usage (void);
 
 static const action_t actions[] =
@@ -45,56 +36,6 @@ static const action_t actions[] =
 };
 static const size_t actions_num = sizeof (actions) / sizeof (actions[0]);
 
-#if 0
-static str_array_t *array_alloc (void) /* {{{ */
-{
-  str_array_t *a;
-
-  a = malloc (sizeof (*a));
-  if (a == NULL)
-    return (NULL);
-
-  memset (a, 0, sizeof (*a));
-  a->ptr = NULL;
-  a->size = 0;
-
-  return (a);
-} /* }}} str_array_t *array_alloc */
-
-static void array_free (str_array_t *a) /* {{{ */
-{
-  if (a == NULL)
-    return;
-
-  free (a->ptr);
-  a->ptr = NULL;
-  a->size = 0;
-
-  free (a);
-} /* }}} void array_free */
-
-static int array_add (const char *entry, void *user_data) /* {{{ */
-{
-  str_array_t *a = user_data;
-  char **ptr;
-
-  if ((entry == NULL) || (a == NULL))
-    return (EINVAL);
-
-  ptr = realloc (a->ptr, sizeof (*a->ptr) * (a->size + 1));
-  if (ptr == NULL)
-    return (ENOMEM);
-  a->ptr = ptr;
-  ptr = a->ptr + a->size;
-
-  *ptr = strdup (entry);
-  if (*ptr == NULL)
-    return (ENOMEM);
-
-  a->size++;
-  return (0);
-} /* }}} int array_add */
-#endif
 
 static int action_usage (void) /* {{{ */
 {