]> git.itanic.dy.fi Git - rrdd/commitdiff
Add Initial version of config file handling
authorTimo Kokkonen <timo.t.kokkonen@iki.fi>
Wed, 20 Jun 2012 19:55:42 +0000 (22:55 +0300)
committerTimo Kokkonen <timo.t.kokkonen@iki.fi>
Wed, 20 Jun 2012 19:55:42 +0000 (22:55 +0300)
Support for reading and writing database entries from and to config
files. Can handle most of the normal cases.

Signed-off-by: Timo Kokkonen <timo.t.kokkonen@iki.fi>
config.c [new file with mode: 0644]
config.h [new file with mode: 0644]

diff --git a/config.c b/config.c
new file mode 100644 (file)
index 0000000..db77a2e
--- /dev/null
+++ b/config.c
@@ -0,0 +1,502 @@
+#include "debug.h"
+#include "config.h"
+#include "rrdtool.h"
+#include "parser.h"
+
+#define RRD_DATABASE_LIST "rrd_database"
+#define RRD_DATABASE_NAME "name"
+
+static int read_strings_from_list(config_setting_t *list, const char ***strings)
+{
+       config_setting_t *string;
+       int j;
+       int str_count = config_setting_length(list);
+       const char **strs;
+
+       strs = calloc(sizeof(*strs), str_count + 1);
+
+       for (j = 0; j < str_count; j++) {
+               const char *str;
+
+               string = config_setting_get_elem(list, j);
+               str = config_setting_get_string(string);
+               strs[j] = strdup(str);
+       }
+       *strings = strs;
+
+       return 0;
+}
+
+static int parse_images(config_setting_t *list, struct rrd_database *db)
+{
+       int i, count;
+       config_setting_t *image, *str_list;
+       const char *database = NULL, *filename = NULL, *timestart = NULL;
+       const char *timeend = NULL, *imageformat = NULL;
+       const char **options = NULL, **text = NULL;
+       int width = 0, height = 0, text_lead = 0;
+
+       count = config_setting_length(list);
+
+       pr_info("%s: Parsing %d images\n", db->name, count);
+       db->images = calloc(sizeof(*db->images), count + 1);
+
+       for (i = 0; i < count; i++) {
+               image = config_setting_get_elem(list, i);
+               db->images[i] = calloc(sizeof(*db->images[i]), 1);
+
+               config_setting_lookup_string(image, "database", &database);
+               config_setting_lookup_int(image, "text_lead", &text_lead);
+
+               /*
+                * The config_setting_lookup_* functions will leave
+                * the destination unchanged in case requested value
+                * is not found. If that is the case, the value from
+                * previous image group is used. That makes it
+                * possible for the user to only define once all
+                * fields and then leave identical fields unset on the
+                * following groups, making it easier to define many
+                * almost identical images.
+                */
+
+               config_setting_lookup_string(image, "filename", &filename);
+               if (!filename) {
+                       pr_err("Database %s does not have \"filename\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               config_setting_lookup_int(image, "width", &width);
+               if (!width) {
+                       pr_err("Database %s does not have \"width\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               config_setting_lookup_int(image, "height", &height);
+               if (!height) {
+                       pr_err("Database %s does not have \"height\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               config_setting_lookup_string(image, "timestart", &timestart);
+               if (!timestart) {
+                       pr_err("Database %s does not have \"height\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               config_setting_lookup_string(image, "timeend", &timeend);
+               if (!timeend) {
+                       pr_err("Database %s does not have \"height\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               config_setting_lookup_string(image, "imageformat",
+                                       &imageformat);
+               if (!imageformat) {
+                       pr_err("Database %s does not have \"height\" entry "
+                               " in image data\n",
+                               db->name);
+                       return -1;
+               }
+
+               str_list = config_setting_get_member(image, "options");
+               if (str_list)
+                       read_strings_from_list(str_list, &options);
+
+               str_list = config_setting_get_member(image, "text");
+               if (str_list)
+                       read_strings_from_list(str_list, &text);
+
+               db->images[i]->rrd_database     =
+                       database ? strdup(database) : NULL;
+               db->images[i]->image_filename   = strdup(filename);
+               db->images[i]->width            = width;
+               db->images[i]->height           = height;
+               strncpy(db->images[i]->timestart, timestart,
+                       sizeof(db->images[i]->timestart));
+               strncpy(db->images[i]->timeend, timeend,
+                       sizeof(db->images[i]->timeend));
+               strncpy(db->images[i]->imageformat, imageformat,
+                       sizeof(db->images[i]->imageformat));
+               db->images[i]->options          = options;
+               db->images[i]->text_lead        = text_lead;
+               db->images[i]->text             = text;
+       }
+
+       return 0;
+}
+
+static int (*str_to_parser(const char *str))(char *rrd_data, void *parser_data)
+{
+       if (!str)
+               return NULL;
+
+       if (!strcmp(str, "cpu"))
+               return cpu_parser;
+
+       if (!strcmp(str, "mem"))
+               return mem_parser;
+
+       if (!strcmp(str, "cpu_mem"))
+               return cpu_mem_parser;
+
+       if (!strcmp(str, "digitemp"))
+               return digitemp_parser;
+
+       if (!strcmp(str, "digitemp_mod"))
+               return digitemp_parser_mod;
+
+       if (!strcmp(str, "script"))
+               return script_parser;
+
+       if (!strcmp(str, "netstats"))
+               return netstats_parser;
+
+       return NULL;
+}
+
+static int parse_data_sources(config_setting_t *rrd, struct rrd_database *db)
+{
+       config_setting_t *list, *group;
+       int i, count;
+       const char *type = NULL, *name = NULL;
+       int heartbeat = 0;
+       double min = 0;
+       double max = 0;
+
+       list = config_setting_get_member(rrd, "sources");
+       if (!list) {
+               pr_info("No data sources\n");
+               return 0;
+       }
+
+       if (!config_setting_is_list(list)) {
+               pr_err("Data sources have no list\n");
+               return 0;
+       }
+
+       count = config_setting_length(list);
+       db->sources = calloc(sizeof(*db->sources), count + 1);
+
+       for (i = 0; i < count; i++) {
+               group = config_setting_get_elem(list, i);
+
+               config_setting_lookup_string(group, "type", &type);
+               config_setting_lookup_string(group, "name", &name);
+               config_setting_lookup_float(group, "min", &min);
+               config_setting_lookup_float(group, "max", &max);
+               config_setting_lookup_int(group, "heartbeat", &heartbeat);
+
+               db->sources[i].type = strdup(type);
+               db->sources[i].name = strdup(name);
+               db->sources[i].heartbeat = heartbeat;
+               db->sources[i].min = min;
+               db->sources[i].max = max;
+       }
+
+       return 0;
+}
+
+static int parse_archives(config_setting_t *rrd, struct rrd_database *db)
+{
+       config_setting_t *list, *group;
+       int i, count;
+       const char *type = NULL;
+       double xff = 0;
+       int steps = 0;
+       int rows = 0;
+
+       list = config_setting_get_member(rrd, "archives");
+       if (!list) {
+               pr_info("No archive found\n");
+               return 0;
+       }
+
+       if (!config_setting_is_list(list)) {
+               pr_err("Archive does not contain a list\n");
+               return 0;
+       }
+
+       count = config_setting_length(list);
+       db->archives = calloc(sizeof(*db->archives), count + 1);
+
+       for (i = 0; i < count; i++) {
+               group = config_setting_get_elem(list, i);
+
+               config_setting_lookup_string(group, "type", &type);
+               config_setting_lookup_float(group, "xff", &xff);
+               config_setting_lookup_int(group, "steps", &steps);
+               config_setting_lookup_int(group, "rows", &rows);
+
+               db->archives[i].type = strdup(type);
+               db->archives[i].xff = xff;
+               db->archives[i].steps = steps;
+               db->archives[i].rows = rows;
+       }
+
+       return 0;
+}
+
+static int parse_database(config_setting_t *rrd, struct rrd_database *db)
+{
+       config_setting_t *list, *str_list;
+       const char *name, *parser = NULL, *filename, **parser_data;
+
+       if (!config_setting_lookup_string(rrd, "name", &name)) {
+               pr_err("Database entry does not contain name\n");
+               return -1;
+       }
+
+       pr_info("parsing database %s\n", name);
+       db->name = strdup(name);
+
+       if (!config_setting_lookup_string(rrd, "filename", &filename)) {
+               pr_err("Database %s does not contain filename\n", db->name);
+               return -1;
+       }
+       db->filename = strdup(filename);
+
+       if (!config_setting_lookup_int(rrd, "interval", &db->interval)) {
+               pr_err("Database %s does not have interval set\n", name);
+               return -1;
+       }
+
+       /* Parser is not a mandatory parameter */
+       config_setting_lookup_string(rrd, "parser", &parser);
+       db->parse = str_to_parser(parser);
+
+       list = config_setting_get_member(rrd, "image");
+       parse_images(list, db);
+       parse_data_sources(rrd, db);
+       parse_archives(rrd, db);
+
+       str_list = config_setting_get_member(rrd, "parser_data");
+       if (str_list) {
+               read_strings_from_list(str_list, &parser_data);
+               db->parser_data = parser_data;
+       }
+
+       return 0;
+}
+
+struct rrd_database **populate_database(const char *conffile)
+{
+       struct rrd_database **rrd_db = NULL;
+       config_t config;
+       config_setting_t *rrd_database;
+       int i, count;
+
+       config_init(&config);
+
+       if (!config_read_file(&config, conffile)) {
+               pr_err("%s:%d - %s\n", config_error_file(&config),
+                       config_error_line(&config),
+                       config_error_text(&config));
+               goto out;
+       }
+
+       rrd_database = config_lookup(&config, "rrd_database");
+       count = config_setting_length(rrd_database);
+
+       /*
+        * Allocate one element extra. The last one is zeroed out to
+        * indicate the end of the db list
+        */
+       rrd_db = calloc(count + 1, sizeof(*rrd_db));
+
+       pr_info("There are %d database entries\n", count);
+
+       for (i = 0; i < count; i++) {
+               config_setting_t *rrd;
+               rrd_db[i] = calloc(1, sizeof(*rrd_db[i]));
+               rrd = config_setting_get_elem(rrd_database, i);
+               parse_database(rrd, rrd_db[i]);
+       }
+
+out:
+       config_destroy(&config);
+       return rrd_db;
+}
+
+#define CONFIG_ADD_STRING(_config, _setting, _name, _val)              \
+       do {                                                            \
+               setting = config_setting_add(_config, _name,            \
+                                       CONFIG_TYPE_STRING);            \
+               config_setting_set_string(_setting, _val);              \
+       } while (0);                                                    \
+
+#define CONFIG_ADD_INT(_config, _setting, _name, _val)                 \
+       do {                                                            \
+               _setting = config_setting_add(_config, _name,           \
+                                       CONFIG_TYPE_INT);               \
+               config_setting_set_int(_setting, _val);                 \
+       } while (0);                                                    \
+
+#define CONFIG_ADD_FLOAT(_config, _setting, _name, _val)               \
+       do {                                                            \
+               _setting = config_setting_add(_config, _name,           \
+                                       CONFIG_TYPE_FLOAT);             \
+               config_setting_set_float(_setting, _val);               \
+       } while (0);                                                    \
+
+static void put_strings_to_list(config_setting_t *config,
+                               const char *entry_name, const char **strings)
+{
+       config_setting_t *list, *setting;
+       int i;
+
+       list = config_setting_add(config, entry_name, CONFIG_TYPE_LIST);
+       for (i = 0; strings[i]; i++)
+               CONFIG_ADD_STRING(list, setting, NULL, strings[i]);
+}
+
+static void put_image_to_list(config_setting_t *config,
+                       struct rrd_image *image)
+{
+       config_setting_t *setting, *group;
+
+       group = config_setting_add(config, "image", CONFIG_TYPE_GROUP);
+
+       CONFIG_ADD_STRING(group, setting, "rrd_database", image->rrd_database);
+       CONFIG_ADD_STRING(group, setting, "filename", image->image_filename);
+       CONFIG_ADD_INT(group, setting, "width", image->width);
+       CONFIG_ADD_INT(group, setting, "height", image->height);
+       CONFIG_ADD_STRING(group, setting, "timestart", image->timestart);
+       CONFIG_ADD_STRING(group, setting, "timeend", image->timeend);
+       CONFIG_ADD_STRING(group, setting, "imageformat", image->imageformat);
+
+       put_strings_to_list(group, "options", image->options);
+
+       CONFIG_ADD_INT(group, setting, "text_lead", image->text_lead);
+
+       put_strings_to_list(group, "text", image->text);
+}
+
+static void put_data_source_to_list(config_setting_t *list,
+                               struct rrd_data_source *source)
+{
+       config_setting_t *setting, *group;
+
+       group = config_setting_add(list, "data_source", CONFIG_TYPE_GROUP);
+
+       CONFIG_ADD_STRING(group, setting, "type", source->type);
+       CONFIG_ADD_STRING(group, setting, "name", source->name);
+       CONFIG_ADD_INT(group, setting, "heartbeat", source->heartbeat);
+       CONFIG_ADD_FLOAT(group, setting, "min", source->min);
+       CONFIG_ADD_FLOAT(group, setting, "max", source->max);
+}
+
+static void put_archive_to_list(config_setting_t *list,
+                               struct rrd_archive *archive)
+{
+       config_setting_t *setting, *group;
+
+       group = config_setting_add(list, "archive", CONFIG_TYPE_GROUP);
+
+       CONFIG_ADD_STRING(group, setting, "type", archive->type);
+       CONFIG_ADD_FLOAT(group, setting, "xff", archive->xff);
+       CONFIG_ADD_INT(group, setting, "steps", archive->steps);
+       CONFIG_ADD_INT(group, setting, "rows", archive->rows);
+}
+
+static char *parser_to_str(int (*parser)(char *rrd_data, void *parser_data))
+{
+       if (parser == cpu_parser)
+               return "cpu";
+
+       if (parser == mem_parser)
+               return "mem";
+
+       if (parser == cpu_mem_parser)
+               return "cpu_mem";
+
+       if (parser == digitemp_parser)
+               return "digitemp";
+
+       if (parser == digitemp_parser_mod)
+               return "digitemp_mod";
+
+       if (parser == script_parser)
+               return "script";
+
+       if (parser == netstats_parser)
+               return "netstats";
+
+       return NULL;
+}
+
+static void put_database_to_list(config_setting_t *config,
+                               struct rrd_database *db)
+{
+       config_setting_t *setting;
+       config_setting_t *list, *group;
+       char *str = parser_to_str(db->parse);
+       int i;
+
+       group = config_setting_add(config, RRD_DATABASE_LIST,
+                               CONFIG_TYPE_GROUP);
+
+       CONFIG_ADD_STRING(group, setting, "name", db->name);
+       CONFIG_ADD_STRING(group, setting, "filename", db->filename);
+       CONFIG_ADD_INT(group, setting, "interval", db->interval);
+       CONFIG_ADD_STRING(group, setting, "parser", str);
+
+       if (db->parser_data)
+               put_strings_to_list(group, "parser_data", db->parser_data);
+
+       list = config_setting_add(group, "image", CONFIG_TYPE_LIST);
+       for (i = 0; db->images[i]; i++) {
+               put_image_to_list(list, db->images[i]);
+       }
+
+       if (db->sources) {
+               list = config_setting_add(group, "sources", CONFIG_TYPE_LIST);
+               for (i = 0; db->sources[i].type; i++) {
+                       put_data_source_to_list(list, &db->sources[i]);
+               }
+       }
+
+       if (db->archives) {
+               list = config_setting_add(group, "archives", CONFIG_TYPE_LIST);
+               for (i = 0; db->archives[i].type; i++) {
+                       put_archive_to_list(list, &db->archives[i]);
+               }
+       }
+}
+
+int write_database(const char *conffile, struct rrd_database **rrd_db)
+{
+       config_t config;
+       config_setting_t *root, *rrd_database_list;
+       int i;
+       int ret;
+
+       config_init(&config);
+
+       config_set_tab_width(&config, 4);
+
+       root = config_root_setting(&config);
+
+       rrd_database_list = config_setting_add(root, RRD_DATABASE_LIST,
+                                       CONFIG_TYPE_LIST);
+       for (i = 0; rrd_db[i]; i++) {
+               put_database_to_list(rrd_database_list, rrd_db[i]);
+       }
+
+       ret = !config_write_file(&config, conffile);
+       if (ret)
+               pr_err("Error while writing file.\n");
+
+       config_destroy(&config);
+
+       return ret;
+}
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..d6c0f19
--- /dev/null
+++ b/config.h
@@ -0,0 +1,11 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#include <libconfig.h>
+
+#include "rrdtool.h"
+
+struct rrd_database **populate_database(const char *conffile);
+int write_database(const char *conffile, struct rrd_database **rrd_db);
+
+#endif