diff options
-rw-r--r-- | include/common.h | 1 | ||||
-rw-r--r-- | include/dbcache.h | 3 | ||||
-rw-r--r-- | include/zbxeval.h | 75 | ||||
-rw-r--r-- | include/zbxserver.h | 8 | ||||
-rw-r--r-- | src/libs/zbxcommon/str.c | 53 | ||||
-rw-r--r-- | src/libs/zbxdbcache/dbconfig.c | 36 | ||||
-rw-r--r-- | src/libs/zbxdbupgrade/dbupgrade_5030.c | 4 | ||||
-rw-r--r-- | src/libs/zbxeval/Makefile.am | 4 | ||||
-rw-r--r-- | src/libs/zbxeval/execute.c | 118 | ||||
-rw-r--r-- | src/libs/zbxeval/misc.c | 82 | ||||
-rw-r--r-- | src/libs/zbxeval/parse.c | 72 | ||||
-rw-r--r-- | src/libs/zbxserver/evalfunc2.c | 33 | ||||
-rw-r--r-- | src/libs/zbxserver/expression.c | 359 | ||||
-rw-r--r-- | tests/libs/zbxcommon/zbx_token_find.yaml | 2 | ||||
-rw-r--r-- | tests/libs/zbxeval/zbx_eval_execute_ext.c | 8 | ||||
-rw-r--r-- | tests/libs/zbxeval/zbx_eval_execute_ext.yaml | 8 | ||||
-rw-r--r-- | tests/libs/zbxeval/zbx_eval_parse_expression.c | 2 | ||||
-rw-r--r-- | tests/libs/zbxeval/zbx_eval_parse_expression.yaml | 66 |
18 files changed, 684 insertions, 250 deletions
diff --git a/include/common.h b/include/common.h index b7f3bde2b46..fc2a669d77d 100644 --- a/include/common.h +++ b/include/common.h @@ -1183,6 +1183,7 @@ void zbx_strncpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char void zbx_strcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src); void zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c); void zbx_str_memcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src, size_t n); +void zbx_strquote_alloc(char **str, size_t *str_alloc, size_t *str_offset, const char *value_str); void zbx_strsplit(const char *src, char delimiter, char **left, char **right); diff --git a/include/dbcache.h b/include/dbcache.h index 41bba8facc9..3aacdd44a13 100644 --- a/include/dbcache.h +++ b/include/dbcache.h @@ -975,6 +975,9 @@ const char *zbx_dc_get_instanceid(void); char *zbx_dc_expand_user_macros(const char *text, zbx_uint64_t hostid); char *zbx_dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid); +int zbx_dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num, + char **value, char **error); + /* diagnostic data */ void zbx_hc_get_diag_stats(zbx_uint64_t *items_num, zbx_uint64_t *values_num); diff --git a/include/zbxeval.h b/include/zbxeval.h index 85d7f6fee2d..73bf9b87530 100644 --- a/include/zbxeval.h +++ b/include/zbxeval.h @@ -58,21 +58,20 @@ #define ZBX_EVAL_TOKEN_OP_NOT (14 | ZBX_EVAL_CLASS_OPERATOR1 | ZBX_EVAL_OP_SET_PRECEDENCE(2)) #define ZBX_EVAL_TOKEN_VAR_NUM (15 | ZBX_EVAL_CLASS_OPERAND) #define ZBX_EVAL_TOKEN_VAR_STR (16 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_VAR_TIME (17 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_VAR_MACRO (18 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_VAR_USERMACRO (19 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_VAR_LLDMACRO (20 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_FUNCTIONID (21 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_FUNCTION (22 | ZBX_EVAL_CLASS_FUNCTION) -#define ZBX_EVAL_TOKEN_HIST_FUNCTION (23 | ZBX_EVAL_CLASS_FUNCTION) -#define ZBX_EVAL_TOKEN_GROUP_OPEN (24 | ZBX_EVAL_CLASS_SEPARATOR) -#define ZBX_EVAL_TOKEN_GROUP_CLOSE (25 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_COMMA (26 | ZBX_EVAL_CLASS_SEPARATOR) -#define ZBX_EVAL_TOKEN_ARG_QUERY (27 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_ARG_PERIOD (28 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_ARG_NULL (29 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_ARG_RAW (30 | ZBX_EVAL_CLASS_OPERAND) -#define ZBX_EVAL_TOKEN_EXCEPTION (31 | ZBX_EVAL_CLASS_FUNCTION) +#define ZBX_EVAL_TOKEN_VAR_MACRO (17 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_VAR_USERMACRO (18 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_VAR_LLDMACRO (19 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_FUNCTIONID (20 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_FUNCTION (21 | ZBX_EVAL_CLASS_FUNCTION) +#define ZBX_EVAL_TOKEN_HIST_FUNCTION (22 | ZBX_EVAL_CLASS_FUNCTION) +#define ZBX_EVAL_TOKEN_GROUP_OPEN (23 | ZBX_EVAL_CLASS_SEPARATOR) +#define ZBX_EVAL_TOKEN_GROUP_CLOSE (24 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_COMMA (25 | ZBX_EVAL_CLASS_SEPARATOR) +#define ZBX_EVAL_TOKEN_ARG_QUERY (26 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_ARG_PERIOD (27 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_ARG_NULL (28 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_ARG_RAW (29 | ZBX_EVAL_CLASS_OPERAND) +#define ZBX_EVAL_TOKEN_EXCEPTION (30 | ZBX_EVAL_CLASS_FUNCTION) /* expression parsing rules */ @@ -89,7 +88,11 @@ ZBX_EVAL_PARSE_FUNCTIONID | ZBX_EVAL_PARSE_FUNCTION) #define ZBX_EVAL_PARSE_CALC_EXPRESSSION (ZBX_EVAL_PARSE_MACRO | ZBX_EVAL_PARSE_USERMACRO | \ - ZBX_EVAL_PARSE_ITEM_QUERY | ZBX_EVAL_PARSE_FUNCTION) + ZBX_EVAL_PARSE_ITEM_QUERY | ZBX_EVAL_PARSE_FUNCTION | \ + ZBX_EVAL_PARSE_COMPOUND_CONST) + +#define ZBX_EVAL_PARSE_EXPRESSION_MACRO (ZBX_EVAL_PARSE_USERMACRO | ZBX_EVAL_PARSE_ITEM_QUERY | \ + ZBX_EVAL_PARSE_FUNCTION | ZBX_EVAL_PARSE_COMPOUND_CONST) /* expression composition rules */ @@ -111,6 +114,11 @@ ZBX_EVAL_COMPOSE_LLD | \ ZBX_EVAL_COMPOSE_FUNCTIONID) +#define ZBX_EVAL_CALC_EXPRESSION_LLD (ZBX_EVAL_PARSE_CALC_EXPRESSSION | \ + ZBX_EVAL_PARSE_LLDMACRO | \ + ZBX_EVAL_COMPOSE_LLD) + + typedef zbx_uint32_t zbx_token_type_t; /****************************************************************************** @@ -123,6 +131,8 @@ typedef zbx_uint32_t zbx_token_type_t; * len - [IN] the function name length * * args_num - [IN] the number of function arguments * * args - [IN] an array of the function arguments. * + * data - [IN] the caller data used for function evaluation * + * ts - [IN] the function execution time * * value - [OUT] the function return value * * error - [OUT] the error message if function failed * * * @@ -131,7 +141,7 @@ typedef zbx_uint32_t zbx_token_type_t; * * ******************************************************************************/ typedef int (*zbx_eval_function_cb_t)(const char *name, size_t len, int args_num, const zbx_variant_t *args, - zbx_variant_t *value, char **error); + void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error); typedef struct { @@ -154,7 +164,9 @@ typedef struct zbx_timespec_t ts; zbx_vector_eval_token_t stack; zbx_vector_eval_token_t ops; - zbx_eval_function_cb_t function_cb; + zbx_eval_function_cb_t common_func_cb; + zbx_eval_function_cb_t history_func_cb; + void *data_cb; } zbx_eval_context_t; @@ -162,7 +174,6 @@ typedef int (*zbx_macro_resolve_func_t)(const char *str, size_t length, zbx_uint int hostids_num, char **value, char **error); int zbx_eval_parse_expression(zbx_eval_context_t *ctx, const char *expression, zbx_uint64_t rules, char **error); -zbx_eval_context_t *zbx_eval_parse_expression_dyn(const char *expression, zbx_uint64_t rules, char **error); void zbx_eval_init(zbx_eval_context_t *ctx); void zbx_eval_clear(zbx_eval_context_t *ctx); int zbx_eval_status(const zbx_eval_context_t *ctx); @@ -171,8 +182,8 @@ void zbx_eval_deserialize(zbx_eval_context_t *ctx, const char *expression, zbx_u const unsigned char *data); void zbx_eval_compose_expression(const zbx_eval_context_t *ctx, char **expression); int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_variant_t *value, char **error); -int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t function_cb, - zbx_variant_t *value, char **error); +int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t common_func_cb, + zbx_eval_function_cb_t history_func_cb, void *data, zbx_variant_t *value, char **error); void zbx_eval_get_functionids(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids); void zbx_eval_get_functionids_ordered(zbx_eval_context_t *ctx, zbx_vector_uint64_t *functionids); int zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *hostids, int hostids_num, @@ -198,4 +209,26 @@ void zbx_eval_copy(zbx_eval_context_t *dst, const zbx_eval_context_t *src, const char *zbx_eval_format_function_error(const char *function, const char *host, const char *key, const char *parameter, const char *error); +void zbx_eval_extract_item_refs(zbx_eval_context_t *ctx, zbx_vector_str_t *refs); + +typedef enum +{ + ZBX_ITEM_QUERY_UNKNOWN, + ZBX_ITEM_QUERY_SINGLE, + ZBX_ITEM_QUERY_MULTI +} +zbx_item_query_type_t; + +typedef struct +{ + char *host; + char *key; + zbx_item_query_type_t type; + int index; +} +zbx_item_query_t; + +void zbx_eval_parse_query(const char *str, size_t len, zbx_item_query_t *query); +void zbx_eval_clear_query(zbx_item_query_t *query); + #endif diff --git a/include/zbxserver.h b/include/zbxserver.h index 4f540cea9dc..1c6509b02cd 100644 --- a/include/zbxserver.h +++ b/include/zbxserver.h @@ -50,10 +50,9 @@ #define MACRO_TYPE_ALLOWED_HOSTS 0x00800000 #define MACRO_TYPE_ITEM_TAG 0x01000000 #define MACRO_TYPE_EVENT_NAME 0x02000000 /* event name in trigger configuration */ -#define MACRO_TYPE_EXPRESSION 0x04000000 /* macros in expression macro */ -#define MACRO_TYPE_SCRIPT_PARAMS_FIELD 0x08000000 -#define MACRO_TYPE_SCRIPT_NORMAL 0x10000000 -#define MACRO_TYPE_SCRIPT_RECOVERY 0x20000000 +#define MACRO_TYPE_SCRIPT_PARAMS_FIELD 0x04000000 +#define MACRO_TYPE_SCRIPT_NORMAL 0x08000000 +#define MACRO_TYPE_SCRIPT_RECOVERY 0x10000000 #define MACRO_EXPAND_NO 0 #define MACRO_EXPAND_YES 1 @@ -65,6 +64,7 @@ int evaluate_function(char **value, DC_ITEM *item, const char *function, const c int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function, const char *parameter, const zbx_timespec_t *ts, char **error); +int zbx_is_trigger_function(const char *name, size_t len); int substitute_simple_macros(const zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event, const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item, diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c index 87bb5d57834..eae0c246893 100644 --- a/src/libs/zbxcommon/str.c +++ b/src/libs/zbxcommon/str.c @@ -358,6 +358,58 @@ void zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c) zbx_strncpy_alloc(str, alloc_len, offset, &c, 1); } +void zbx_strquote_alloc(char **str, size_t *str_alloc, size_t *str_offset, const char *value_str) +{ + size_t size; + const char *src; + char *dst; + + for (size = 2, src = value_str; '\0' != *src; src++) + { + switch (*src) + { + case '\\': + case '"': + size++; + } + size++; + } + + if (*str_alloc <= *str_offset + size) + { + if (0 == *str_alloc) + *str_alloc = size; + + do + { + *str_alloc *= 2; + } + while (*str_alloc - *str_offset <= size); + + *str = zbx_realloc(*str, *str_alloc); + } + + dst = *str + *str_offset; + *dst++ = '"'; + + for (src = value_str; '\0' != *src; src++, dst++) + { + switch (*src) + { + case '\\': + case '"': + *dst++ = '\\'; + break; + } + + *dst = *src; + } + + *dst++ = '"'; + *dst = '\0'; + *str_offset += size; +} + /* Has to be rewritten to avoid malloc */ char *string_replace(const char *str, const char *sub_str1, const char *sub_str2) { @@ -3687,6 +3739,7 @@ static int token_parse_expression_macro(const char *expression, const char *macr { switch (tmp.type) { + case ZBX_TOKEN_MACRO: case ZBX_TOKEN_LLD_MACRO: case ZBX_TOKEN_LLD_FUNC_MACRO: case ZBX_TOKEN_USER_MACRO: diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c index 15499201d0b..8e36a10f769 100644 --- a/src/libs/zbxdbcache/dbconfig.c +++ b/src/libs/zbxdbcache/dbconfig.c @@ -10902,6 +10902,42 @@ int dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *h /****************************************************************************** * * + * Function: zbx_dc_expand_user_macros_len * + * * + * Purpose: expand user macros in the specified text * + * * + * Parameters: text - [IN] the text value to expand * + * len - [IN] the text length * + * hostids - [IN] an array of related hostids * + * hostids_num - [IN] the number of hostids * + * value - [IN] the expanded macro with expanded user * + * macros. Unknown or invalid macros will be * + * left unresolved. * + * error - [IN] the error message, optional. If specified * + * the function will return failure on first * + * unknown user macro * + * * + * Return value: SUCCEED - the macros were expanded successfully * + * FAIL - error parameter was given and at least one of * + * macros was not expanded * + * * + * Comments: The returned value must be freed by the caller. * + * * + ******************************************************************************/ +int zbx_dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num, + char **value, char **error) +{ + int ret; + + RDLOCK_CACHE; + ret = dc_expand_user_macros_len(text, text_len, hostids, hostids_num, value, error); + UNLOCK_CACHE; + + return ret; +} + +/****************************************************************************** + * * * Function: dc_expand_user_macros * * * * Purpose: expand user macros in the specified text value * diff --git a/src/libs/zbxdbupgrade/dbupgrade_5030.c b/src/libs/zbxdbupgrade/dbupgrade_5030.c index 5d08bc83d05..0377916cf15 100644 --- a/src/libs/zbxdbupgrade/dbupgrade_5030.c +++ b/src/libs/zbxdbupgrade/dbupgrade_5030.c @@ -2750,10 +2750,12 @@ static void dbpatch_convert_simple_macro(const char *expression, const zbx_token host = zbx_substr(expression, data->host.l, data->host.r); key = zbx_substr(expression, data->key.l, data->key.r); + /* TODO: clarify if {HOST.HOST} should be replaced with // if (0 == strcmp(host, "{HOST.HOST}")) func->arg0 = zbx_dsprintf(NULL, "//%s", key); else - func->arg0 = zbx_dsprintf(NULL, "/%s/%s", host, key); + */ + func->arg0 = zbx_dsprintf(NULL, "/%s/%s", host, key); zbx_vector_ptr_append(&functions, func); diff --git a/src/libs/zbxeval/Makefile.am b/src/libs/zbxeval/Makefile.am index a788c852c12..c6d4dc4c93a 100644 --- a/src/libs/zbxeval/Makefile.am +++ b/src/libs/zbxeval/Makefile.am @@ -5,5 +5,5 @@ noinst_LIBRARIES = libzbxeval.a libzbxeval_a_SOURCES = \ parse.c \ execute.c \ - misc.c - + misc.c \ + query.c diff --git a/src/libs/zbxeval/execute.c b/src/libs/zbxeval/execute.c index 2a9007007b4..761d0866a6e 100644 --- a/src/libs/zbxeval/execute.c +++ b/src/libs/zbxeval/execute.c @@ -428,11 +428,6 @@ static int eval_execute_push_value(const zbx_eval_context_t *ctx, const zbx_eval suffix2factor(ctx->expression[token->loc.r])); } } - else if (ZBX_EVAL_TOKEN_VAR_TIME == token->type) - { - zbx_variant_set_dbl(&value, atof(ctx->expression + token->loc.l) * - suffix2factor(ctx->expression[token->loc.r])); - } else { dst = zbx_malloc(NULL, token->loc.r - token->loc.l + 2); @@ -1248,50 +1243,47 @@ static int eval_execute_function_bitand(const zbx_eval_context_t *ctx, const zbx * * * Purpose: evaluate function by calling custom callback (if configured) * * * - * Parameters: ctx - [IN] the evaluation context * - * token - [IN] the function token * - * output - [IN/OUT] the output value stack * - * error - [OUT] the error message in the case of failure * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * functio_cb - [IN] the callback function * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * * * * Return value: SUCCEED - the function was executed successfully * * FAIL - otherwise * * * ******************************************************************************/ static int eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, - zbx_vector_var_t *output, char **error) + zbx_eval_function_cb_t function_cb, zbx_vector_var_t *output, char **error) { zbx_variant_t value, *args; - - if (NULL == ctx->function_cb) - { - *error = zbx_dsprintf(*error, "unknown function at \"%s\"", ctx->expression + token->loc.l); - return FAIL; - } + char *errmsg = NULL; args = (0 == token->opt ? NULL : &output->values[output->values_num - token->opt]); - if (SUCCEED != ctx->function_cb(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1, - token->opt, args, &value, error)) + if (SUCCEED != function_cb(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1, + token->opt, args, ctx->data_cb, &ctx->ts, &value, &errmsg)) { - return FAIL; - } + *error = zbx_dsprintf(*error, "%s at \"%s\".", errmsg, ctx->expression + token->loc.l); + zbx_free(errmsg); - if (ZBX_VARIANT_ERR == value.type && 0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR)) - { - *error = zbx_dsprintf(*error, "%s at \"%s\"", value.data.err, ctx->expression + token->loc.l); - zbx_variant_clear(&value); - return FAIL; + if (0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR)) + return FAIL; + + zbx_variant_set_error(&value, *error); + *error = NULL; } eval_function_return(token->opt, &value, output); + return SUCCEED; } /****************************************************************************** * * - * Function: eval_execute_function * + * Function: eval_execute_common_function * * * - * Purpose: evaluate normal (non history) function * + * Purpose: evaluate common function * * * * Parameters: ctx - [IN] the evaluation context * * token - [IN] the function token * @@ -1302,11 +1294,9 @@ static int eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eva * FAIL - otherwise * * * ******************************************************************************/ -static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, +static int eval_execute_common_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, zbx_vector_var_t *output, char **error) { - char *errmsg = NULL; - if ((zbx_uint32_t)output->values_num < token->opt) { *error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"", @@ -1339,19 +1329,16 @@ static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_t if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitand", ZBX_CONST_STRLEN("bitand"))) return eval_execute_function_bitand(ctx, token, output, error); - if (FAIL == eval_execute_cb_function(ctx, token, output, &errmsg)) - { - *error = zbx_dsprintf(*error, "%s at \"%s\"", errmsg, ctx->expression + token->loc.l); - zbx_free(errmsg); - return FAIL; - } + if (NULL != ctx->common_func_cb) + return eval_execute_cb_function(ctx, token, ctx->common_func_cb, output, error); - return SUCCEED; + *error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l); + return FAIL; } /****************************************************************************** * * - * Function: eval_execute_hist_function * + * Function: eval_execute_history_function * * * * Purpose: evaluate history function * * * @@ -1364,19 +1351,21 @@ static int eval_execute_function(const zbx_eval_context_t *ctx, const zbx_eval_t * FAIL - otherwise * * * ******************************************************************************/ -static int eval_execute_hist_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, +static int eval_execute_history_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, zbx_vector_var_t *output, char **error) { - char *errmsg = NULL; - - if (FAIL == eval_execute_cb_function(ctx, token, output, &errmsg)) + if ((zbx_uint32_t)output->values_num < token->opt) { - *error = zbx_dsprintf(*error, "%s at \"%s\"", errmsg, ctx->expression + token->loc.l); - zbx_free(errmsg); + *error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"", + ctx->expression + token->loc.l); return FAIL; } - return SUCCEED; + if (NULL != ctx->history_func_cb) + return eval_execute_cb_function(ctx, token, ctx->history_func_cb, output, error); + + *error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l); + return FAIL; } /****************************************************************************** @@ -1445,7 +1434,6 @@ static int eval_execute(const zbx_eval_context_t *ctx, zbx_variant_t *value, cha switch (token->type) { case ZBX_EVAL_TOKEN_VAR_NUM: - case ZBX_EVAL_TOKEN_VAR_TIME: case ZBX_EVAL_TOKEN_VAR_STR: case ZBX_EVAL_TOKEN_VAR_MACRO: case ZBX_EVAL_TOKEN_VAR_USERMACRO: @@ -1461,11 +1449,11 @@ static int eval_execute(const zbx_eval_context_t *ctx, zbx_variant_t *value, cha eval_execute_push_null(&output); break; case ZBX_EVAL_TOKEN_FUNCTION: - if (SUCCEED != eval_execute_function(ctx, token, &output, error)) + if (SUCCEED != eval_execute_common_function(ctx, token, &output, error)) goto out; break; case ZBX_EVAL_TOKEN_HIST_FUNCTION: - if (SUCCEED != eval_execute_hist_function(ctx, token, &output, error)) + if (SUCCEED != eval_execute_history_function(ctx, token, &output, error)) goto out; break; case ZBX_EVAL_TOKEN_FUNCTIONID: @@ -1520,15 +1508,20 @@ out: * * * Purpose: initialize execution context * * * - * Parameters: ctx - [IN] the evaluation context * - * ts - [IN] the timestamp of the execution time * - * function_cb - [IN] the callback for function processing * + * Parameters: ctx - [IN] the evaluation context * + * ts - [IN] the timestamp of the execution time * + * common_func_cb - [IN] the common function callback (optional) * + * history_func_cb - [IN] the history function callback (optional)* + * data_cb - [IN] the caller data to be passed to callback* + * functions * * * ******************************************************************************/ static void eval_init_execute_context(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, - zbx_eval_function_cb_t function_cb) + zbx_eval_function_cb_t common_func_cb, zbx_eval_function_cb_t history_func_cb, void *data_cb) { - ctx->function_cb = function_cb; + ctx->common_func_cb = common_func_cb; + ctx->history_func_cb = history_func_cb; + ctx->data_cb = data_cb; if (NULL == ts) ctx->ts.sec = ctx->ts.ns = 0; @@ -1553,7 +1546,7 @@ static void eval_init_execute_context(zbx_eval_context_t *ctx, const zbx_timespe ******************************************************************************/ int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_variant_t *value, char **error) { - eval_init_execute_context(ctx, ts, NULL); + eval_init_execute_context(ctx, ts, NULL, NULL, NULL); return eval_execute(ctx, value, error); } @@ -1565,11 +1558,12 @@ int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_vari * Purpose: evaluate parsed expression with callback for custom function * * processing * * * - * Parameters: ctx - [IN] the evaluation context * - * ts - [IN] the timestamp of the execution time * - * function_cb - [IN] the callback for function processing * - * value - [OUT] the resulting value * - * error - [OUT] the error message in the case of failure * + * Parameters: ctx - [IN] the evaluation context * + * ts - [IN] the timestamp of the execution time * + * common_func_cb - [IN] the common function callback (optional) * + * history_func_cb - [IN] the history function callback (optional)* + * value - [OUT] the resulting value * + * error - [OUT] the error message * * * * Return value: SUCCEED - the expression was evaluated successfully * * FAIL - otherwise * @@ -1578,10 +1572,10 @@ int zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_vari * functions. * * * ******************************************************************************/ -int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t function_cb, - zbx_variant_t *value, char **error) +int zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t common_func_cb, + zbx_eval_function_cb_t history_func_cb, void *data, zbx_variant_t *value, char **error) { - eval_init_execute_context(ctx, ts, function_cb); + eval_init_execute_context(ctx, ts, common_func_cb, history_func_cb, data); return eval_execute(ctx, value, error); } diff --git a/src/libs/zbxeval/misc.c b/src/libs/zbxeval/misc.c index 7d2275792fb..ec877071b5f 100644 --- a/src/libs/zbxeval/misc.c +++ b/src/libs/zbxeval/misc.c @@ -277,9 +277,7 @@ static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, si const zbx_eval_token_t *token) { int quoted = 0, check_value = 0; - const char *src, *value_str; - char *dst; - size_t size; + const char *value_str; if (ZBX_VARIANT_NONE == token->value.type) return; @@ -338,55 +336,9 @@ static void eval_token_print_alloc(const zbx_eval_context_t *ctx, char **str, si value_str = zbx_variant_value_desc(&token->value); if (0 == quoted) - { zbx_strcpy_alloc(str, str_alloc, str_offset, value_str); - return; - } - - for (size = 2, src = value_str; '\0' != *src; src++) - { - switch (*src) - { - case '\\': - case '"': - size++; - } - size++; - } - - if (*str_alloc <= *str_offset + size) - { - if (0 == *str_alloc) - *str_alloc = size; - - do - { - *str_alloc *= 2; - } - while (*str_alloc - *str_offset <= size); - - *str = zbx_realloc(*str, *str_alloc); - } - - dst = *str + *str_offset; - *dst++ = '"'; - - for (src = value_str; '\0' != *src; src++, dst++) - { - switch (*src) - { - case '\\': - case '"': - *dst++ = '\\'; - break; - } - - *dst = *src; - } - - *dst++ = '"'; - *dst = '\0'; - *str_offset += size; + else + zbx_strquote_alloc(str, str_alloc, str_offset, value_str); } /****************************************************************************** @@ -473,6 +425,8 @@ int zbx_eval_expand_user_macros(const zbx_eval_context_t *ctx, zbx_uint64_t *hos hostids, hostids_num, &value, error); break; case ZBX_EVAL_TOKEN_VAR_STR: + case ZBX_EVAL_TOKEN_VAR_NUM: + case ZBX_EVAL_TOKEN_ARG_PERIOD: if (NULL == (ptr = strstr(ctx->expression + token->loc.l, "{$")) || ptr >= ctx->expression + token->loc.r) { @@ -970,3 +924,29 @@ char *zbx_eval_format_function_error(const char *function, const char *host, con return msg; } + +/****************************************************************************** + * * + * Function: zbx_eval_extract_history_queries * + * * + * Purpose: copy history query into vector and replace it with vector index * + * * + * Parameters: ctx - [IN] the evaluation context * + * refs - [OUT] the item references * + * * + ******************************************************************************/ +void zbx_eval_extract_item_refs(zbx_eval_context_t *ctx, zbx_vector_str_t *refs) +{ + int i; + + for (i = 0; i < ctx->stack.values_num; i++) + { + zbx_eval_token_t *token = &ctx->stack.values[i]; + + if (ZBX_EVAL_TOKEN_ARG_QUERY != token->type) + continue; + + zbx_variant_set_ui64(&token->value, refs->values_num); + zbx_vector_str_append(refs, zbx_substr(ctx->expression, token->loc.l, token->loc.r)); + } +} diff --git a/src/libs/zbxeval/parse.c b/src/libs/zbxeval/parse.c index 2602a03f6e0..f76f95c887e 100644 --- a/src/libs/zbxeval/parse.c +++ b/src/libs/zbxeval/parse.c @@ -468,19 +468,7 @@ static int eval_parse_number_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval len += offset; - switch (ctx->expression[pos + len - 1]) - { - case 's': - case 'm': - case 'h': - case 'd': - case 'w': - token->type = ZBX_EVAL_TOKEN_VAR_TIME; - break; - default: - token->type = ZBX_EVAL_TOKEN_VAR_NUM; - break; - } + token->type = ZBX_EVAL_TOKEN_VAR_NUM; tmp = strtod(ctx->expression + pos, &end) * suffix2factor(ctx->expression[pos + len - 1]); if (HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno) @@ -594,7 +582,7 @@ static int eval_parse_function_token(zbx_eval_context_t *ctx, size_t pos, zbx_ev ******************************************************************************/ static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_token_t *token, char **error) { -#define MVAR_HOST_HOST "{HOST.HOST}" +#define MVAR_HOST_HOST "{HOST.HOST" const char *ptr = ctx->expression + pos + 1, *key; @@ -605,8 +593,25 @@ static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_ break; case '{': if (0 == strncmp(ptr, MVAR_HOST_HOST, ZBX_CONST_STRLEN(MVAR_HOST_HOST))) - ptr += ZBX_CONST_STRLEN(MVAR_HOST_HOST); - break; + { + int offset = 0; + + if ('}' == ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST)]) + { + offset = 1; + } + else if (0 != isdigit((unsigned char)ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST)]) && + '}' == ptr[ZBX_CONST_STRLEN(MVAR_HOST_HOST) + 1]) + { + offset = 2; + } + + if (0 != offset) + { + ptr += ZBX_CONST_STRLEN(MVAR_HOST_HOST) + offset; + break; + } + } default: while (SUCCEED == is_hostname_char(*ptr)) ptr++; @@ -614,7 +619,13 @@ static int eval_parse_query_token(zbx_eval_context_t *ctx, size_t pos, zbx_eval_ if ('/' != *ptr) { - *error = zbx_dsprintf(*error, "invalid host name in query starting at \"%s\"", ctx->expression + pos); + if (ptr == ctx->expression + pos + 1) + { + *error = zbx_dsprintf(*error, "invalid host name in query starting at \"%s\"", ctx->expression + pos); + return FAIL; + } + + *error = zbx_dsprintf(*error, "missing item key in query starting at \"%s\"", ctx->expression + pos); return FAIL; } @@ -953,7 +964,8 @@ static int eval_parse_expression(zbx_eval_context_t *ctx, const char *expression goto out; } - if (ZBX_EVAL_TOKEN_ARG_QUERY == ctx->last_token_type && ZBX_EVAL_TOKEN_COMMA != token.type) + if (ZBX_EVAL_TOKEN_ARG_QUERY == ctx->last_token_type && ZBX_EVAL_TOKEN_COMMA != token.type && + ZBX_EVAL_TOKEN_GROUP_CLOSE != token.type) { *error = zbx_dsprintf(*error, "invalid expression following query token at \"%s\"", ctx->expression + pos); @@ -1173,30 +1185,6 @@ int zbx_eval_parse_expression(zbx_eval_context_t *ctx, const char *expression, z /****************************************************************************** * * - * Function: zbx_eval_parse_expression * - * * - * Purpose: parse expression into tokens in postfix notation order * - * * - * Parameters: expression - [IN] the expression to parse * - * rules - [IN] the parsing rules * - * error - [OUT] the error message in the case of failure * - * * - * Return value: The evaluation context or NULL in the case of error. * - * * - ******************************************************************************/ -zbx_eval_context_t *zbx_eval_parse_expression_dyn(const char *expression, zbx_uint64_t rules, char **error) -{ - zbx_eval_context_t *ctx; - - ctx = (zbx_eval_context_t *)zbx_malloc(NULL, sizeof(zbx_eval_context_t)); - if (SUCCEED != zbx_eval_parse_expression(ctx, expression, rules, error)) - zbx_free(ctx); - - return ctx; -} - -/****************************************************************************** - * * * Function: zbx_eval_init * * * * Purpose: initialize context so it can be cleared without parsing * diff --git a/src/libs/zbxserver/evalfunc2.c b/src/libs/zbxserver/evalfunc2.c index 4897f358d89..afc577adc47 100644 --- a/src/libs/zbxserver/evalfunc2.c +++ b/src/libs/zbxserver/evalfunc2.c @@ -2340,3 +2340,36 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function return ret; } + +/****************************************************************************** + * * + * Function: zbx_is_trigger_function * + * * + * Purpose: check if the specified function is a trigger function * + * * + * Parameters: name - [IN] the function name to check * + * len - [IN] the length of function name * + * * + * Return value: SUCCEED - the function is a trigger function * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_is_trigger_function(const char *name, size_t len) +{ + char *functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "nodata", "change", "find", + "fuzzytime", "logeventid", "logseverity", "logsource", "band", "forecast", "timeleft", + "trendavg", "trendcount", "trendmax", "trendmin", "trendsum", + NULL}; + char **ptr; + + for (ptr = functions; NULL != *ptr; ptr++) + { + size_t compare_len; + + compare_len = strlen(*ptr); + if (compare_len == len && 0 == memcmp(*ptr, name, len)) + return SUCCEED; + } + + return FAIL; +} diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c index 0706454d648..582409470a3 100644 --- a/src/libs/zbxserver/expression.c +++ b/src/libs/zbxserver/expression.c @@ -22,6 +22,7 @@ #include "log.h" #include "zbxregexp.h" #include "zbxvariant.h" +#include "zbxeval.h" #include "valuecache.h" #include "macrofunc.h" @@ -2368,40 +2369,6 @@ static void get_event_value(const char *macro, const DB_EVENT *event, char **rep /****************************************************************************** * * - * Function: get_expression_macro_result * - * * - * Purpose: calculate result of expression macro * - * * - * Return value: upon successful completion return SUCCEED * - * otherwise FAIL * - * * - ******************************************************************************/ -static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_event, char **expression, - char **replace_to, char *error, int maxerrlen) -{ - int ret; - double expression_result; - - zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, *expression); - - substitute_simple_macros_impl(NULL, event, r_event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, expression, - MACRO_TYPE_EXPRESSION, error, maxerrlen); - - if (SUCCEED == (ret = evaluate(&expression_result, *expression, error, maxerrlen, NULL))) - { - char buffer[ZBX_MAX_DOUBLE_LEN + 1]; - - zbx_print_double(buffer, sizeof(buffer), expression_result); - *replace_to = zbx_strdup(*replace_to, buffer); - } - - zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); - - return ret; -} - -/****************************************************************************** - * * * Function: get_history_log_value * * * * Purpose: retrieve a particular attribute of a log value * @@ -2643,6 +2610,294 @@ out: return ret; } + +typedef struct +{ + const DB_EVENT *event; +} +zbx_expression_macro_data_t; + +/****************************************************************************** + * * + * Function: expression_macro_common_func_cb * + * * + * Purpose: evaluate common function * + * * + * Parameters: name - [IN] the function name (not zero terminated) * + * len - [IN] the function name length * + * args_num - [IN] the number of function arguments * + * args - [IN] an array of the function arguments. * + * data - [IN] the caller data used for function evaluation * + * ts - [IN] the function execution time * + * value - [OUT] the function return value * + * error - [OUT] the error message if function failed * + * * + * Return value: SUCCEED - the function was executed successfully * + * FAIL - otherwise * + * * + * Comments: There are no custom common functions for expression macros, but * + * it's used to check for /host/key query quoting errors instead. * + * * + ******************************************************************************/ +static int expression_macro_common_func_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args, + void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error) +{ + ZBX_UNUSED(data); + ZBX_UNUSED(ts); + ZBX_UNUSED(value); + + if (SUCCEED != zbx_is_trigger_function(name, len)) + { + *error = zbx_strdup(NULL, "Cannot evaluate formula: unsupported function"); + return FAIL; + } + + if (0 == args_num) + { + *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments"); + return FAIL; + } + + if (ZBX_VARIANT_STR == args[0].type) + { + zbx_item_query_t query; + + zbx_eval_parse_query(args[0].data.str, strlen(args[0].data.str), &query); + + if (ZBX_ITEM_QUERY_UNKNOWN != query.type) + { + zbx_eval_clear_query(&query); + *error = zbx_strdup(NULL, "Cannot evaluate function: quoted item query argument"); + return FAIL; + } + } + + *error = zbx_strdup(NULL, "Cannot evaluate function: invalid first argument"); + return FAIL; +} + +static int expression_macro_history_func_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args, + void *data, const zbx_timespec_t *ts, zbx_variant_t *value, char **error) +{ + zbx_expression_macro_data_t *md = (zbx_expression_macro_data_t *)data; + zbx_item_query_t query; + zbx_host_key_t hkey; + DC_ITEM item; + int i, errcode, ret = FAIL; + char func_name[MAX_STRING_LEN], *params = NULL, *errmsg = NULL, *host = NULL; + size_t params_alloc = 0, params_offset = 0; + int N_functionid = 0; + + if (SUCCEED != zbx_is_trigger_function(name, len)) + { + *error = zbx_strdup(NULL, "Cannot evaluate formula: unsupported function"); + return FAIL; + } + + if (0 == args_num) + { + *error = zbx_strdup(NULL, "Cannot evaluate function: invalid number of arguments"); + return FAIL; + } + + if (ZBX_VARIANT_STR != args[0].type) + { + *error = zbx_strdup(NULL, "Cannot evaluate function: invalid first argument"); + return FAIL; + } + + zbx_eval_parse_query(args[0].data.str, strlen(args[0].data.str), &query); + + if (ZBX_ITEM_QUERY_SINGLE != query.type) + { + zbx_eval_clear_query(&query); + *error = zbx_strdup(NULL, "Cannot evaluate function: invalid item query"); + return FAIL; + } + + if (query.host != NULL) + { + zbx_strloc_t loc; + + loc.l = 0; + loc.r = strlen(query.host) - 1; + macro_in_list(query.host, loc, simple_host_macros, &N_functionid); + } + else + N_functionid = 1; + + if (0 != N_functionid) + { + if (SUCCEED != DBget_trigger_value(&md->event->trigger, &host, N_functionid, + ZBX_REQUEST_HOST_HOST)) + { + *error = zbx_dsprintf(NULL, "cannot get host from trigger expression by index"); + goto out; + } + hkey.host = host; + } + else + hkey.host = query.host; + + hkey.key = query.key; + + DCconfig_get_items_by_keys(&item, &hkey, &errcode, 1); + + if (SUCCEED != errcode) + { + *error = zbx_dsprintf(NULL, "Cannot evaluate function because item \"/%s/%s\" does not exist", + hkey.host, hkey.key); + goto out; + } + + /* do not evaluate if the item is disabled or belongs to a disabled host */ + + if (ITEM_STATUS_ACTIVE != item.status) + { + *error = zbx_dsprintf(NULL, "Cannot evaluate function with disabled item \"/%s/%s\"", + hkey.host, hkey.key); + goto out; + } + + if (HOST_STATUS_MONITORED != item.host.status) + { + *error = zbx_dsprintf(NULL, "Cannot evaluate function with item \"/%s/%s\" belonging to a disabled host", + hkey.host, hkey.key); + goto out; + } + + memcpy(func_name, name, len); + func_name[len] = '\0'; + + /* If the item is NOTSUPPORTED then evaluation is allowed for: */ + /* - functions white-listed in evaluatable_for_notsupported(). */ + /* Their values can be evaluated to regular numbers even for */ + /* NOTSUPPORTED items. */ + /* - other functions. Result of evaluation is ZBX_UNKNOWN. */ + + if (ITEM_STATE_NOTSUPPORTED == item.state && FAIL == zbx_evaluatable_for_notsupported(func_name)) + { + *error = zbx_dsprintf(NULL,"Cannot evaluate function with not supported item \"/%s/%s\"", + hkey.host, hkey.key); + goto out; + } + + if (1 == args_num) + { + if (SUCCEED != (ret = evaluate_function2(value, &item, func_name, "", ts, &errmsg))) + { + *error = zbx_dsprintf(NULL, "Cannot evaluate calculated item formula: %s", errmsg); + zbx_free(errmsg); + } + goto out; + } + + for (i = 1; i < args_num; i++) + { + if (0 != i) + zbx_chrcpy_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ','); + + switch (args[i].type) + { + case ZBX_VARIANT_DBL: + zbx_snprintf_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ZBX_FS_DBL64, + args[i].data.dbl); + break; + case ZBX_VARIANT_STR: + zbx_strquote_alloc(¶ms, ¶ms_alloc, ¶ms_offset, args[i].data.str); + break; + case ZBX_VARIANT_UI64: + zbx_snprintf_alloc(¶ms, ¶ms_alloc, ¶ms_offset, ZBX_FS_UI64, + args[i].data.ui64); + break; + case ZBX_VARIANT_NONE: + break; + default: + *error = zbx_dsprintf(NULL,"Cannot evaluate function \"%s\":" + " unsupported argument #%d type: %s", + func_name, i + 1, zbx_variant_type_desc(&args[i])); + goto out; + } + } + + if (SUCCEED != (ret = evaluate_function2(value, &item, func_name, params, ts, &errmsg))) + { + *error = zbx_dsprintf(NULL, "Cannot evaluate calculated item formula: %s", errmsg); + zbx_free(errmsg); + } + +out: + zbx_free(params); + zbx_free(host); + zbx_eval_clear_query(&query); + DCconfig_clean_items(&item, &errcode, 1); + + return ret; +} + + +/****************************************************************************** + * * + * Function: get_expression_macro_result * + * * + * Purpose: calculate result of expression macro * + * * + * Return value: upon successful completion return SUCCEED * + * otherwise FAIL * + * * + ******************************************************************************/ +static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_event, const char *expression, + char **replace_to, char **error) +{ + int ret = FAIL; + zbx_eval_context_t ctx; + const zbx_vector_uint64_t *hostids; + zbx_timespec_t ts; + zbx_variant_t value; + zbx_expression_macro_data_t data; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression); + + ZBX_UNUSED(r_event); + + if (SUCCEED != zbx_eval_parse_expression(&ctx, expression, ZBX_EVAL_PARSE_EXPRESSION_MACRO, error)) + goto out; + + if (SUCCEED != zbx_db_trigger_get_all_hostids(&event->trigger, &hostids)) + { + *error = zbx_strdup(NULL, "cannot obtain host identifiers for the expression macro"); + goto out; + } + + if (SUCCEED != zbx_eval_expand_user_macros(&ctx, hostids->values, hostids->values_num, + zbx_dc_expand_user_macros_len, error)) + { + goto out; + } + + ts.sec = event->clock; + ts.ns = event->ns; + + data.event = event; + + if (SUCCEED != zbx_eval_execute_ext(&ctx, &ts, expression_macro_common_func_cb, + expression_macro_history_func_cb, (void *)&data, &value, error)) + { + goto out; + } + + *replace_to = zbx_strdup(NULL, zbx_variant_value_desc(&value)); + zbx_variant_clear(&value); + + ret = SUCCEED; +out: + zbx_eval_clear(&ctx); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + /****************************************************************************** * * * Function: cache_item_hostid * @@ -2961,8 +3216,8 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_ break; case ZBX_TOKEN_SIMPLE_MACRO: if (0 == (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY | - MACRO_TYPE_MESSAGE_ACK | MACRO_TYPE_EXPRESSION | - MACRO_TYPE_SCRIPT_NORMAL | MACRO_TYPE_SCRIPT_RECOVERY)) || + MACRO_TYPE_MESSAGE_ACK | MACRO_TYPE_SCRIPT_NORMAL | + MACRO_TYPE_SCRIPT_RECOVERY)) || EVENT_SOURCE_TRIGGERS != ((NULL != r_event) ? r_event : event)->source) { pos++; @@ -4108,16 +4363,24 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_ { if (0 != (macro_type & MACRO_TYPE_EVENT_NAME)) { - char *exp = NULL; + char *exp = NULL, *errmsg = NULL; size_t exp_alloc = 0, exp_offset = 0; zbx_strloc_t *loc = &inner_token.data.expression_macro.expression; zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, *data + loc->l, loc->r - loc->l + 1); - ret = get_expression_macro_result(event, r_event, &exp, &replace_to, - error, maxerrlen); + ret = get_expression_macro_result(event, r_event, exp, &replace_to, + &errmsg); zbx_free(exp); + + if (SUCCEED != ret) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot evaluate" + " expression macro: %s", __func__, errmsg); + zbx_strlcpy(error, errmsg, maxerrlen); + zbx_free(errmsg); + } } } else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME)) @@ -4666,24 +4929,6 @@ static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_ } } } - else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_EXPRESSION)) - { - const DB_EVENT *c_event; - - c_event = ((NULL != r_event) ? r_event : event); - - if (ZBX_TOKEN_USER_MACRO == token.type) - { - if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger, &phostids)) - DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to); - pos = token.loc.r; - } - else if (ZBX_TOKEN_SIMPLE_MACRO == token.type) - { - ret = get_trigger_function_value(&c_event->trigger, &replace_to, - *data, &token.data.simple_macro, ZBX_FORMAT_RAW); - } - } if (0 != (macro_type & MACRO_TYPE_HTTP_JSON) && NULL != replace_to) zbx_json_escape(&replace_to); diff --git a/tests/libs/zbxcommon/zbx_token_find.yaml b/tests/libs/zbxcommon/zbx_token_find.yaml index 798680d3e45..c09ddf73479 100644 --- a/tests/libs/zbxcommon/zbx_token_find.yaml +++ b/tests/libs/zbxcommon/zbx_token_find.yaml @@ -543,7 +543,7 @@ in: out: token: '{?{HOST.HOST}' token_type: ZBX_TOKEN_EXPRESSION_MACRO - expression: '{HOST.HOST' + expression: '{HOST.HOST}' return: SUCCEED --- test case: 'Success: {?{$MACRO}}' diff --git a/tests/libs/zbxeval/zbx_eval_execute_ext.c b/tests/libs/zbxeval/zbx_eval_execute_ext.c index 185c3ad5f84..0a03776c7bd 100644 --- a/tests/libs/zbxeval/zbx_eval_execute_ext.c +++ b/tests/libs/zbxeval/zbx_eval_execute_ext.c @@ -112,12 +112,14 @@ static void mock_read_callbacks(const char *path) } } -static int callback_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args, - zbx_variant_t *value, char **error) +static int callback_cb(const char *name, size_t len, int args_num, const zbx_variant_t *args, void *data, + const zbx_timespec_t *ts, zbx_variant_t *value, char **error) { int i; ZBX_UNUSED(args); + ZBX_UNUSED(data); + ZBX_UNUSED(ts); for (i = 0; i < callbacks.values_num; i++) { @@ -167,7 +169,7 @@ void zbx_mock_test_entry(void **state) mock_eval_read_values(&ctx, "in.replace"); mock_read_callbacks("in.callbacks"); - returned_ret = zbx_eval_execute_ext(&ctx, NULL, callback_cb, &value, &error); + returned_ret = zbx_eval_execute_ext(&ctx, NULL, callback_cb, callback_cb, NULL, &value, &error); if (SUCCEED != returned_ret) printf("ERROR: %s\n", error); diff --git a/tests/libs/zbxeval/zbx_eval_execute_ext.yaml b/tests/libs/zbxeval/zbx_eval_execute_ext.yaml index c01faf467ff..4c9aea8aaca 100644 --- a/tests/libs/zbxeval/zbx_eval_execute_ext.yaml +++ b/tests/libs/zbxeval/zbx_eval_execute_ext.yaml @@ -52,7 +52,7 @@ in: callbacks: - name: err args_num: 0 - reterr: 'forced return error' + error: 'forced return error' out: result: SUCCEED value: 1 @@ -64,7 +64,7 @@ in: callbacks: - name: err args_num: 0 - reterr: 'forced return error' + error: 'forced return error' out: result: FAIL --- @@ -75,7 +75,7 @@ in: callbacks: - name: err args_num: 0 - reterr: 'forced return error' + error: 'forced return error' out: result: SUCCEED value: 0 @@ -87,7 +87,7 @@ in: callbacks: - name: err args_num: 0 - reterr: 'forced return error' + error: 'forced return error' out: result: FAIL --- diff --git a/tests/libs/zbxeval/zbx_eval_parse_expression.c b/tests/libs/zbxeval/zbx_eval_parse_expression.c index d1fcb36549a..4669d5e81d3 100644 --- a/tests/libs/zbxeval/zbx_eval_parse_expression.c +++ b/tests/libs/zbxeval/zbx_eval_parse_expression.c @@ -48,7 +48,6 @@ static const char *mock_token_type2str(zbx_uint32_t type) ZBX_MOCK_TOKEN_CASE(OP_NOT) ZBX_MOCK_TOKEN_CASE(VAR_NUM) ZBX_MOCK_TOKEN_CASE(VAR_STR) - ZBX_MOCK_TOKEN_CASE(VAR_TIME) ZBX_MOCK_TOKEN_CASE(VAR_MACRO) ZBX_MOCK_TOKEN_CASE(VAR_USERMACRO) ZBX_MOCK_TOKEN_CASE(VAR_LLDMACRO) @@ -90,7 +89,6 @@ static zbx_uint32_t mock_token_str2type(const char *str) ZBX_MOCK_TOKEN_IF(OP_NOT) ZBX_MOCK_TOKEN_IF(VAR_NUM) ZBX_MOCK_TOKEN_IF(VAR_STR) - ZBX_MOCK_TOKEN_IF(VAR_TIME) ZBX_MOCK_TOKEN_IF(VAR_MACRO) ZBX_MOCK_TOKEN_IF(VAR_USERMACRO) ZBX_MOCK_TOKEN_IF(VAR_LLDMACRO) diff --git a/tests/libs/zbxeval/zbx_eval_parse_expression.yaml b/tests/libs/zbxeval/zbx_eval_parse_expression.yaml index 4d5e1251d80..0be187fded3 100644 --- a/tests/libs/zbxeval/zbx_eval_parse_expression.yaml +++ b/tests/libs/zbxeval/zbx_eval_parse_expression.yaml @@ -1508,6 +1508,59 @@ in: out: result: FAIL --- +test case: Succeed 'last(/host/key)' +in: + rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION] + expression: 'last(/host/key)' +out: + stack: + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 1} + result: SUCCEED +--- +test case: Succeed 'last(/host/key,#1)' +in: + rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION] + expression: 'last(/host/key,#1)' +out: + stack: + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#1', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 2} + result: SUCCEED +--- +test case: Succeed 'count(//trap[1],#5,,0)' +in: + rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION] + expression: 'count(//trap[1],#5,,0)' +out: + stack: + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '//trap[1]', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#5', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_NULL, token: '', opt: 0} + - {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '0', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4} + result: SUCCEED +--- +test case: Succeed 'count(//trap[1],#5,,0) + count(/Trapper/trap[1] ,5m ,"1h ","1 ")' +in: + rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION] + expression: 'count(//trap[1],#5,,0) + count(/Trapper/trap[1] ,5m ,"1h","1")' +out: + stack: + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '//trap[1]', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#5', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_NULL, token: '', opt: 0} + - {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '0', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4} + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/Trapper/trap[1]', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '5m', opt: 0} + - {type: ZBX_EVAL_TOKEN_VAR_STR, token: '"1h"', opt: 0} + - {type: ZBX_EVAL_TOKEN_VAR_STR, token: '"1"', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'count', opt: 4} + - {type: ZBX_EVAL_TOKEN_OP_ADD, token: '+', opt: 0} + result: SUCCEED +--- test case: Succeed 'min(1 + 2, 0.5 + 1.5)' in: rules: [ZBX_EVAL_PARSE_FUNCTION] @@ -1557,4 +1610,17 @@ out: - {type: ZBX_EVAL_TOKEN_VAR_NUM, token: '-1', opt: 0} - {type: ZBX_EVAL_TOKEN_OP_EQ, token: '=', opt: 0} result: SUCCEED +--- +test case: Succeed 'last(/host/key,#1:now-1h)' +in: + rules: [ZBX_EVAL_PARSE_ITEM_QUERY,ZBX_EVAL_PARSE_FUNCTION] + expression: 'last(/host/key,#1:now-1h)' +out: + stack: + - {type: ZBX_EVAL_TOKEN_ARG_QUERY, token: '/host/key', opt: 0} + - {type: ZBX_EVAL_TOKEN_ARG_PERIOD, token: '#1:now-1h', opt: 0} + - {type: ZBX_EVAL_TOKEN_HIST_FUNCTION, token: 'last', opt: 2} + result: SUCCEED ... + + |