health configuration now parses templates too
Costa Tsaousis committed
Aug 14, 2016 at 00:39 UTC
1273bad26b0e6fd34e3b5a9227c0a0bb89b37537
6 files changed
+190
-37
src/health.c
+166
-32
@@ -503,6 +503,12 @@ static inline void rrdcalc_unlinked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc)
503
static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
504
rc->rrdset = st;
505
506
+ if(rc->green)
507
+ st->green = rc->green;
508
+
509
+ if(rc->red)
510
+ st->red = rc->red;
511
+
512
rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
513
rc->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
514
rc->host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
@@ -648,10 +654,8 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
654
else if(host->calculations) {
655
RRDCALC *t, *last = host->calculations;
656
651
- for(t = last->next; t ; last = t, t = t->next)
652
- if(t == rc) break;
653
-
654
- if(last)
657
+ for(t = last->next; t && t != rc; last = t, t = t->next) ;
658
+ if(last && last->next == rc)
659
last->next = rc->next;
660
else
661
error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': not found", rc->name, host->hostname);
@@ -662,6 +666,7 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
666
if(rc->warning) expression_free(rc->warning);
667
if(rc->critical) expression_free(rc->critical);
668
669
+ freez(rc->source);
670
freez(rc->name);
671
freez(rc->chart);
672
freez(rc->dimensions);
@@ -670,6 +675,37 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
675
freez(rc);
676
}
677
678
+// ----------------------------------------------------------------------------
679
+// RRDCALCTEMPLATE management
680
+
681
+static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
682
+ if(host->templates) {
683
+ if(host->templates == rt) {
684
+ host->templates = rt->next;
685
+ }
686
+ else {
687
+ RRDCALCTEMPLATE *t, *last = host->templates;
688
+ for (t = last->next; t && t != rt; last = t, t = t->next ) ;
689
+ if(last && last->next == rt) {
690
+ last->next = rt->next;
691
+ rt->next = NULL;
692
+ }
693
+ else
694
+ error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
695
+ }
696
+ }
697
+
698
+ if(rt->warning) expression_free(rt->warning);
699
+ if(rt->critical) expression_free(rt->critical);
700
+
701
+ freez(rt->dimensions);
702
+ freez(rt->context);
703
+ freez(rt->name);
704
+ freez(rt->exec);
705
+ freez(rt->source);
706
+ freez(rt);
707
+}
708
+
709
// ----------------------------------------------------------------------------
710
// load health configuration
711
@@ -686,7 +722,7 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
722
#define HEALTH_EXEC_KEY "exec"
723
724
static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
689
- info("Health configuration examining alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s'",
725
+ info("Health configuration examining alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s', source '%s",
726
rc->name,
727
(rc->chart)?rc->chart:"NONE",
728
(rc->exec)?rc->exec:"DEFAULT",
@@ -699,20 +735,20 @@ static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
735
rc->update_every,
736
(rc->dimensions)?rc->dimensions:"NONE",
737
(rc->warning)?rc->warning->parsed_as:"NONE",
702
- (rc->critical)?rc->critical->parsed_as:"NONE");
738
+ (rc->critical)?rc->critical->parsed_as:"NONE",
739
+ rc->source
740
+ );
741
704
- if(!rc->chart) {
705
- error("Health configuration for alarm '%s' does not have a chart", rc->name);
742
+ if(rrdcalc_exists(host, rc->name, rc->hash))
743
return 0;
707
- }
744
709
- if(!rc->after) {
710
- error("Health configuration for alarm '%s' does not have a calculation", rc->name);
745
+ if(!rc->chart) {
746
+ error("Health configuration for alarm '%s' does not have a chart", rc->name);
747
return 0;
748
}
749
714
- if(!rc->group) {
715
- error("Health configuration for alarm '%s' does not specify a chart name", rc->name);
750
+ if(!RRDCALC_HAS_CALCULATION(rc) && !rc->warning && !rc->critical) {
751
+ error("Health configuration for alarm '%s' is useless (no calculation, no warning and no critical evaluation)", rc->name);
752
return 0;
753
}
754
@@ -721,10 +757,39 @@ static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
757
}
758
759
static inline int rrdcalctemplate_add(RRDHOST *host, RRDCALCTEMPLATE *rt) {
724
-}
760
+ info("Health configuration examining template '%s': context '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s', source '%s'",
761
+ rt->name,
762
+ (rt->context)?rt->context:"NONE",
763
+ (rt->exec)?rt->exec:"DEFAULT",
764
+ rt->green,
765
+ rt->red,
766
+ rt->group,
767
+ rt->after,
768
+ rt->before,
769
+ rt->options,
770
+ rt->update_every,
771
+ (rt->dimensions)?rt->dimensions:"NONE",
772
+ (rt->warning)?rt->warning->parsed_as:"NONE",
773
+ (rt->critical)?rt->critical->parsed_as:"NONE",
774
+ rt->source
775
+ );
776
+
777
+ if(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical) {
778
+ error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
779
+ return 0;
780
+ }
781
726
-static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
782
+ RRDCALCTEMPLATE *t;
783
+ for (t = host->templates; t ; t = t->next) {
784
+ if(t->hash_name == rt->hash_name && !strcmp(t->name, rt->name)) {
785
+ error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
786
+ return 0;
787
+ }
788
+ }
789
790
+ rt->next = host->templates;
791
+ host->templates = rt;
792
+ return 1;
793
}
794
795
static inline int health_parse_time(char *string, int *result) {
@@ -769,22 +834,16 @@ static inline int health_parse_time(char *string, int *result) {
834
return 1;
835
}
836
772
-static inline int health_parse_chart_calc(size_t line,
773
- const char *path,
774
- const char *file,
775
- char *string,
776
- int *group_method,
777
- int *after,
778
- int *before,
779
- int *every,
780
- uint32_t *options,
781
- char **dimensions
837
+static inline int health_parse_chart_calc(
838
+ size_t line, const char *path, const char *file, char *string,
839
+ int *group_method, int *after, int *before, int *every,
840
+ uint32_t *options, char **dimensions
841
) {
842
if(*dimensions) freez(*dimensions);
843
*dimensions = NULL;
785
- *after = -1;
844
+ *after = 0;
845
*before = 0;
787
- *every = 1;
846
+ *every = 0;
847
*options = 0;
848
849
char *s = string, *key;
@@ -816,6 +875,9 @@ static inline int health_parse_chart_calc(size_t line,
875
return 0;
876
}
877
878
+ // sane defaults
879
+ *every = abs(*after);
880
+
881
// now we may have optional parameters
882
while(*s) {
883
key = s;
@@ -859,7 +921,8 @@ static inline int health_parse_chart_calc(size_t line,
921
*options |= RRDR_OPTION_NOT_ALIGNED;
922
}
923
else if(!strcasecmp(key, "of")) {
862
- *dimensions = strdupz(s);
924
+ if(*s && strcasecmp(s, "all"))
925
+ *dimensions = strdupz(s);
926
break;
927
}
928
}
@@ -867,6 +930,12 @@ static inline int health_parse_chart_calc(size_t line,
930
return 1;
931
}
932
933
+static inline char *health_source_file(int line, const char *path, const char *filename) {
934
+ char buffer[FILENAME_MAX + 1];
935
+ snprintfz(buffer, FILENAME_MAX, "%d@%s/%s", line, path, filename);
936
+ return strdupz(buffer);
937
+}
938
+
939
int health_readfile(const char *path, const char *filename) {
940
static uint32_t hash_alarm = 0, hash_template = 0, hash_on = 0, hash_calc = 0, hash_green = 0, hash_red = 0, hash_warn = 0, hash_crit = 0, hash_exec = 0;
941
char buffer[HEALTH_CONF_MAX_LINE + 1];
@@ -945,18 +1014,21 @@ int health_readfile(const char *path, const char *filename) {
1014
if(rc && !rrdcalc_add(&localhost, rc))
1015
rrdcalc_free(&localhost, rc);
1016
948
- if(rt && !rrdcalctemplate_add(&localhost, rt)) {
949
- rrdcalctemplate_free(&localhost, rt);
1017
+ if(rt) {
1018
+ if (!rrdcalctemplate_add(&localhost, rt))
1019
+ rrdcalctemplate_free(&localhost, rt);
1020
rt = NULL;
1021
}
1022
1023
rc = callocz(1, sizeof(RRDCALC));
1024
rc->name = strdupz(value);
1025
rc->hash = simple_hash(rc->name);
1026
+ rc->source = health_source_file(line, path, filename);
1027
}
1028
else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
958
- if(rc && !rrdcalc_add(&localhost, rc)) {
959
- rrdcalc_free(&localhost, rc);
1029
+ if(rc) {
1030
+ if(!rrdcalc_add(&localhost, rc))
1031
+ rrdcalc_free(&localhost, rc);
1032
rc = NULL;
1033
}
1034
@@ -966,6 +1038,7 @@ int health_readfile(const char *path, const char *filename) {
1038
rt = callocz(1, sizeof(RRDCALCTEMPLATE));
1039
rt->name = strdupz(value);
1040
rt->hash_name = simple_hash(rt->name);
1041
+ rt->source = health_source_file(line, path, filename);
1042
}
1043
else if(rc) {
1044
if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
@@ -1032,7 +1105,68 @@ int health_readfile(const char *path, const char *filename) {
1105
}
1106
}
1107
else if(rt) {
1108
+ if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
1109
+ if(rt->context) {
1110
+ if(strcmp(rt->context, value))
1111
+ info("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1112
+ line, path, filename, rt->name, key, rt->context, value, value);
1113
1114
+ freez(rt->context);
1115
+ }
1116
+ rt->context = strdupz(value);
1117
+ rt->hash_context = simple_hash(rt->context);
1118
+ }
1119
+ else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
1120
+ health_parse_chart_calc(line, path, filename, value, &rt->group, &rt->after, &rt->before, &rt->update_every, &rt->options, &rt->dimensions);
1121
+ }
1122
+ else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
1123
+ char *e;
1124
+ rt->green = strtold(value, &e);
1125
+ if(e && *e) {
1126
+ info("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1127
+ line, path, filename, rt->name, key, e);
1128
+ }
1129
+ }
1130
+ else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
1131
+ char *e;
1132
+ rt->red = strtold(value, &e);
1133
+ if(e && *e) {
1134
+ info("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1135
+ line, path, filename, rt->name, key, e);
1136
+ }
1137
+ }
1138
+ else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
1139
+ const char *failed_at = NULL;
1140
+ int error = 0;
1141
+ rt->warning = expression_parse(value, &failed_at, &error);
1142
+ if(!rt->warning) {
1143
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1144
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
1145
+ }
1146
+ }
1147
+ else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
1148
+ const char *failed_at = NULL;
1149
+ int error = 0;
1150
+ rt->critical = expression_parse(value, &failed_at, &error);
1151
+ if(!rt->critical) {
1152
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1153
+ line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
1154
+ }
1155
+ }
1156
+ else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
1157
+ if(rt->exec) {
1158
+ if(strcmp(rt->exec, value))
1159
+ info("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1160
+ line, path, filename, rt->name, key, rt->exec, value, value);
1161
+
1162
+ freez(rt->exec);
1163
+ }
1164
+ rt->exec = strdupz(value);
1165
+ }
1166
+ else {
1167
+ error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
1168
+ line, path, filename, rt->name, key);
1169
+ }
1170
}
1171
else {
1172
error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
src/health.h
+10
@@ -150,6 +150,8 @@ typedef struct rrdcalc {
150
char *chart; // the chart name
151
uint32_t hash_chart;
152
153
+ char *source; // the source of this calculation
154
+
155
char *dimensions; // the chart dimensions
156
157
int group; // grouping method: average, max, etc.
@@ -180,6 +182,7 @@ typedef struct rrdcalc {
182
struct rrdcalc *next;
183
} RRDCALC;
184
185
+#define RRDCALC_HAS_CALCULATION(rc) ((rc)->after && (rc)->update_every)
186
187
// RRDCALCTEMPLATE
188
// these are to be applied to charts found dynamically
@@ -193,6 +196,8 @@ typedef struct rrdcalctemplate {
196
char *context;
197
uint32_t hash_context;
198
199
+ char *source; // the source of this template
200
+
201
char *dimensions;
202
203
int group; // grouping method: average, max, etc.
@@ -201,12 +206,17 @@ typedef struct rrdcalctemplate {
206
uint32_t options; // calculation options
207
int update_every; // update frequency for the calculation
208
209
+ EVAL_EXPRESSION *warning;
210
+ EVAL_EXPRESSION *critical;
211
+
212
calculated_number green;
213
calculated_number red;
214
215
struct rrdcalctemplate *next;
216
} RRDCALCTEMPLATE;
217
218
+#define RRDCALCTEMPLATE_HAS_CALCULATION(rt) ((rt)->after && (rt)->update_every)
219
+
220
221
#include "rrd.h"
222
src/log.c
+4
-2
@@ -38,8 +38,10 @@ int open_log_file(int fd, FILE **fp, const char *filename, int *enabled_syslog)
38
39
// don't do anything if the user is willing
40
// to have the standard one
41
- if(!strcmp(filename, "system"))
42
- return fd;
41
+ if(!strcmp(filename, "system")) {
42
+ if(fd != -1) return fd;
43
+ filename = "stdout";
44
+ }
45
46
if(!strcmp(filename, "stdout"))
47
f = STDOUT_FILENO;
src/main.c
+2
-1
@@ -597,7 +597,8 @@ int main(int argc, char **argv)
597
598
// --------------------------------------------------------------------
599
600
- create_listen_sockets();
600
+ if(!check_config)
601
+ create_listen_sockets();
602
}
603
604
// initialize the log files
src/rrd.c
+3
-2
@@ -56,9 +56,10 @@ void rrdhost_unlock(RRDHOST *host) {
56
}
57
58
void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
59
- if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
59
+ int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
60
+
61
+ if(ret != 0)
62
fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
61
- }
63
}
64
65
// ----------------------------------------------------------------------------
src/rrd.h
+5
@@ -256,6 +256,9 @@ struct rrdset {
256
// ------------------------------------------------------------------------
257
// local variables
258
259
+ calculated_number green;
260
+ calculated_number red;
261
+
262
avl_tree_lock variables_root_index;
263
RRDSETVAR *variables;
264
RRDCALC *calculations;
@@ -298,6 +301,8 @@ struct rrdhost {
301
// (charts may or may not exist when these are loaded)
302
RRDCALC *calculations;
303
304
+ RRDCALCTEMPLATE *templates;
305
+
306
// all variable references are linked here
307
// RRDVARs may be free'd, so every time this happens
308
// we need to find all their references and invalidate them