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