allow alerts to be created without too many requirements (#17894)
Costa Tsaousis committed
Jun 14, 2024 at 17:17 UTC
03b138974eee7a17ece5164842581d233f774a7b
5 files changed
+37
-26
src/health/health_config.c
+2
-2
@@ -651,7 +651,7 @@ int health_readfile(const char *filename, void *data __maybe_unused, bool stock_
651
lookup_data_source_from_rrdr_options(ap);
652
dims_grouping_from_rrdr_options(ap);
653
replace_green_red(ap, green, red);
654
- health_prototype_add(ap);
654
+ health_prototype_add(ap, NULL);
655
freez(ap);
656
}
657
@@ -833,7 +833,7 @@ int health_readfile(const char *filename, void *data __maybe_unused, bool stock_
833
lookup_data_source_from_rrdr_options(ap);
834
dims_grouping_from_rrdr_options(ap);
835
replace_green_red(ap, green, red);
836
- health_prototype_add(ap);
836
+ health_prototype_add(ap, NULL);
837
freez(ap);
838
}
839
src/health/health_dyncfg.c
+24
-21
@@ -96,8 +96,8 @@ static bool parse_config_value_database_lookup(json_object *jobj, const char *pa
96
97
static bool parse_config_value(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
98
JSONC_PARSE_SUBOBJECT(jobj, path, "database_lookup", config, parse_config_value_database_lookup, error, strict);
99
- JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "calculation", config->calculation, error, strict);
100
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "units", config->units, error, strict);
99
+ JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "calculation", config->calculation, error, false);
100
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "units", config->units, error, false);
101
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "update_every", config->update_every, error, strict);
102
return true;
103
}
@@ -137,15 +137,15 @@ static bool parse_config(json_object *jobj, const char *path, RRD_ALERT_PROTOTYP
137
// JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "source_type", dyncfg_source_type2id, ap->config.source_type, error, strict);
138
// JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "source", ap->config.source, error, strict);
139
140
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "summary", ap->config.summary, error, strict);
141
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "info", ap->config.info, error, strict);
142
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "type", ap->config.type, error, strict);
143
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "component", ap->config.component, error, strict);
144
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "classification", ap->config.classification, error, strict);
140
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "summary", ap->config.summary, error, false);
141
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "info", ap->config.info, error, false);
142
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "type", ap->config.type, error, false);
143
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "component", ap->config.component, error, false);
144
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "classification", ap->config.classification, error, false);
145
146
JSONC_PARSE_SUBOBJECT(jobj, path, "value", &ap->config, parse_config_value, error, strict);
147
- JSONC_PARSE_SUBOBJECT(jobj, path, "conditions", &ap->config, parse_config_conditions, error, strict);
148
- JSONC_PARSE_SUBOBJECT(jobj, path, "action", &ap->config, parse_config_action, error, strict);
147
+ JSONC_PARSE_SUBOBJECT(jobj, path, "conditions", &ap->config, parse_config_conditions, error, false);
148
+ JSONC_PARSE_SUBOBJECT(jobj, path, "action", &ap->config, parse_config_action, error, false);
149
JSONC_PARSE_SUBOBJECT(jobj, path, "match", &ap->match, parse_match, error, strict);
150
151
return true;
@@ -227,6 +227,11 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
227
if(!base->config.name && name)
228
base->config.name = string_strdupz(name);
229
230
+ if(name && *name && string_strcmp(base->config.name, name) != 0) {
231
+ string_freez(base->config.name);
232
+ base->config.name = string_strdupz(name);
233
+ }
234
+
235
int i = 1;
236
for(RRD_ALERT_PROTOTYPE *ap = base; ap; ap = ap->_internal.next, i++) {
237
if(ap->config.name != base->config.name) {
@@ -235,7 +240,7 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
240
}
241
242
if(!RRDCALC_HAS_DB_LOOKUP(ap) && !ap->config.calculation && strict) {
238
- buffer_sprintf(error, "the rule No %d has neither database lookup nor calculation", i);
243
+ buffer_sprintf(error, "Item %d has neither database lookup nor calculation", i - 1);
244
goto cleanup;
245
}
246
@@ -246,13 +251,6 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
251
base->_internal.enabled = true;
252
}
253
249
- if(string_strcmp(base->config.name, name) != 0) {
250
- buffer_sprintf(error,
251
- "name parsed ('%s') does not match the name of the alert prototype ('%s')",
252
- string2str(base->config.name), name);
253
- goto cleanup;
254
- }
255
-
254
return base;
255
256
cleanup:
@@ -552,12 +550,15 @@ static int dyncfg_health_prototype_template_action(BUFFER *result, DYNCFG_CMDS c
550
if(!nap)
551
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
552
else {
553
+ char *msg = "";
554
+
555
nap->config.source_type = DYNCFG_SOURCE_TYPE_DYNCFG;
556
- bool added = health_prototype_add(nap); // this swaps ap <-> nap
556
+ bool added = health_prototype_add(nap, &msg); // this swaps ap <-> nap
557
558
if(!added) {
559
health_prototype_free(nap);
560
- return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "required attributes are missing");
560
+ if(!msg || !*msg) msg = "required attributes are missing";
561
+ return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, msg);
562
}
563
else
564
freez(nap);
@@ -677,12 +678,14 @@ static int dyncfg_health_prototype_job_action(BUFFER *result, DYNCFG_CMDS cmd, B
678
if(!nap)
679
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
680
else {
681
+ char *msg = "";
682
nap->config.source_type = DYNCFG_SOURCE_TYPE_DYNCFG;
681
- bool added = health_prototype_add(nap); // this swaps ap <-> nap
683
+ bool added = health_prototype_add(nap, &msg); // this swaps ap <-> nap
684
685
if(!added) {
686
health_prototype_free(nap);
685
- return dyncfg_default_response( result, HTTP_RESP_BAD_REQUEST, "required attributes are missing");
687
+ if(!msg || !*msg) msg = "required attributes are missing";
688
+ return dyncfg_default_response( result, HTTP_RESP_BAD_REQUEST, msg);
689
}
690
else
691
freez(nap);
src/health/health_internals.h
+1
-1
@@ -60,7 +60,7 @@ typedef struct rrd_alert_prototype {
60
struct rrd_alert_prototype *prev, *next;
61
} _internal;
62
} RRD_ALERT_PROTOTYPE;
63
-bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap);
63
+bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg);
64
void health_prototype_cleanup(RRD_ALERT_PROTOTYPE *ap);
65
void health_prototype_free(RRD_ALERT_PROTOTYPE *ap);
66
src/health/health_prototypes.c
+9
-1
@@ -395,12 +395,14 @@ void health_prototype_hash_id(RRD_ALERT_PROTOTYPE *ap) {
395
sql_alert_store_config(ap);
396
}
397
398
-bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
398
+bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg) {
399
if(!ap->match.is_template) {
400
if(!ap->match.on.chart) {
401
netdata_log_error(
402
"HEALTH: alert '%s' does not define a instance (parameter 'on'). Source: %s",
403
string2str(ap->config.name), string2str(ap->config.source));
404
+ if(msg)
405
+ *msg = "missing match 'on' parameter for instance";
406
return false;
407
}
408
}
@@ -409,6 +411,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
411
netdata_log_error(
412
"HEALTH: alert '%s' does not define a context (parameter 'on'). Source: %s",
413
string2str(ap->config.name), string2str(ap->config.source));
414
+ if(msg)
415
+ *msg = "missing match 'on' parameter for context";
416
return false;
417
}
418
}
@@ -417,6 +421,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
421
netdata_log_error(
422
"HEALTH: alert '%s' has no frequency (parameter 'every'). Source: %s",
423
string2str(ap->config.name), string2str(ap->config.source));
424
+ if(msg)
425
+ *msg = "missing update frequency";
426
return false;
427
}
428
@@ -424,6 +430,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
430
netdata_log_error(
431
"HEALTH: alert '%s' is useless (no db lookup, no calculation, no warning and no critical expressions). Source: %s",
432
string2str(ap->config.name), string2str(ap->config.source));
433
+ if(msg)
434
+ *msg = "no db lookup, calculation and warning/critical conditions";
435
return false;
436
}
437
src/health/schema.d/health%3Aalert%3Aprototype.json
+1
-1
@@ -122,7 +122,7 @@
122
},
123
"after": {
124
"type": "integer",
125
- "default": -600,
125
+ "default": 0,
126
"title": "From",
127
"description": "Relative to 'To'"
128
},