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 "db.h"
22 #include "log.h"
23 
24 #include "actions.h"
25 #include "events.h"
26 #include "zbxserver.h"
27 #include "export.h"
28 
29 /* event recovery data */
30 typedef struct
31 {
32 	zbx_uint64_t	eventid;
33 	zbx_uint64_t	objectid;
34 	DB_EVENT	*r_event;
35 	zbx_uint64_t	correlationid;
36 	zbx_uint64_t	c_eventid;
37 	zbx_uint64_t	userid;
38 	zbx_timespec_t	ts;
39 }
40 zbx_event_recovery_t;
41 
42 /* problem event, used to cache open problems for recovery attempts */
43 typedef struct
44 {
45 	zbx_uint64_t		eventid;
46 	zbx_uint64_t		triggerid;
47 
48 	zbx_vector_ptr_t	tags;
49 }
50 zbx_event_problem_t;
51 
52 typedef enum
53 {
54 	CORRELATION_MATCH = 0,
55 	CORRELATION_NO_MATCH,
56 	CORRELATION_MAY_MATCH
57 }
58 zbx_correlation_match_result_t;
59 
60 static zbx_vector_ptr_t		events;
61 static zbx_hashset_t		event_recovery;
62 static zbx_hashset_t		correlation_cache;
63 static zbx_correlation_rules_t	correlation_rules;
64 
65 /******************************************************************************
66  *                                                                            *
67  * Function: validate_event_tag                                               *
68  *                                                                            *
69  ******************************************************************************/
validate_event_tag(const DB_EVENT * event,const zbx_tag_t * tag)70 static int	validate_event_tag(const DB_EVENT* event, const zbx_tag_t *tag)
71 {
72 	int	i;
73 
74 	if ('\0' == *tag->tag)
75 		return FAIL;
76 
77 	/* check for duplicated tags */
78 	for (i = 0; i < event->tags.values_num; i++)
79 	{
80 		zbx_tag_t	*event_tag = (zbx_tag_t *)event->tags.values[i];
81 
82 		if (0 == strcmp(event_tag->tag, tag->tag) && 0 == strcmp(event_tag->value, tag->value))
83 			return FAIL;
84 	}
85 
86 	return SUCCEED;
87 }
88 
89 /******************************************************************************
90  *                                                                            *
91  * Function: zbx_add_event                                                    *
92  *                                                                            *
93  * Purpose: add event to an array                                             *
94  *                                                                            *
95  * Parameters: source   - [IN] event source (EVENT_SOURCE_*)                  *
96  *             object   - [IN] event object (EVENT_OBJECT_*)                  *
97  *             objectid - [IN] trigger, item ... identificator from database, *
98  *                             depends on source and object                   *
99  *             timespec - [IN] event time                                     *
100  *             value    - [IN] event value (TRIGGER_VALUE_*,                  *
101  *                             TRIGGER_STATE_*, ITEM_STATE_* ... depends on   *
102  *                             source and object)                             *
103  *             trigger_description         - [IN] trigger description         *
104  *             trigger_expression          - [IN] trigger short expression    *
105  *             trigger_recovery_expression - [IN] trigger recovery expression *
106  *             trigger_priority            - [IN] trigger priority            *
107  *             trigger_type                - [IN] TRIGGER_TYPE_* defines      *
108  *             trigger_tags                - [IN] trigger tags                *
109  *             trigger_correlation_mode    - [IN] trigger correlation mode    *
110  *             trigger_correlation_tag     - [IN] trigger correlation tag     *
111  *             trigger_value               - [IN] trigger value               *
112  *             error                       - [IN] error for internal events   *
113  *                                                                            *
114  * Return value: The added event.                                             *
115  *                                                                            *
116  ******************************************************************************/
zbx_add_event(unsigned char source,unsigned char object,zbx_uint64_t objectid,const zbx_timespec_t * timespec,int value,const char * trigger_description,const char * trigger_expression,const char * trigger_recovery_expression,unsigned char trigger_priority,unsigned char trigger_type,const zbx_vector_ptr_t * trigger_tags,unsigned char trigger_correlation_mode,const char * trigger_correlation_tag,unsigned char trigger_value,const char * error)117 DB_EVENT	*zbx_add_event(unsigned char source, unsigned char object, zbx_uint64_t objectid,
118 		const zbx_timespec_t *timespec, int value, const char *trigger_description,
119 		const char *trigger_expression, const char *trigger_recovery_expression, unsigned char trigger_priority,
120 		unsigned char trigger_type, const zbx_vector_ptr_t *trigger_tags,
121 		unsigned char trigger_correlation_mode, const char *trigger_correlation_tag,
122 		unsigned char trigger_value, const char *error)
123 {
124 	int		i;
125 	DB_EVENT	*event;
126 
127 	event = zbx_malloc(NULL, sizeof(DB_EVENT));
128 
129 	event->eventid = 0;
130 	event->source = source;
131 	event->object = object;
132 	event->objectid = objectid;
133 	event->name = NULL;
134 	event->clock = timespec->sec;
135 	event->ns = timespec->ns;
136 	event->value = value;
137 	event->acknowledged = EVENT_NOT_ACKNOWLEDGED;
138 	event->flags = ZBX_FLAGS_DB_EVENT_CREATE;
139 	event->severity = TRIGGER_SEVERITY_NOT_CLASSIFIED;
140 	event->suppressed = ZBX_PROBLEM_SUPPRESSED_FALSE;
141 
142 	if (EVENT_SOURCE_TRIGGERS == source)
143 	{
144 		if (TRIGGER_VALUE_PROBLEM == value)
145 			event->severity = trigger_priority;
146 
147 		event->trigger.triggerid = objectid;
148 		event->trigger.description = zbx_strdup(NULL, trigger_description);
149 		event->trigger.expression = zbx_strdup(NULL, trigger_expression);
150 		event->trigger.recovery_expression = zbx_strdup(NULL, trigger_recovery_expression);
151 		event->trigger.priority = trigger_priority;
152 		event->trigger.type = trigger_type;
153 		event->trigger.correlation_mode = trigger_correlation_mode;
154 		event->trigger.correlation_tag = zbx_strdup(NULL, trigger_correlation_tag);
155 		event->trigger.value = trigger_value;
156 		event->name = zbx_strdup(NULL, trigger_description);
157 
158 		substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
159 				&event->trigger.correlation_tag, MACRO_TYPE_TRIGGER_TAG, NULL, 0);
160 
161 		substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
162 				&event->name, MACRO_TYPE_TRIGGER_DESCRIPTION, NULL, 0);
163 
164 		zbx_vector_ptr_create(&event->tags);
165 
166 		if (NULL != trigger_tags)
167 		{
168 			for (i = 0; i < trigger_tags->values_num; i++)
169 			{
170 				const zbx_tag_t	*trigger_tag = (const zbx_tag_t *)trigger_tags->values[i];
171 				zbx_tag_t	*tag;
172 
173 				tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t));
174 				tag->tag = zbx_strdup(NULL, trigger_tag->tag);
175 				tag->value = zbx_strdup(NULL, trigger_tag->value);
176 
177 				substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL,
178 						NULL, &tag->tag, MACRO_TYPE_TRIGGER_TAG, NULL, 0);
179 
180 				substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL,
181 						NULL, &tag->value, MACRO_TYPE_TRIGGER_TAG, NULL, 0);
182 
183 				zbx_ltrim(tag->tag, ZBX_WHITESPACE);
184 				zbx_ltrim(tag->value, ZBX_WHITESPACE);
185 
186 				if (TAG_NAME_LEN < zbx_strlen_utf8(tag->tag))
187 					tag->tag[zbx_strlen_utf8_nchars(tag->tag, TAG_NAME_LEN)] = '\0';
188 				if (TAG_VALUE_LEN < zbx_strlen_utf8(tag->value))
189 					tag->value[zbx_strlen_utf8_nchars(tag->value, TAG_VALUE_LEN)] = '\0';
190 
191 				zbx_rtrim(tag->tag, ZBX_WHITESPACE);
192 				zbx_rtrim(tag->value, ZBX_WHITESPACE);
193 
194 				if (SUCCEED == validate_event_tag(event, tag))
195 					zbx_vector_ptr_append(&event->tags, tag);
196 				else
197 					zbx_free_tag(tag);
198 			}
199 		}
200 	}
201 	else if (EVENT_SOURCE_INTERNAL == source && NULL != error)
202 		event->name = zbx_strdup(NULL, error);
203 
204 	zbx_vector_ptr_append(&events, event);
205 
206 	return event;
207 }
208 
209 /******************************************************************************
210  *                                                                            *
211  * Function: close_trigger_event                                              *
212  *                                                                            *
213  * Purpose: add closing OK event for the specified problem event to an array  *
214  *                                                                            *
215  * Parameters: eventid  - [IN] the problem eventid                            *
216  *             objectid - [IN] trigger, item ... identificator from database, *
217  *                             depends on source and object                   *
218  *             ts       - [IN] event time                                     *
219  *             userid   - [IN] the user closing the problem                   *
220  *             correlationid - [IN] the correlation rule                      *
221  *             c_eventid - [IN] the correlation event                         *
222  *             trigger_description         - [IN] trigger description         *
223  *             trigger_expression          - [IN] trigger short expression    *
224  *             trigger_recovery_expression - [IN] trigger recovery expression *
225  *             trigger_priority            - [IN] trigger priority            *
226  *             trigger_type                - [IN] TRIGGER_TYPE_* defines      *
227  *                                                                            *
228  * Return value: Recovery event, created to close the specified event.        *
229  *                                                                            *
230  ******************************************************************************/
close_trigger_event(zbx_uint64_t eventid,zbx_uint64_t objectid,const zbx_timespec_t * ts,zbx_uint64_t userid,zbx_uint64_t correlationid,zbx_uint64_t c_eventid,const char * trigger_description,const char * trigger_expression,const char * trigger_recovery_expression,unsigned char trigger_priority,unsigned char trigger_type)231 static DB_EVENT	*close_trigger_event(zbx_uint64_t eventid, zbx_uint64_t objectid, const zbx_timespec_t *ts,
232 		zbx_uint64_t userid, zbx_uint64_t correlationid, zbx_uint64_t c_eventid,
233 		const char *trigger_description, const char *trigger_expression,
234 		const char *trigger_recovery_expression, unsigned char trigger_priority, unsigned char trigger_type)
235 {
236 	zbx_event_recovery_t	recovery_local;
237 	DB_EVENT		*r_event;
238 
239 	r_event = zbx_add_event(EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER, objectid, ts, TRIGGER_VALUE_OK,
240 			trigger_description, trigger_expression, trigger_recovery_expression, trigger_priority,
241 			trigger_type, NULL, ZBX_TRIGGER_CORRELATION_NONE, "", TRIGGER_VALUE_PROBLEM,
242 			NULL);
243 
244 	recovery_local.eventid = eventid;
245 	recovery_local.objectid = objectid;
246 	recovery_local.correlationid = correlationid;
247 	recovery_local.c_eventid = c_eventid;
248 	recovery_local.r_event = r_event;
249 	recovery_local.userid = userid;
250 
251 	zbx_hashset_insert(&event_recovery, &recovery_local, sizeof(recovery_local));
252 
253 	return r_event;
254 }
255 
256 /******************************************************************************
257  *                                                                            *
258  * Function: save_events                                                      *
259  *                                                                            *
260  * Purpose: flushes the events into a database                                *
261  *                                                                            *
262  ******************************************************************************/
save_events(void)263 static int	save_events(void)
264 {
265 	int			i;
266 	zbx_db_insert_t		db_insert, db_insert_tags;
267 	int			j, num = 0, insert_tags = 0;
268 	zbx_uint64_t		eventid;
269 	DB_EVENT		*event;
270 
271 	for (i = 0; i < events.values_num; i++)
272 	{
273 		event = (DB_EVENT *)events.values[i];
274 
275 		if (0 != (event->flags & ZBX_FLAGS_DB_EVENT_CREATE) && 0 == event->eventid)
276 			num++;
277 	}
278 
279 	zbx_db_insert_prepare(&db_insert, "events", "eventid", "source", "object", "objectid", "clock", "ns", "value",
280 			"name", "severity", NULL);
281 
282 	eventid = DBget_maxid_num("events", num);
283 
284 	num = 0;
285 
286 	for (i = 0; i < events.values_num; i++)
287 	{
288 		event = (DB_EVENT *)events.values[i];
289 
290 		if (0 == (event->flags & ZBX_FLAGS_DB_EVENT_CREATE))
291 			continue;
292 
293 		if (0 == event->eventid)
294 			event->eventid = eventid++;
295 
296 		zbx_db_insert_add_values(&db_insert, event->eventid, event->source, event->object,
297 				event->objectid, event->clock, event->ns, event->value,
298 				ZBX_NULL2EMPTY_STR(event->name), event->severity);
299 
300 		num++;
301 
302 		if (EVENT_SOURCE_TRIGGERS != event->source)
303 			continue;
304 
305 		if (0 == event->tags.values_num)
306 			continue;
307 
308 		if (0 == insert_tags)
309 		{
310 			zbx_db_insert_prepare(&db_insert_tags, "event_tag", "eventtagid", "eventid", "tag", "value",
311 					NULL);
312 			insert_tags = 1;
313 		}
314 
315 		for (j = 0; j < event->tags.values_num; j++)
316 		{
317 			zbx_tag_t	*tag = (zbx_tag_t *)event->tags.values[j];
318 
319 			zbx_db_insert_add_values(&db_insert_tags, __UINT64_C(0), event->eventid, tag->tag, tag->value);
320 		}
321 	}
322 
323 	zbx_db_insert_execute(&db_insert);
324 	zbx_db_insert_clean(&db_insert);
325 
326 	if (0 != insert_tags)
327 	{
328 		zbx_db_insert_autoincrement(&db_insert_tags, "eventtagid");
329 		zbx_db_insert_execute(&db_insert_tags);
330 		zbx_db_insert_clean(&db_insert_tags);
331 	}
332 
333 	return num;
334 }
335 
336 /******************************************************************************
337  *                                                                            *
338  * Function: save_problems                                                    *
339  *                                                                            *
340  * Purpose: generates problems from problem events (trigger and internal      *
341  *          event sources)                                                    *
342  *                                                                            *
343  ******************************************************************************/
save_problems(void)344 static void	save_problems(void)
345 {
346 	int			i;
347 	zbx_vector_ptr_t	problems;
348 	int			j, tags_num = 0;
349 
350 	zbx_vector_ptr_create(&problems);
351 
352 	for (i = 0; i < events.values_num; i++)
353 	{
354 		DB_EVENT	*event = events.values[i];
355 
356 		if (0 == (event->flags & ZBX_FLAGS_DB_EVENT_CREATE))
357 			continue;
358 
359 		if (EVENT_SOURCE_TRIGGERS == event->source)
360 		{
361 			if (EVENT_OBJECT_TRIGGER != event->object || TRIGGER_VALUE_PROBLEM != event->value)
362 				continue;
363 
364 			tags_num += event->tags.values_num;
365 		}
366 		else if (EVENT_SOURCE_INTERNAL == event->source)
367 		{
368 			switch (event->object)
369 			{
370 				case EVENT_OBJECT_TRIGGER:
371 					if (TRIGGER_STATE_UNKNOWN != event->value)
372 						continue;
373 					break;
374 				case EVENT_OBJECT_ITEM:
375 					if (ITEM_STATE_NOTSUPPORTED != event->value)
376 						continue;
377 					break;
378 				case EVENT_OBJECT_LLDRULE:
379 					if (ITEM_STATE_NOTSUPPORTED != event->value)
380 						continue;
381 					break;
382 				default:
383 					continue;
384 			}
385 		}
386 		else
387 			continue;
388 
389 		zbx_vector_ptr_append(&problems, event);
390 	}
391 
392 	if (0 != problems.values_num)
393 	{
394 		zbx_db_insert_t	db_insert;
395 
396 		zbx_db_insert_prepare(&db_insert, "problem", "eventid", "source", "object", "objectid", "clock", "ns",
397 				"name", "severity", NULL);
398 
399 		for (j = 0; j < problems.values_num; j++)
400 		{
401 			const DB_EVENT	*event = (const DB_EVENT *)problems.values[j];
402 
403 			zbx_db_insert_add_values(&db_insert, event->eventid, event->source, event->object,
404 					event->objectid, event->clock, event->ns, ZBX_NULL2EMPTY_STR(event->name),
405 					event->severity);
406 		}
407 
408 		zbx_db_insert_execute(&db_insert);
409 		zbx_db_insert_clean(&db_insert);
410 
411 		if (0 != tags_num)
412 		{
413 			int	k;
414 
415 			zbx_db_insert_prepare(&db_insert, "problem_tag", "problemtagid", "eventid", "tag", "value",
416 					NULL);
417 
418 			for (j = 0; j < problems.values_num; j++)
419 			{
420 				const DB_EVENT	*event = (const DB_EVENT *)problems.values[j];
421 
422 				if (EVENT_SOURCE_TRIGGERS != event->source)
423 					continue;
424 
425 				for (k = 0; k < event->tags.values_num; k++)
426 				{
427 					zbx_tag_t	*tag = (zbx_tag_t *)event->tags.values[k];
428 
429 					zbx_db_insert_add_values(&db_insert, __UINT64_C(0), event->eventid, tag->tag,
430 							tag->value);
431 				}
432 			}
433 
434 			zbx_db_insert_autoincrement(&db_insert, "problemtagid");
435 			zbx_db_insert_execute(&db_insert);
436 			zbx_db_insert_clean(&db_insert);
437 		}
438 	}
439 
440 	zbx_vector_ptr_destroy(&problems);
441 }
442 
443 /******************************************************************************
444  *                                                                            *
445  * Function: save_event_recovery                                              *
446  *                                                                            *
447  * Purpose: saves event recovery data and removes recovered events from       *
448  *          problem table                                                     *
449  *                                                                            *
450  ******************************************************************************/
save_event_recovery(void)451 static void	save_event_recovery(void)
452 {
453 	zbx_db_insert_t		db_insert;
454 	zbx_event_recovery_t	*recovery;
455 	char			*sql = NULL;
456 	size_t			sql_alloc = 0, sql_offset = 0;
457 	zbx_hashset_iter_t	iter;
458 
459 	if (0 == event_recovery.num_data)
460 		return;
461 
462 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
463 
464 	zbx_db_insert_prepare(&db_insert, "event_recovery", "eventid", "r_eventid", "correlationid", "c_eventid",
465 			"userid", NULL);
466 
467 	zbx_hashset_iter_reset(&event_recovery, &iter);
468 	while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
469 	{
470 		zbx_db_insert_add_values(&db_insert, recovery->eventid, recovery->r_event->eventid,
471 				recovery->correlationid, recovery->c_eventid, recovery->userid);
472 
473 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
474 			"update problem set"
475 			" r_eventid=" ZBX_FS_UI64
476 			",r_clock=%d"
477 			",r_ns=%d"
478 			",userid=" ZBX_FS_UI64,
479 			recovery->r_event->eventid,
480 			recovery->r_event->clock,
481 			recovery->r_event->ns,
482 			recovery->userid);
483 
484 		if (0 != recovery->correlationid)
485 		{
486 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ",correlationid=" ZBX_FS_UI64,
487 					recovery->correlationid);
488 		}
489 
490 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where eventid=" ZBX_FS_UI64 ";\n",
491 				recovery->eventid);
492 
493 		DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
494 	}
495 
496 	zbx_db_insert_execute(&db_insert);
497 	zbx_db_insert_clean(&db_insert);
498 
499 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
500 
501 	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
502 		DBexecute("%s", sql);
503 
504 	zbx_free(sql);
505 }
506 
507 /******************************************************************************
508  *                                                                            *
509  * Function: get_event_index_by_source_object_id                              *
510  *                                                                            *
511  * Purpose: find event index by its source object                             *
512  *                                                                            *
513  * Parameters: source   - [IN] the event source                               *
514  *             object   - [IN] the object type                                *
515  *             objectid - [IN] the object id                                  *
516  *                                                                            *
517  * Return value: the event or NULL                                            *
518  *                                                                            *
519  ******************************************************************************/
get_event_by_source_object_id(int source,int object,zbx_uint64_t objectid)520 static DB_EVENT	*get_event_by_source_object_id(int source, int object, zbx_uint64_t objectid)
521 {
522 	int		i;
523 	DB_EVENT	*event;
524 
525 	for (i = 0; i < events.values_num; i++)
526 	{
527 		event = (DB_EVENT *)events.values[i];
528 
529 		if (event->source == source && event->object == object && event->objectid == objectid)
530 			return event;
531 	}
532 
533 	return NULL;
534 }
535 
536 /******************************************************************************
537  *                                                                            *
538  * Function: correlation_match_event_hostgroup                                *
539  *                                                                            *
540  * Purpose: checks if the event matches the specified host group              *
541  *          (including nested groups)                                         *
542  *                                                                            *
543  * Parameters: event   - [IN] the new event to check                          *
544  *             groupid - [IN] the group id to match                           *
545  *                                                                            *
546  * Return value: SUCCEED - the group matches                                  *
547  *               FAIL    - otherwise                                          *
548  *                                                                            *
549  ******************************************************************************/
correlation_match_event_hostgroup(const DB_EVENT * event,zbx_uint64_t groupid)550 static int	correlation_match_event_hostgroup(const DB_EVENT *event, zbx_uint64_t groupid)
551 {
552 	DB_RESULT		result;
553 	int			ret = FAIL;
554 	zbx_vector_uint64_t	groupids;
555 	char			*sql = NULL;
556 	size_t			sql_alloc = 0, sql_offset = 0;
557 
558 	zbx_vector_uint64_create(&groupids);
559 	zbx_dc_get_nested_hostgroupids(&groupid, 1, &groupids);
560 
561 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
562 			"select hg.groupid"
563 				" from hstgrp g,hosts_groups hg,items i,functions f"
564 				" where f.triggerid=" ZBX_FS_UI64
565 				" and i.itemid=f.itemid"
566 				" and hg.hostid=i.hostid"
567 				" and",
568 				event->objectid);
569 
570 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.groupid", groupids.values,
571 			groupids.values_num);
572 
573 	result = DBselect("%s", sql);
574 
575 	if (NULL != DBfetch(result))
576 		ret = SUCCEED;
577 
578 	DBfree_result(result);
579 	zbx_free(sql);
580 	zbx_vector_uint64_destroy(&groupids);
581 
582 	return ret;
583 }
584 
585 /******************************************************************************
586  *                                                                            *
587  * Function: correlation_condition_match_new_event                            *
588  *                                                                            *
589  * Purpose: checks if the correlation condition matches the new event         *
590  *                                                                            *
591  * Parameters: condition - [IN] the correlation condition to check            *
592  *             event     - [IN] the new event to match                        *
593  *             old_value - [IN] SUCCEED - the old event conditions may        *
594  *                                        match event                         *
595  *                              FAIL    - the old event conditions never      *
596  *                                        match event                         *
597  *                                                                            *
598  * Return value: "1"            - the correlation rule match event            *
599  *               "0"            - the correlation rule doesn't match event    *
600  *               "ZBX_UNKNOWN0" - the correlation rule might match            *
601  *                                depending on old events                     *
602  *                                                                            *
603  ******************************************************************************/
correlation_condition_match_new_event(zbx_corr_condition_t * condition,const DB_EVENT * event,int old_value)604 static const char	*correlation_condition_match_new_event(zbx_corr_condition_t *condition, const DB_EVENT *event,
605 		int old_value)
606 {
607 	int		i, ret;
608 	zbx_tag_t	*tag;
609 
610 	/* return SUCCEED for conditions using old events */
611 	switch (condition->type)
612 	{
613 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
614 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
615 			return (SUCCEED == old_value) ? ZBX_UNKNOWN_STR "0" : "0";
616 	}
617 
618 	switch (condition->type)
619 	{
620 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
621 			for (i = 0; i < event->tags.values_num; i++)
622 			{
623 				tag = (zbx_tag_t *)event->tags.values[i];
624 
625 				if (0 == strcmp(tag->tag, condition->data.tag.tag))
626 					return "1";
627 			}
628 			break;
629 
630 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
631 			for (i = 0; i < event->tags.values_num; i++)
632 			{
633 				zbx_corr_condition_tag_value_t	*cond = &condition->data.tag_value;
634 
635 				tag = (zbx_tag_t *)event->tags.values[i];
636 
637 				if (0 == strcmp(tag->tag, cond->tag) &&
638 					SUCCEED == zbx_strmatch_condition(tag->value, cond->value, cond->op))
639 				{
640 					return "1";
641 				}
642 			}
643 			break;
644 
645 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
646 			ret =  correlation_match_event_hostgroup(event, condition->data.group.groupid);
647 
648 			if (CONDITION_OPERATOR_NOT_EQUAL == condition->data.group.op)
649 				return (SUCCEED == ret ? "0" : "1");
650 
651 			return (SUCCEED == ret ? "1" : "0");
652 
653 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
654 			for (i = 0; i < event->tags.values_num; i++)
655 			{
656 				tag = (zbx_tag_t *)event->tags.values[i];
657 
658 				if (0 == strcmp(tag->tag, condition->data.tag_pair.newtag))
659 					return (SUCCEED == old_value) ? ZBX_UNKNOWN_STR "0" : "0";
660 			}
661 			break;
662 	}
663 
664 	return "0";
665 }
666 
667 /******************************************************************************
668  *                                                                            *
669  * Function: correlation_match_new_event                                      *
670  *                                                                            *
671  * Purpose: checks if the correlation rule might match the new event          *
672  *                                                                            *
673  * Parameters: correlation - [IN] the correlation rule to check               *
674  *             event       - [IN] the new event to match                      *
675  *             old_value   - [IN] SUCCEED - the old event conditions may      *
676  *                                          match event                       *
677  *                                FAIL    - the old event conditions never    *
678  *                                          match event                       *
679  *                                                                            *
680  * Return value: CORRELATION_MATCH     - the correlation rule match           *
681  *               CORRELATION_MAY_MATCH - the correlation rule might match     *
682  *                                       depending on old events              *
683  *               CORRELATION_NO_MATCH  - the correlation rule doesn't match   *
684  *                                                                            *
685  ******************************************************************************/
correlation_match_new_event(zbx_correlation_t * correlation,const DB_EVENT * event,int old_value)686 static zbx_correlation_match_result_t	correlation_match_new_event(zbx_correlation_t *correlation,
687 		const DB_EVENT *event, int old_value)
688 {
689 	char				*expression, error[256];
690 	const char			*value;
691 	zbx_token_t			token;
692 	int				pos = 0;
693 	zbx_uint64_t			conditionid;
694 	zbx_strloc_t			*loc;
695 	zbx_corr_condition_t		*condition;
696 	double				result;
697 	zbx_correlation_match_result_t	ret = CORRELATION_NO_MATCH;
698 
699 	if ('\0' == *correlation->formula)
700 		return CORRELATION_MAY_MATCH;
701 
702 	expression = zbx_strdup(NULL, correlation->formula);
703 
704 	for (; SUCCEED == zbx_token_find(expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
705 	{
706 		if (ZBX_TOKEN_OBJECTID != token.type)
707 			continue;
708 
709 		loc = &token.data.objectid.name;
710 
711 		if (SUCCEED != is_uint64_n(expression + loc->l, loc->r - loc->l + 1, &conditionid))
712 			continue;
713 
714 		if (NULL == (condition = (zbx_corr_condition_t *)zbx_hashset_search(&correlation_rules.conditions,
715 				&conditionid)))
716 			goto out;
717 
718 		value = correlation_condition_match_new_event(condition, event, old_value);
719 
720 		zbx_replace_string(&expression, token.loc.l, &token.loc.r, value);
721 		pos = token.loc.r;
722 	}
723 
724 	if (SUCCEED == evaluate_unknown(expression, &result, error, sizeof(error)))
725 	{
726 		if (result == ZBX_UNKNOWN)
727 			ret = CORRELATION_MAY_MATCH;
728 		else if (SUCCEED == zbx_double_compare(result, 1))
729 			ret = CORRELATION_MATCH;
730 	}
731 
732 out:
733 	zbx_free(expression);
734 
735 	return ret;
736 }
737 
738 /******************************************************************************
739  *                                                                            *
740  * Function: correlation_has_old_event_operation                              *
741  *                                                                            *
742  * Purpose: checks if correlation has operations to change old events         *
743  *                                                                            *
744  * Parameters: correlation - [IN] the correlation to check                    *
745  *                                                                            *
746  * Return value: SUCCEED - correlation has operations to change old events    *
747  *               FAIL    - otherwise                                          *
748  *                                                                            *
749  ******************************************************************************/
correlation_has_old_event_operation(const zbx_correlation_t * correlation)750 static int	correlation_has_old_event_operation(const zbx_correlation_t *correlation)
751 {
752 	int				i;
753 	const zbx_corr_operation_t	*operation;
754 
755 	for (i = 0; i < correlation->operations.values_num; i++)
756 	{
757 		operation = (zbx_corr_operation_t *)correlation->operations.values[i];
758 
759 		switch (operation->type)
760 		{
761 			case ZBX_CORR_OPERATION_CLOSE_OLD:
762 				return SUCCEED;
763 		}
764 	}
765 
766 	return FAIL;
767 }
768 
769 /******************************************************************************
770  *                                                                            *
771  * Function: correlation_condition_add_tag_match                              *
772  *                                                                            *
773  * Purpose: adds sql statement to match tag according to the defined          *
774  *          matching operation                                                *
775  *                                                                            *
776  * Parameters: sql         - [IN/OUT]                                         *
777  *             sql_alloc   - [IN/OUT]                                         *
778  *             sql_offset  - [IN/OUT]                                         *
779  *             tag         - [IN] the tag to match                            *
780  *             value       - [IN] the tag value to match                      *
781  *             op          - [IN] the matching operation (CONDITION_OPERATOR_)*
782  *                                                                            *
783  ******************************************************************************/
correlation_condition_add_tag_match(char ** sql,size_t * sql_alloc,size_t * sql_offset,const char * tag,const char * value,unsigned char op)784 static void	correlation_condition_add_tag_match(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *tag,
785 		const char *value, unsigned char op)
786 {
787 	char	*tag_esc, *value_esc;
788 
789 	tag_esc = DBdyn_escape_string(tag);
790 	value_esc = DBdyn_escape_string(value);
791 
792 	switch (op)
793 	{
794 		case CONDITION_OPERATOR_NOT_EQUAL:
795 		case CONDITION_OPERATOR_NOT_LIKE:
796 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "not ");
797 			break;
798 	}
799 
800 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset,
801 			"exists (select null from problem_tag pt where p.eventid=pt.eventid and ");
802 
803 	switch (op)
804 	{
805 		case CONDITION_OPERATOR_EQUAL:
806 		case CONDITION_OPERATOR_NOT_EQUAL:
807 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "pt.tag='%s' and pt.value" ZBX_SQL_STRCMP,
808 					tag_esc, ZBX_SQL_STRVAL_EQ(value_esc));
809 			break;
810 		case CONDITION_OPERATOR_LIKE:
811 		case CONDITION_OPERATOR_NOT_LIKE:
812 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "pt.tag='%s' and pt.value like '%%%s%%'",
813 					tag_esc, value_esc);
814 			break;
815 	}
816 
817 	zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
818 
819 	zbx_free(value_esc);
820 	zbx_free(tag_esc);
821 }
822 
823 
824 /******************************************************************************
825  *                                                                            *
826  * Function: correlation_condition_get_event_filter                           *
827  *                                                                            *
828  * Purpose: creates sql filter to find events matching a correlation          *
829  *          condition                                                         *
830  *                                                                            *
831  * Parameters: condition - [IN] the correlation condition to match            *
832  *             event     - [IN] the new event to match                        *
833  *                                                                            *
834  * Return value: the created filter or NULL                                   *
835  *                                                                            *
836  ******************************************************************************/
correlation_condition_get_event_filter(zbx_corr_condition_t * condition,const DB_EVENT * event)837 static char	*correlation_condition_get_event_filter(zbx_corr_condition_t *condition, const DB_EVENT *event)
838 {
839 	int			i;
840 	zbx_tag_t		*tag;
841 	char			*tag_esc, *filter = NULL;
842 	size_t			filter_alloc = 0, filter_offset = 0;
843 	zbx_vector_str_t	values;
844 
845 	/* replace new event dependent condition with precalculated value */
846 	switch (condition->type)
847 	{
848 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
849 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
850 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
851 			return zbx_dsprintf(NULL, "%s=1",
852 					correlation_condition_match_new_event(condition, event, SUCCEED));
853 	}
854 
855 	/* replace old event dependent condition with sql filter on problem_tag pt table */
856 	switch (condition->type)
857 	{
858 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
859 			tag_esc = DBdyn_escape_string(condition->data.tag.tag);
860 			zbx_snprintf_alloc(&filter, &filter_alloc, &filter_offset,
861 					"exists (select null from problem_tag pt"
862 						" where p.eventid=pt.eventid"
863 							" and pt.tag='%s')",
864 					tag_esc);
865 			zbx_free(tag_esc);
866 			return filter;
867 
868 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
869 			zbx_vector_str_create(&values);
870 
871 			for (i = 0; i < event->tags.values_num; i++)
872 			{
873 				tag = (zbx_tag_t *)event->tags.values[i];
874 				if (0 == strcmp(tag->tag, condition->data.tag_pair.newtag))
875 					zbx_vector_str_append(&values, zbx_strdup(NULL, tag->value));
876 			}
877 
878 			if (0 == values.values_num)
879 			{
880 				/* no new tag found, substitute condition with failure expression */
881 				filter = zbx_strdup(NULL, "0");
882 			}
883 			else
884 			{
885 				tag_esc = DBdyn_escape_string(condition->data.tag_pair.oldtag);
886 
887 				zbx_snprintf_alloc(&filter, &filter_alloc, &filter_offset,
888 						"exists (select null from problem_tag pt"
889 							" where p.eventid=pt.eventid"
890 								" and pt.tag='%s'"
891 								" and",
892 						tag_esc);
893 
894 				DBadd_str_condition_alloc(&filter, &filter_alloc, &filter_offset, "pt.value",
895 						(const char **)values.values, values.values_num);
896 
897 				zbx_chrcpy_alloc(&filter, &filter_alloc, &filter_offset, ')');
898 
899 				zbx_free(tag_esc);
900 				zbx_vector_str_clear_ext(&values, zbx_str_free);
901 			}
902 
903 			zbx_vector_str_destroy(&values);
904 			return filter;
905 
906 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
907 			correlation_condition_add_tag_match(&filter, &filter_alloc, &filter_offset,
908 					condition->data.tag_value.tag, condition->data.tag_value.value,
909 					condition->data.tag_value.op);
910 			return filter;
911 	}
912 
913 	return NULL;
914 }
915 
916 /******************************************************************************
917  *                                                                            *
918  * Function: correlation_add_event_filter                                     *
919  *                                                                            *
920  * Purpose: add sql statement to filter out correlation conditions and        *
921  *          matching events                                                   *
922  *                                                                            *
923  * Parameters: sql         - [IN/OUT]                                         *
924  *             sql_alloc   - [IN/OUT]                                         *
925  *             sql_offset  - [IN/OUT]                                         *
926  *             correlation - [IN] the correlation rule to match               *
927  *             event       - [IN] the new event to match                      *
928  *                                                                            *
929  * Return value: SUCCEED - the filter was added successfully                  *
930  *               FAIL    - otherwise                                          *
931  *                                                                            *
932  ******************************************************************************/
correlation_add_event_filter(char ** sql,size_t * sql_alloc,size_t * sql_offset,zbx_correlation_t * correlation,const DB_EVENT * event)933 static int	correlation_add_event_filter(char **sql, size_t *sql_alloc, size_t *sql_offset,
934 		zbx_correlation_t *correlation, const DB_EVENT *event)
935 {
936 	char			*expression, *filter;
937 	zbx_token_t		token;
938 	int			pos = 0, ret = FAIL;
939 	zbx_uint64_t		conditionid;
940 	zbx_strloc_t		*loc;
941 	zbx_corr_condition_t	*condition;
942 
943 	zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "c.correlationid=" ZBX_FS_UI64, correlation->correlationid);
944 
945 	expression = zbx_strdup(NULL, correlation->formula);
946 
947 	for (; SUCCEED == zbx_token_find(expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
948 	{
949 		if (ZBX_TOKEN_OBJECTID != token.type)
950 			continue;
951 
952 		loc = &token.data.objectid.name;
953 
954 		if (SUCCEED != is_uint64_n(expression + loc->l, loc->r - loc->l + 1, &conditionid))
955 			continue;
956 
957 		if (NULL == (condition = (zbx_corr_condition_t *)zbx_hashset_search(&correlation_rules.conditions, &conditionid)))
958 			goto out;
959 
960 		if (NULL == (filter = correlation_condition_get_event_filter(condition, event)))
961 		{
962 			THIS_SHOULD_NEVER_HAPPEN;
963 			goto out;
964 		}
965 
966 		zbx_replace_string(&expression, token.loc.l, &token.loc.r, filter);
967 		pos = token.loc.r;
968 		zbx_free(filter);
969 	}
970 
971 	if ('\0' != *expression)
972 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " and (%s)", expression);
973 
974 	ret = SUCCEED;
975 out:
976 	zbx_free(expression);
977 
978 	return ret;
979 }
980 
981 /******************************************************************************
982  *                                                                            *
983  * Function: correlation_execute_operations                                   *
984  *                                                                            *
985  * Purpose: execute correlation operations for the new event and matched      *
986  *          old eventid                                                       *
987  *                                                                            *
988  * Parameters: correlation  - [IN] the correlation to execute                 *
989  *             event        - [IN] the new event                              *
990  *             old_eventid  - [IN] the old eventid                            *
991  *             old_objectid - [IN] the old event source objectid (triggerid)  *
992  *                                                                            *
993  ******************************************************************************/
correlation_execute_operations(zbx_correlation_t * correlation,DB_EVENT * event,zbx_uint64_t old_eventid,zbx_uint64_t old_objectid)994 static void	correlation_execute_operations(zbx_correlation_t *correlation, DB_EVENT *event,
995 		zbx_uint64_t old_eventid, zbx_uint64_t old_objectid)
996 {
997 	int			i;
998 	zbx_corr_operation_t	*operation;
999 	zbx_event_recovery_t	recovery_local;
1000 	zbx_timespec_t		ts;
1001 	DB_EVENT		*r_event;
1002 
1003 	for (i = 0; i < correlation->operations.values_num; i++)
1004 	{
1005 		operation = (zbx_corr_operation_t *)correlation->operations.values[i];
1006 
1007 		switch (operation->type)
1008 		{
1009 			case ZBX_CORR_OPERATION_CLOSE_NEW:
1010 				/* generate OK event to close the new event */
1011 
1012 				/* check if this event was not been closed by another correlation rule */
1013 				if (NULL != zbx_hashset_search(&event_recovery, &event->eventid))
1014 					break;
1015 
1016 				ts.sec = event->clock;
1017 				ts.ns = event->ns;
1018 
1019 				r_event = close_trigger_event(event->eventid, event->objectid, &ts, 0,
1020 						correlation->correlationid, event->eventid, event->trigger.description,
1021 						event->trigger.expression, event->trigger.recovery_expression,
1022 						event->trigger.priority, event->trigger.type);
1023 
1024 				event->flags |= ZBX_FLAGS_DB_EVENT_NO_ACTION;
1025 				r_event->flags |= ZBX_FLAGS_DB_EVENT_NO_ACTION;
1026 
1027 				break;
1028 			case ZBX_CORR_OPERATION_CLOSE_OLD:
1029 				/* queue closing of old events to lock them by triggerids */
1030 				if (0 != old_eventid)
1031 				{
1032 					recovery_local.eventid = old_eventid;
1033 					recovery_local.c_eventid = event->eventid;
1034 					recovery_local.correlationid = correlation->correlationid;
1035 					recovery_local.objectid = old_objectid;
1036 					recovery_local.ts.sec = event->clock;
1037 					recovery_local.ts.ns = event->ns;
1038 
1039 					zbx_hashset_insert(&correlation_cache, &recovery_local, sizeof(recovery_local));
1040 				}
1041 				break;
1042 		}
1043 	}
1044 }
1045 
1046 /* specifies correlation execution scope */
1047 typedef enum
1048 {
1049 	ZBX_CHECK_NEW_EVENTS,
1050 	ZBX_CHECK_OLD_EVENTS
1051 }
1052 zbx_correlation_scope_t;
1053 
1054 /* flag to cache state of problem table during event correlation */
1055 typedef enum
1056 {
1057 	/* unknown state, not initialized */
1058 	ZBX_PROBLEM_STATE_UNKNOWN = -1,
1059 	/* all problems are resolved */
1060 	ZBX_PROBLEM_STATE_RESOLVED,
1061 	/* at least one open problem exists */
1062 	ZBX_PROBLEM_STATE_OPEN
1063 }
1064 zbx_problem_state_t;
1065 
1066 /******************************************************************************
1067  *                                                                            *
1068  * Function: correlate_event_by_global_rules                                  *
1069  *                                                                            *
1070  * Purpose: find problem events that must be recovered by global correlation  *
1071  *          rules and check if the new event must be closed                   *
1072  *                                                                            *
1073  * Parameters: event         - [IN] the new event                             *
1074  *             problem_state - [IN/OUT] problem state cache variable          *
1075  *                                                                            *
1076  * Comments: The correlation data (zbx_event_recovery_t) of events that       *
1077  *           must be closed are added to event_correlation hashset            *
1078  *                                                                            *
1079  *           The global event correlation matching is done in two parts:      *
1080  *             1) exclude correlations that can't possibly match the event    *
1081  *                based on new event tag/value/group conditions               *
1082  *             2) assemble sql statement to select problems/correlations      *
1083  *                based on the rest correlation conditions                    *
1084  *                                                                            *
1085  ******************************************************************************/
correlate_event_by_global_rules(DB_EVENT * event,zbx_problem_state_t * problem_state)1086 static void	correlate_event_by_global_rules(DB_EVENT *event, zbx_problem_state_t *problem_state)
1087 {
1088 	int			i;
1089 	zbx_correlation_t	*correlation;
1090 	zbx_vector_ptr_t	corr_old, corr_new;
1091 	char			*sql = NULL;
1092 	const char		*delim = "";
1093 	size_t			sql_alloc = 0, sql_offset = 0;
1094 	zbx_uint64_t		eventid, correlationid, objectid;
1095 
1096 	zbx_vector_ptr_create(&corr_old);
1097 	zbx_vector_ptr_create(&corr_new);
1098 
1099 	for (i = 0; i < correlation_rules.correlations.values_num; i++)
1100 	{
1101 		zbx_correlation_scope_t	scope;
1102 
1103 		correlation = (zbx_correlation_t *)correlation_rules.correlations.values[i];
1104 
1105 		switch (correlation_match_new_event(correlation, event, SUCCEED))
1106 		{
1107 			case CORRELATION_MATCH:
1108 				if (SUCCEED == correlation_has_old_event_operation(correlation))
1109 					scope = ZBX_CHECK_OLD_EVENTS;
1110 				else
1111 					scope = ZBX_CHECK_NEW_EVENTS;
1112 				break;
1113 			case CORRELATION_NO_MATCH:	/* proceed with next rule */
1114 				continue;
1115 			case CORRELATION_MAY_MATCH:	/* might match depending on old events */
1116 				scope = ZBX_CHECK_OLD_EVENTS;
1117 				break;
1118 		}
1119 
1120 		if (ZBX_CHECK_OLD_EVENTS == scope)
1121 		{
1122 			if (ZBX_PROBLEM_STATE_UNKNOWN == *problem_state)
1123 			{
1124 				DB_RESULT	result;
1125 
1126 				result = DBselectN("select eventid from problem"
1127 						" where r_eventid is null and source="
1128 						ZBX_STR(EVENT_SOURCE_TRIGGERS), 1);
1129 
1130 				if (NULL == DBfetch(result))
1131 					*problem_state = ZBX_PROBLEM_STATE_RESOLVED;
1132 				else
1133 					*problem_state = ZBX_PROBLEM_STATE_OPEN;
1134 				DBfree_result(result);
1135 			}
1136 
1137 			if (ZBX_PROBLEM_STATE_RESOLVED == *problem_state)
1138 			{
1139 				/* with no open problems all conditions involving old events will fail       */
1140 				/* so there are no need to check old events. Instead re-check if correlation */
1141 				/* still matches the new event and must be processed in new event scope.     */
1142 				if (CORRELATION_MATCH == correlation_match_new_event(correlation, event, FAIL))
1143 					zbx_vector_ptr_append(&corr_new, correlation);
1144 			}
1145 			else
1146 				zbx_vector_ptr_append(&corr_old, correlation);
1147 		}
1148 		else
1149 			zbx_vector_ptr_append(&corr_new, correlation);
1150 	}
1151 
1152 	if (0 != corr_new.values_num)
1153 	{
1154 		/* Process correlations that matches new event and does not use or affect old events. */
1155 		/* Those correlations can be executed directly, without checking database.            */
1156 		for (i = 0; i < corr_new.values_num; i++)
1157 			correlation_execute_operations((zbx_correlation_t *)corr_new.values[i], event, 0, 0);
1158 	}
1159 
1160 	if (0 != corr_old.values_num)
1161 	{
1162 		DB_RESULT	result;
1163 		DB_ROW		row;
1164 
1165 		/* Process correlations that matches new event and either uses old events in conditions */
1166 		/* or has operations involving old events.                                              */
1167 
1168 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select p.eventid,p.objectid,c.correlationid"
1169 								" from correlation c,problem p"
1170 								" where p.r_eventid is null"
1171 								" and p.source=" ZBX_STR(EVENT_SOURCE_TRIGGERS)
1172 								" and (");
1173 
1174 		for (i = 0; i < corr_old.values_num; i++)
1175 		{
1176 			correlation = (zbx_correlation_t *)corr_old.values[i];
1177 
1178 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, delim);
1179 			correlation_add_event_filter(&sql, &sql_alloc, &sql_offset, correlation, event);
1180 			delim = " or ";
1181 		}
1182 
1183 		zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
1184 		result = DBselect("%s", sql);
1185 
1186 		while (NULL != (row = DBfetch(result)))
1187 		{
1188 			ZBX_STR2UINT64(eventid, row[0]);
1189 
1190 			/* check if this event is not already recovered by another correlation rule */
1191 			if (NULL != zbx_hashset_search(&correlation_cache, &eventid))
1192 				continue;
1193 
1194 			ZBX_STR2UINT64(correlationid, row[2]);
1195 
1196 			if (FAIL == (i = zbx_vector_ptr_bsearch(&corr_old, &correlationid,
1197 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1198 			{
1199 				THIS_SHOULD_NEVER_HAPPEN;
1200 				continue;
1201 			}
1202 
1203 			ZBX_STR2UINT64(objectid, row[1]);
1204 			correlation_execute_operations((zbx_correlation_t *)corr_old.values[i], event, eventid, objectid);
1205 		}
1206 
1207 		DBfree_result(result);
1208 		zbx_free(sql);
1209 	}
1210 
1211 	zbx_vector_ptr_destroy(&corr_new);
1212 	zbx_vector_ptr_destroy(&corr_old);
1213 }
1214 
1215 /******************************************************************************
1216  *                                                                            *
1217  * Function: correlate_events_by_global_rules                                 *
1218  *                                                                            *
1219  * Purpose: add events to the closing queue according to global correlation   *
1220  *          rules                                                             *
1221  *                                                                            *
1222  ******************************************************************************/
correlate_events_by_global_rules(zbx_vector_ptr_t * trigger_events,zbx_vector_ptr_t * trigger_diff)1223 static void	correlate_events_by_global_rules(zbx_vector_ptr_t *trigger_events, zbx_vector_ptr_t *trigger_diff)
1224 {
1225 	const char		*__function_name = "correlate_events_by_global_rules";
1226 
1227 	int			i, index;
1228 	zbx_trigger_diff_t	*diff;
1229 	zbx_problem_state_t	problem_state = ZBX_PROBLEM_STATE_UNKNOWN;
1230 
1231 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() events:%d", __function_name, correlation_cache.num_data);
1232 
1233 	zbx_dc_correlation_rules_get(&correlation_rules);
1234 
1235 	if (0 == correlation_rules.correlations.values_num)
1236 		goto out;
1237 
1238 	/* process global correlation and queue the events that must be closed */
1239 	for (i = 0; i < trigger_events->values_num; i++)
1240 	{
1241 		DB_EVENT	*event = (DB_EVENT *)trigger_events->values[i];
1242 
1243 		if (0 == (ZBX_FLAGS_DB_EVENT_CREATE & event->flags))
1244 			continue;
1245 
1246 		correlate_event_by_global_rules(event, &problem_state);
1247 
1248 		/* force value recalculation based on open problems for triggers with */
1249 		/* events closed by 'close new' correlation operation                */
1250 		if (0 != (event->flags & ZBX_FLAGS_DB_EVENT_NO_ACTION))
1251 		{
1252 			if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_diff, &event->objectid,
1253 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1254 			{
1255 				diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
1256 				diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_RECALCULATE_PROBLEM_COUNT;
1257 			}
1258 		}
1259 	}
1260 
1261 out:
1262 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1263 }
1264 
1265 /******************************************************************************
1266  *                                                                            *
1267  * Function: flush_correlation_queue                                          *
1268  *                                                                            *
1269  * Purpose: try flushing correlation close events queue, generated by         *
1270  *          correlation rules                                                 *
1271  *                                                                            *
1272  ******************************************************************************/
flush_correlation_queue(zbx_vector_ptr_t * trigger_diff,zbx_vector_uint64_t * triggerids_lock)1273 static void	flush_correlation_queue(zbx_vector_ptr_t *trigger_diff, zbx_vector_uint64_t *triggerids_lock)
1274 {
1275 	const char		*__function_name = "flush_correlation_queue";
1276 
1277 	zbx_vector_uint64_t	triggerids, lockids, eventids;
1278 	zbx_hashset_iter_t	iter;
1279 	zbx_event_recovery_t	*recovery;
1280 	int			i, closed_num = 0;
1281 
1282 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() events:%d", __function_name, correlation_cache.num_data);
1283 
1284 	if (0 == correlation_cache.num_data)
1285 		goto out;
1286 
1287 	zbx_vector_uint64_create(&triggerids);
1288 	zbx_vector_uint64_create(&lockids);
1289 	zbx_vector_uint64_create(&eventids);
1290 
1291 	/* lock source triggers of events to be closed by global correlation rules */
1292 
1293 	zbx_vector_uint64_sort(triggerids_lock, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1294 
1295 	/* create a list of triggers that must be locked to close correlated events */
1296 	zbx_hashset_iter_reset(&correlation_cache, &iter);
1297 	while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
1298 	{
1299 		if (FAIL != zbx_vector_uint64_bsearch(triggerids_lock, recovery->objectid,
1300 				ZBX_DEFAULT_UINT64_COMPARE_FUNC))
1301 		{
1302 			/* trigger already locked by this process, add to locked triggerids */
1303 			zbx_vector_uint64_append(&triggerids, recovery->objectid);
1304 		}
1305 		else
1306 			zbx_vector_uint64_append(&lockids, recovery->objectid);
1307 	}
1308 
1309 	if (0 != lockids.values_num)
1310 	{
1311 		int	num = triggerids_lock->values_num;
1312 
1313 		zbx_vector_uint64_sort(&lockids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1314 		zbx_vector_uint64_uniq(&lockids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1315 
1316 		DCconfig_lock_triggers_by_triggerids(&lockids, triggerids_lock);
1317 
1318 		/* append the locked trigger ids to already locked trigger ids */
1319 		for (i = num; i < triggerids_lock->values_num; i++)
1320 			zbx_vector_uint64_append(&triggerids, triggerids_lock->values[i]);
1321 	}
1322 
1323 	/* process global correlation actions if we have successfully locked trigger(s) */
1324 	if (0 != triggerids.values_num)
1325 	{
1326 		DC_TRIGGER		*triggers, *trigger;
1327 		int			*errcodes, index;
1328 		char			*sql = NULL;
1329 		size_t			sql_alloc = 0, sql_offset = 0;
1330 		zbx_trigger_diff_t	*diff;
1331 
1332 		/* get locked trigger data - needed for trigger diff and event generation */
1333 
1334 		zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1335 
1336 		triggers = (DC_TRIGGER *)zbx_malloc(NULL, sizeof(DC_TRIGGER) * triggerids.values_num);
1337 		errcodes = (int *)zbx_malloc(NULL, sizeof(int) * triggerids.values_num);
1338 
1339 		DCconfig_get_triggers_by_triggerids(triggers, triggerids.values, errcodes, triggerids.values_num);
1340 
1341 		/* add missing diffs to the trigger changeset */
1342 
1343 		for (i = 0; i < triggerids.values_num; i++)
1344 		{
1345 			if (SUCCEED != errcodes[i])
1346 				continue;
1347 
1348 			trigger = &triggers[i];
1349 
1350 			if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_diff, &triggerids.values[i],
1351 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1352 			{
1353 				zbx_append_trigger_diff(trigger_diff, trigger->triggerid, trigger->priority,
1354 						ZBX_FLAGS_TRIGGER_DIFF_RECALCULATE_PROBLEM_COUNT, trigger->value,
1355 						TRIGGER_STATE_NORMAL, 0, NULL);
1356 
1357 				/* TODO: should we store trigger diffs in hashset rather than vector? */
1358 				zbx_vector_ptr_sort(trigger_diff, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1359 			}
1360 			else
1361 			{
1362 				diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
1363 				diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_RECALCULATE_PROBLEM_COUNT;
1364 			}
1365 		}
1366 
1367 		/* get correlated eventids that are still open (unresolved) */
1368 
1369 		zbx_hashset_iter_reset(&correlation_cache, &iter);
1370 		while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
1371 		{
1372 			/* close event only if its source trigger has been locked */
1373 			if (FAIL == (index = zbx_vector_uint64_bsearch(&triggerids, recovery->objectid,
1374 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1375 			{
1376 				continue;
1377 			}
1378 
1379 			if (SUCCEED != errcodes[index])
1380 				continue;
1381 
1382 			zbx_vector_uint64_append(&eventids, recovery->eventid);
1383 		}
1384 
1385 		zbx_vector_uint64_sort(&eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1386 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select eventid from problem"
1387 								" where r_eventid is null and");
1388 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "eventid", eventids.values, eventids.values_num);
1389 		zbx_vector_uint64_clear(&eventids);
1390 		DBselect_uint64(sql, &eventids);
1391 		zbx_free(sql);
1392 
1393 		/* generate OK events and add event_recovery data for closed events */
1394 		zbx_hashset_iter_reset(&correlation_cache, &iter);
1395 		while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
1396 		{
1397 			if (FAIL == (index = zbx_vector_uint64_bsearch(&triggerids, recovery->objectid,
1398 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1399 			{
1400 				continue;
1401 			}
1402 
1403 			/* close the old problem only if it's still open and trigger is not removed */
1404 			if (SUCCEED == errcodes[index] && FAIL != zbx_vector_uint64_bsearch(&eventids, recovery->eventid,
1405 					ZBX_DEFAULT_UINT64_COMPARE_FUNC))
1406 			{
1407 				trigger = &triggers[index];
1408 
1409 				close_trigger_event(recovery->eventid, recovery->objectid, &recovery->ts, 0,
1410 						recovery->correlationid, recovery->c_eventid, trigger->description,
1411 						trigger->expression_orig, trigger->recovery_expression_orig,
1412 						trigger->priority, trigger->type);
1413 
1414 				closed_num++;
1415 			}
1416 
1417 			zbx_hashset_iter_remove(&iter);
1418 		}
1419 
1420 		DCconfig_clean_triggers(triggers, errcodes, triggerids.values_num);
1421 		zbx_free(errcodes);
1422 		zbx_free(triggers);
1423 	}
1424 
1425 	zbx_vector_uint64_destroy(&eventids);
1426 	zbx_vector_uint64_destroy(&lockids);
1427 	zbx_vector_uint64_destroy(&triggerids);
1428 out:
1429 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() closed:%d", __function_name, closed_num);
1430 }
1431 
1432 /******************************************************************************
1433  *                                                                            *
1434  * Function: update_trigger_problem_count                                     *
1435  *                                                                            *
1436  * Purpose: update number of open problems                                    *
1437  *                                                                            *
1438  * Parameters: trigger_diff    - [IN/OUT] the changeset of triggers that      *
1439  *                               generated the events in local cache.         *
1440  *                                                                            *
1441  * Comments: When a specific event is closed (by correlation or manually) the *
1442  *           open problem count has to be queried from problem table to       *
1443  *           correctly calculate new trigger value.                           *
1444  *                                                                            *
1445  ******************************************************************************/
update_trigger_problem_count(zbx_vector_ptr_t * trigger_diff)1446 static void	update_trigger_problem_count(zbx_vector_ptr_t *trigger_diff)
1447 {
1448 	DB_RESULT		result;
1449 	DB_ROW			row;
1450 	zbx_vector_uint64_t	triggerids;
1451 	zbx_trigger_diff_t	*diff;
1452 	int			i, index;
1453 	char			*sql = NULL;
1454 	size_t			sql_alloc = 0, sql_offset = 0;
1455 	zbx_uint64_t		triggerid;
1456 
1457 	zbx_vector_uint64_create(&triggerids);
1458 
1459 	for (i = 0; i < trigger_diff->values_num; i++)
1460 	{
1461 		diff = (zbx_trigger_diff_t *)trigger_diff->values[i];
1462 
1463 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_RECALCULATE_PROBLEM_COUNT))
1464 		{
1465 			zbx_vector_uint64_append(&triggerids, diff->triggerid);
1466 
1467 			/* reset problem count, it will be updated from database if there are open problems */
1468 			diff->problem_count = 0;
1469 			diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_PROBLEM_COUNT;
1470 		}
1471 	}
1472 
1473 	if (0 == triggerids.values_num)
1474 		goto out;
1475 
1476 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1477 			"select objectid,count(objectid) from problem"
1478 			" where r_eventid is null"
1479 				" and source=%d"
1480 				" and object=%d"
1481 				" and",
1482 			EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER);
1483 
1484 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "objectid", triggerids.values, triggerids.values_num);
1485 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by objectid");
1486 
1487 	result = DBselect("%s", sql);
1488 
1489 	while (NULL != (row = DBfetch(result)))
1490 	{
1491 		ZBX_STR2UINT64(triggerid, row[0]);
1492 
1493 		if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_diff, &triggerid,
1494 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1495 		{
1496 			THIS_SHOULD_NEVER_HAPPEN;
1497 			continue;
1498 		}
1499 
1500 		diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
1501 		diff->problem_count = atoi(row[1]);
1502 		diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_PROBLEM_COUNT;
1503 	}
1504 	DBfree_result(result);
1505 
1506 	zbx_free(sql);
1507 out:
1508 	zbx_vector_uint64_destroy(&triggerids);
1509 }
1510 
1511 /******************************************************************************
1512  *                                                                            *
1513  * Function: update_trigger_changes                                           *
1514  *                                                                            *
1515  * Purpose: update trigger value, problem count fields depending on problem   *
1516  *          and recovered events                                              *
1517  *                                                                            *
1518  ******************************************************************************/
update_trigger_changes(zbx_vector_ptr_t * trigger_diff)1519 static void	update_trigger_changes(zbx_vector_ptr_t *trigger_diff)
1520 {
1521 	int			i;
1522 	int			index, j, new_value;
1523 	zbx_trigger_diff_t	*diff;
1524 
1525 	update_trigger_problem_count(trigger_diff);
1526 
1527 	/* update trigger problem_count for new problem events */
1528 	for (i = 0; i < events.values_num; i++)
1529 	{
1530 		DB_EVENT	*event = (DB_EVENT *)events.values[i];
1531 
1532 		if (EVENT_SOURCE_TRIGGERS != event->source || EVENT_OBJECT_TRIGGER != event->object)
1533 			continue;
1534 
1535 		if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_diff, &event->objectid,
1536 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1537 		{
1538 			THIS_SHOULD_NEVER_HAPPEN;
1539 			continue;
1540 		}
1541 
1542 		diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
1543 
1544 		if (0 == (event->flags & ZBX_FLAGS_DB_EVENT_CREATE))
1545 		{
1546 			diff->flags &= ~(zbx_uint64_t)(ZBX_FLAGS_TRIGGER_DIFF_UPDATE_PROBLEM_COUNT |
1547 					ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE);
1548 			continue;
1549 		}
1550 
1551 		/* always update trigger last change whenever a trigger event has been created */
1552 		diff->lastchange = event->clock;
1553 		diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE;
1554 	}
1555 
1556 	/* recalculate trigger value from problem_count and mark for updating if necessary */
1557 	for (j = 0; j < trigger_diff->values_num; j++)
1558 	{
1559 		diff = (zbx_trigger_diff_t *)trigger_diff->values[j];
1560 
1561 		if (0 == (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_PROBLEM_COUNT))
1562 			continue;
1563 
1564 		new_value = (0 == diff->problem_count ? TRIGGER_VALUE_OK : TRIGGER_VALUE_PROBLEM);
1565 
1566 		if (new_value != diff->value)
1567 		{
1568 			diff->value = new_value;
1569 			diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE;
1570 		}
1571 	}
1572 }
1573 
1574 /******************************************************************************
1575  *                                                                            *
1576  * Function: zbx_initialize_events                                            *
1577  *                                                                            *
1578  * Purpose: initializes the data structures required for event processing     *
1579  *                                                                            *
1580  ******************************************************************************/
zbx_initialize_events(void)1581 void	zbx_initialize_events(void)
1582 {
1583 	zbx_vector_ptr_create(&events);
1584 	zbx_hashset_create(&event_recovery, 0, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1585 	zbx_hashset_create(&correlation_cache, 0, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1586 
1587 	zbx_dc_correlation_rules_init(&correlation_rules);
1588 }
1589 
1590 /******************************************************************************
1591  *                                                                            *
1592  * Function: zbx_uninitialize_events                                          *
1593  *                                                                            *
1594  * Purpose: uninitializes the data structures required for event processing   *
1595  *                                                                            *
1596  ******************************************************************************/
zbx_uninitialize_events(void)1597 void	zbx_uninitialize_events(void)
1598 {
1599 	zbx_vector_ptr_destroy(&events);
1600 	zbx_hashset_destroy(&event_recovery);
1601 	zbx_hashset_destroy(&correlation_cache);
1602 
1603 	zbx_dc_correlation_rules_free(&correlation_rules);
1604 }
1605 
1606 /******************************************************************************
1607  *                                                                            *
1608  * Function: zbx_reset_event_recovery                                         *
1609  *                                                                            *
1610  * Purpose: reset event_recovery data                                         *
1611  *                                                                            *
1612  ******************************************************************************/
zbx_reset_event_recovery(void)1613 void	zbx_reset_event_recovery(void)
1614 {
1615 	zbx_hashset_clear(&event_recovery);
1616 }
1617 
1618 /******************************************************************************
1619  *                                                                            *
1620  * Function: zbx_clean_event                                                  *
1621  *                                                                            *
1622  * Purpose: cleans single event                                               *
1623  *                                                                            *
1624  ******************************************************************************/
zbx_clean_event(DB_EVENT * event)1625 static void	zbx_clean_event(DB_EVENT *event)
1626 {
1627 	zbx_free(event->name);
1628 
1629 	if (EVENT_SOURCE_TRIGGERS == event->source)
1630 	{
1631 		zbx_free(event->trigger.description);
1632 		zbx_free(event->trigger.expression);
1633 		zbx_free(event->trigger.recovery_expression);
1634 		zbx_free(event->trigger.correlation_tag);
1635 
1636 		zbx_vector_ptr_clear_ext(&event->tags, (zbx_clean_func_t)zbx_free_tag);
1637 		zbx_vector_ptr_destroy(&event->tags);
1638 	}
1639 
1640 	zbx_free(event);
1641 }
1642 
1643 /******************************************************************************
1644  *                                                                            *
1645  * Function: zbx_clean_events                                                 *
1646  *                                                                            *
1647  * Purpose: cleans all events and events recoveries                           *
1648  *                                                                            *
1649  ******************************************************************************/
zbx_clean_events(void)1650 void	zbx_clean_events(void)
1651 {
1652 	zbx_vector_ptr_clear_ext(&events, (zbx_clean_func_t)zbx_clean_event);
1653 
1654 	zbx_reset_event_recovery();
1655 }
1656 
1657 /******************************************************************************
1658  *                                                                            *
1659  * Function: get_hosts_by_expression                                          *
1660  *                                                                            *
1661  * Purpose:  get hosts that are used in expression                            *
1662  *                                                                            *
1663  ******************************************************************************/
get_hosts_by_expression(zbx_hashset_t * hosts,const char * expression,const char * recovery_expression)1664 static void	get_hosts_by_expression(zbx_hashset_t *hosts, const char *expression, const char *recovery_expression)
1665 {
1666 	zbx_vector_uint64_t	functionids;
1667 
1668 	zbx_vector_uint64_create(&functionids);
1669 	get_functionids(&functionids, expression);
1670 	get_functionids(&functionids, recovery_expression);
1671 	DCget_hosts_by_functionids(&functionids, hosts);
1672 	zbx_vector_uint64_destroy(&functionids);
1673 }
1674 
1675 /******************************************************************************
1676  *                                                                            *
1677  * Function: zbx_export_events                                                *
1678  *                                                                            *
1679  * Purpose: export events                                                     *
1680  *                                                                            *
1681  ******************************************************************************/
zbx_export_events(void)1682 void	zbx_export_events(void)
1683 {
1684 	const char		*__function_name = "zbx_export_events";
1685 
1686 	int			i, j;
1687 	struct zbx_json		json;
1688 	size_t			sql_alloc = 256, sql_offset;
1689 	char			*sql = NULL;
1690 	DB_RESULT		result;
1691 	DB_ROW			row;
1692 	zbx_hashset_t		hosts;
1693 	zbx_vector_uint64_t	hostids;
1694 	zbx_hashset_iter_t	iter;
1695 	zbx_event_recovery_t	*recovery;
1696 
1697 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() events:" ZBX_FS_SIZE_T, __function_name, (zbx_fs_size_t)events.values_num);
1698 
1699 	if (0 == events.values_num)
1700 		goto exit;
1701 
1702 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
1703 	sql = (char *)zbx_malloc(sql, sql_alloc);
1704 	zbx_hashset_create(&hosts, events.values_num, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1705 	zbx_vector_uint64_create(&hostids);
1706 
1707 	for (i = 0; i < events.values_num; i++)
1708 	{
1709 		DC_HOST		*host;
1710 		DB_EVENT	*event;
1711 
1712 		event = (DB_EVENT *)events.values[i];
1713 
1714 		if (EVENT_SOURCE_TRIGGERS != event->source || 0 == (event->flags & ZBX_FLAGS_DB_EVENT_CREATE))
1715 			continue;
1716 
1717 		if (TRIGGER_VALUE_PROBLEM != event->value)
1718 			continue;
1719 
1720 		zbx_json_clean(&json);
1721 
1722 		zbx_json_addint64(&json, ZBX_PROTO_TAG_CLOCK, event->clock);
1723 		zbx_json_addint64(&json, ZBX_PROTO_TAG_NS, event->ns);
1724 		zbx_json_addint64(&json, ZBX_PROTO_TAG_VALUE, event->value);
1725 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_EVENTID, event->eventid);
1726 		zbx_json_addstring(&json, ZBX_PROTO_TAG_NAME, event->name, ZBX_JSON_TYPE_STRING);
1727 
1728 		get_hosts_by_expression(&hosts, event->trigger.expression,
1729 				event->trigger.recovery_expression);
1730 
1731 		zbx_json_addarray(&json, ZBX_PROTO_TAG_HOSTS);
1732 
1733 		zbx_hashset_iter_reset(&hosts, &iter);
1734 		while (NULL != (host = (DC_HOST *)zbx_hashset_iter_next(&iter)))
1735 		{
1736 			zbx_json_addstring(&json, NULL, host->name, ZBX_JSON_TYPE_STRING);
1737 			zbx_vector_uint64_append(&hostids, host->hostid);
1738 		}
1739 
1740 		zbx_json_close(&json);
1741 
1742 		sql_offset = 0;
1743 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1744 					"select distinct g.name"
1745 					" from hstgrp g, hosts_groups hg"
1746 					" where g.groupid=hg.groupid"
1747 						" and");
1748 
1749 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.hostid", hostids.values,
1750 				hostids.values_num);
1751 
1752 		result = DBselect("%s", sql);
1753 
1754 		zbx_json_addarray(&json, ZBX_PROTO_TAG_GROUPS);
1755 
1756 		while (NULL != (row = DBfetch(result)))
1757 			zbx_json_addstring(&json, NULL, row[0], ZBX_JSON_TYPE_STRING);
1758 		DBfree_result(result);
1759 
1760 		zbx_json_close(&json);
1761 
1762 		zbx_json_addarray(&json, ZBX_PROTO_TAG_TAGS);
1763 		for (j = 0; j < event->tags.values_num; j++)
1764 		{
1765 			zbx_tag_t	*tag = (zbx_tag_t *)event->tags.values[j];
1766 
1767 			zbx_json_addobject(&json, NULL);
1768 			zbx_json_addstring(&json, ZBX_PROTO_TAG_TAG, tag->tag, ZBX_JSON_TYPE_STRING);
1769 			zbx_json_addstring(&json, ZBX_PROTO_TAG_VALUE, tag->value, ZBX_JSON_TYPE_STRING);
1770 			zbx_json_close(&json);
1771 		}
1772 
1773 		zbx_hashset_clear(&hosts);
1774 		zbx_vector_uint64_clear(&hostids);
1775 
1776 		zbx_problems_export_write(json.buffer, json.buffer_size);
1777 	}
1778 
1779 	zbx_hashset_iter_reset(&event_recovery, &iter);
1780 	while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
1781 	{
1782 		if (EVENT_SOURCE_TRIGGERS != recovery->r_event->source)
1783 			continue;
1784 
1785 		zbx_json_clean(&json);
1786 
1787 		zbx_json_addint64(&json, ZBX_PROTO_TAG_CLOCK, recovery->r_event->clock);
1788 		zbx_json_addint64(&json, ZBX_PROTO_TAG_NS, recovery->r_event->ns);
1789 		zbx_json_addint64(&json, ZBX_PROTO_TAG_VALUE, recovery->r_event->value);
1790 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_EVENTID, recovery->r_event->eventid);
1791 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_PROBLEM_EVENTID, recovery->eventid);
1792 
1793 		zbx_problems_export_write(json.buffer, json.buffer_size);
1794 	}
1795 
1796 	zbx_problems_export_flush();
1797 
1798 	zbx_hashset_destroy(&hosts);
1799 	zbx_vector_uint64_destroy(&hostids);
1800 	zbx_free(sql);
1801 	zbx_json_free(&json);
1802 exit:
1803 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1804 }
1805 
1806 /******************************************************************************
1807  *                                                                            *
1808  * Function: add_event_suppress_data                                          *
1809  *                                                                            *
1810  * Purpose: adds event suppress data for problem events matching active       *
1811  *          maintenance periods                                               *
1812  *                                                                            *
1813  ******************************************************************************/
add_event_suppress_data(zbx_vector_ptr_t * event_refs,zbx_vector_uint64_t * maintenanceids)1814 static void	add_event_suppress_data(zbx_vector_ptr_t *event_refs, zbx_vector_uint64_t *maintenanceids)
1815 {
1816 	zbx_vector_ptr_t		event_queries;
1817 	int				i, j;
1818 	zbx_event_suppress_query_t	*query;
1819 
1820 	/* prepare query data  */
1821 
1822 	zbx_vector_ptr_create(&event_queries);
1823 
1824 	for (i = 0; i < event_refs->values_num; i++)
1825 	{
1826 		DB_EVENT	*event = (DB_EVENT *)event_refs->values[i];
1827 
1828 		query = (zbx_event_suppress_query_t *)zbx_malloc(NULL, sizeof(zbx_event_suppress_query_t));
1829 		query->eventid = event->eventid;
1830 
1831 		zbx_vector_uint64_create(&query->functionids);
1832 		get_functionids(&query->functionids, event->trigger.expression);
1833 		get_functionids(&query->functionids, event->trigger.recovery_expression);
1834 
1835 		zbx_vector_ptr_create(&query->tags);
1836 		if (0 != event->tags.values_num)
1837 			zbx_vector_ptr_append_array(&query->tags, event->tags.values, event->tags.values_num);
1838 
1839 		zbx_vector_uint64_pair_create(&query->maintenances);
1840 
1841 		zbx_vector_ptr_append(&event_queries, query);
1842 	}
1843 
1844 	if (0 != event_queries.values_num)
1845 	{
1846 		zbx_db_insert_t	db_insert;
1847 
1848 		/* get maintenance data and save it in database */
1849 		if (SUCCEED == zbx_dc_get_event_maintenances(&event_queries, maintenanceids) &&
1850 				SUCCEED == zbx_db_lock_maintenanceids(maintenanceids))
1851 		{
1852 			zbx_db_insert_prepare(&db_insert, "event_suppress", "event_suppressid", "eventid",
1853 					"maintenanceid", "suppress_until", NULL);
1854 
1855 			for (j = 0; j < event_queries.values_num; j++)
1856 			{
1857 				query = (zbx_event_suppress_query_t *)event_queries.values[j];
1858 
1859 				for (i = 0; i < query->maintenances.values_num; i++)
1860 				{
1861 					/* when locking maintenances not-locked (deleted) maintenance ids */
1862 					/* are removed from the maintenanceids vector                   */
1863 					if (FAIL == zbx_vector_uint64_bsearch(maintenanceids,
1864 							query->maintenances.values[i].first,
1865 							ZBX_DEFAULT_UINT64_COMPARE_FUNC))
1866 					{
1867 						continue;
1868 					}
1869 
1870 					zbx_db_insert_add_values(&db_insert, __UINT64_C(0), query->eventid,
1871 							query->maintenances.values[i].first,
1872 							(int)query->maintenances.values[i].second);
1873 
1874 					((DB_EVENT *)event_refs->values[j])->suppressed = ZBX_PROBLEM_SUPPRESSED_TRUE;
1875 				}
1876 			}
1877 
1878 			zbx_db_insert_autoincrement(&db_insert, "event_suppressid");
1879 			zbx_db_insert_execute(&db_insert);
1880 			zbx_db_insert_clean(&db_insert);
1881 		}
1882 
1883 		for (j = 0; j < event_queries.values_num; j++)
1884 		{
1885 			query = (zbx_event_suppress_query_t *)event_queries.values[j];
1886 			/* reset tags vector to avoid double freeing copied tag name/value pointers */
1887 			zbx_vector_ptr_clear(&query->tags);
1888 		}
1889 		zbx_vector_ptr_clear_ext(&event_queries, (zbx_clean_func_t)zbx_event_suppress_query_free);
1890 	}
1891 
1892 	zbx_vector_ptr_destroy(&event_queries);
1893 }
1894 
1895 /******************************************************************************
1896  *                                                                            *
1897  * Function: save_event_suppress_data                                         *
1898  *                                                                            *
1899  * Purpose: retrieve running maintenances for each event and saves it in      *
1900  *          event_suppress table                                              *
1901  *                                                                            *
1902  ******************************************************************************/
update_event_suppress_data(void)1903 static void	update_event_suppress_data(void)
1904 {
1905 	zbx_vector_ptr_t	event_refs;
1906 	zbx_vector_uint64_t	maintenanceids;
1907 	int			i;
1908 	DB_EVENT		*event;
1909 
1910 	zbx_vector_uint64_create(&maintenanceids);
1911 	zbx_vector_ptr_create(&event_refs);
1912 	zbx_vector_ptr_reserve(&event_refs, events.values_num);
1913 
1914 	/* prepare trigger problem event vector */
1915 	for (i = 0; i < events.values_num; i++)
1916 	{
1917 		event = (DB_EVENT *)events.values[i];
1918 
1919 		if (0 == (event->flags & ZBX_FLAGS_DB_EVENT_CREATE))
1920 			continue;
1921 
1922 		if (EVENT_SOURCE_TRIGGERS != event->source)
1923 			continue;
1924 
1925 		if (TRIGGER_VALUE_PROBLEM == event->value)
1926 			zbx_vector_ptr_append(&event_refs, event);
1927 	}
1928 
1929 	if (0 == event_refs.values_num)
1930 		goto out;
1931 
1932 	if (SUCCEED != zbx_dc_get_running_maintenanceids(&maintenanceids))
1933 		goto out;
1934 
1935 	if (0 != event_refs.values_num)
1936 		add_event_suppress_data(&event_refs, &maintenanceids);
1937 out:
1938 	zbx_vector_ptr_destroy(&event_refs);
1939 	zbx_vector_uint64_destroy(&maintenanceids);
1940 }
1941 
1942 /******************************************************************************
1943  *                                                                            *
1944  * Function: flush_events                                                     *
1945  *                                                                            *
1946  * Purpose: flushes local event cache to database                             *
1947  *                                                                            *
1948  ******************************************************************************/
flush_events(void)1949 static int	flush_events(void)
1950 {
1951 	int				ret;
1952 	zbx_event_recovery_t		*recovery;
1953 	zbx_vector_uint64_pair_t	closed_events;
1954 	zbx_hashset_iter_t		iter;
1955 
1956 	ret = save_events();
1957 	save_problems();
1958 	save_event_recovery();
1959 	update_event_suppress_data();
1960 
1961 	zbx_vector_uint64_pair_create(&closed_events);
1962 
1963 	zbx_hashset_iter_reset(&event_recovery, &iter);
1964 	while (NULL != (recovery = (zbx_event_recovery_t *)zbx_hashset_iter_next(&iter)))
1965 	{
1966 		zbx_uint64_pair_t	pair = {recovery->eventid, recovery->r_event->eventid};
1967 
1968 		zbx_vector_uint64_pair_append_ptr(&closed_events, &pair);
1969 	}
1970 
1971 	zbx_vector_uint64_pair_sort(&closed_events, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1972 
1973 	process_actions(&events, &closed_events);
1974 	zbx_vector_uint64_pair_destroy(&closed_events);
1975 
1976 	return ret;
1977 }
1978 
1979 /******************************************************************************
1980  *                                                                            *
1981  * Function: recover_event                                                    *
1982  *                                                                            *
1983  * Purpose: recover an event                                                  *
1984  *                                                                            *
1985  * Parameters: eventid   - [IN] the event to recover                          *
1986  *             source    - [IN] the recovery event source                     *
1987  *             object    - [IN] the recovery event object                     *
1988  *             objectid  - [IN] the recovery event object id                  *
1989  *                                                                            *
1990  ******************************************************************************/
recover_event(zbx_uint64_t eventid,int source,int object,zbx_uint64_t objectid)1991 static void	recover_event(zbx_uint64_t eventid, int source, int object, zbx_uint64_t objectid)
1992 {
1993 	DB_EVENT		*event;
1994 	zbx_event_recovery_t	recovery_local;
1995 
1996 	if (NULL == (event = get_event_by_source_object_id(source, object, objectid)))
1997 	{
1998 		THIS_SHOULD_NEVER_HAPPEN;
1999 		return;
2000 	}
2001 
2002 	if (EVENT_SOURCE_INTERNAL == source)
2003 		event->flags |= ZBX_FLAGS_DB_EVENT_RECOVER;
2004 
2005 	recovery_local.eventid = eventid;
2006 
2007 	if (NULL != zbx_hashset_search(&event_recovery, &recovery_local))
2008 	{
2009 		THIS_SHOULD_NEVER_HAPPEN;
2010 		return;
2011 	}
2012 
2013 	recovery_local.objectid = objectid;
2014 	recovery_local.r_event = event;
2015 	recovery_local.correlationid = 0;
2016 	recovery_local.c_eventid = 0;
2017 	recovery_local.userid = 0;
2018 	zbx_hashset_insert(&event_recovery, &recovery_local, sizeof(recovery_local));
2019 }
2020 
2021 /******************************************************************************
2022  *                                                                            *
2023  * Function: process_internal_ok_events                                       *
2024  *                                                                            *
2025  * Purpose: process internal recovery events                                  *
2026  *                                                                            *
2027  * Parameters: ok_events - [IN] the recovery events to process                *
2028  *                                                                            *
2029  ******************************************************************************/
process_internal_ok_events(zbx_vector_ptr_t * ok_events)2030 static void	process_internal_ok_events(zbx_vector_ptr_t *ok_events)
2031 {
2032 	int			i, object;
2033 	zbx_uint64_t		objectid, eventid;
2034 	char			*sql = NULL;
2035 	const char		*separator = "";
2036 	size_t			sql_alloc = 0, sql_offset = 0;
2037 	zbx_vector_uint64_t	triggerids, itemids, lldruleids;
2038 	DB_RESULT		result;
2039 	DB_ROW			row;
2040 	DB_EVENT		*event;
2041 
2042 	zbx_vector_uint64_create(&triggerids);
2043 	zbx_vector_uint64_create(&itemids);
2044 	zbx_vector_uint64_create(&lldruleids);
2045 
2046 	for (i = 0; i < ok_events->values_num; i++)
2047 	{
2048 		event = (DB_EVENT *)ok_events->values[i];
2049 
2050 		if (ZBX_FLAGS_DB_EVENT_UNSET == event->flags)
2051 			continue;
2052 
2053 		switch (event->object)
2054 		{
2055 			case EVENT_OBJECT_TRIGGER:
2056 				zbx_vector_uint64_append(&triggerids, event->objectid);
2057 				break;
2058 			case EVENT_OBJECT_ITEM:
2059 				zbx_vector_uint64_append(&itemids, event->objectid);
2060 				break;
2061 			case EVENT_OBJECT_LLDRULE:
2062 				zbx_vector_uint64_append(&lldruleids, event->objectid);
2063 				break;
2064 		}
2065 	}
2066 
2067 	if (0 == triggerids.values_num && 0 == itemids.values_num && 0 == lldruleids.values_num)
2068 		goto out;
2069 
2070 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2071 			"select eventid,object,objectid from problem"
2072 			" where r_eventid is null"
2073 				" and source=%d"
2074 			" and (", EVENT_SOURCE_INTERNAL);
2075 
2076 	if (0 != triggerids.values_num)
2077 	{
2078 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s (object=%d and",
2079 				separator, EVENT_OBJECT_TRIGGER);
2080 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "objectid", triggerids.values,
2081 				triggerids.values_num);
2082 		zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
2083 		separator=" or";
2084 	}
2085 
2086 	if (0 != itemids.values_num)
2087 	{
2088 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s (object=%d and",
2089 				separator, EVENT_OBJECT_ITEM);
2090 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "objectid", itemids.values,
2091 				itemids.values_num);
2092 		zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
2093 		separator=" or";
2094 	}
2095 
2096 	if (0 != lldruleids.values_num)
2097 	{
2098 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s (object=%d and",
2099 				separator, EVENT_OBJECT_LLDRULE);
2100 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "objectid", lldruleids.values,
2101 				lldruleids.values_num);
2102 		zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
2103 	}
2104 
2105 	zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
2106 	result = DBselect("%s", sql);
2107 
2108 	while (NULL != (row = DBfetch(result)))
2109 	{
2110 		ZBX_STR2UINT64(eventid, row[0]);
2111 		object = atoi(row[1]);
2112 		ZBX_STR2UINT64(objectid, row[2]);
2113 
2114 		recover_event(eventid, EVENT_SOURCE_INTERNAL, object, objectid);
2115 	}
2116 
2117 	DBfree_result(result);
2118 	zbx_free(sql);
2119 
2120 out:
2121 	zbx_vector_uint64_destroy(&lldruleids);
2122 	zbx_vector_uint64_destroy(&itemids);
2123 	zbx_vector_uint64_destroy(&triggerids);
2124 }
2125 
2126 /******************************************************************************
2127  *                                                                            *
2128  * Function: process_internal_events_without_actions                          *
2129  *                                                                            *
2130  * Purpose: do not generate unnecessary internal events if there are no       *
2131  *          internal actions and no problem recovery from when actions were   *
2132  *          enabled                                                           *
2133  *                                                                            *
2134  * Parameters: internal_problem_events - [IN/OUT] problem events to process   *
2135  * Parameters: internal_ok_events      - [IN/OUT] recovery events to process  *
2136  *                                                                            *
2137  ******************************************************************************/
process_internal_events_without_actions(zbx_vector_ptr_t * internal_problem_events,zbx_vector_ptr_t * internal_ok_events)2138 static void	process_internal_events_without_actions(zbx_vector_ptr_t *internal_problem_events,
2139 		zbx_vector_ptr_t *internal_ok_events)
2140 {
2141 	DB_EVENT	*event;
2142 	int		i;
2143 
2144 	if (0 != DCget_internal_action_count())
2145 		return;
2146 
2147 	for (i = 0; i < internal_problem_events->values_num; i++)
2148 		((DB_EVENT *)internal_problem_events->values[i])->flags = ZBX_FLAGS_DB_EVENT_UNSET;
2149 
2150 	for (i = 0; i < internal_ok_events->values_num; i++)
2151 	{
2152 		event = (DB_EVENT *)internal_ok_events->values[i];
2153 
2154 		if (0 == (event->flags & ZBX_FLAGS_DB_EVENT_RECOVER))
2155 			event->flags = ZBX_FLAGS_DB_EVENT_UNSET;
2156 	}
2157 }
2158 
2159 /******************************************************************************
2160  *                                                                            *
2161  * Function: get_open_problems                                                *
2162  *                                                                            *
2163  * Purpose: gets open problems created by the specified triggers              *
2164  *                                                                            *
2165  * Parameters: triggerids - [IN] the trigger identifiers (sorted)             *
2166  *             problems   - [OUT] the problems                                *
2167  *                                                                            *
2168  ******************************************************************************/
get_open_problems(const zbx_vector_uint64_t * triggerids,zbx_vector_ptr_t * problems)2169 static void	get_open_problems(const zbx_vector_uint64_t *triggerids, zbx_vector_ptr_t *problems)
2170 {
2171 	DB_RESULT		result;
2172 	DB_ROW			row;
2173 	char			*sql = NULL;
2174 	size_t			sql_alloc = 0, sql_offset = 0;
2175 	zbx_event_problem_t	*problem;
2176 	zbx_tag_t		*tag;
2177 	zbx_uint64_t		eventid;
2178 	int			index;
2179 	zbx_vector_uint64_t	eventids;
2180 
2181 	zbx_vector_uint64_create(&eventids);
2182 
2183 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2184 			"select eventid,objectid from problem where source=%d and object=%d and",
2185 			EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER);
2186 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "objectid", triggerids->values, triggerids->values_num);
2187 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and r_eventid is null");
2188 
2189 	result = DBselect("%s", sql);
2190 
2191 	while (NULL != (row = DBfetch(result)))
2192 	{
2193 		problem = (zbx_event_problem_t *)zbx_malloc(NULL, sizeof(zbx_event_problem_t));
2194 
2195 		ZBX_STR2UINT64(problem->eventid, row[0]);
2196 		ZBX_STR2UINT64(problem->triggerid, row[1]);
2197 		zbx_vector_ptr_create(&problem->tags);
2198 		zbx_vector_ptr_append(problems, problem);
2199 
2200 		zbx_vector_uint64_append(&eventids, problem->eventid);
2201 	}
2202 	DBfree_result(result);
2203 
2204 	if (0 != problems->values_num)
2205 	{
2206 		zbx_vector_ptr_sort(problems, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2207 		zbx_vector_uint64_sort(&eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2208 
2209 		sql_offset = 0;
2210 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select eventid,tag,value from problem_tag where");
2211 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "eventid", eventids.values, eventids.values_num);
2212 
2213 		result = DBselect("%s", sql);
2214 
2215 		while (NULL != (row = DBfetch(result)))
2216 		{
2217 			ZBX_STR2UINT64(eventid, row[0]);
2218 			if (FAIL == (index = zbx_vector_ptr_bsearch(problems, &eventid,
2219 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2220 			{
2221 				THIS_SHOULD_NEVER_HAPPEN;
2222 				continue;
2223 			}
2224 
2225 			problem = (zbx_event_problem_t *)problems->values[index];
2226 
2227 			tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t));
2228 			tag->tag = zbx_strdup(NULL, row[1]);
2229 			tag->value = zbx_strdup(NULL, row[2]);
2230 			zbx_vector_ptr_append(&problem->tags, tag);
2231 		}
2232 		DBfree_result(result);
2233 	}
2234 
2235 	zbx_free(sql);
2236 
2237 	zbx_vector_uint64_destroy(&eventids);
2238 }
2239 
2240 /******************************************************************************
2241  *                                                                            *
2242  * Function: event_problem_free                                               *
2243  *                                                                            *
2244  * Purpose: frees cached problem event                                        *
2245  *                                                                            *
2246  ******************************************************************************/
event_problem_free(zbx_event_problem_t * problem)2247 static void	event_problem_free(zbx_event_problem_t *problem)
2248 {
2249 	zbx_vector_ptr_clear_ext(&problem->tags, (zbx_clean_func_t)zbx_free_tag);
2250 	zbx_vector_ptr_destroy(&problem->tags);
2251 	zbx_free(problem);
2252 }
2253 
2254 
2255 /******************************************************************************
2256  *                                                                            *
2257  * Function: trigger_dep_free                                                 *
2258  *                                                                            *
2259  * Purpose: frees trigger dependency                                          *
2260  *                                                                            *
2261  ******************************************************************************/
2262 
trigger_dep_free(zbx_trigger_dep_t * dep)2263 static void	trigger_dep_free(zbx_trigger_dep_t *dep)
2264 {
2265 	zbx_vector_uint64_destroy(&dep->masterids);
2266 	zbx_free(dep);
2267 }
2268 
2269 /******************************************************************************
2270  *                                                                            *
2271  * Function: event_check_dependency                                           *
2272  *                                                                            *
2273  * Purpose: check event dependency based on cached and actual trigger values  *
2274  *                                                                            *
2275  * Parameters: event        - [IN] the event to check                         *
2276  *             deps         - [IN] the trigger dependency data (sorted by     *
2277  *                                 triggerid)                                 *
2278  *             trigger_diff - [IN] the trigger changeset - source of actual   *
2279  *                                 trigger values (sorted by triggerid)       *
2280  *                                                                            *
2281  ******************************************************************************/
event_check_dependency(const DB_EVENT * event,const zbx_vector_ptr_t * deps,const zbx_vector_ptr_t * trigger_diff)2282 static int	event_check_dependency(const DB_EVENT *event, const zbx_vector_ptr_t *deps,
2283 		const zbx_vector_ptr_t *trigger_diff)
2284 {
2285 	int			i, index;
2286 	zbx_trigger_dep_t	*dep;
2287 	zbx_trigger_diff_t	*diff;
2288 
2289 	if (FAIL == (index = zbx_vector_ptr_bsearch(deps, &event->objectid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2290 		return SUCCEED;
2291 
2292 	dep = (zbx_trigger_dep_t *)deps->values[index];
2293 
2294 	if (ZBX_TRIGGER_DEPENDENCY_FAIL == dep->status)
2295 		return FAIL;
2296 
2297 	/* check the trigger dependency based on actual (currently being processed) trigger values */
2298 	for (i = 0; i < dep->masterids.values_num; i++)
2299 	{
2300 		if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_diff, &dep->masterids.values[i],
2301 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2302 		{
2303 			THIS_SHOULD_NEVER_HAPPEN;
2304 			continue;
2305 		}
2306 
2307 		diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
2308 
2309 		if (0 == (ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE & diff->flags))
2310 			continue;
2311 
2312 		if (TRIGGER_VALUE_PROBLEM == diff->value)
2313 			return FAIL;
2314 	}
2315 
2316 	return SUCCEED;
2317 }
2318 
2319 /******************************************************************************
2320  *                                                                            *
2321  * Function: match_tag                                                        *
2322  *                                                                            *
2323  * Purpose: checks if the two tag sets have matching tag                      *
2324  *                                                                            *
2325  * Parameters: name  - [IN] the name of tag to match                          *
2326  *             tags1 - [IN] the first tag vector                              *
2327  *             tags2 - [IN] the second tag vector                             *
2328  *                                                                            *
2329  * Return value: SUCCEED - both tag sets contains a tag with the specified    *
2330  *                         name and the same value                            *
2331  *               FAIL    - otherwise.                                         *
2332  *                                                                            *
2333  ******************************************************************************/
match_tag(const char * name,const zbx_vector_ptr_t * tags1,const zbx_vector_ptr_t * tags2)2334 static int	match_tag(const char *name, const zbx_vector_ptr_t *tags1, const zbx_vector_ptr_t *tags2)
2335 {
2336 	int		i, j;
2337 	zbx_tag_t	*tag1, *tag2;
2338 
2339 	for (i = 0; i < tags1->values_num; i++)
2340 	{
2341 		tag1 = (zbx_tag_t *)tags1->values[i];
2342 
2343 		if (0 != strcmp(tag1->tag, name))
2344 			continue;
2345 
2346 		for (j = 0; j < tags2->values_num; j++)
2347 		{
2348 			tag2 = (zbx_tag_t *)tags2->values[j];
2349 
2350 			if (0 == strcmp(tag2->tag, name) && 0 == strcmp(tag1->value, tag2->value))
2351 				return SUCCEED;
2352 		}
2353 	}
2354 
2355 	return FAIL;
2356 }
2357 
2358 /******************************************************************************
2359  *                                                                            *
2360  * Function: process_trigger_events                                           *
2361  *                                                                            *
2362  * Purpose: processes trigger events                                          *
2363  *                                                                            *
2364  * Parameters: trigger_events - [IN] the trigger events to process            *
2365  *             trigger_diff   - [IN] the trigger changeset                    *
2366  *                                                                            *
2367  ******************************************************************************/
process_trigger_events(zbx_vector_ptr_t * trigger_events,zbx_vector_ptr_t * trigger_diff)2368 static void	process_trigger_events(zbx_vector_ptr_t *trigger_events, zbx_vector_ptr_t *trigger_diff)
2369 {
2370 	int			i, j, index;
2371 	zbx_vector_uint64_t	triggerids;
2372 	zbx_vector_ptr_t	problems, deps;
2373 	DB_EVENT		*event;
2374 	zbx_event_problem_t	*problem;
2375 	zbx_trigger_diff_t	*diff;
2376 	unsigned char		value;
2377 
2378 	zbx_vector_uint64_create(&triggerids);
2379 	zbx_vector_uint64_reserve(&triggerids, trigger_events->values_num);
2380 
2381 	zbx_vector_ptr_create(&problems);
2382 	zbx_vector_ptr_reserve(&problems, trigger_events->values_num);
2383 
2384 	zbx_vector_ptr_create(&deps);
2385 	zbx_vector_ptr_reserve(&deps, trigger_events->values_num);
2386 
2387 	/* cache relevant problems */
2388 
2389 	for (i = 0; i < trigger_events->values_num; i++)
2390 	{
2391 		event = (DB_EVENT *)trigger_events->values[i];
2392 
2393 		if (TRIGGER_VALUE_OK == event->value)
2394 			zbx_vector_uint64_append(&triggerids, event->objectid);
2395 	}
2396 
2397 	if (0 != triggerids.values_num)
2398 	{
2399 		zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2400 		get_open_problems(&triggerids, &problems);
2401 	}
2402 
2403 	/* get trigger dependency data */
2404 
2405 	zbx_vector_uint64_clear(&triggerids);
2406 	for (i = 0; i < trigger_events->values_num; i++)
2407 	{
2408 		event = (DB_EVENT *)trigger_events->values[i];
2409 		zbx_vector_uint64_append(&triggerids, event->objectid);
2410 	}
2411 
2412 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2413 	zbx_dc_get_trigger_dependencies(&triggerids, &deps);
2414 
2415 	/* process trigger events */
2416 
2417 	for (i = 0; i < trigger_events->values_num; i++)
2418 	{
2419 		event = (DB_EVENT *)trigger_events->values[i];
2420 
2421 		if (FAIL == (index = zbx_vector_ptr_search(trigger_diff, &event->objectid,
2422 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2423 		{
2424 			THIS_SHOULD_NEVER_HAPPEN;
2425 			continue;
2426 		}
2427 
2428 		diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
2429 
2430 		if (FAIL == (event_check_dependency(event, &deps, trigger_diff)))
2431 		{
2432 			/* reset event data/trigger changeset if dependency check failed */
2433 			event->flags = ZBX_FLAGS_DB_EVENT_UNSET;
2434 			diff->flags = ZBX_FLAGS_TRIGGER_DIFF_UNSET;
2435 			continue;
2436 		}
2437 
2438 		if (TRIGGER_VALUE_PROBLEM == event->value)
2439 		{
2440 			/* Problem events always sets problem value to trigger.    */
2441 			/* if the trigger is affected by global correlation rules, */
2442 			/* its value is recalculated later.                        */
2443 			diff->value = TRIGGER_VALUE_PROBLEM;
2444 			diff->lastchange = event->clock;
2445 			diff->flags |= (ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE | ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE);
2446 			continue;
2447 		}
2448 
2449 		if (TRIGGER_VALUE_OK != event->value)
2450 			continue;
2451 
2452 		/* attempt to recover problem events/triggers */
2453 
2454 		if (ZBX_TRIGGER_CORRELATION_NONE == event->trigger.correlation_mode)
2455 		{
2456 			/* with trigger correlation disabled the recovery event recovers */
2457 			/* all problem events generated by the same trigger and sets     */
2458 			/* trigger value to OK                                           */
2459 			for (j = 0; j < problems.values_num; j++)
2460 			{
2461 				problem = (zbx_event_problem_t *)problems.values[j];
2462 
2463 				if (problem->triggerid == event->objectid)
2464 				{
2465 					recover_event(problem->eventid, EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER,
2466 							event->objectid);
2467 				}
2468 			}
2469 
2470 			diff->value = TRIGGER_VALUE_OK;
2471 			diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE;
2472 		}
2473 		else
2474 		{
2475 			/* With trigger correlation enabled the recovery event recovers    */
2476 			/* all problem events generated by the same trigger and matching   */
2477 			/* recovery event tags. The trigger value is set to OK only if all */
2478 			/* problem events were recovered.                                  */
2479 
2480 			value = TRIGGER_VALUE_OK;
2481 			event->flags = ZBX_FLAGS_DB_EVENT_UNSET;
2482 
2483 			for (j = 0; j < problems.values_num; j++)
2484 			{
2485 				problem = (zbx_event_problem_t *)problems.values[j];
2486 
2487 				if (problem->triggerid == event->objectid)
2488 				{
2489 					if (SUCCEED == match_tag(event->trigger.correlation_tag,
2490 							&problem->tags, &event->tags))
2491 					{
2492 						recover_event(problem->eventid, EVENT_SOURCE_TRIGGERS,
2493 								EVENT_OBJECT_TRIGGER, event->objectid);
2494 						event->flags = ZBX_FLAGS_DB_EVENT_CREATE;
2495 					}
2496 					else
2497 						value = TRIGGER_VALUE_PROBLEM;
2498 
2499 				}
2500 			}
2501 
2502 			diff->value = value;
2503 			diff->flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE;
2504 		}
2505 	}
2506 
2507 	zbx_vector_ptr_clear_ext(&problems, (zbx_clean_func_t)event_problem_free);
2508 	zbx_vector_ptr_destroy(&problems);
2509 
2510 	zbx_vector_ptr_clear_ext(&deps, (zbx_clean_func_t)trigger_dep_free);
2511 	zbx_vector_ptr_destroy(&deps);
2512 
2513 	zbx_vector_uint64_destroy(&triggerids);
2514 }
2515 
2516 /******************************************************************************
2517  *                                                                            *
2518  * Function: process_internal_events_dependency                               *
2519  *                                                                            *
2520  * Purpose: process internal trigger events                                   *
2521  *          to avoid trigger dependency                                       *
2522  *                                                                            *
2523  * Parameters: internal_events - [IN] the internal events to process          *
2524  *             trigger_events  - [IN] the trigger events used for dependency  *
2525  *             trigger_diff   -  [IN] the trigger changeset                   *
2526  *                                                                            *
2527  ******************************************************************************/
process_internal_events_dependency(zbx_vector_ptr_t * internal_events,zbx_vector_ptr_t * trigger_events,zbx_vector_ptr_t * trigger_diff)2528 static void	process_internal_events_dependency(zbx_vector_ptr_t *internal_events, zbx_vector_ptr_t *trigger_events,
2529 		zbx_vector_ptr_t *trigger_diff)
2530 {
2531 	int			i, index;
2532 	DB_EVENT		*event;
2533 	zbx_vector_uint64_t	triggerids;
2534 	zbx_vector_ptr_t	deps;
2535 	zbx_trigger_diff_t	*diff;
2536 
2537 	zbx_vector_uint64_create(&triggerids);
2538 	zbx_vector_uint64_reserve(&triggerids, internal_events->values_num + trigger_events->values_num);
2539 
2540 	zbx_vector_ptr_create(&deps);
2541 	zbx_vector_ptr_reserve(&deps, internal_events->values_num + trigger_events->values_num);
2542 
2543 	for (i = 0; i < internal_events->values_num; i++)
2544 	{
2545 		event = (DB_EVENT *)internal_events->values[i];
2546 		zbx_vector_uint64_append(&triggerids, event->objectid);
2547 	}
2548 
2549 	for (i = 0; i < trigger_events->values_num; i++)
2550 	{
2551 		event = (DB_EVENT *)trigger_events->values[i];
2552 		zbx_vector_uint64_append(&triggerids, event->objectid);
2553 	}
2554 
2555 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2556 	zbx_vector_uint64_uniq(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2557 	zbx_dc_get_trigger_dependencies(&triggerids, &deps);
2558 
2559 	for (i = 0; i < internal_events->values_num; i++)
2560 	{
2561 		event = (DB_EVENT *)internal_events->values[i];
2562 
2563 		if (FAIL == (index = zbx_vector_ptr_search(trigger_diff, &event->objectid,
2564 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2565 		{
2566 			THIS_SHOULD_NEVER_HAPPEN;
2567 			continue;
2568 		}
2569 
2570 		diff = (zbx_trigger_diff_t *)trigger_diff->values[index];
2571 
2572 		if (FAIL == (event_check_dependency(event, &deps, trigger_diff)))
2573 		{
2574 			/* reset event data/trigger changeset if dependency check failed */
2575 			event->flags = ZBX_FLAGS_DB_EVENT_UNSET;
2576 			diff->flags = ZBX_FLAGS_TRIGGER_DIFF_UNSET;
2577 			continue;
2578 		}
2579 	}
2580 
2581 	zbx_vector_ptr_clear_ext(&deps, (zbx_clean_func_t)trigger_dep_free);
2582 	zbx_vector_ptr_destroy(&deps);
2583 
2584 	zbx_vector_uint64_destroy(&triggerids);
2585 }
2586 
2587 /******************************************************************************
2588  *                                                                            *
2589  * Function: zbx_process_events                                               *
2590  *                                                                            *
2591  * Purpose: processes cached events                                           *
2592  *                                                                            *
2593  * Parameters: trigger_diff    - [IN/OUT] the changeset of triggers that      *
2594  *                               generated the events in local cache. When    *
2595  *                               processing global correlation rules new      *
2596  *                               diffs can be added to trigger changeset.     *
2597  *                               Can be NULL when processing events from      *
2598  *                               non trigger sources                          *
2599  *             triggerids_lock - [IN/OUT] the ids of triggers locked by items.*
2600  *                               When processing global correlation rules new *
2601  *                               triggers can be locked and added to this     *
2602  *                               vector.                                      *
2603  *                               Can be NULL when processing events from      *
2604  *                               non trigger sources                          *
2605  *                                                                            *
2606  * Return value: The number of processed events                               *
2607  *                                                                            *
2608  ******************************************************************************/
zbx_process_events(zbx_vector_ptr_t * trigger_diff,zbx_vector_uint64_t * triggerids_lock)2609 int	zbx_process_events(zbx_vector_ptr_t *trigger_diff, zbx_vector_uint64_t *triggerids_lock)
2610 {
2611 	const char		*__function_name = "zbx_process_events";
2612 	int			i, processed_num = 0;
2613 	zbx_uint64_t		eventid;
2614 	zbx_vector_ptr_t	internal_problem_events, internal_ok_events, trigger_events, internal_events;
2615 
2616 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() events_num:" ZBX_FS_SIZE_T, __function_name,
2617 			(zbx_fs_size_t)events.values_num);
2618 
2619 	if (NULL != trigger_diff && 0 != correlation_cache.num_data)
2620 		flush_correlation_queue(trigger_diff, triggerids_lock);
2621 
2622 	if (0 != events.values_num)
2623 	{
2624 		zbx_vector_ptr_create(&internal_problem_events);
2625 		zbx_vector_ptr_reserve(&internal_problem_events, events.values_num);
2626 		zbx_vector_ptr_create(&internal_ok_events);
2627 		zbx_vector_ptr_reserve(&internal_ok_events, events.values_num);
2628 
2629 		zbx_vector_ptr_create(&trigger_events);
2630 		zbx_vector_ptr_reserve(&trigger_events, events.values_num);
2631 
2632 		zbx_vector_ptr_create(&internal_events);
2633 		zbx_vector_ptr_reserve(&internal_events, events.values_num);
2634 
2635 		/* assign event identifiers - they are required to set correlation event ids */
2636 		eventid = DBget_maxid_num("events", events.values_num);
2637 		for (i = 0; i < events.values_num; i++)
2638 		{
2639 			DB_EVENT	*event = (DB_EVENT *)events.values[i];
2640 
2641 			event->eventid = eventid++;
2642 
2643 			if (EVENT_SOURCE_TRIGGERS == event->source)
2644 			{
2645 				zbx_vector_ptr_append(&trigger_events, event);
2646 				continue;
2647 			}
2648 
2649 			if (EVENT_SOURCE_INTERNAL == event->source)
2650 			{
2651 				switch (event->object)
2652 				{
2653 					case EVENT_OBJECT_TRIGGER:
2654 						if (TRIGGER_STATE_NORMAL == event->value)
2655 							zbx_vector_ptr_append(&internal_ok_events, event);
2656 						else
2657 							zbx_vector_ptr_append(&internal_problem_events, event);
2658 						zbx_vector_ptr_append(&internal_events, event);
2659 						break;
2660 					case EVENT_OBJECT_ITEM:
2661 						if (ITEM_STATE_NORMAL == event->value)
2662 							zbx_vector_ptr_append(&internal_ok_events, event);
2663 						else
2664 							zbx_vector_ptr_append(&internal_problem_events, event);
2665 						break;
2666 					case EVENT_OBJECT_LLDRULE:
2667 						if (ITEM_STATE_NORMAL == event->value)
2668 							zbx_vector_ptr_append(&internal_ok_events, event);
2669 						else
2670 							zbx_vector_ptr_append(&internal_problem_events, event);
2671 						break;
2672 				}
2673 			}
2674 		}
2675 
2676 		if (0 != internal_events.values_num)
2677 			process_internal_events_dependency(&internal_events, &trigger_events, trigger_diff);
2678 
2679 		if (0 != internal_ok_events.values_num)
2680 			process_internal_ok_events(&internal_ok_events);
2681 
2682 		if (0 != internal_problem_events.values_num || 0 != internal_ok_events.values_num)
2683 			process_internal_events_without_actions(&internal_problem_events, &internal_ok_events);
2684 
2685 		if (0 != trigger_events.values_num)
2686 		{
2687 			process_trigger_events(&trigger_events, trigger_diff);
2688 			correlate_events_by_global_rules(&trigger_events, trigger_diff);
2689 			flush_correlation_queue(trigger_diff, triggerids_lock);
2690 		}
2691 
2692 		processed_num = flush_events();
2693 
2694 		if (0 != trigger_events.values_num)
2695 			update_trigger_changes(trigger_diff);
2696 
2697 		zbx_vector_ptr_destroy(&trigger_events);
2698 		zbx_vector_ptr_destroy(&internal_ok_events);
2699 		zbx_vector_ptr_destroy(&internal_problem_events);
2700 		zbx_vector_ptr_destroy(&internal_events);
2701 	}
2702 
2703 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() processed:%d", __function_name, (int)processed_num);
2704 
2705 	return processed_num;
2706 }
2707 
2708 /******************************************************************************
2709  *                                                                            *
2710  * Function: zbx_close_problem                                                *
2711  *                                                                            *
2712  * Purpose: closes problem event                                              *
2713  *                                                                            *
2714  * Parameters: triggerid - [IN] the source trigger id                         *
2715  *             eventid   - [IN] the event to close                            *
2716  *             userid    - [IN] the user closing the event                    *
2717  *                                                                            *
2718  * Return value: SUCCEED - the problem was closed                             *
2719  *               FAIL    - otherwise                                          *
2720  *                                                                            *
2721  ******************************************************************************/
zbx_close_problem(zbx_uint64_t triggerid,zbx_uint64_t eventid,zbx_uint64_t userid)2722 int	zbx_close_problem(zbx_uint64_t triggerid, zbx_uint64_t eventid, zbx_uint64_t userid)
2723 {
2724 	DC_TRIGGER	trigger;
2725 	int		errcode, processed_num = 0;
2726 	zbx_timespec_t	ts;
2727 	DB_EVENT	*r_event;
2728 
2729 	DCconfig_get_triggers_by_triggerids(&trigger, &triggerid, &errcode, 1);
2730 
2731 	if (SUCCEED == errcode)
2732 	{
2733 		zbx_vector_ptr_t	trigger_diff;
2734 
2735 		zbx_vector_ptr_create(&trigger_diff);
2736 
2737 		zbx_append_trigger_diff(&trigger_diff, triggerid, trigger.priority,
2738 				ZBX_FLAGS_TRIGGER_DIFF_RECALCULATE_PROBLEM_COUNT, trigger.value,
2739 				TRIGGER_STATE_NORMAL, 0, NULL);
2740 
2741 		zbx_timespec(&ts);
2742 
2743 		DBbegin();
2744 
2745 		r_event = close_trigger_event(eventid, triggerid, &ts, userid, 0, 0, trigger.description,
2746 				trigger.expression_orig, trigger.recovery_expression_orig, trigger.priority,
2747 				trigger.type);
2748 
2749 		r_event->eventid = DBget_maxid_num("events", 1);
2750 
2751 		processed_num = flush_events();
2752 		update_trigger_changes(&trigger_diff);
2753 		zbx_db_save_trigger_changes(&trigger_diff);
2754 
2755 		DBcommit();
2756 
2757 		DCconfig_triggers_apply_changes(&trigger_diff);
2758 		DBupdate_itservices(&trigger_diff);
2759 
2760 		if (SUCCEED == zbx_is_export_enabled())
2761 			zbx_export_events();
2762 
2763 		zbx_clean_events();
2764 		zbx_vector_ptr_clear_ext(&trigger_diff, (zbx_clean_func_t)zbx_trigger_diff_free);
2765 		zbx_vector_ptr_destroy(&trigger_diff);
2766 	}
2767 
2768 	DCconfig_clean_triggers(&trigger, &errcode, 1);
2769 
2770 	return (0 == processed_num ? FAIL : SUCCEED);
2771 }
2772