1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "log.h"
22 #include "valuecache.h"
23 #include "dbcache.h"
24 
25 #include "checks_aggregate.h"
26 
27 #define ZBX_VALUE_FUNC_MIN	0
28 #define ZBX_VALUE_FUNC_AVG	1
29 #define ZBX_VALUE_FUNC_MAX	2
30 #define ZBX_VALUE_FUNC_SUM	3
31 #define ZBX_VALUE_FUNC_COUNT	4
32 #define ZBX_VALUE_FUNC_LAST	5
33 
34 /******************************************************************************
35  *                                                                            *
36  * Function: evaluate_history_func_min                                        *
37  *                                                                            *
38  * Purpose: calculate minimum value from the history value vector             *
39  *                                                                            *
40  * Parameters: values      - [IN] a vector containing history values          *
41  *             value_type  - [IN] the type of values. Only float/uint64       *
42  *                           values are supported.                            *
43  *             result      - [OUT] the resulting value                        *
44  *                                                                            *
45  ******************************************************************************/
evaluate_history_func_min(zbx_vector_history_record_t * values,int value_type,history_value_t * result)46 static void	evaluate_history_func_min(zbx_vector_history_record_t *values, int value_type, history_value_t *result)
47 {
48 	int	i;
49 
50 	*result = values->values[0].value;
51 
52 	if (ITEM_VALUE_TYPE_UINT64 == value_type)
53 	{
54 		for (i = 1; i < values->values_num; i++)
55 			if (values->values[i].value.ui64 < result->ui64)
56 				result->ui64 = values->values[i].value.ui64;
57 	}
58 	else
59 	{
60 		for (i = 1; i < values->values_num; i++)
61 			if (values->values[i].value.dbl < result->dbl)
62 				result->dbl = values->values[i].value.dbl;
63 	}
64 }
65 
66 /******************************************************************************
67  *                                                                            *
68  * Function: evaluate_history_func_max                                        *
69  *                                                                            *
70  * Purpose: calculate maximum value from the history value vector             *
71  *                                                                            *
72  * Parameters: values      - [IN] a vector containing history values          *
73  *             value_type  - [IN] the type of values. Only float/uint64       *
74  *                           values are supported.                            *
75  *             result      - [OUT] the resulting value                        *
76  *                                                                            *
77  ******************************************************************************/
evaluate_history_func_max(zbx_vector_history_record_t * values,int value_type,history_value_t * result)78 static void	evaluate_history_func_max(zbx_vector_history_record_t *values, int value_type, history_value_t *result)
79 {
80 	int	i;
81 
82 	*result = values->values[0].value;
83 
84 	if (ITEM_VALUE_TYPE_UINT64 == value_type)
85 	{
86 		for (i = 1; i < values->values_num; i++)
87 			if (values->values[i].value.ui64 > result->ui64)
88 				result->ui64 = values->values[i].value.ui64;
89 	}
90 	else
91 	{
92 		for (i = 1; i < values->values_num; i++)
93 			if (values->values[i].value.dbl > result->dbl)
94 				result->dbl = values->values[i].value.dbl;
95 	}
96 }
97 
98 /******************************************************************************
99  *                                                                            *
100  * Function: evaluate_history_func_sum                                        *
101  *                                                                            *
102  * Purpose: calculate sum of values from the history value vector             *
103  *                                                                            *
104  * Parameters: values      - [IN] a vector containing history values          *
105  *             value_type  - [IN] the type of values. Only float/uint64       *
106  *                           values are supported.                            *
107  *             result      - [OUT] the resulting value                        *
108  *                                                                            *
109  ******************************************************************************/
evaluate_history_func_sum(zbx_vector_history_record_t * values,int value_type,history_value_t * result)110 static void	evaluate_history_func_sum(zbx_vector_history_record_t *values, int value_type, history_value_t *result)
111 {
112 	int	i;
113 
114 	if (ITEM_VALUE_TYPE_UINT64 == value_type)
115 	{
116 		result->ui64 = 0;
117 		for (i = 0; i < values->values_num; i++)
118 			result->ui64 += values->values[i].value.ui64;
119 	}
120 	else
121 	{
122 		result->dbl = 0;
123 		for (i = 0; i < values->values_num; i++)
124 			result->dbl += values->values[i].value.dbl;
125 	}
126 }
127 
128 /******************************************************************************
129  *                                                                            *
130  * Function: evaluate_history_func_avg                                        *
131  *                                                                            *
132  * Purpose: calculate average value of values from the history value vector   *
133  *                                                                            *
134  * Parameters: values      - [IN] a vector containing history values          *
135  *             value_type  - [IN] the type of values. Only float/uint64       *
136  *                           values are supported.                            *
137  *             result      - [OUT] the resulting value                        *
138  *                                                                            *
139  ******************************************************************************/
evaluate_history_func_avg(zbx_vector_history_record_t * values,int value_type,history_value_t * result)140 static void	evaluate_history_func_avg(zbx_vector_history_record_t *values, int value_type, history_value_t *result)
141 {
142 	evaluate_history_func_sum(values, value_type, result);
143 
144 	if (ITEM_VALUE_TYPE_UINT64 == value_type)
145 		result->ui64 /= values->values_num;
146 	else
147 		result->dbl /= values->values_num;
148 }
149 
150 /******************************************************************************
151  *                                                                            *
152  * Function: evaluate_history_func_count                                      *
153  *                                                                            *
154  * Purpose: calculate number of values in value vector                        *
155  *                                                                            *
156  * Parameters: values      - [IN] a vector containing history values          *
157  *             value_type  - [IN] the type of values. Only float/uint64       *
158  *                           values are supported.                            *
159  *             result      - [OUT] the resulting value                        *
160  *                                                                            *
161  ******************************************************************************/
evaluate_history_func_count(zbx_vector_history_record_t * values,int value_type,history_value_t * result)162 static void	evaluate_history_func_count(zbx_vector_history_record_t *values, int value_type,
163 		history_value_t *result)
164 {
165 	if (ITEM_VALUE_TYPE_UINT64 == value_type)
166 		result->ui64 = values->values_num;
167 	else
168 		result->dbl = values->values_num;
169 }
170 
171 /******************************************************************************
172  *                                                                            *
173  * Function: evaluate_history_func_last                                       *
174  *                                                                            *
175  * Purpose: calculate the last (newest) value in value vector                 *
176  *                                                                            *
177  * Parameters: values      - [IN] a vector containing history values          *
178  *             result      - [OUT] the resulting value                        *
179  *                                                                            *
180  ******************************************************************************/
evaluate_history_func_last(zbx_vector_history_record_t * values,history_value_t * result)181 static void	evaluate_history_func_last(zbx_vector_history_record_t *values, history_value_t *result)
182 {
183 	*result = values->values[0].value;
184 }
185 
186 /******************************************************************************
187  *                                                                            *
188  * Function: evaluate_history_func                                            *
189  *                                                                            *
190  * Purpose: calculate function with values from value vector                  *
191  *                                                                            *
192  * Parameters: values      - [IN] a vector containing history values          *
193  *             value_type  - [IN] the type of values. Only float/uint64       *
194  *                           values are supported.                            *
195  *             func        - [IN] the function to calculate. Only             *
196  *                           ZBX_VALUE_FUNC_MIN, ZBX_VALUE_FUNC_AVG,          *
197  *                           ZBX_VALUE_FUNC_MAX, ZBX_VALUE_FUNC_SUM,          *
198  *                           ZBX_VALUE_FUNC_COUNT, ZBX_VALUE_FUNC_LAST        *
199  *                           functions are supported.                         *
200  *             result      - [OUT] the resulting value                        *
201  *                                                                            *
202  ******************************************************************************/
evaluate_history_func(zbx_vector_history_record_t * values,int value_type,int func,history_value_t * result)203 static void	evaluate_history_func(zbx_vector_history_record_t *values, int value_type, int func,
204 		history_value_t *result)
205 {
206 	switch (func)
207 	{
208 		case ZBX_VALUE_FUNC_MIN:
209 			evaluate_history_func_min(values, value_type, result);
210 			break;
211 		case ZBX_VALUE_FUNC_AVG:
212 			evaluate_history_func_avg(values, value_type, result);
213 			break;
214 		case ZBX_VALUE_FUNC_MAX:
215 			evaluate_history_func_max(values, value_type, result);
216 			break;
217 		case ZBX_VALUE_FUNC_SUM:
218 			evaluate_history_func_sum(values, value_type, result);
219 			break;
220 		case ZBX_VALUE_FUNC_COUNT:
221 			evaluate_history_func_count(values, value_type, result);
222 			break;
223 		case ZBX_VALUE_FUNC_LAST:
224 			evaluate_history_func_last(values, result);
225 			break;
226 	}
227 }
228 
229 /******************************************************************************
230  *                                                                            *
231  * Function: quote_string                                                     *
232  *                                                                            *
233  * Purpose: quotes string by enclosing it in double quotes and escaping       *
234  *          double quotes inside string with '\'.                             *
235  *                                                                            *
236  * Parameters: str    - [IN/OUT] the string to quote                          *
237  *             sz_str - [IN] the string length                                *
238  *                                                                            *
239  * Comments: The '\' character itself is not quoted. As the result if string  *
240  *           ends with '\' it can be quoted (for example for error messages), *
241  *           but it's impossible to unquote it.                               *
242  *                                                                            *
243  ******************************************************************************/
quote_string(char ** str,size_t sz_src)244 static void	quote_string(char **str, size_t sz_src)
245 {
246 	size_t	sz_dst;
247 
248 	sz_dst = zbx_get_escape_string_len(*str, "\"") + 3;
249 
250 	*str = (char *)zbx_realloc(*str, sz_dst);
251 
252 	(*str)[--sz_dst] = '\0';
253 	(*str)[--sz_dst] = '"';
254 
255 	while (0 < sz_src)
256 	{
257 		(*str)[--sz_dst] = (*str)[--sz_src];
258 
259 		if ('"' == (*str)[sz_src])
260 			(*str)[--sz_dst] = '\\';
261 	}
262 	(*str)[--sz_dst] = '"';
263 }
264 
265 /******************************************************************************
266  *                                                                            *
267  * Function: aggregate_quote_groups                                           *
268  *                                                                            *
269  * Purpose: quotes the individual groups in the list if necessary             *
270  *                                                                            *
271  ******************************************************************************/
aggregate_quote_groups(char ** str,size_t * str_alloc,size_t * str_offset,zbx_vector_str_t * groups)272 static void	aggregate_quote_groups(char **str, size_t *str_alloc, size_t *str_offset, zbx_vector_str_t *groups)
273 {
274 	int	i;
275 	char	*group, *separator = "";
276 
277 	for (i = 1; i <= groups->values_num; i++)
278 	{
279 		group = zbx_strdup(NULL, groups->values[i - 1]);
280 		zbx_strcpy_alloc(str, str_alloc, str_offset, separator);
281 		separator = (char *)", ";
282 
283 		quote_string(&group, strlen(group));
284 		zbx_strcpy_alloc(str, str_alloc, str_offset, group);
285 		zbx_free(group);
286 	}
287 }
288 
289 /******************************************************************************
290  *                                                                            *
291  * Function: aggregate_get_items                                              *
292  *                                                                            *
293  * Purpose: get array of items specified by key for selected groups           *
294  *          (including nested groups)                                         *
295  *                                                                            *
296  * Parameters: itemids - [OUT] list of item ids                               *
297  *             groups  - [IN] list of host groups                             *
298  *             itemkey - [IN] item key to aggregate                           *
299  *             error   - [OUT] the error message                              *
300  *                                                                            *
301  * Return value: SUCCEED - item identifier(s) were retrieved successfully     *
302  *               FAIL    - no items matching the specified groups or keys     *
303  *                                                                            *
304  ******************************************************************************/
aggregate_get_items(zbx_vector_uint64_t * itemids,zbx_vector_str_t * groups,const char * itemkey,char ** error)305 static int	aggregate_get_items(zbx_vector_uint64_t *itemids, zbx_vector_str_t *groups, const char *itemkey,
306 		char **error)
307 {
308 	char			*esc;
309 	DB_RESULT		result;
310 	DB_ROW			row;
311 	zbx_uint64_t		itemid;
312 	char			*sql = NULL;
313 	size_t			sql_alloc = ZBX_KIBIBYTE, sql_offset = 0, error_alloc = 0, error_offset = 0;
314 	int			ret = FAIL;
315 	zbx_vector_uint64_t	groupids;
316 
317 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemkey:'%s'", __func__, itemkey);
318 
319 	zbx_vector_uint64_create(&groupids);
320 	zbx_dc_get_nested_hostgroupids_by_names(groups, &groupids);
321 
322 	if (0 == groupids.values_num)
323 	{
324 		zbx_strcpy_alloc(error, &error_alloc, &error_offset, "None of the groups in list ");
325 		aggregate_quote_groups(error, &error_alloc, &error_offset, groups);
326 		zbx_strcpy_alloc(error, &error_alloc, &error_offset, " is correct.");
327 		goto out;
328 	}
329 
330 	sql = (char *)zbx_malloc(sql, sql_alloc);
331 	esc = DBdyn_escape_string(itemkey);
332 
333 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
334 			"select distinct i.itemid"
335 			" from items i,hosts h,hosts_groups hg,item_rtdata ir"
336 			" where i.hostid=h.hostid"
337 				" and h.hostid=hg.hostid"
338 				" and i.key_='%s'"
339 				" and i.status=%d"
340 				" and ir.itemid=i.itemid"
341 				" and ir.state=%d"
342 				" and h.status=%d"
343 				" and",
344 			esc, ITEM_STATUS_ACTIVE, ITEM_STATE_NORMAL, HOST_STATUS_MONITORED);
345 
346 	zbx_free(esc);
347 
348 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.groupid", groupids.values, groupids.values_num);
349 	result = DBselect("%s", sql);
350 	zbx_free(sql);
351 
352 	while (NULL != (row = DBfetch(result)))
353 	{
354 		ZBX_STR2UINT64(itemid, row[0]);
355 		zbx_vector_uint64_append(itemids, itemid);
356 	}
357 	DBfree_result(result);
358 
359 	if (0 == itemids->values_num)
360 	{
361 		zbx_snprintf_alloc(error, &error_alloc, &error_offset, "No items for key \"%s\" in group(s) ", itemkey);
362 		aggregate_quote_groups(error, &error_alloc, &error_offset, groups);
363 		zbx_chrcpy_alloc(error, &error_alloc, &error_offset, '.');
364 		goto out;
365 	}
366 
367 	zbx_vector_uint64_sort(itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
368 
369 	ret = SUCCEED;
370 
371 out:
372 	zbx_vector_uint64_destroy(&groupids);
373 
374 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
375 
376 	return ret;
377 }
378 
379 /******************************************************************************
380  *                                                                            *
381  * Function: evaluate_aggregate                                               *
382  *                                                                            *
383  * Parameters: item      - [IN] aggregated item                               *
384  *             grp_func  - [IN] one of ZBX_GRP_FUNC_*                         *
385  *             groups    - [IN] list of host groups                           *
386  *             itemkey   - [IN] item key to aggregate                         *
387  *             item_func - [IN] one of ZBX_VALUE_FUNC_*                       *
388  *             param     - [IN] item_func parameter (optional)                *
389  *                                                                            *
390  * Return value: SUCCEED - aggregate item evaluated successfully              *
391  *               FAIL - otherwise                                             *
392  *                                                                            *
393  ******************************************************************************/
evaluate_aggregate(const DC_ITEM * item,AGENT_RESULT * res,int grp_func,zbx_vector_str_t * groups,const char * itemkey,int item_func,const char * param)394 static int	evaluate_aggregate(const DC_ITEM *item, AGENT_RESULT *res, int grp_func, zbx_vector_str_t *groups,
395 		const char *itemkey, int item_func, const char *param)
396 {
397 	zbx_vector_uint64_t		itemids;
398 	history_value_t			value, item_result;
399 	zbx_history_record_t		group_value;
400 	int				ret = FAIL, *errcodes = NULL, i, count, seconds;
401 	DC_ITEM				*items = NULL;
402 	zbx_vector_history_record_t	values, group_values;
403 	char				*error = NULL;
404 	zbx_timespec_t			ts;
405 
406 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() grp_func:%d itemkey:'%s' item_func:%d param:'%s'",
407 			__func__, grp_func, itemkey, item_func, ZBX_NULL2STR(param));
408 
409 	zbx_timespec(&ts);
410 	zbx_vector_uint64_create(&itemids);
411 
412 	if (FAIL == aggregate_get_items(&itemids, groups, itemkey, &error))
413 	{
414 		SET_MSG_RESULT(res, error);
415 		goto clean1;
416 	}
417 
418 	memset(&value, 0, sizeof(value));
419 	zbx_history_record_vector_create(&group_values);
420 
421 	items = (DC_ITEM *)zbx_malloc(items, sizeof(DC_ITEM) * itemids.values_num);
422 	errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * itemids.values_num);
423 
424 	DCconfig_get_items_by_itemids(items, itemids.values, errcodes, itemids.values_num);
425 
426 	if (ZBX_VALUE_FUNC_LAST == item_func)
427 	{
428 		count = 1;
429 		seconds = 0;
430 	}
431 	else
432 	{
433 		if (FAIL == is_time_suffix(param, &seconds, ZBX_LENGTH_UNLIMITED))
434 		{
435 			SET_MSG_RESULT(res, zbx_strdup(NULL, "Invalid fourth parameter."));
436 			goto clean2;
437 		}
438 		count = 0;
439 	}
440 
441 	for (i = 0; i < itemids.values_num; i++)
442 	{
443 		if (SUCCEED != errcodes[i])
444 			continue;
445 
446 		if (ITEM_STATUS_ACTIVE != items[i].status)
447 			continue;
448 
449 		if (HOST_STATUS_MONITORED != items[i].host.status)
450 			continue;
451 
452 		if (ITEM_VALUE_TYPE_FLOAT != items[i].value_type && ITEM_VALUE_TYPE_UINT64 != items[i].value_type)
453 			continue;
454 
455 		zbx_history_record_vector_create(&values);
456 
457 		if (SUCCEED == zbx_vc_get_values(items[i].itemid, items[i].value_type, &values, seconds, count, &ts) &&
458 				0 < values.values_num)
459 		{
460 			evaluate_history_func(&values, items[i].value_type, item_func, &item_result);
461 
462 			if (item->value_type == items[i].value_type)
463 				group_value.value = item_result;
464 			else
465 			{
466 				if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
467 					group_value.value.ui64 = (zbx_uint64_t)item_result.dbl;
468 				else
469 					group_value.value.dbl = (double)item_result.ui64;
470 			}
471 
472 			zbx_vector_history_record_append_ptr(&group_values, &group_value);
473 		}
474 
475 		zbx_history_record_vector_destroy(&values, items[i].value_type);
476 	}
477 
478 	zbx_vc_flush_stats();
479 
480 	if (0 == group_values.values_num)
481 	{
482 		char	*tmp = NULL;
483 		size_t	tmp_alloc = 0, tmp_offset = 0;
484 
485 		aggregate_quote_groups(&tmp, &tmp_alloc, &tmp_offset, groups);
486 		SET_MSG_RESULT(res, zbx_dsprintf(NULL, "No values for key \"%s\" in group(s) %s.", itemkey, tmp));
487 		zbx_free(tmp);
488 
489 		goto clean2;
490 	}
491 
492 	evaluate_history_func(&group_values, item->value_type, grp_func, &value);
493 
494 	if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
495 		SET_DBL_RESULT(res, value.dbl);
496 	else
497 		SET_UI64_RESULT(res, value.ui64);
498 
499 	ret = SUCCEED;
500 clean2:
501 	DCconfig_clean_items(items, errcodes, itemids.values_num);
502 
503 	zbx_free(errcodes);
504 	zbx_free(items);
505 	zbx_history_record_vector_destroy(&group_values, item->value_type);
506 clean1:
507 	zbx_vector_uint64_destroy(&itemids);
508 
509 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
510 
511 	return ret;
512 }
513 
514 /******************************************************************************
515  *                                                                            *
516  * Function: get_value_aggregate                                              *
517  *                                                                            *
518  * Purpose: retrieve data from Zabbix server (aggregate items)                *
519  *                                                                            *
520  * Parameters: item - item we are interested in                               *
521  *                                                                            *
522  * Return value: SUCCEED - data successfully retrieved and stored in result   *
523  *                         and result_str (as string)                         *
524  *               NOTSUPPORTED - requested item is not supported               *
525  *                                                                            *
526  * Author: Alexei Vladishev                                                   *
527  *                                                                            *
528  ******************************************************************************/
get_value_aggregate(const DC_ITEM * item,AGENT_RESULT * result)529 int	get_value_aggregate(const DC_ITEM *item, AGENT_RESULT *result)
530 {
531 	AGENT_REQUEST		request;
532 	int			ret = NOTSUPPORTED;
533 	const char		*tmp, *groups, *itemkey, *funcp = NULL;
534 	int			grp_func, item_func, params_num;
535 	zbx_vector_str_t	group_names;
536 
537 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __func__, item->key_orig);
538 
539 	init_request(&request);
540 	zbx_vector_str_create(&group_names);
541 
542 	if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
543 	{
544 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Value type must be Numeric for aggregate items"));
545 		goto out;
546 	}
547 
548 	if (SUCCEED != parse_item_key(item->key, &request))
549 	{
550 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item key format."));
551 		goto out;
552 	}
553 
554 	if (0 == strcmp(get_rkey(&request), "grpmin"))
555 	{
556 		grp_func = ZBX_VALUE_FUNC_MIN;
557 	}
558 	else if (0 == strcmp(get_rkey(&request), "grpavg"))
559 	{
560 		grp_func = ZBX_VALUE_FUNC_AVG;
561 	}
562 	else if (0 == strcmp(get_rkey(&request), "grpmax"))
563 	{
564 		grp_func = ZBX_VALUE_FUNC_MAX;
565 	}
566 	else if (0 == strcmp(get_rkey(&request), "grpsum"))
567 	{
568 		grp_func = ZBX_VALUE_FUNC_SUM;
569 	}
570 	else
571 	{
572 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item key."));
573 		goto out;
574 	}
575 
576 	params_num = get_rparams_num(&request);
577 
578 	if (3 > params_num || params_num > 4)
579 	{
580 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
581 		goto out;
582 	}
583 
584 	groups = get_rparam(&request, 0);
585 	itemkey = get_rparam(&request, 1);
586 	tmp = get_rparam(&request, 2);
587 
588 	if (REQUEST_PARAMETER_TYPE_ARRAY == get_rparam_type(&request, 0))
589 	{
590 		int				i, groups_num;
591 		char				*group;
592 		zbx_request_parameter_type_t	type;
593 
594 		groups_num = num_param(groups);
595 
596 		for (i = 1; i <= groups_num; i++)
597 		{
598 			if (NULL == (group = get_param_dyn(groups, i, &type)))
599 				continue;
600 
601 			zbx_vector_str_append(&group_names, group);
602 
603 			if (REQUEST_PARAMETER_TYPE_STRING != type)
604 			{
605 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Invalid host group list: %s", groups));
606 				goto out;
607 			}
608 		}
609 	}
610 	else
611 		zbx_vector_str_append(&group_names, zbx_strdup(NULL, groups));
612 
613 	zabbix_log(LOG_LEVEL_DEBUG, "Host groups: '%s', Item key: '%s', Item function: '%s'", groups, itemkey, tmp);
614 
615 	if (0 == strcmp(tmp, "min"))
616 		item_func = ZBX_VALUE_FUNC_MIN;
617 	else if (0 == strcmp(tmp, "avg"))
618 		item_func = ZBX_VALUE_FUNC_AVG;
619 	else if (0 == strcmp(tmp, "max"))
620 		item_func = ZBX_VALUE_FUNC_MAX;
621 	else if (0 == strcmp(tmp, "sum"))
622 		item_func = ZBX_VALUE_FUNC_SUM;
623 	else if (0 == strcmp(tmp, "count"))
624 		item_func = ZBX_VALUE_FUNC_COUNT;
625 	else if (0 == strcmp(tmp, "last"))
626 		item_func = ZBX_VALUE_FUNC_LAST;
627 	else
628 	{
629 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
630 		goto out;
631 	}
632 
633 	if (4 == params_num)
634 	{
635 		funcp = get_rparam(&request, 3);
636 	}
637 	else if (3 == params_num && ZBX_VALUE_FUNC_LAST != item_func)
638 	{
639 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
640 		goto out;
641 	}
642 
643 	if (SUCCEED != evaluate_aggregate(item, result, grp_func, &group_names, itemkey, item_func, funcp))
644 		goto out;
645 
646 	ret = SUCCEED;
647 out:
648 	zbx_vector_str_clear_ext(&group_names, zbx_str_free);
649 	zbx_vector_str_destroy(&group_names);
650 	free_request(&request);
651 
652 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
653 
654 	return ret;
655 }
656