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