mirror of
https://github.com/netdata/netdata.git
synced 2025-04-17 11:12:42 +00:00
DYNCFG: health, generate userconfig for incomplete alerts (#17859)
* allow userconfig to generate incomplete configurations for health alerts * when adding an alert, add 1 rule by default
This commit is contained in:
parent
77358d9ee8
commit
734272c213
3 changed files with 86 additions and 83 deletions
src
|
@ -53,112 +53,114 @@ static void data_source_to_rrdr_options(RRD_ALERT_PROTOTYPE *ap) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool parse_match(json_object *jobj, const char *path, struct rrd_alert_match *match, BUFFER *error) {
|
||||
static bool parse_match(json_object *jobj, const char *path, struct rrd_alert_match *match, BUFFER *error, bool strict) {
|
||||
STRING *on = NULL;
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "on", on, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "on", on, error, strict);
|
||||
if(match->is_template)
|
||||
match->on.context = on;
|
||||
else
|
||||
match->on.chart = on;
|
||||
|
||||
JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, "host_labels", match->host_labels, error);
|
||||
JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, "instance_labels", match->chart_labels, error);
|
||||
JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, "host_labels", match->host_labels, error, strict);
|
||||
JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, "instance_labels", match->chart_labels, error, strict);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config_value_database_lookup(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "after", config->after, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "before", config->before, error);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "time_group", time_grouping_txt2id, config->time_group, error);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "dims_group", alerts_dims_grouping2id, config->dims_group, error);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "data_source", alerts_data_sources2id, config->data_source, error);
|
||||
static bool parse_config_value_database_lookup(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "after", config->after, error, strict);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "before", config->before, error, strict);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "time_group", time_grouping_txt2id, config->time_group, error, strict);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "dims_group", alerts_dims_grouping2id, config->dims_group, error, strict);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "data_source", alerts_data_sources2id, config->data_source, error, strict);
|
||||
|
||||
switch(config->time_group) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case RRDR_GROUPING_COUNTIF:
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "time_group_condition", alerts_group_condition2id, config->time_group_condition, error);
|
||||
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "time_group_condition", alerts_group_condition2id, config->time_group_condition, error, strict);
|
||||
// fall through
|
||||
|
||||
case RRDR_GROUPING_TRIMMED_MEAN:
|
||||
case RRDR_GROUPING_TRIMMED_MEDIAN:
|
||||
case RRDR_GROUPING_PERCENTILE:
|
||||
JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, "time_group_value", config->time_group_value, error);
|
||||
JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, "time_group_value", config->time_group_value, error, strict);
|
||||
break;
|
||||
}
|
||||
|
||||
JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "options", rrdr_options_parse_one, config->options, error);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "dimensions", config->dimensions, error, true);
|
||||
return true;
|
||||
}
|
||||
static bool parse_config_value(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "database_lookup", config, parse_config_value_database_lookup, error);
|
||||
JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "calculation", config->calculation, error);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "units", config->units, error, true);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "update_every", config->update_every, error);
|
||||
JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "options", rrdr_options_parse_one, config->options, error, strict);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "dimensions", config->dimensions, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config_conditions(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "warning_condition", config->warning, error);
|
||||
JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "critical_condition", config->critical, error);
|
||||
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_INT_OR_ERROR_AND_RETURN(jobj, path, "update_every", config->update_every, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config_action_delay(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "up", config->delay_up_duration, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "down", config->delay_down_duration, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "max", config->delay_max_duration, error);
|
||||
JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, "multiplier", config->delay_multiplier, error);
|
||||
return true;
|
||||
}
|
||||
static bool parse_config_action_repeat(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "enabled", config->has_custom_repeat_config, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "warning", config->warn_repeat_every, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "critical", config->crit_repeat_every, error);
|
||||
static bool parse_config_conditions(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
|
||||
JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "warning_condition", config->warning, error, strict);
|
||||
JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, "critical_condition", config->critical, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config_action(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error) {
|
||||
JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "options", alert_action_options_parse_one, config->alert_action_options, error);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "execute", config->exec, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "recipient", config->recipient, error, true);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "delay", config, parse_config_action_delay, error);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "repeat", config, parse_config_action_repeat, error);
|
||||
static bool parse_config_action_delay(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "up", config->delay_up_duration, error, strict);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "down", config->delay_down_duration, error, strict);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "max", config->delay_max_duration, error, strict);
|
||||
JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, "multiplier", config->delay_multiplier, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config(json_object *jobj, const char *path, RRD_ALERT_PROTOTYPE *ap, BUFFER *error) {
|
||||
static bool parse_config_action_repeat(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
|
||||
JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "enabled", config->has_custom_repeat_config, error, strict);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "warning", config->warn_repeat_every, error, strict);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "critical", config->crit_repeat_every, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config_action(json_object *jobj, const char *path, struct rrd_alert_config *config, BUFFER *error, bool strict) {
|
||||
JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "options", alert_action_options_parse_one, config->alert_action_options, error, strict);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "execute", config->exec, error, strict);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "recipient", config->recipient, error, strict);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "delay", config, parse_config_action_delay, error, strict);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "repeat", config, parse_config_action_repeat, error, strict);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_config(json_object *jobj, const char *path, RRD_ALERT_PROTOTYPE *ap, BUFFER *error, bool strict) {
|
||||
// we shouldn't parse these from the payload - they are given to us via the function call
|
||||
// JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "source_type", dyncfg_source_type2id, ap->config.source_type, error);
|
||||
// JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "source", ap->config.source, error, true);
|
||||
// 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, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "info", ap->config.info, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "type", ap->config.type, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "component", ap->config.component, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "classification", ap->config.classification, error, true);
|
||||
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_SUBOBJECT(jobj, path, "value", &ap->config, parse_config_value, error);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "conditions", &ap->config, parse_config_conditions, error);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "action", &ap->config, parse_config_action, error);
|
||||
JSONC_PARSE_SUBOBJECT(jobj, path, "match", &ap->match, parse_match, error);
|
||||
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, "match", &ap->match, parse_match, error, strict);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_prototype(json_object *jobj, const char *path, RRD_ALERT_PROTOTYPE *base, BUFFER *error, const char *name) {
|
||||
static bool parse_prototype(json_object *jobj, const char *path, RRD_ALERT_PROTOTYPE *base, BUFFER *error, const char *name, bool strict) {
|
||||
int64_t version;
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "format_version", version, error);
|
||||
JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, "format_version", version, error, strict);
|
||||
|
||||
if(version != 1) {
|
||||
buffer_sprintf(error, "unsupported document version");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "name", base->config.name, error, !name && !*name);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, "name", base->config.name, error, !name && !*name && strict);
|
||||
|
||||
json_object *rules;
|
||||
if (json_object_object_get_ex(jobj, "rules", &rules)) {
|
||||
|
@ -174,10 +176,10 @@ static bool parse_prototype(json_object *jobj, const char *path, RRD_ALERT_PROTO
|
|||
|
||||
json_object *rule = json_object_array_get_idx(rules, i);
|
||||
|
||||
JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(rule, path, "enabled", ap->match.enabled, error);
|
||||
JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(rule, path, "enabled", ap->match.enabled, error, strict);
|
||||
|
||||
STRING *type = NULL;
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(rule, path, "type", type, error, true);
|
||||
JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(rule, path, "type", type, error, strict);
|
||||
if(string_strcmp(type, "template") == 0)
|
||||
ap->match.is_template = true;
|
||||
else if(string_strcmp(type, "instance") == 0)
|
||||
|
@ -187,7 +189,7 @@ static bool parse_prototype(json_object *jobj, const char *path, RRD_ALERT_PROTO
|
|||
return false;
|
||||
}
|
||||
|
||||
JSONC_PARSE_SUBOBJECT(rule, path, "config", ap, parse_config, error);
|
||||
JSONC_PARSE_SUBOBJECT(rule, path, "config", ap, parse_config, error, strict);
|
||||
|
||||
ap = NULL; // so that we will create another one, if available
|
||||
}
|
||||
|
@ -200,7 +202,7 @@ static bool parse_prototype(json_object *jobj, const char *path, RRD_ALERT_PROTO
|
|||
return true;
|
||||
}
|
||||
|
||||
static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload, size_t payload_len, BUFFER *error, const char *name) {
|
||||
static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload, size_t payload_len, BUFFER *error, const char *name, bool strict) {
|
||||
RRD_ALERT_PROTOTYPE *base = callocz(1, sizeof(*base));
|
||||
CLEAN_JSON_OBJECT *jobj = NULL;
|
||||
|
||||
|
@ -219,7 +221,7 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
|
|||
}
|
||||
json_tokener_free(tokener);
|
||||
|
||||
if(!parse_prototype(jobj, "", base, error, name))
|
||||
if(!parse_prototype(jobj, "", base, error, name, strict))
|
||||
goto cleanup;
|
||||
|
||||
if(!base->config.name && name)
|
||||
|
@ -232,7 +234,7 @@ static RRD_ALERT_PROTOTYPE *health_prototype_payload_parse(const char *payload,
|
|||
ap->config.name = string_dup(base->config.name);
|
||||
}
|
||||
|
||||
if(!RRDCALC_HAS_DB_LOOKUP(ap) && !ap->config.calculation) {
|
||||
if(!RRDCALC_HAS_DB_LOOKUP(ap) && !ap->config.calculation && strict) {
|
||||
buffer_sprintf(error, "the rule No %d has neither database lookup nor calculation", i);
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -546,7 +548,7 @@ static int dyncfg_health_prototype_template_action(BUFFER *result, DYNCFG_CMDS c
|
|||
switch(cmd) {
|
||||
case DYNCFG_CMD_ADD: {
|
||||
CLEAN_BUFFER *error = buffer_create(0, NULL);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, add_name);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, add_name, true);
|
||||
if(!nap)
|
||||
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
|
||||
else {
|
||||
|
@ -578,7 +580,7 @@ static int dyncfg_health_prototype_template_action(BUFFER *result, DYNCFG_CMDS c
|
|||
|
||||
case DYNCFG_CMD_USERCONFIG: {
|
||||
CLEAN_BUFFER *error = buffer_create(0, NULL);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, add_name);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, add_name, false);
|
||||
if(!nap)
|
||||
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
|
||||
else {
|
||||
|
@ -671,7 +673,7 @@ static int dyncfg_health_prototype_job_action(BUFFER *result, DYNCFG_CMDS cmd, B
|
|||
|
||||
case DYNCFG_CMD_UPDATE: {
|
||||
CLEAN_BUFFER *error = buffer_create(0, NULL);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, alert_name);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, alert_name, true);
|
||||
if(!nap)
|
||||
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
|
||||
else {
|
||||
|
@ -694,7 +696,7 @@ static int dyncfg_health_prototype_job_action(BUFFER *result, DYNCFG_CMDS cmd, B
|
|||
|
||||
case DYNCFG_CMD_USERCONFIG: {
|
||||
CLEAN_BUFFER *error = buffer_create(0, NULL);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, alert_name);
|
||||
RRD_ALERT_PROTOTYPE *nap = health_prototype_payload_parse(buffer_tostring(payload), buffer_strlen(payload), error, alert_name, false);
|
||||
if(!nap)
|
||||
code = dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, buffer_tostring(error));
|
||||
else {
|
||||
|
|
|
@ -467,6 +467,7 @@
|
|||
"ui:widget": "hidden"
|
||||
},
|
||||
"rules": {
|
||||
"ui:openEmptyItem": true,
|
||||
"items": {
|
||||
"ui:classNames": "dyncfg-grid dyncfg-grid-col-6",
|
||||
"enabled": {
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
#ifndef NETDATA_JSON_C_PARSER_INLINE_H
|
||||
#define NETDATA_JSON_C_PARSER_INLINE_H
|
||||
|
||||
#define JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, member, dst, error) do { \
|
||||
#define JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j) && json_object_is_type(_j, json_type_boolean)) \
|
||||
dst = json_object_get_boolean(_j); \
|
||||
else { \
|
||||
else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type for '%s.%s' boolean", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
|
@ -48,7 +48,7 @@
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, member, dst, error) do { \
|
||||
#define JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j) && json_object_is_type(_j, json_type_string)) { \
|
||||
string_freez(dst); \
|
||||
|
@ -58,13 +58,13 @@
|
|||
else \
|
||||
dst = string_strdupz(_v); \
|
||||
} \
|
||||
else { \
|
||||
else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type for '%s.%s' string", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, member, dst, error) do { \
|
||||
#define JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j) && json_object_is_type(_j, json_type_string)) { \
|
||||
const char *_t = json_object_get_string(_j); \
|
||||
|
@ -80,13 +80,13 @@
|
|||
} \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type for '%s.%s' expression", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error) do { \
|
||||
#define JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error, required) do { \
|
||||
json_object *_jarray; \
|
||||
if (json_object_object_get_ex(jobj, member, &_jarray) && json_object_is_type(_jarray, json_type_array)) { \
|
||||
size_t _num_options = json_object_array_length(_jarray); \
|
||||
|
@ -105,24 +105,24 @@
|
|||
} \
|
||||
dst |= _bit; \
|
||||
} \
|
||||
} else { \
|
||||
} else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type for '%s.%s' array", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error) do { \
|
||||
#define JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j) && json_object_is_type(_j, json_type_string)) \
|
||||
dst = converter(json_object_get_string(_j)); \
|
||||
else { \
|
||||
else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type (expected text value) for '%s.%s' enum", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, member, dst, error) do { \
|
||||
#define JSONC_PARSE_INT_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j)) { \
|
||||
if (_j != NULL && json_object_is_type(_j, json_type_int)) \
|
||||
|
@ -135,13 +135,13 @@
|
|||
buffer_sprintf(error, "not supported type (expected int) for '%s.%s'", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} else { \
|
||||
} else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type (expected double value or null) for '%s.%s'", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, member, dst, error) do { \
|
||||
#define JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j)) { \
|
||||
if (_j != NULL && json_object_is_type(_j, json_type_double)) \
|
||||
|
@ -154,21 +154,21 @@
|
|||
buffer_sprintf(error, "not supported type (expected double) for '%s.%s'", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} else { \
|
||||
} else if(required) { \
|
||||
buffer_sprintf(error, "missing or invalid type (expected double value or null) for '%s.%s'", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JSONC_PARSE_SUBOBJECT(jobj, path, member, dst, callback, error) do { \
|
||||
#define JSONC_PARSE_SUBOBJECT(jobj, path, member, dst, callback, error, required) do { \
|
||||
json_object *_j; \
|
||||
if (json_object_object_get_ex(jobj, member, &_j)) { \
|
||||
char _new_path[strlen(path) + strlen(member) + 2]; \
|
||||
snprintfz(_new_path, sizeof(_new_path), "%s%s%s", path, *path?".":"", member); \
|
||||
if (!callback(_j, _new_path, dst, error)) { \
|
||||
if (!callback(_j, _new_path, dst, error, required)) { \
|
||||
return false; \
|
||||
} \
|
||||
} else { \
|
||||
} else if(required) { \
|
||||
buffer_sprintf(error, "missing '%s.%s' object", path, member); \
|
||||
return false; \
|
||||
} \
|
||||
|
|
Loading…
Add table
Reference in a new issue