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