summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@netdata.cloud>2024-06-14 17:17:08 +0300
committerGitHub <noreply@github.com>2024-06-14 17:17:08 +0300
commit03b138974eee7a17ece5164842581d233f774a7b (patch)
tree51b4fab8fe68576b1e08dce1306660ef30ae6fbd /src
parent2d0cf8ed9a4fbad8dff06630056966bb861c30b4 (diff)
allow alerts to be created without too many requirements (#17894)
Diffstat (limited to 'src')
-rw-r--r--src/health/health_config.c4
-rw-r--r--src/health/health_dyncfg.c45
-rw-r--r--src/health/health_internals.h2
-rw-r--r--src/health/health_prototypes.c10
-rw-r--r--src/health/schema.d/health%3Aalert%3Aprototype.json2
5 files changed, 37 insertions, 26 deletions
diff --git a/src/health/health_config.c b/src/health/health_config.c
index 05ced8bddc..c17f7e21dc 100644
--- a/src/health/health_config.c
+++ b/src/health/health_config.c
@@ -651,7 +651,7 @@ int health_readfile(const char *filename, void *data __maybe_unused, bool stock_
lookup_data_source_from_rrdr_options(ap);
dims_grouping_from_rrdr_options(ap);
replace_green_red(ap, green, red);
- health_prototype_add(ap);
+ health_prototype_add(ap, NULL);
freez(ap);
}
@@ -833,7 +833,7 @@ int health_readfile(const char *filename, void *data __maybe_unused, bool stock_
lookup_data_source_from_rrdr_options(ap);
dims_grouping_from_rrdr_options(ap);
replace_green_red(ap, green, red);
- health_prototype_add(ap);
+ health_prototype_add(ap, NULL);
freez(ap);
}
diff --git a/src/health/health_dyncfg.c b/src/health/health_dyncfg.c
index 092fda51c4..4bbda1a92f 100644
--- a/src/health/health_dyncfg.c
+++ b/src/health/health_dyncfg.c
@@ -96,8 +96,8 @@ static bool parse_config_value_database_lookup(json_object *jobj, const char *pa
static bool parse_config_value(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
JSONC_PARSE_SUBOBJECT(jobj, path, "database_lookup", config, parse_config_value_database_lookup, error, strict);
- JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "calculation", config->calculation, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "units", config->units, error, strict);
+ JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "calculation", config->calculation, error, false);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "units", config->units, error, false);
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "update_every", config->update_every, error, strict);
return true;
}
@@ -137,15 +137,15 @@ static bool parse_config(json_object *jobj, const char *path, RRD_ALERT_PROTOTYP
// JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "source_type", dyncfg_source_type2id, ap->config.source_type, error, strict);
// JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "source", ap->config.source, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "summary", ap->config.summary, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "info", ap->config.info, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "type", ap->config.type, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "component", ap->config.component, error, strict);
- JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "classification", ap->config.classification, error, strict);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "summary", ap->config.summary, error, false);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "info", ap->config.info, error, false);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "type", ap->config.type, error, false);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "component", ap->config.component, error, false);
+ JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "classification", ap->config.classification, error, false);
JSONC_PARSE_SUBOBJECT(jobj, path, "value", &ap->config, parse_config_value, error, strict);
- JSONC_PARSE_SUBOBJECT(jobj, path, "conditions", &ap->config, parse_config_conditions, error, strict);
- JSONC_PARSE_SUBOBJECT(jobj, path, "action", &ap->config, parse_config_action, error, strict);
+ JSONC_PARSE_SUBOBJECT(jobj, path, "conditions", &ap->config, parse_config_conditions, error, false);
+ JSONC_PARSE_SUBOBJECT(jobj, path, "action", &ap->config, parse_config_action, error, false);
JSONC_PARSE_SUBOBJECT(jobj, path, "match", &ap->match, parse_match, error, strict);
return true;
@@ -227,6 +227,11 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
if(!base->config.name && name)
base->config.name = string_strdupz(name);
+ if(name && *name && string_strcmp(base->config.name, name) != 0) {
+ string_freez(base->config.name);
+ base->config.name = string_strdupz(name);
+ }
+
int i = 1;
for(RRD_ALERT_PROTOTYPE *ap = base; ap; ap = ap->_internal.next, i++) {
if(ap->config.name != base->config.name) {
@@ -235,7 +240,7 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
}
if(!RRDCALC_HAS_DB_LOOKUP(ap) && !ap->config.calculation && strict) {
- buffer_sprintf(error, "the rule No %d has neither database lookup nor calculation", i);
+ buffer_sprintf(error, "Item %d has neither database lookup nor calculation", i - 1);
goto cleanup;
}
@@ -246,13 +251,6 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
base->_internal.enabled = true;
}
- if(string_strcmp(base->config.name, name) != 0) {
- buffer_sprintf(error,
- "name parsed ('%s') does not match the name of the alert prototype ('%s')",
- string2str(base->config.name), name);
- goto cleanup;
- }
-
return base;
cleanup:
@@ -552,12 +550,15 @@ static int dyncfg_health_prototype_template_action(BUFFER *result, DYNCFG_CMDS c
if(!nap)
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
else {
+ char *msg = "";
+
nap->config.source_type = DYNCFG_SOURCE_TYPE_DYNCFG;
- bool added = health_prototype_add(nap); // this swaps ap <-> nap
+ bool added = health_prototype_add(nap, &msg); // this swaps ap <-> nap
if(!added) {
health_prototype_free(nap);
- return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "required attributes are missing");
+ if(!msg || !*msg) msg = "required attributes are missing";
+ return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, msg);
}
else
freez(nap);
@@ -677,12 +678,14 @@ static int dyncfg_health_prototype_job_action(BUFFER *result, DYNCFG_CMDS cmd, B
if(!nap)
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
else {
+ char *msg = "";
nap->config.source_type = DYNCFG_SOURCE_TYPE_DYNCFG;
- bool added = health_prototype_add(nap); // this swaps ap <-> nap
+ bool added = health_prototype_add(nap, &msg); // this swaps ap <-> nap
if(!added) {
health_prototype_free(nap);
- return dyncfg_default_response( result, HTTP_RESP_BAD_REQUEST, "required attributes are missing");
+ if(!msg || !*msg) msg = "required attributes are missing";
+ return dyncfg_default_response( result, HTTP_RESP_BAD_REQUEST, msg);
}
else
freez(nap);
diff --git a/src/health/health_internals.h b/src/health/health_internals.h
index 251400241f..638a961959 100644
--- a/src/health/health_internals.h
+++ b/src/health/health_internals.h
@@ -60,7 +60,7 @@ typedef struct rrd_alert_prototype {
struct rrd_alert_prototype *prev, *next;
} _internal;
} RRD_ALERT_PROTOTYPE;
-bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap);
+bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg);
void health_prototype_cleanup(RRD_ALERT_PROTOTYPE *ap);
void health_prototype_free(RRD_ALERT_PROTOTYPE *ap);
diff --git a/src/health/health_prototypes.c b/src/health/health_prototypes.c
index 075e9cbe97..c430961156 100644
--- a/src/health/health_prototypes.c
+++ b/src/health/health_prototypes.c
@@ -395,12 +395,14 @@ void health_prototype_hash_id(RRD_ALERT_PROTOTYPE *ap) {
sql_alert_store_config(ap);
}
-bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
+bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg) {
if(!ap->match.is_template) {
if(!ap->match.on.chart) {
netdata_log_error(
"HEALTH: alert '%s' does not define a instance (parameter 'on'). Source: %s",
string2str(ap->config.name), string2str(ap->config.source));
+ if(msg)
+ *msg = "missing match 'on' parameter for instance";
return false;
}
}
@@ -409,6 +411,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
netdata_log_error(
"HEALTH: alert '%s' does not define a context (parameter 'on'). Source: %s",
string2str(ap->config.name), string2str(ap->config.source));
+ if(msg)
+ *msg = "missing match 'on' parameter for context";
return false;
}
}
@@ -417,6 +421,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
netdata_log_error(
"HEALTH: alert '%s' has no frequency (parameter 'every'). Source: %s",
string2str(ap->config.name), string2str(ap->config.source));
+ if(msg)
+ *msg = "missing update frequency";
return false;
}
@@ -424,6 +430,8 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap) {
netdata_log_error(
"HEALTH: alert '%s' is useless (no db lookup, no calculation, no warning and no critical expressions). Source: %s",
string2str(ap->config.name), string2str(ap->config.source));
+ if(msg)
+ *msg = "no db lookup, calculation and warning/critical conditions";
return false;
}
diff --git a/src/health/schema.d/health%3Aalert%3Aprototype.json b/src/health/schema.d/health%3Aalert%3Aprototype.json
index 309d052de9..6c5e8c756a 100644
--- a/src/health/schema.d/health%3Aalert%3Aprototype.json
+++ b/src/health/schema.d/health%3Aalert%3Aprototype.json
@@ -122,7 +122,7 @@
},
"after": {
"type": "integer",
- "default": -600,
+ "default": 0,
"title": "From",
"description": "Relative to 'To'"
},