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 "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25
26 typedef struct
27 {
28 zbx_uint64_t triggerid;
29 char *description;
30 char *expression;
31 char *comments;
32 char *url;
33 unsigned char status;
34 unsigned char type;
35 unsigned char priority;
36 zbx_vector_ptr_t functions;
37 zbx_vector_ptr_t dependencies;
38 }
39 zbx_lld_trigger_prototype_t;
40
41 typedef struct
42 {
43 zbx_uint64_t triggerid;
44 zbx_uint64_t parent_triggerid;
45 char *description;
46 char *description_orig;
47 char *expression;
48 char *expression_orig;
49 char *comments;
50 char *comments_orig;
51 char *url;
52 char *url_orig;
53 zbx_vector_ptr_t functions;
54 zbx_vector_ptr_t dependencies;
55 zbx_vector_ptr_t dependents;
56 #define ZBX_FLAG_LLD_TRIGGER_UNSET __UINT64_C(0x00)
57 #define ZBX_FLAG_LLD_TRIGGER_DISCOVERED __UINT64_C(0x01)
58 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION __UINT64_C(0x02)
59 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION __UINT64_C(0x04)
60 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE __UINT64_C(0x08)
61 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY __UINT64_C(0x10)
62 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS __UINT64_C(0x20)
63 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_URL __UINT64_C(0x40)
64 #define ZBX_FLAG_LLD_TRIGGER_UPDATE \
65 (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION | \
66 ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE | ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY | \
67 ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS | ZBX_FLAG_LLD_TRIGGER_UPDATE_URL)
68 zbx_uint64_t flags;
69 }
70 zbx_lld_trigger_t;
71
72 typedef struct
73 {
74 zbx_uint64_t functionid;
75 zbx_uint64_t index;
76 zbx_uint64_t itemid;
77 zbx_uint64_t itemid_orig;
78 char *function;
79 char *function_orig;
80 char *parameter;
81 char *parameter_orig;
82 #define ZBX_FLAG_LLD_FUNCTION_UNSET __UINT64_C(0x00)
83 #define ZBX_FLAG_LLD_FUNCTION_DISCOVERED __UINT64_C(0x01)
84 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID __UINT64_C(0x02)
85 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION __UINT64_C(0x04)
86 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER __UINT64_C(0x08)
87 #define ZBX_FLAG_LLD_FUNCTION_UPDATE \
88 (ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID | ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION | \
89 ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER)
90 #define ZBX_FLAG_LLD_FUNCTION_DELETE __UINT64_C(0x10)
91 zbx_uint64_t flags;
92 }
93 zbx_lld_function_t;
94
95 typedef struct
96 {
97 zbx_uint64_t triggerdepid;
98 zbx_uint64_t triggerid_up; /* generic trigger */
99 zbx_lld_trigger_t *trigger_up; /* lld-created trigger; (null) if trigger depends on generic trigger */
100 #define ZBX_FLAG_LLD_DEPENDENCY_UNSET __UINT64_C(0x00)
101 #define ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED __UINT64_C(0x01)
102 #define ZBX_FLAG_LLD_DEPENDENCY_DELETE __UINT64_C(0x02)
103 zbx_uint64_t flags;
104 }
105 zbx_lld_dependency_t;
106
107 typedef struct
108 {
109 zbx_uint64_t parent_triggerid;
110 zbx_uint64_t itemid;
111 zbx_lld_trigger_t *trigger;
112 }
113 zbx_lld_item_trigger_t;
114
115 typedef struct
116 {
117 zbx_uint64_t itemid;
118 unsigned char flags;
119 }
120 zbx_lld_item_t;
121
122 /* a reference to trigger which could be either existing trigger in database or */
123 /* a just discovered trigger stored in memory */
124 typedef struct
125 {
126 /* trigger id, 0 for newly discovered triggers */
127 zbx_uint64_t triggerid;
128
129 /* trigger data, NULL for non-discovered triggers */
130 zbx_lld_trigger_t *trigger;
131
132 /* flags to mark trigger dependencies during trigger dependency validation */
133 #define ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL 0
134 #define ZBX_LLD_TRIGGER_DEPENDENCY_NEW 1
135 #define ZBX_LLD_TRIGGER_DEPENDENCY_DELETE 2
136
137 /* flags used to mark dependencies when trigger reference is use to store dependency links */
138 int flags;
139 }
140 zbx_lld_trigger_ref_t;
141
142 /* a trigger node used to build trigger tree for dependency validation */
143 typedef struct
144 {
145 /* trigger reference */
146 zbx_lld_trigger_ref_t trigger_ref;
147
148 /* the current iteration number, used during dependency validation */
149 int iter_num;
150
151 /* the number of dependents */
152 int parents;
153
154 /* trigger dependency list */
155 zbx_vector_ptr_t dependencies;
156 }
157 zbx_lld_trigger_node_t;
158
159 /* a structure to keep information about current iteration during trigger dependencies validation */
160 typedef struct
161 {
162 /* iteration number */
163 int iter_num;
164
165 /* the dependency (from->to) that should be removed in the case of recursive loop */
166 zbx_lld_trigger_ref_t *ref_from;
167 zbx_lld_trigger_ref_t *ref_to;
168 }
169 zbx_lld_trigger_node_iter_t;
170
171
lld_item_free(zbx_lld_item_t * item)172 static void lld_item_free(zbx_lld_item_t *item)
173 {
174 zbx_free(item);
175 }
176
lld_function_free(zbx_lld_function_t * function)177 static void lld_function_free(zbx_lld_function_t *function)
178 {
179 zbx_free(function->parameter_orig);
180 zbx_free(function->parameter);
181 zbx_free(function->function_orig);
182 zbx_free(function->function);
183 zbx_free(function);
184 }
185
lld_trigger_prototype_free(zbx_lld_trigger_prototype_t * trigger_prototype)186 static void lld_trigger_prototype_free(zbx_lld_trigger_prototype_t *trigger_prototype)
187 {
188 zbx_vector_ptr_clear_ext(&trigger_prototype->dependencies, zbx_ptr_free);
189 zbx_vector_ptr_destroy(&trigger_prototype->dependencies);
190 zbx_vector_ptr_clear_ext(&trigger_prototype->functions, (zbx_mem_free_func_t)lld_function_free);
191 zbx_vector_ptr_destroy(&trigger_prototype->functions);
192 zbx_free(trigger_prototype->url);
193 zbx_free(trigger_prototype->comments);
194 zbx_free(trigger_prototype->expression);
195 zbx_free(trigger_prototype->description);
196 zbx_free(trigger_prototype);
197 }
198
lld_trigger_free(zbx_lld_trigger_t * trigger)199 static void lld_trigger_free(zbx_lld_trigger_t *trigger)
200 {
201 zbx_vector_ptr_destroy(&trigger->dependents);
202 zbx_vector_ptr_clear_ext(&trigger->dependencies, zbx_ptr_free);
203 zbx_vector_ptr_destroy(&trigger->dependencies);
204 zbx_vector_ptr_clear_ext(&trigger->functions, (zbx_clean_func_t)lld_function_free);
205 zbx_vector_ptr_destroy(&trigger->functions);
206 zbx_free(trigger->url_orig);
207 zbx_free(trigger->url);
208 zbx_free(trigger->comments_orig);
209 zbx_free(trigger->comments);
210 zbx_free(trigger->expression_orig);
211 zbx_free(trigger->expression);
212 zbx_free(trigger->description_orig);
213 zbx_free(trigger->description);
214 zbx_free(trigger);
215 }
216
217 /******************************************************************************
218 * *
219 * Function: lld_trigger_prototypes_get *
220 * *
221 * Purpose: retrieve trigger prototypes which are inherited from the *
222 * discovery rule *
223 * *
224 * Parameters: lld_ruleid - [IN] discovery rule id *
225 * trigger_prototypes - [OUT] sorted list of trigger prototypes *
226 * *
227 ******************************************************************************/
lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * trigger_prototypes)228 static void lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *trigger_prototypes)
229 {
230 DB_RESULT result;
231 DB_ROW row;
232 zbx_lld_trigger_prototype_t *trigger_prototype;
233
234 result = DBselect(
235 "select distinct t.triggerid,t.description,t.expression,t.status,t.type,t.priority,t.comments,"
236 "t.url"
237 " from triggers t,functions f,items i,item_discovery id"
238 " where t.triggerid=f.triggerid"
239 " and f.itemid=i.itemid"
240 " and i.itemid=id.itemid"
241 " and id.parent_itemid=" ZBX_FS_UI64,
242 lld_ruleid);
243
244 /* run through trigger prototypes */
245 while (NULL != (row = DBfetch(result)))
246 {
247 trigger_prototype = zbx_malloc(NULL, sizeof(zbx_lld_trigger_prototype_t));
248
249 ZBX_STR2UINT64(trigger_prototype->triggerid, row[0]);
250 trigger_prototype->description = zbx_strdup(NULL, row[1]);
251 trigger_prototype->expression = zbx_strdup(NULL, row[2]);
252 ZBX_STR2UCHAR(trigger_prototype->status, row[3]);
253 ZBX_STR2UCHAR(trigger_prototype->type, row[4]);
254 ZBX_STR2UCHAR(trigger_prototype->priority, row[5]);
255 trigger_prototype->comments = zbx_strdup(NULL, row[6]);
256 trigger_prototype->url = zbx_strdup(NULL, row[7]);
257
258 zbx_vector_ptr_create(&trigger_prototype->functions);
259 zbx_vector_ptr_create(&trigger_prototype->dependencies);
260
261 zbx_vector_ptr_append(trigger_prototypes, trigger_prototype);
262 }
263 DBfree_result(result);
264
265 zbx_vector_ptr_sort(trigger_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
266 }
267
268 /******************************************************************************
269 * *
270 * Function: lld_triggers_get *
271 * *
272 * Purpose: retrieve triggers which were created by the specified trigger *
273 * prototypes *
274 * *
275 * Parameters: trigger_prototypes - [IN] sorted list of trigger prototypes *
276 * triggers - [OUT] sorted list of triggers *
277 * *
278 ******************************************************************************/
lld_triggers_get(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)279 static void lld_triggers_get(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
280 {
281 const char *__function_name = "lld_triggers_get";
282
283 DB_RESULT result;
284 DB_ROW row;
285 zbx_vector_uint64_t parent_triggerids;
286 char *sql = NULL;
287 size_t sql_alloc = 256, sql_offset = 0;
288 int i;
289
290 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
291
292 zbx_vector_uint64_create(&parent_triggerids);
293 zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
294
295 for (i = 0; i < trigger_prototypes->values_num; i++)
296 {
297 const zbx_lld_trigger_prototype_t *trigger_prototype;
298
299 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
300
301 zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
302 }
303
304 sql = zbx_malloc(sql, sql_alloc);
305
306 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
307 "select td.parent_triggerid,t.triggerid,t.description,t.expression,t.type,t.priority,"
308 "t.comments,t.url"
309 " from triggers t,trigger_discovery td"
310 " where t.triggerid=td.triggerid"
311 " and");
312 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.parent_triggerid",
313 parent_triggerids.values, parent_triggerids.values_num);
314
315 zbx_vector_uint64_destroy(&parent_triggerids);
316
317 result = DBselect("%s", sql);
318
319 zbx_free(sql);
320
321 while (NULL != (row = DBfetch(result)))
322 {
323 zbx_uint64_t parent_triggerid;
324 const zbx_lld_trigger_prototype_t *trigger_prototype;
325 zbx_lld_trigger_t *trigger;
326 int index;
327
328 ZBX_STR2UINT64(parent_triggerid, row[0]);
329
330 if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_prototypes, &parent_triggerid,
331 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
332 {
333 THIS_SHOULD_NEVER_HAPPEN;
334 continue;
335 }
336
337 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
338
339 trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
340
341 ZBX_STR2UINT64(trigger->triggerid, row[1]);
342 trigger->parent_triggerid = parent_triggerid;
343 trigger->description = zbx_strdup(NULL, row[2]);
344 trigger->description_orig = NULL;
345 trigger->expression = zbx_strdup(NULL, row[3]);
346 trigger->expression_orig = NULL;
347
348 trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
349
350 if ((unsigned char)atoi(row[4]) != trigger_prototype->type)
351 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE;
352
353 if ((unsigned char)atoi(row[5]) != trigger_prototype->priority)
354 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY;
355
356 trigger->comments = zbx_strdup(NULL, row[6]);
357 trigger->comments_orig = NULL;
358 trigger->url = zbx_strdup(NULL, row[7]);
359 trigger->url_orig = NULL;
360
361 zbx_vector_ptr_create(&trigger->functions);
362 zbx_vector_ptr_create(&trigger->dependencies);
363 zbx_vector_ptr_create(&trigger->dependents);
364
365 zbx_vector_ptr_append(triggers, trigger);
366 }
367 DBfree_result(result);
368
369 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
370
371 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
372 }
373
374 /******************************************************************************
375 * *
376 * Function: lld_functions_get *
377 * *
378 * Purpose: retrieve functions which are used by all triggers in the host of *
379 * the trigger prototype *
380 * *
381 ******************************************************************************/
lld_functions_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)382 static void lld_functions_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
383 {
384 const char *__function_name = "lld_functions_get";
385
386 int i;
387 zbx_lld_trigger_prototype_t *trigger_prototype;
388 zbx_lld_trigger_t *trigger;
389 zbx_vector_uint64_t triggerids;
390
391 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
392
393 zbx_vector_uint64_create(&triggerids);
394
395 if (NULL != trigger_prototypes)
396 {
397 for (i = 0; i < trigger_prototypes->values_num; i++)
398 {
399 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
400
401 zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
402 }
403 }
404
405 for (i = 0; i < triggers->values_num; i++)
406 {
407 trigger = (zbx_lld_trigger_t *)triggers->values[i];
408
409 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
410 }
411
412 if (0 != triggerids.values_num)
413 {
414 DB_RESULT result;
415 DB_ROW row;
416 zbx_lld_function_t *function;
417 zbx_uint64_t triggerid;
418 char *sql = NULL;
419 size_t sql_alloc = 256, sql_offset = 0;
420 int index;
421
422 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
423
424 sql = zbx_malloc(sql, sql_alloc);
425
426 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
427 "select functionid,triggerid,itemid,function,parameter"
428 " from functions"
429 " where");
430 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
431 triggerids.values, triggerids.values_num);
432
433 result = DBselect("%s", sql);
434
435 zbx_free(sql);
436
437 while (NULL != (row = DBfetch(result)))
438 {
439 function = zbx_malloc(NULL, sizeof(zbx_lld_function_t));
440
441 function->index = 0;
442 ZBX_STR2UINT64(function->functionid, row[0]);
443 ZBX_STR2UINT64(triggerid, row[1]);
444 ZBX_STR2UINT64(function->itemid, row[2]);
445 function->itemid_orig = 0;
446 function->function = zbx_strdup(NULL, row[3]);
447 function->function_orig = NULL;
448 function->parameter = zbx_strdup(NULL, row[4]);
449 function->parameter_orig = NULL;
450 function->flags = ZBX_FLAG_LLD_FUNCTION_UNSET;
451
452 if (NULL != trigger_prototypes && FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes,
453 &triggerid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
454 {
455 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
456
457 zbx_vector_ptr_append(&trigger_prototype->functions, function);
458 }
459 else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
460 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
461 {
462 trigger = (zbx_lld_trigger_t *)triggers->values[index];
463
464 zbx_vector_ptr_append(&trigger->functions, function);
465 }
466 else
467 {
468 THIS_SHOULD_NEVER_HAPPEN;
469 lld_function_free(function);
470 }
471 }
472 DBfree_result(result);
473
474 if (NULL != trigger_prototypes)
475 {
476 for (i = 0; i < trigger_prototypes->values_num; i++)
477 {
478 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
479
480 zbx_vector_ptr_sort(&trigger_prototype->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
481 }
482 }
483
484 for (i = 0; i < triggers->values_num; i++)
485 {
486 trigger = (zbx_lld_trigger_t *)triggers->values[i];
487
488 zbx_vector_ptr_sort(&trigger->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
489 }
490 }
491
492 zbx_vector_uint64_destroy(&triggerids);
493
494 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
495 }
496
497 /******************************************************************************
498 * *
499 * Function: lld_dependencies_get *
500 * *
501 * Purpose: retrieve trigger dependencies *
502 * *
503 ******************************************************************************/
lld_dependencies_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)504 static void lld_dependencies_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
505 {
506 const char *__function_name = "lld_dependencies_get";
507
508 DB_RESULT result;
509 DB_ROW row;
510 zbx_lld_trigger_prototype_t *trigger_prototype;
511 zbx_lld_trigger_t *trigger;
512 zbx_lld_dependency_t *dependency;
513 zbx_vector_uint64_t triggerids;
514 zbx_uint64_t triggerid_down;
515 char *sql = NULL;
516 size_t sql_alloc = 256, sql_offset = 0;
517 int i, index;
518
519 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
520
521 zbx_vector_uint64_create(&triggerids);
522
523 for (i = 0; i < trigger_prototypes->values_num; i++)
524 {
525 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
526
527 zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
528 }
529
530 for (i = 0; i < triggers->values_num; i++)
531 {
532 trigger = (zbx_lld_trigger_t *)triggers->values[i];
533
534 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
535 }
536
537 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
538
539 sql = zbx_malloc(sql, sql_alloc);
540
541 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
542 "select triggerdepid,triggerid_down,triggerid_up"
543 " from trigger_depends"
544 " where");
545 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid_down",
546 triggerids.values, triggerids.values_num);
547
548 zbx_vector_uint64_destroy(&triggerids);
549
550 result = DBselect("%s", sql);
551
552 zbx_free(sql);
553
554 while (NULL != (row = DBfetch(result)))
555 {
556 dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
557
558 ZBX_STR2UINT64(dependency->triggerdepid, row[0]);
559 ZBX_STR2UINT64(triggerid_down, row[1]);
560 ZBX_STR2UINT64(dependency->triggerid_up, row[2]);
561 dependency->trigger_up = NULL;
562 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
563
564 if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_down,
565 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
566 {
567 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
568
569 zbx_vector_ptr_append(&trigger_prototype->dependencies, dependency);
570 }
571 else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid_down,
572 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
573 {
574 trigger = (zbx_lld_trigger_t *)triggers->values[index];
575
576 zbx_vector_ptr_append(&trigger->dependencies, dependency);
577 }
578 else
579 {
580 THIS_SHOULD_NEVER_HAPPEN;
581 zbx_ptr_free(dependency);
582 }
583 }
584 DBfree_result(result);
585
586 for (i = 0; i < trigger_prototypes->values_num; i++)
587 {
588 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
589
590 zbx_vector_ptr_sort(&trigger_prototype->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
591 }
592
593 for (i = 0; i < triggers->values_num; i++)
594 {
595 trigger = (zbx_lld_trigger_t *)triggers->values[i];
596
597 zbx_vector_ptr_sort(&trigger->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
598 }
599
600 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
601 }
602
603 /******************************************************************************
604 * *
605 * Function: lld_items_get *
606 * *
607 * Purpose: returns the list of items which are related to the trigger *
608 * prototypes *
609 * *
610 * Parameters: trigger_prototypes - [IN] a vector of trigger prototypes *
611 * items - [OUT] sorted list of items *
612 * *
613 ******************************************************************************/
lld_items_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * items)614 static void lld_items_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *items)
615 {
616 const char *__function_name = "lld_items_get";
617
618 DB_RESULT result;
619 DB_ROW row;
620 zbx_lld_item_t *item;
621 zbx_vector_uint64_t parent_triggerids;
622 char *sql = NULL;
623 size_t sql_alloc = 256, sql_offset = 0;
624 int i;
625
626 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
627
628 zbx_vector_uint64_create(&parent_triggerids);
629 zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
630
631 for (i = 0; i < trigger_prototypes->values_num; i++)
632 {
633 zbx_lld_trigger_prototype_t *trigger_prototype;
634
635 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
636
637 zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
638 }
639 sql = zbx_malloc(sql, sql_alloc);
640
641 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
642 "select distinct i.itemid,i.flags"
643 " from items i,functions f"
644 " where i.itemid=f.itemid"
645 " and");
646 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "f.triggerid",
647 parent_triggerids.values, parent_triggerids.values_num);
648
649 zbx_vector_uint64_destroy(&parent_triggerids);
650
651 result = DBselect("%s", sql);
652
653 zbx_free(sql);
654
655 while (NULL != (row = DBfetch(result)))
656 {
657 item = zbx_malloc(NULL, sizeof(zbx_lld_item_t));
658
659 ZBX_STR2UINT64(item->itemid, row[0]);
660 ZBX_STR2UCHAR(item->flags, row[1]);
661
662 zbx_vector_ptr_append(items, item);
663 }
664 DBfree_result(result);
665
666 zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
667
668 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
669 }
670
671 /******************************************************************************
672 * *
673 * Function: lld_trigger_get *
674 * *
675 * Purpose: finds already existing trigger, using an item prototype and items *
676 * already created by it *
677 * *
678 * Return value: upon successful completion return pointer to the trigger *
679 * *
680 ******************************************************************************/
lld_trigger_get(zbx_uint64_t parent_triggerid,zbx_hashset_t * items_triggers,const zbx_vector_ptr_t * item_links)681 static zbx_lld_trigger_t *lld_trigger_get(zbx_uint64_t parent_triggerid, zbx_hashset_t *items_triggers,
682 const zbx_vector_ptr_t *item_links)
683 {
684 int i;
685
686 for (i = 0; i < item_links->values_num; i++)
687 {
688 zbx_lld_item_trigger_t *item_trigger, item_trigger_local;
689 const zbx_lld_item_link_t *item_link = (zbx_lld_item_link_t *)item_links->values[i];
690
691 item_trigger_local.parent_triggerid = parent_triggerid;
692 item_trigger_local.itemid = item_link->itemid;
693
694 if (NULL != (item_trigger = zbx_hashset_search(items_triggers, &item_trigger_local)))
695 return item_trigger->trigger;
696 }
697
698 return NULL;
699 }
700
lld_expression_simplify(char ** expression,zbx_vector_ptr_t * functions)701 static void lld_expression_simplify(char **expression, zbx_vector_ptr_t *functions)
702 {
703 const char *__function_name = "lld_expression_simplify";
704
705 size_t l, r;
706 int index;
707 zbx_uint64_t functionid, function_index = 0;
708 zbx_lld_function_t *function;
709 char buffer[ZBX_MAX_UINT64_LEN];
710
711 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
712
713 for (l = 0; '\0' != (*expression)[l]; l++)
714 {
715 if ('{' != (*expression)[l])
716 continue;
717
718 if ('$' == (*expression)[l + 1])
719 {
720 int macro_r, context_l, context_r;
721
722 if (SUCCEED == zbx_user_macro_parse(*expression + l, ¯o_r, &context_l, &context_r))
723 l += macro_r;
724 else
725 l++;
726
727 continue;
728 }
729
730 for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
731 ;
732
733 if ('}' != (*expression)[r])
734 continue;
735
736 /* ... > 0 | {12345} + ... */
737 /* l r */
738
739 if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &functionid))
740 continue;
741
742 if (FAIL != (index = zbx_vector_ptr_bsearch(functions, &functionid,
743 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
744 {
745 function = (zbx_lld_function_t *)functions->values[index];
746
747 if (0 == function->index)
748 function->index = ++function_index;
749
750 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->index);
751
752 r--;
753 zbx_replace_string(expression, l + 1, &r, buffer);
754 r++;
755 }
756
757 l = r;
758 }
759
760 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
761 }
762
lld_expression_expand(const char * expression,const zbx_vector_ptr_t * functions)763 static char *lld_expression_expand(const char *expression, const zbx_vector_ptr_t *functions)
764 {
765 const char *__function_name = "lld_expression_expand";
766
767 size_t l, r;
768 int i;
769 zbx_uint64_t index;
770 char *buffer = NULL;
771 size_t buffer_alloc = 64, buffer_offset = 0;
772
773 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, expression);
774
775 buffer = zbx_malloc(buffer, buffer_alloc);
776
777 *buffer = '\0';
778
779 for (l = 0; '\0' != expression[l]; l++)
780 {
781 zbx_chrcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, expression[l]);
782
783 if ('{' != expression[l])
784 continue;
785
786 if ('$' == expression[l + 1])
787 {
788 int macro_r, context_l, context_r;
789
790 if (SUCCEED == zbx_user_macro_parse(expression + l, ¯o_r, &context_l, &context_r))
791 l += macro_r;
792 else
793 l++;
794
795 continue;
796 }
797
798 for (r = l + 1; '\0' != expression[r] && '}' != expression[r]; r++)
799 ;
800
801 if ('}' != expression[r])
802 continue;
803
804 /* ... > 0 | {1} + ... */
805 /* l r */
806
807 if (SUCCEED != is_uint64_n(expression + l + 1, r - l - 1, &index))
808 continue;
809
810 for (i = 0; i < functions->values_num; i++)
811 {
812 const zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
813
814 if (function->index != index)
815 continue;
816
817 zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, ZBX_FS_UI64 ":%s(%s)",
818 function->itemid, function->function, function->parameter);
819
820 break;
821 }
822
823 l = r - 1;
824 }
825
826 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():'%s'", __function_name, buffer);
827
828 return buffer;
829 }
830
lld_function_make(const zbx_lld_function_t * function_proto,zbx_vector_ptr_t * functions,zbx_uint64_t itemid)831 static void lld_function_make(const zbx_lld_function_t *function_proto, zbx_vector_ptr_t *functions,
832 zbx_uint64_t itemid)
833 {
834 int i;
835 zbx_lld_function_t *function = NULL;
836
837 for (i = 0; i < functions->values_num; i++)
838 {
839 function = (zbx_lld_function_t *)functions->values[i];
840
841 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
842 continue;
843
844 if (function->index == function_proto->index)
845 break;
846 }
847
848 if (i == functions->values_num)
849 {
850 function = zbx_malloc(NULL, sizeof(zbx_lld_function_t));
851
852 function->index = function_proto->index;
853 function->functionid = 0;
854 function->itemid = itemid;
855 function->itemid_orig = 0;
856 function->function = zbx_strdup(NULL, function_proto->function);
857 function->function_orig = NULL;
858 function->parameter = zbx_strdup(NULL, function_proto->parameter);
859 function->parameter_orig = NULL;
860 function->flags = ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
861
862 zbx_vector_ptr_append(functions, function);
863 }
864 else
865 {
866 if (function->itemid != itemid)
867 {
868 function->itemid_orig = function->itemid;
869 function->itemid = itemid;
870 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID;
871 }
872
873 if (0 != strcmp(function->function, function_proto->function))
874 {
875 function->function_orig = function->function;
876 function->function = zbx_strdup(NULL, function_proto->function);
877 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION;
878 }
879
880 if (0 != strcmp(function->parameter, function_proto->parameter))
881 {
882 function->parameter_orig = function->parameter;
883 function->parameter = zbx_strdup(NULL, function_proto->parameter);
884 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER;
885 }
886
887 function->flags |= ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
888 }
889 }
890
lld_functions_delete(zbx_vector_ptr_t * functions)891 static void lld_functions_delete(zbx_vector_ptr_t *functions)
892 {
893 int i;
894
895 for (i = 0; i < functions->values_num; i++)
896 {
897 zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
898
899 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
900 continue;
901
902 function->flags |= ZBX_FLAG_LLD_FUNCTION_DELETE;
903 }
904 }
905
lld_functions_make(const zbx_vector_ptr_t * functions_proto,zbx_vector_ptr_t * functions,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * item_links)906 static int lld_functions_make(const zbx_vector_ptr_t *functions_proto, zbx_vector_ptr_t *functions,
907 const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *item_links)
908 {
909 const char *__function_name = "lld_functions_make";
910
911 int i, index, ret = FAIL;
912 const zbx_lld_function_t *function_proto;
913 const zbx_lld_item_t *item_proto;
914 const zbx_lld_item_link_t *item_link;
915 zbx_uint64_t itemid;
916
917 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
918
919 for (i = 0; i < functions_proto->values_num; i++)
920 {
921 function_proto = (zbx_lld_function_t *)functions_proto->values[i];
922
923 index = zbx_vector_ptr_bsearch(items, &function_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
924
925 if (FAIL == index)
926 goto out;
927
928 item_proto = (zbx_lld_item_t *)items->values[index];
929
930 if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
931 {
932 index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid,
933 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
934
935 if (FAIL == index)
936 goto out;
937
938 item_link = (zbx_lld_item_link_t *)item_links->values[index];
939
940 itemid = item_link->itemid;
941 }
942 else
943 itemid = item_proto->itemid;
944
945 lld_function_make(function_proto, functions, itemid);
946 }
947
948 lld_functions_delete(functions);
949
950 ret = SUCCEED;
951 out:
952 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
953
954 return ret;
955 }
956
957 /******************************************************************************
958 * *
959 * Function: lld_trigger_make *
960 * *
961 * Purpose: create a trigger based on lld rule and add it to the list *
962 * *
963 ******************************************************************************/
lld_trigger_make(const zbx_lld_trigger_prototype_t * trigger_prototype,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)964 static void lld_trigger_make(const zbx_lld_trigger_prototype_t *trigger_prototype, zbx_vector_ptr_t *triggers,
965 const zbx_vector_ptr_t *items, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row, char **error)
966 {
967 const char *__function_name = "lld_trigger_make";
968
969 zbx_lld_trigger_t *trigger;
970 char *buffer = NULL, *expression = NULL, err[64];
971 const struct zbx_json_parse *jp_row = &lld_row->jp_row;
972
973 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
974
975 trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links);
976
977 expression = zbx_strdup(expression, trigger_prototype->expression);
978 if (SUCCEED != substitute_discovery_macros(&expression, jp_row, ZBX_MACRO_NUMERIC, err, sizeof(err)))
979 {
980 *error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", (NULL != trigger ? "update" : "create"), err);
981 goto out;
982 }
983
984 if (NULL != trigger)
985 {
986 buffer = zbx_strdup(buffer, trigger_prototype->description);
987 substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
988 zbx_lrtrim(buffer, ZBX_WHITESPACE);
989 if (0 != strcmp(trigger->description, buffer))
990 {
991 trigger->description_orig = trigger->description;
992 trigger->description = buffer;
993 buffer = NULL;
994 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION;
995 }
996
997 if (0 != strcmp(trigger->expression, expression))
998 {
999 trigger->expression_orig = trigger->expression;
1000 trigger->expression = expression;
1001 expression = NULL;
1002 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION;
1003 }
1004
1005 buffer = zbx_strdup(buffer, trigger_prototype->comments);
1006 substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
1007 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1008 if (0 != strcmp(trigger->comments, buffer))
1009 {
1010 trigger->comments_orig = trigger->comments;
1011 trigger->comments = buffer;
1012 buffer = NULL;
1013 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS;
1014 }
1015
1016 buffer = zbx_strdup(buffer, trigger_prototype->url);
1017 substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
1018 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1019 if (0 != strcmp(trigger->url, buffer))
1020 {
1021 trigger->url_orig = trigger->url;
1022 trigger->url = buffer;
1023 buffer = NULL;
1024 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_URL;
1025 }
1026 }
1027 else
1028 {
1029 trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1030
1031 trigger->triggerid = 0;
1032 trigger->parent_triggerid = trigger_prototype->triggerid;
1033
1034 trigger->description = zbx_strdup(NULL, trigger_prototype->description);
1035 trigger->description_orig = NULL;
1036 substitute_discovery_macros(&trigger->description, jp_row, ZBX_MACRO_ANY, NULL, 0);
1037 zbx_lrtrim(trigger->description, ZBX_WHITESPACE);
1038
1039 trigger->expression = expression;
1040 trigger->expression_orig = NULL;
1041 expression = NULL;
1042
1043 trigger->comments = zbx_strdup(NULL, trigger_prototype->comments);
1044 trigger->comments_orig = NULL;
1045 substitute_discovery_macros(&trigger->comments, jp_row, ZBX_MACRO_ANY, NULL, 0);
1046 zbx_lrtrim(trigger->comments, ZBX_WHITESPACE);
1047
1048 trigger->url = zbx_strdup(NULL, trigger_prototype->url);
1049 trigger->url_orig = NULL;
1050 substitute_discovery_macros(&trigger->url, jp_row, ZBX_MACRO_ANY, NULL, 0);
1051 zbx_lrtrim(trigger->url, ZBX_WHITESPACE);
1052
1053 zbx_vector_ptr_create(&trigger->functions);
1054 zbx_vector_ptr_create(&trigger->dependencies);
1055 zbx_vector_ptr_create(&trigger->dependents);
1056
1057 trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1058
1059 zbx_vector_ptr_append(triggers, trigger);
1060 }
1061
1062 zbx_free(buffer);
1063
1064 if (SUCCEED != lld_functions_make(&trigger_prototype->functions, &trigger->functions, items,
1065 &lld_row->item_links))
1066 goto out;
1067
1068 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1069 out:
1070 zbx_free(expression);
1071
1072 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1073 }
1074
items_triggers_hash_func(const void * data)1075 static zbx_hash_t items_triggers_hash_func(const void *data)
1076 {
1077 const zbx_lld_item_trigger_t *item_trigger = data;
1078 zbx_hash_t hash;
1079
1080 hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_trigger->parent_triggerid);
1081 hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&item_trigger->itemid, sizeof(zbx_uint64_t), hash);
1082
1083 return hash;
1084 }
1085
items_triggers_compare_func(const void * d1,const void * d2)1086 static int items_triggers_compare_func(const void *d1, const void *d2)
1087 {
1088 const zbx_lld_item_trigger_t *item_trigger1 = d1, *item_trigger2 = d2;
1089
1090 ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->parent_triggerid, item_trigger2->parent_triggerid);
1091 ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->itemid, item_trigger2->itemid);
1092
1093 return 0;
1094 }
1095
lld_triggers_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * lld_rows,char ** error)1096 static void lld_triggers_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1097 const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows, char **error)
1098 {
1099 const zbx_lld_trigger_prototype_t *trigger_prototype;
1100 int i, j;
1101 zbx_hashset_t items_triggers;
1102 zbx_lld_trigger_t *trigger;
1103 const zbx_lld_function_t *function;
1104 zbx_lld_item_trigger_t item_trigger;
1105
1106 /* used for fast search of trigger by item prototype */
1107 zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1108
1109 for (i = 0; i < triggers->values_num; i++)
1110 {
1111 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1112
1113 for (j = 0; j < trigger->functions.values_num; j++)
1114 {
1115 function = (zbx_lld_function_t *)trigger->functions.values[j];
1116
1117 item_trigger.parent_triggerid = trigger->parent_triggerid;
1118 item_trigger.itemid = function->itemid;
1119 item_trigger.trigger = trigger;
1120 zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1121 }
1122 }
1123
1124 for (i = 0; i < trigger_prototypes->values_num; i++)
1125 {
1126 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1127
1128 for (j = 0; j < lld_rows->values_num; j++)
1129 {
1130 zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1131
1132 lld_trigger_make(trigger_prototype, triggers, items, &items_triggers, lld_row, error);
1133 }
1134 }
1135
1136 zbx_hashset_destroy(&items_triggers);
1137
1138 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1139 }
1140
1141 /******************************************************************************
1142 * *
1143 * Function: lld_trigger_dependency_make *
1144 * *
1145 * Purpose: create a trigger dependencies *
1146 * *
1147 ******************************************************************************/
lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t * trigger_prototype,const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * items,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)1148 static void lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t *trigger_prototype,
1149 const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *items,
1150 zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row, char **error)
1151 {
1152 const char *__function_name = "lld_trigger_dependency_make";
1153
1154 zbx_lld_trigger_t *trigger, *dep_trigger;
1155 const zbx_lld_trigger_prototype_t *dep_trigger_prototype;
1156 zbx_lld_dependency_t *dependency;
1157 zbx_uint64_t triggerid_up;
1158 int i, j, index;
1159
1160 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1161
1162 if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1163 goto out;
1164
1165 for (i = 0; i < trigger_prototype->dependencies.values_num; i++)
1166 {
1167 triggerid_up = ((zbx_lld_dependency_t *)trigger_prototype->dependencies.values[i])->triggerid_up;
1168
1169 index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_up, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1170
1171 if (FAIL != index)
1172 {
1173 /* creating trigger dependency based on trigger prototype */
1174
1175 dep_trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1176
1177 dep_trigger = lld_trigger_get(dep_trigger_prototype->triggerid, items_triggers,
1178 &lld_row->item_links);
1179
1180 if (NULL != dep_trigger)
1181 {
1182 if (0 == dep_trigger->triggerid)
1183 {
1184 dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1185
1186 dependency->triggerdepid = 0;
1187 dependency->triggerid_up = 0;
1188
1189 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1190 }
1191 else
1192 {
1193 for (j = 0; j < trigger->dependencies.values_num; j++)
1194 {
1195 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1196
1197 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1198 continue;
1199
1200 if (dependency->triggerid_up == dep_trigger->triggerid)
1201 break;
1202 }
1203
1204 if (j == trigger->dependencies.values_num)
1205 {
1206 dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1207
1208 dependency->triggerdepid = 0;
1209 dependency->triggerid_up = dep_trigger->triggerid;
1210
1211 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1212 }
1213 }
1214
1215 zbx_vector_ptr_append(&dep_trigger->dependents, trigger);
1216
1217 dependency->trigger_up = dep_trigger;
1218 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1219 }
1220 else
1221 {
1222 *error = zbx_strdcatf(*error, "Cannot create dependency on trigger \"%s\".\n",
1223 trigger->description);
1224 }
1225 }
1226 else
1227 {
1228 /* creating trigger dependency based on generic trigger */
1229
1230 for (j = 0; j < trigger->dependencies.values_num; j++)
1231 {
1232 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1233
1234 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1235 continue;
1236
1237 if (dependency->triggerid_up == triggerid_up)
1238 break;
1239 }
1240
1241 if (j == trigger->dependencies.values_num)
1242 {
1243 dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1244
1245 dependency->triggerdepid = 0;
1246 dependency->triggerid_up = triggerid_up;
1247 dependency->trigger_up = NULL;
1248
1249 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1250 }
1251
1252 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1253 }
1254 }
1255 out:
1256 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1257 }
1258
lld_trigger_dependencies_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * items,const zbx_vector_ptr_t * lld_rows,char ** error)1259 static void lld_trigger_dependencies_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1260 zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows, char **error)
1261 {
1262 const zbx_lld_trigger_prototype_t *trigger_prototype;
1263 int i, j;
1264 zbx_hashset_t items_triggers;
1265 zbx_lld_trigger_t *trigger;
1266 zbx_lld_function_t *function;
1267 zbx_lld_item_trigger_t item_trigger;
1268 zbx_lld_dependency_t *dependency;
1269
1270 for (i = 0; i < trigger_prototypes->values_num; i++)
1271 {
1272 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1273
1274 if (0 != trigger_prototype->dependencies.values_num)
1275 break;
1276 }
1277
1278 for (j = 0; j < triggers->values_num; j++)
1279 {
1280 trigger = (zbx_lld_trigger_t *)triggers->values[j];
1281
1282 if (0 != trigger->dependencies.values_num)
1283 break;
1284 }
1285
1286 /* all trigger prototypes and triggers have no dependencies */
1287 if (i == trigger_prototypes->values_num && j == triggers->values_num)
1288 return;
1289
1290 /* used for fast search of trigger by item prototype */
1291 zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1292
1293 for (i = 0; i < triggers->values_num; i++)
1294 {
1295 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1296
1297 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1298 continue;
1299
1300 for (j = 0; j < trigger->functions.values_num; j++)
1301 {
1302 function = (zbx_lld_function_t *)trigger->functions.values[j];
1303
1304 item_trigger.parent_triggerid = trigger->parent_triggerid;
1305 item_trigger.itemid = function->itemid;
1306 item_trigger.trigger = trigger;
1307 zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1308 }
1309 }
1310
1311 for (i = 0; i < trigger_prototypes->values_num; i++)
1312 {
1313 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1314
1315 for (j = 0; j < lld_rows->values_num; j++)
1316 {
1317 zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1318
1319 lld_trigger_dependency_make(trigger_prototype, trigger_prototypes, triggers, items,
1320 &items_triggers, lld_row, error);
1321 }
1322 }
1323
1324 /* marking dependencies which will be deleted */
1325 for (i = 0; i < triggers->values_num; i++)
1326 {
1327 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1328
1329 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1330 continue;
1331
1332 for (j = 0; j < trigger->dependencies.values_num; j++)
1333 {
1334 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1335
1336 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1337 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DELETE;
1338 }
1339 }
1340
1341 zbx_hashset_destroy(&items_triggers);
1342
1343 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1344 }
1345
1346 /******************************************************************************
1347 * *
1348 * Function: lld_validate_trigger_field *
1349 * *
1350 ******************************************************************************/
lld_validate_trigger_field(zbx_lld_trigger_t * trigger,char ** field,char ** field_orig,zbx_uint64_t flag,size_t field_len,char ** error)1351 static void lld_validate_trigger_field(zbx_lld_trigger_t *trigger, char **field, char **field_orig,
1352 zbx_uint64_t flag, size_t field_len, char **error)
1353 {
1354 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1355 return;
1356
1357 /* only new triggers or triggers with changed data will be validated */
1358 if (0 != trigger->triggerid && 0 == (trigger->flags & flag))
1359 return;
1360
1361 if (SUCCEED != zbx_is_utf8(*field))
1362 {
1363 zbx_replace_invalid_utf8(*field);
1364 *error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" has invalid UTF-8 sequence.\n",
1365 (0 != trigger->triggerid ? "update" : "create"), *field);
1366 }
1367 else if (zbx_strlen_utf8(*field) > field_len)
1368 {
1369 *error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" is too long.\n",
1370 (0 != trigger->triggerid ? "update" : "create"), *field);
1371 }
1372 else if (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION == flag && '\0' == **field)
1373 {
1374 *error = zbx_strdcatf(*error, "Cannot %s trigger: name is empty.\n",
1375 (0 != trigger->triggerid ? "update" : "create"));
1376 }
1377 else
1378 return;
1379
1380 if (0 != trigger->triggerid)
1381 lld_field_str_rollback(field, field_orig, &trigger->flags, flag);
1382 else
1383 trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1384 }
1385
1386 /******************************************************************************
1387 * *
1388 * Function: lld_trigger_changed *
1389 * *
1390 * Return value: returns SUCCEED if a trigger description or expression has *
1391 * been changed; FAIL - otherwise *
1392 * *
1393 ******************************************************************************/
lld_trigger_changed(const zbx_lld_trigger_t * trigger)1394 static int lld_trigger_changed(const zbx_lld_trigger_t *trigger)
1395 {
1396 int i;
1397 zbx_lld_function_t *function;
1398
1399 if (0 == trigger->triggerid)
1400 return SUCCEED;
1401
1402 if (0 != (trigger->flags & (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION)))
1403 return SUCCEED;
1404
1405 for (i = 0; i < trigger->functions.values_num; i++)
1406 {
1407 function = (zbx_lld_function_t *)trigger->functions.values[i];
1408
1409 if (0 == function->functionid)
1410 {
1411 THIS_SHOULD_NEVER_HAPPEN;
1412 return SUCCEED;
1413 }
1414
1415 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1416 return SUCCEED;
1417 }
1418
1419 return FAIL;
1420 }
1421
1422 /******************************************************************************
1423 * *
1424 * Function: lld_triggers_equal *
1425 * *
1426 * Return value: returns SUCCEED if descriptions and expressions of *
1427 * the triggers are identical; FAIL - otherwise *
1428 * *
1429 ******************************************************************************/
lld_triggers_equal(const zbx_lld_trigger_t * trigger,const zbx_lld_trigger_t * trigger_b)1430 static int lld_triggers_equal(const zbx_lld_trigger_t *trigger, const zbx_lld_trigger_t *trigger_b)
1431 {
1432 const char *__function_name = "lld_triggers_equal";
1433
1434 int ret = FAIL;
1435
1436 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1437
1438 if (0 == strcmp(trigger->description, trigger_b->description))
1439 {
1440 char *expression, *expression_b;
1441
1442 expression = lld_expression_expand(trigger->expression, &trigger->functions);
1443 expression_b = lld_expression_expand(trigger_b->expression, &trigger_b->functions);
1444
1445 if (0 == strcmp(expression, expression_b))
1446 ret = SUCCEED;
1447
1448 zbx_free(expression);
1449 zbx_free(expression_b);
1450 }
1451
1452 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1453
1454 return ret;
1455 }
1456
1457 /******************************************************************************
1458 * *
1459 * Function: lld_triggers_validate *
1460 * *
1461 * Parameters: triggers - [IN] sorted list of triggers *
1462 * *
1463 ******************************************************************************/
lld_triggers_validate(zbx_uint64_t hostid,zbx_vector_ptr_t * triggers,char ** error)1464 static void lld_triggers_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *triggers, char **error)
1465 {
1466 const char *__function_name = "lld_triggers_validate";
1467
1468 int i, j, k;
1469 zbx_lld_trigger_t *trigger;
1470 zbx_lld_function_t *function;
1471 zbx_vector_uint64_t triggerids;
1472 zbx_vector_str_t descriptions;
1473
1474 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1475
1476 zbx_vector_uint64_create(&triggerids);
1477 zbx_vector_str_create(&descriptions);
1478
1479 /* checking a validity of the fields */
1480
1481 for (i = 0; i < triggers->values_num; i++)
1482 {
1483 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1484
1485 lld_validate_trigger_field(trigger, &trigger->description, &trigger->description_orig,
1486 ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION, TRIGGER_DESCRIPTION_LEN, error);
1487 lld_validate_trigger_field(trigger, &trigger->comments, &trigger->comments_orig,
1488 ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS, TRIGGER_COMMENTS_LEN, error);
1489 lld_validate_trigger_field(trigger, &trigger->url, &trigger->url_orig,
1490 ZBX_FLAG_LLD_TRIGGER_UPDATE_URL, TRIGGER_URL_LEN, error);
1491 }
1492
1493 /* checking duplicated triggers in DB */
1494
1495 for (i = 0; i < triggers->values_num; i++)
1496 {
1497 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1498
1499 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1500 continue;
1501
1502 if (0 != trigger->triggerid)
1503 {
1504 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
1505
1506 if (SUCCEED != lld_trigger_changed(trigger))
1507 continue;
1508 }
1509
1510 zbx_vector_str_append(&descriptions, trigger->description);
1511 }
1512
1513 if (0 != descriptions.values_num)
1514 {
1515 char *sql = NULL;
1516 size_t sql_alloc = 256, sql_offset = 0;
1517 DB_RESULT result;
1518 DB_ROW row;
1519 zbx_vector_ptr_t db_triggers;
1520 zbx_lld_trigger_t *db_trigger;
1521
1522 zbx_vector_ptr_create(&db_triggers);
1523
1524 zbx_vector_str_sort(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
1525 zbx_vector_str_uniq(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
1526
1527 sql = zbx_malloc(sql, sql_alloc);
1528
1529 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1530 "select distinct t.triggerid,t.description,t.expression"
1531 " from triggers t,functions f,items i"
1532 " where t.triggerid=f.triggerid"
1533 " and f.itemid=i.itemid"
1534 " and i.hostid=" ZBX_FS_UI64
1535 " and",
1536 hostid);
1537 DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.description",
1538 (const char **)descriptions.values, descriptions.values_num);
1539
1540 if (0 != triggerids.values_num)
1541 {
1542 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1543 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
1544 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid",
1545 triggerids.values, triggerids.values_num);
1546 }
1547
1548 result = DBselect("%s", sql);
1549
1550 while (NULL != (row = DBfetch(result)))
1551 {
1552 db_trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1553
1554 ZBX_STR2UINT64(db_trigger->triggerid, row[0]);
1555 db_trigger->description = zbx_strdup(NULL, row[1]);
1556 db_trigger->description_orig = NULL;
1557 db_trigger->expression = zbx_strdup(NULL, row[2]);
1558 db_trigger->expression_orig = NULL;
1559 db_trigger->comments = NULL;
1560 db_trigger->comments_orig = NULL;
1561 db_trigger->url = NULL;
1562 db_trigger->url_orig = NULL;
1563 db_trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1564
1565 zbx_vector_ptr_create(&db_trigger->functions);
1566 zbx_vector_ptr_create(&db_trigger->dependencies);
1567 zbx_vector_ptr_create(&db_trigger->dependents);
1568
1569 zbx_vector_ptr_append(&db_triggers, db_trigger);
1570 }
1571 DBfree_result(result);
1572
1573 zbx_vector_ptr_sort(&db_triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1574
1575 lld_functions_get(NULL, &db_triggers);
1576
1577 for (i = 0; i < db_triggers.values_num; i++)
1578 {
1579 db_trigger = (zbx_lld_trigger_t *)db_triggers.values[i];
1580
1581 lld_expression_simplify(&db_trigger->expression, &db_trigger->functions);
1582
1583 for (j = 0; j < triggers->values_num; j++)
1584 {
1585 trigger = (zbx_lld_trigger_t *)triggers->values[j];
1586
1587 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1588 continue;
1589
1590 if (SUCCEED != lld_triggers_equal(trigger, db_trigger))
1591 continue;
1592
1593 *error = zbx_strdcatf(*error, "Cannot %s trigger: trigger \"%s\" already exists.\n",
1594 (0 != trigger->triggerid ? "update" : "create"), trigger->description);
1595
1596 if (0 != trigger->triggerid)
1597 {
1598 lld_field_str_rollback(&trigger->description, &trigger->description_orig,
1599 &trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION);
1600
1601 lld_field_str_rollback(&trigger->expression, &trigger->expression_orig,
1602 &trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION);
1603
1604 for (k = 0; k < trigger->functions.values_num; k++)
1605 {
1606 function = (zbx_lld_function_t *)trigger->functions.values[k];
1607
1608 if (0 != function->functionid)
1609 {
1610 lld_field_uint64_rollback(&function->itemid,
1611 &function->itemid_orig,
1612 &function->flags,
1613 ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID);
1614
1615 lld_field_str_rollback(&function->function,
1616 &function->function_orig,
1617 &function->flags,
1618 ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION);
1619
1620 lld_field_str_rollback(&function->parameter,
1621 &function->parameter_orig,
1622 &function->flags,
1623 ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER);
1624
1625 function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DELETE;
1626 }
1627 else
1628 function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1629 }
1630 }
1631 else
1632 trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1633
1634 break; /* only one same trigger can be here */
1635 }
1636 }
1637
1638 zbx_vector_ptr_clear_ext(&db_triggers, (zbx_clean_func_t)lld_trigger_free);
1639 zbx_vector_ptr_destroy(&db_triggers);
1640
1641 zbx_free(sql);
1642 }
1643
1644 zbx_vector_str_destroy(&descriptions);
1645 zbx_vector_uint64_destroy(&triggerids);
1646
1647 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1648 }
1649
1650 /******************************************************************************
1651 * *
1652 * Function: lld_expression_create *
1653 * *
1654 * Purpose: transforms the simple trigger expression to the DB format *
1655 * *
1656 * Example: *
1657 * *
1658 * "{1} > 5" => "{84756} > 5" *
1659 * ^ ^ *
1660 * | functionid from the database *
1661 * internal function index *
1662 * *
1663 ******************************************************************************/
lld_expression_create(char ** expression,const zbx_vector_ptr_t * functions)1664 static void lld_expression_create(char **expression, const zbx_vector_ptr_t *functions)
1665 {
1666 const char *__function_name = "lld_expression_create";
1667
1668 size_t l, r;
1669 int i;
1670 zbx_uint64_t function_index;
1671 char buffer[ZBX_MAX_UINT64_LEN];
1672
1673 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
1674
1675 for (l = 0; '\0' != (*expression)[l]; l++)
1676 {
1677 if ('{' != (*expression)[l])
1678 continue;
1679
1680 if ('$' == (*expression)[l + 1])
1681 {
1682 int macro_r, context_l, context_r;
1683
1684 if (SUCCEED == zbx_user_macro_parse(*expression + l, ¯o_r, &context_l, &context_r))
1685 l += macro_r;
1686 else
1687 l++;
1688
1689 continue;
1690 }
1691
1692 for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
1693 ;
1694
1695 if ('}' != (*expression)[r])
1696 continue;
1697
1698 /* ... > 0 | {1} + ... */
1699 /* l r */
1700
1701 if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &function_index))
1702 continue;
1703
1704 for (i = 0; i < functions->values_num; i++)
1705 {
1706 const zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
1707
1708 if (function->index != function_index)
1709 continue;
1710
1711 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->functionid);
1712
1713 r--;
1714 zbx_replace_string(expression, l + 1, &r, buffer);
1715 r++;
1716
1717 break;
1718 }
1719
1720 l = r;
1721 }
1722
1723 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
1724 }
1725
1726 /******************************************************************************
1727 * *
1728 * Function: lld_triggers_save *
1729 * *
1730 * Purpose: add or update triggers in database based on discovery rule *
1731 * *
1732 * Parameters: hostid - [IN] parent host id *
1733 * lld_triggers_save - [IN] trigger prototypes *
1734 * triggers - [IN/OUT] triggers to save *
1735 * *
1736 * Return value: SUCCEED - if triggers was successfully saved or saving *
1737 * was not necessary *
1738 * FAIL - triggers cannot be saved *
1739 * *
1740 ******************************************************************************/
lld_triggers_save(zbx_uint64_t hostid,const zbx_vector_ptr_t * trigger_prototypes,const zbx_vector_ptr_t * triggers)1741 static int lld_triggers_save(zbx_uint64_t hostid, const zbx_vector_ptr_t *trigger_prototypes,
1742 const zbx_vector_ptr_t *triggers)
1743 {
1744 const char *__function_name = "lld_triggers_save";
1745
1746 int ret = SUCCEED, i, j, new_triggers = 0, upd_triggers = 0,
1747 new_functions = 0, new_dependencies = 0;
1748 const zbx_lld_trigger_prototype_t *trigger_prototype;
1749 zbx_lld_trigger_t *trigger;
1750 zbx_lld_function_t *function;
1751 zbx_lld_dependency_t *dependency;
1752 zbx_vector_ptr_t upd_functions; /* the ordered list of functions which will be updated */
1753 zbx_vector_uint64_t del_functionids, del_triggerdepids;
1754 zbx_uint64_t triggerid = 0, functionid = 0, triggerdepid = 0, triggerid_up;
1755 char *sql = NULL, *function_esc, *parameter_esc;
1756 size_t sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
1757 zbx_db_insert_t db_insert, db_insert_tdiscovery, db_insert_tfunctions, db_insert_tdepends;
1758
1759 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1760
1761 zbx_vector_ptr_create(&upd_functions);
1762 zbx_vector_uint64_create(&del_functionids);
1763 zbx_vector_uint64_create(&del_triggerdepids);
1764
1765 for (i = 0; i < triggers->values_num; i++)
1766 {
1767 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1768
1769 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1770 continue;
1771
1772 if (0 == trigger->triggerid)
1773 new_triggers++;
1774 else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
1775 upd_triggers++;
1776
1777 for (j = 0; j < trigger->functions.values_num; j++)
1778 {
1779 function = (zbx_lld_function_t *)trigger->functions.values[j];
1780
1781 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
1782 {
1783 zbx_vector_uint64_append(&del_functionids, function->functionid);
1784 continue;
1785 }
1786
1787 if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1788 continue;
1789
1790 if (0 == function->functionid)
1791 new_functions++;
1792 else if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1793 zbx_vector_ptr_append(&upd_functions, function);
1794 }
1795
1796 for (j = 0; j < trigger->dependencies.values_num; j++)
1797 {
1798 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1799
1800 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
1801 {
1802 zbx_vector_uint64_append(&del_triggerdepids, dependency->triggerdepid);
1803 continue;
1804 }
1805
1806 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1807 continue;
1808
1809 if (0 == dependency->triggerdepid)
1810 new_dependencies++;
1811 }
1812 }
1813
1814 if (0 == new_triggers && 0 == new_functions && 0 == new_dependencies && 0 == upd_triggers &&
1815 0 == upd_functions.values_num && 0 == del_functionids.values_num &&
1816 0 == del_triggerdepids.values_num)
1817 {
1818 goto out;
1819 }
1820
1821 DBbegin();
1822
1823 if (SUCCEED != DBlock_hostid(hostid))
1824 {
1825 /* the host was removed while processing lld rule */
1826 DBrollback();
1827 ret = FAIL;
1828 goto out;
1829 }
1830
1831 if (0 != new_triggers)
1832 {
1833 triggerid = DBget_maxid_num("triggers", new_triggers);
1834
1835 zbx_db_insert_prepare(&db_insert, "triggers", "triggerid", "description", "expression", "priority",
1836 "status", "comments", "url", "type", "value", "state", "flags", NULL);
1837
1838 zbx_db_insert_prepare(&db_insert_tdiscovery, "trigger_discovery", "triggerid", "parent_triggerid",
1839 NULL);
1840 }
1841
1842 if (0 != new_functions)
1843 {
1844 functionid = DBget_maxid_num("functions", new_functions);
1845
1846 zbx_db_insert_prepare(&db_insert_tfunctions, "functions", "functionid", "itemid", "triggerid",
1847 "function", "parameter", NULL);
1848 }
1849
1850 if (0 != new_dependencies)
1851 {
1852 triggerdepid = DBget_maxid_num("trigger_depends", new_dependencies);
1853
1854 zbx_db_insert_prepare(&db_insert_tdepends, "trigger_depends", "triggerdepid", "triggerid_down",
1855 "triggerid_up", NULL);
1856 }
1857
1858 if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
1859 0 != del_triggerdepids.values_num)
1860 {
1861 sql = zbx_malloc(sql, sql_alloc);
1862 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1863 }
1864
1865 for (i = 0; i < triggers->values_num; i++)
1866 {
1867 char *description_esc, *expression_esc, *comments_esc, *url_esc;
1868 int index;
1869
1870 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1871
1872 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1873 continue;
1874
1875 index = zbx_vector_ptr_bsearch(trigger_prototypes, &trigger->parent_triggerid,
1876 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1877
1878 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1879
1880 for (j = 0; j < trigger->functions.values_num; j++)
1881 {
1882 function = (zbx_lld_function_t *)trigger->functions.values[j];
1883
1884 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
1885 continue;
1886
1887 if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1888 continue;
1889
1890 if (0 == function->functionid)
1891 {
1892 zbx_db_insert_add_values(&db_insert_tfunctions, functionid, function->itemid,
1893 (0 == trigger->triggerid ? triggerid : trigger->triggerid),
1894 function->function, function->parameter);
1895
1896 function->functionid = functionid++;
1897 }
1898 }
1899
1900 if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
1901 lld_expression_create(&trigger->expression, &trigger->functions);
1902
1903 if (0 == trigger->triggerid)
1904 {
1905 zbx_db_insert_add_values(&db_insert, triggerid, trigger->description, trigger->expression,
1906 (int)trigger_prototype->priority, (int)trigger_prototype->status,
1907 trigger->comments, trigger->url, (int)trigger_prototype->type,
1908 (int)TRIGGER_VALUE_OK, (int)TRIGGER_STATE_NORMAL,
1909 (int)ZBX_FLAG_DISCOVERY_CREATED);
1910
1911 zbx_db_insert_add_values(&db_insert_tdiscovery, triggerid, trigger->parent_triggerid);
1912
1913 trigger->triggerid = triggerid++;
1914 }
1915 else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
1916 {
1917 const char *d = "";
1918
1919 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set ");
1920
1921 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION))
1922 {
1923 description_esc = DBdyn_escape_string(trigger->description);
1924 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "description='%s'",
1925 description_esc);
1926 zbx_free(description_esc);
1927 d = ",";
1928 }
1929
1930 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
1931 {
1932 expression_esc = DBdyn_escape_string(trigger->expression);
1933 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sexpression='%s'", d,
1934 expression_esc);
1935 zbx_free(expression_esc);
1936 d = ",";
1937 }
1938
1939 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE))
1940 {
1941 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d,
1942 (int)trigger_prototype->type);
1943 d = ",";
1944 }
1945
1946 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY))
1947 {
1948 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spriority=%d", d,
1949 (int)trigger_prototype->priority);
1950 d = ",";
1951 }
1952
1953 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS))
1954 {
1955 comments_esc = DBdyn_escape_string(trigger->comments);
1956 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scomments='%s'", d, comments_esc);
1957 zbx_free(comments_esc);
1958 d = ",";
1959 }
1960
1961 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_URL))
1962 {
1963 url_esc = DBdyn_escape_string(trigger->url);
1964 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl='%s'", d, url_esc);
1965 zbx_free(url_esc);
1966 }
1967
1968 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1969 " where triggerid=" ZBX_FS_UI64 ";\n", trigger->triggerid);
1970 }
1971 }
1972
1973 for (i = 0; i < triggers->values_num; i++)
1974 {
1975 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1976
1977 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1978 continue;
1979
1980 for (j = 0; j < trigger->dependencies.values_num; j++)
1981 {
1982 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1983
1984 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
1985 continue;
1986
1987 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1988 continue;
1989
1990 if (0 == dependency->triggerdepid)
1991 {
1992 triggerid_up = (NULL == dependency->trigger_up ? dependency->triggerid_up :
1993 dependency->trigger_up->triggerid);
1994
1995 zbx_db_insert_add_values(&db_insert_tdepends, triggerdepid, trigger->triggerid,
1996 triggerid_up);
1997
1998 dependency->triggerdepid = triggerdepid++;
1999 }
2000 }
2001 }
2002
2003 zbx_vector_ptr_sort(&upd_functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2004
2005 for (i = 0; i < upd_functions.values_num; i++)
2006 {
2007 const char *d = "";
2008
2009 function = (zbx_lld_function_t *)upd_functions.values[i];
2010
2011 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update functions set ");
2012
2013 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID))
2014 {
2015 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64,
2016 function->itemid);
2017 d = ",";
2018 }
2019
2020 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION))
2021 {
2022 function_esc = DBdyn_escape_string(function->function);
2023 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sfunction='%s'", d,
2024 function_esc);
2025 zbx_free(function_esc);
2026 d = ",";
2027 }
2028
2029 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER))
2030 {
2031 parameter_esc = DBdyn_escape_string(function->parameter);
2032 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sparameter='%s'", d,
2033 parameter_esc);
2034 zbx_free(parameter_esc);
2035 }
2036
2037 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2038 " where functionid=" ZBX_FS_UI64 ";\n", function->functionid);
2039 }
2040
2041 if (0 != del_functionids.values_num)
2042 {
2043 zbx_vector_uint64_sort(&del_functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2044
2045 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where");
2046 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "functionid",
2047 del_functionids.values, del_functionids.values_num);
2048 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2049 }
2050
2051 if (0 != del_triggerdepids.values_num)
2052 {
2053 zbx_vector_uint64_sort(&del_triggerdepids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2054
2055 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_depends where");
2056 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerdepid",
2057 del_triggerdepids.values, del_triggerdepids.values_num);
2058 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2059 }
2060
2061 if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2062 0 != del_triggerdepids.values_num)
2063 {
2064 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2065 DBexecute("%s", sql);
2066 zbx_free(sql);
2067 }
2068
2069 if (0 != new_triggers)
2070 {
2071 zbx_db_insert_execute(&db_insert);
2072 zbx_db_insert_clean(&db_insert);
2073
2074 zbx_db_insert_execute(&db_insert_tdiscovery);
2075 zbx_db_insert_clean(&db_insert_tdiscovery);
2076 }
2077
2078 if (0 != new_functions)
2079 {
2080 zbx_db_insert_execute(&db_insert_tfunctions);
2081 zbx_db_insert_clean(&db_insert_tfunctions);
2082 }
2083
2084 if (0 != new_dependencies)
2085 {
2086 zbx_db_insert_execute(&db_insert_tdepends);
2087 zbx_db_insert_clean(&db_insert_tdepends);
2088 }
2089
2090 DBcommit();
2091 out:
2092 zbx_vector_uint64_destroy(&del_triggerdepids);
2093 zbx_vector_uint64_destroy(&del_functionids);
2094 zbx_vector_ptr_destroy(&upd_functions);
2095
2096 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2097
2098 return ret;
2099 }
2100
2101 /* hash/comparison functions to support cache/vector lookups by trigger reference */
zbx_lld_trigger_ref_hash_func(const void * data)2102 zbx_hash_t zbx_lld_trigger_ref_hash_func(const void *data)
2103 {
2104 zbx_hash_t hash;
2105 const zbx_lld_trigger_node_t *trigger_node = (const zbx_lld_trigger_node_t *)data;
2106 void *ptr = NULL;
2107
2108 hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&trigger_node->trigger_ref.triggerid,
2109 sizeof(trigger_node->trigger_ref.triggerid), ZBX_DEFAULT_HASH_SEED);
2110
2111 if (0 == trigger_node->trigger_ref.triggerid)
2112 ptr = trigger_node->trigger_ref.trigger;
2113
2114 return ZBX_DEFAULT_PTR_HASH_ALGO(&ptr, sizeof(trigger_node->trigger_ref.trigger), hash);
2115 }
2116
zbx_lld_trigger_ref_compare_func(const void * d1,const void * d2)2117 int zbx_lld_trigger_ref_compare_func(const void *d1, const void *d2)
2118 {
2119 const zbx_lld_trigger_node_t *n1 = (const zbx_lld_trigger_node_t *)d1;
2120 const zbx_lld_trigger_node_t *n2 = (const zbx_lld_trigger_node_t *)d2;
2121
2122 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2123
2124 /* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2125 if (0 != n1->trigger_ref.triggerid)
2126 return 0;
2127
2128 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2129
2130 return 0;
2131 }
2132
2133 /* comparison function to determine trigger dependency validation order */
zbx_lld_trigger_node_compare_func(const void * d1,const void * d2)2134 int zbx_lld_trigger_node_compare_func(const void *d1, const void *d2)
2135 {
2136 const zbx_lld_trigger_node_t *n1 = *(const zbx_lld_trigger_node_t **)d1;
2137 const zbx_lld_trigger_node_t *n2 = *(const zbx_lld_trigger_node_t **)d2;
2138
2139 /* sort in ascending order, but ensure that existing triggers are first */
2140 if (0 != n1->trigger_ref.triggerid && 0 == n2->trigger_ref.triggerid)
2141 return -1;
2142
2143 /* give priority to nodes with less parents */
2144 ZBX_RETURN_IF_NOT_EQUAL(n1->parents, n2->parents);
2145
2146 /* compare ids */
2147 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2148
2149 /* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2150 if (0 != n1->trigger_ref.triggerid)
2151 return 0;
2152
2153 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2154
2155 return 0;
2156 }
2157
2158 /******************************************************************************
2159 * *
2160 * Function: lld_trigger_cache_append *
2161 * *
2162 * Purpose: adds a node to trigger cache *
2163 * *
2164 * Parameters: cache - [IN] the trigger cache *
2165 * triggerid - [IN] the trigger id *
2166 * trigger - [IN] the trigger data for new triggers *
2167 * *
2168 * Return value: the added node *
2169 * *
2170 ******************************************************************************/
lld_trigger_cache_append(zbx_hashset_t * cache,zbx_uint64_t triggerid,zbx_lld_trigger_t * trigger)2171 static zbx_lld_trigger_node_t *lld_trigger_cache_append(zbx_hashset_t *cache, zbx_uint64_t triggerid,
2172 zbx_lld_trigger_t *trigger)
2173 {
2174 zbx_lld_trigger_node_t node_local;
2175
2176 node_local.trigger_ref.triggerid = triggerid;
2177 node_local.trigger_ref.trigger = trigger;
2178 node_local.trigger_ref.flags = 0;
2179 node_local.iter_num = 0;
2180 node_local.parents = 0;
2181
2182 zbx_vector_ptr_create(&node_local.dependencies);
2183
2184 return zbx_hashset_insert(cache, &node_local, sizeof(node_local));
2185 }
2186
2187 /******************************************************************************
2188 * *
2189 * Function: lld_trigger_cache_add_trigger_node *
2190 * *
2191 * Purpose: add trigger and all triggers related to it to trigger dependency *
2192 * validation cache. *
2193 * *
2194 * Parameters: cache - [IN] the trigger cache *
2195 * trigger - [IN] the trigger to add *
2196 * triggerids_up - [OUT] identifiers of generic trigger *
2197 * dependents *
2198 * triggerids_down - [OUT] identifiers of generic trigger *
2199 * dependencies *
2200 * *
2201 ******************************************************************************/
lld_trigger_cache_add_trigger_node(zbx_hashset_t * cache,zbx_lld_trigger_t * trigger,zbx_vector_uint64_t * triggerids_up,zbx_vector_uint64_t * triggerids_down)2202 static void lld_trigger_cache_add_trigger_node(zbx_hashset_t *cache, zbx_lld_trigger_t *trigger,
2203 zbx_vector_uint64_t *triggerids_up, zbx_vector_uint64_t *triggerids_down)
2204 {
2205 zbx_lld_trigger_ref_t *trigger_ref;
2206 zbx_lld_trigger_node_t *trigger_node, trigger_node_local;
2207 zbx_lld_dependency_t *dependency;
2208 int i;
2209
2210 trigger_node_local.trigger_ref.triggerid = trigger->triggerid;
2211 trigger_node_local.trigger_ref.trigger = trigger;
2212
2213 if (NULL != (trigger_node = zbx_hashset_search(cache, &trigger_node_local)))
2214 return;
2215
2216 trigger_node = lld_trigger_cache_append(cache, trigger->triggerid, trigger);
2217
2218 for (i = 0; i < trigger->dependencies.values_num; i++)
2219 {
2220 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2221
2222 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2223 continue;
2224
2225 trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_ref_t));
2226
2227 trigger_ref->triggerid = dependency->triggerid_up;
2228 trigger_ref->trigger = dependency->trigger_up;
2229 trigger_ref->flags = (0 == dependency->triggerdepid ? ZBX_LLD_TRIGGER_DEPENDENCY_NEW :
2230 ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL);
2231
2232 zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
2233
2234 if (NULL == trigger_ref->trigger)
2235 {
2236 trigger_node_local.trigger_ref.triggerid = trigger_ref->triggerid;
2237 trigger_node_local.trigger_ref.trigger = NULL;
2238
2239 if (NULL == zbx_hashset_search(cache, &trigger_node_local))
2240 {
2241 zbx_vector_uint64_append(triggerids_up, trigger_ref->triggerid);
2242 zbx_vector_uint64_append(triggerids_down, trigger_ref->triggerid);
2243
2244 lld_trigger_cache_append(cache, trigger_ref->triggerid, NULL);
2245 }
2246 }
2247 }
2248
2249 if (0 != trigger->triggerid)
2250 zbx_vector_uint64_append(triggerids_up, trigger->triggerid);
2251
2252 for (i = 0; i < trigger->dependents.values_num; i++)
2253 {
2254 lld_trigger_cache_add_trigger_node(cache, trigger->dependents.values[i], triggerids_up,
2255 triggerids_down);
2256 }
2257
2258 for (i = 0; i < trigger->dependencies.values_num; i++)
2259 {
2260 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2261
2262 if (NULL != dependency->trigger_up)
2263 {
2264 lld_trigger_cache_add_trigger_node(cache, dependency->trigger_up, triggerids_up,
2265 triggerids_down);
2266 }
2267 }
2268 }
2269
2270 /******************************************************************************
2271 * *
2272 * Function: lld_trigger_cache_init *
2273 * *
2274 * Purpose: initializes trigger cache used to perform trigger dependency *
2275 * validation *
2276 * *
2277 * Parameters: cache - [IN] the trigger cache *
2278 * triggers - [IN] the discovered triggers *
2279 * *
2280 * Comments: Triggers with new dependencies and.all triggers related to them *
2281 * are added to cache. *
2282 * *
2283 ******************************************************************************/
lld_trigger_cache_init(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers)2284 static void lld_trigger_cache_init(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers)
2285 {
2286 const char *__function_name = "lld_trigger_cache_init";
2287
2288 zbx_vector_uint64_t triggerids_up, triggerids_down;
2289 int i, j;
2290 char *sql = NULL;
2291 size_t sql_alloc = 0, sql_offset;
2292 DB_RESULT result;
2293 DB_ROW row;
2294 zbx_lld_trigger_ref_t *trigger_ref;
2295 zbx_lld_trigger_node_t *trigger_node, trigger_node_local;
2296
2297 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2298
2299 zbx_hashset_create(cache, triggers->values_num, zbx_lld_trigger_ref_hash_func,
2300 zbx_lld_trigger_ref_compare_func);
2301
2302 zbx_vector_uint64_create(&triggerids_down);
2303 zbx_vector_uint64_create(&triggerids_up);
2304
2305 /* add all triggers with new dependencies to trigger cache */
2306 for (i = 0; i < triggers->values_num; i++)
2307 {
2308 zbx_lld_trigger_t *trigger = (zbx_lld_trigger_t *)triggers->values[i];
2309
2310 for (j = 0; j < trigger->dependencies.values_num; j++)
2311 {
2312 zbx_lld_dependency_t *dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2313
2314 if (0 == dependency->triggerdepid)
2315 break;
2316 }
2317
2318 if (j != trigger->dependencies.values_num)
2319 lld_trigger_cache_add_trigger_node(cache, trigger, &triggerids_up, &triggerids_down);
2320 }
2321
2322 /* keep trying to load generic dependents/dependencies until there are nothing to load */
2323 while (0 != triggerids_up.values_num || 0 != triggerids_down.values_num)
2324 {
2325 /* load dependents */
2326 if (0 != triggerids_down.values_num)
2327 {
2328 sql_offset = 0;
2329 zbx_vector_uint64_sort(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2330 zbx_vector_uint64_uniq(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2331
2332 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2333 "select td.triggerid_down,td.triggerid_up"
2334 " from trigger_depends td"
2335 " left join triggers t"
2336 " on td.triggerid_up=t.triggerid"
2337 " where t.flags<>%d"
2338 " and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
2339 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_down",
2340 triggerids_down.values, triggerids_down.values_num);
2341
2342 zbx_vector_uint64_clear(&triggerids_down);
2343
2344 result = DBselect("%s", sql);
2345
2346 while (NULL != (row = DBfetch(result)))
2347 {
2348 int new_node = 0;
2349 zbx_lld_trigger_node_t *trigger_node_up;
2350
2351 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[1]);
2352
2353 if (NULL == (trigger_node_up = zbx_hashset_search(cache, &trigger_node_local)))
2354 {
2355 trigger_node_up = lld_trigger_cache_append(cache,
2356 trigger_node_local.trigger_ref.triggerid, NULL);
2357 new_node = 1;
2358 }
2359
2360 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
2361
2362 if (NULL == (trigger_node = zbx_hashset_search(cache, &trigger_node_local)))
2363 {
2364 THIS_SHOULD_NEVER_HAPPEN;
2365 continue;
2366 }
2367
2368 /* check if the dependency is not already registered in cache */
2369 for (i = 0; i < trigger_node->dependencies.values_num; i++)
2370 {
2371 trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
2372
2373 /* references to generic triggers will always have valid id value */
2374 if (trigger_ref->triggerid == trigger_node_up->trigger_ref.triggerid)
2375 break;
2376 }
2377
2378 /* if the dependency was not found - add it */
2379 if (i == trigger_node->dependencies.values_num)
2380 {
2381 trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL,
2382 sizeof(zbx_lld_trigger_ref_t));
2383
2384 trigger_ref->triggerid = trigger_node_up->trigger_ref.triggerid;
2385 trigger_ref->trigger = NULL;
2386 trigger_ref->flags = ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL;
2387
2388 zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
2389
2390 trigger_node_up->parents++;
2391 }
2392
2393 if (1 == new_node)
2394 {
2395 /* if the trigger was added to cache, we must check its dependencies */
2396 zbx_vector_uint64_append(&triggerids_up,
2397 trigger_node_up->trigger_ref.triggerid);
2398 zbx_vector_uint64_append(&triggerids_down,
2399 trigger_node_up->trigger_ref.triggerid);
2400 }
2401 }
2402
2403 DBfree_result(result);
2404 }
2405
2406 /* load dependencies */
2407 if (0 != triggerids_up.values_num)
2408 {
2409 sql_offset = 0;
2410 zbx_vector_uint64_sort(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2411 zbx_vector_uint64_uniq(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2412
2413 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2414 "select td.triggerid_down"
2415 " from trigger_depends td"
2416 " left join triggers t"
2417 " on t.triggerid=td.triggerid_down"
2418 " where t.flags<>%d"
2419 " and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
2420 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_up", triggerids_up.values,
2421 triggerids_up.values_num);
2422
2423 zbx_vector_uint64_clear(&triggerids_up);
2424
2425 result = DBselect("%s", sql);
2426
2427 while (NULL != (row = DBfetch(result)))
2428 {
2429 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
2430
2431 if (NULL != zbx_hashset_search(cache, &trigger_node_local))
2432 continue;
2433
2434 trigger_node = lld_trigger_cache_append(cache, trigger_node_local.trigger_ref.triggerid,
2435 NULL);
2436
2437 zbx_vector_uint64_append(&triggerids_up, trigger_node_local.trigger_ref.triggerid);
2438 zbx_vector_uint64_append(&triggerids_down, trigger_node_local.trigger_ref.triggerid);
2439 }
2440
2441 DBfree_result(result);
2442 }
2443
2444 }
2445
2446 zbx_free(sql);
2447
2448 zbx_vector_uint64_destroy(&triggerids_up);
2449 zbx_vector_uint64_destroy(&triggerids_down);
2450
2451 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2452 }
2453
2454 /******************************************************************************
2455 * *
2456 * Function: zbx_trigger_cache_clean *
2457 * *
2458 * Purpose: releases resources allocated by trigger cache *
2459 * validation *
2460 * *
2461 * Parameters: cache - [IN] the trigger cache *
2462 * *
2463 ******************************************************************************/
zbx_trigger_cache_clean(zbx_hashset_t * cache)2464 static void zbx_trigger_cache_clean(zbx_hashset_t *cache)
2465 {
2466 zbx_hashset_iter_t iter;
2467 zbx_lld_trigger_node_t *trigger_node;
2468
2469 zbx_hashset_iter_reset(cache, &iter);
2470 while (NULL != (trigger_node = zbx_hashset_iter_next(&iter)))
2471 {
2472 zbx_vector_ptr_clear_ext(&trigger_node->dependencies, zbx_ptr_free);
2473 zbx_vector_ptr_destroy(&trigger_node->dependencies);
2474 }
2475
2476 zbx_hashset_destroy(cache);
2477 }
2478
2479 /******************************************************************************
2480 * *
2481 * Function: lld_trigger_dependency_delete *
2482 * *
2483 * Purpose: removes trigger dependency *
2484 * *
2485 * Parameters: from - [IN] the reference to dependent trigger *
2486 * to - [IN] the reference to trigger the from depends on *
2487 * error - [OUT] the error message *
2488 * *
2489 * Comments: If possible (the dependency loop was introduced by discovered *
2490 * dependencies) the last dependency in the loop will be removed. *
2491 * Otherwise (the triggers in database already had dependency loop) *
2492 * the last dependency in the loop will be marked as removed, *
2493 * however the dependency in database will be left intact. *
2494 * *
2495 ******************************************************************************/
lld_trigger_dependency_delete(zbx_lld_trigger_ref_t * from,zbx_lld_trigger_ref_t * to,char ** error)2496 static void lld_trigger_dependency_delete(zbx_lld_trigger_ref_t *from, zbx_lld_trigger_ref_t *to, char **error)
2497 {
2498 zbx_lld_trigger_t *trigger;
2499 int i;
2500 char *trigger_desc;
2501
2502 if (ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == to->flags)
2503 {
2504 /* When old dependency loop has been detected mark it as deleted to avoid */
2505 /* infinite recursion during dependency validation, but don't really delete */
2506 /* it because only new dependencies can be deleted. */
2507
2508 /* in old dependency loop there are no new triggers, so all involved */
2509 /* triggers have valid identifiers */
2510 zabbix_log(LOG_LEVEL_CRIT, "existing recursive dependency loop detected for trigger \""
2511 ZBX_FS_UI64 "\"", to->triggerid);
2512 return;
2513 }
2514
2515 trigger = from->trigger;
2516
2517 /* remove the dependency */
2518 for (i = 0; i < trigger->dependencies.values_num; i++)
2519 {
2520 zbx_lld_dependency_t *dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2521
2522 if ((NULL != dependency->trigger_up && dependency->trigger_up == to->trigger) ||
2523 (0 != dependency->triggerid_up && dependency->triggerid_up == to->triggerid))
2524 {
2525 zbx_free(dependency);
2526 zbx_vector_ptr_remove(&trigger->dependencies, i);
2527
2528 break;
2529 }
2530 }
2531
2532 if (0 != from->triggerid)
2533 trigger_desc = zbx_dsprintf(NULL, ZBX_FS_UI64, from->triggerid);
2534 else
2535 trigger_desc = zbx_strdup(NULL, from->trigger->description);
2536
2537 *error = zbx_strdcatf(*error, "Cannot create all trigger \"%s\" dependencies:"
2538 " recursion too deep.\n", trigger_desc);
2539
2540 zbx_free(trigger_desc);
2541 }
2542
2543 /******************************************************************************
2544 * *
2545 * Function: lld_trigger_dependencies_iter *
2546 * *
2547 * Purpose: iterates through trigger dependencies to find dependency loops *
2548 * *
2549 * Parameters: cache - [IN] the trigger cache *
2550 * triggers - [IN] the discovered triggers *
2551 * trigger_node - [IN] the trigger to check *
2552 * iter - [IN] the dependency iterator *
2553 * level - [IN] the dependency level *
2554 * error - [OUT] the error message *
2555 * *
2556 * Return value: SUCCEED - the trigger's dependency chain in valid *
2557 * FAIL - a dependency loop was detected *
2558 * *
2559 * Comments: If the validation fails the offending dependency is removed. *
2560 * *
2561 ******************************************************************************/
lld_trigger_dependencies_iter(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers,zbx_lld_trigger_node_t * trigger_node,zbx_lld_trigger_node_iter_t * iter,int level,char ** error)2562 static int lld_trigger_dependencies_iter(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers,
2563 zbx_lld_trigger_node_t *trigger_node, zbx_lld_trigger_node_iter_t *iter, int level, char **error)
2564 {
2565 int i;
2566 zbx_lld_trigger_ref_t *trigger_ref;
2567 zbx_lld_trigger_node_t *trigger_node_up;
2568 zbx_lld_trigger_node_iter_t child_iter, *piter;
2569
2570 if (trigger_node->iter_num == iter->iter_num || ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
2571 {
2572 /* dependency loop detected, resolve it by deleting corresponding dependency */
2573 lld_trigger_dependency_delete(iter->ref_from, iter->ref_to, error);
2574
2575 /* mark the dependency as removed */
2576 iter->ref_to->flags = ZBX_LLD_TRIGGER_DEPENDENCY_DELETE;
2577
2578 return FAIL;
2579 }
2580
2581 trigger_node->iter_num = iter->iter_num;
2582
2583 for (i = 0; i < trigger_node->dependencies.values_num; i++)
2584 {
2585 trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
2586
2587 /* skip dependencies marked as deleted */
2588 if (ZBX_LLD_TRIGGER_DEPENDENCY_DELETE == trigger_ref->flags)
2589 continue;
2590
2591 if (NULL == (trigger_node_up = zbx_hashset_search(cache, trigger_ref)))
2592 {
2593 THIS_SHOULD_NEVER_HAPPEN;
2594 continue;
2595 }
2596
2597 /* Remember last dependency that could be cut. */
2598 /* It should be either a last new dependency or just a last dependency */
2599 /* if no new dependencies were encountered. */
2600 if (ZBX_LLD_TRIGGER_DEPENDENCY_NEW == trigger_ref->flags || NULL == iter->ref_to ||
2601 ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == iter->ref_to->flags)
2602 {
2603 child_iter.ref_from = &trigger_node->trigger_ref;
2604 child_iter.ref_to = trigger_ref;
2605 child_iter.iter_num = iter->iter_num;
2606
2607 piter = &child_iter;
2608 }
2609 else
2610 piter = iter;
2611
2612 if (FAIL == lld_trigger_dependencies_iter(cache, triggers, trigger_node_up, piter, level + 1, error))
2613 return FAIL;
2614 }
2615
2616 trigger_node->iter_num = 0;
2617
2618 return SUCCEED;
2619 }
2620
2621 /******************************************************************************
2622 * *
2623 * Function: lld_trigger_dependencies_validate *
2624 * *
2625 * Purpose: validate discovered trigger dependencies *
2626 * *
2627 * Parameters: triggers - [IN] the discovered triggers *
2628 * error - [OUT] the error message *
2629 * triggers - [IN] the discovered triggers *
2630 * trigger - [IN] the trigger to check *
2631 * iter - [IN] the dependency iterator *
2632 * level - [IN] the dependency level *
2633 * *
2634 * Comments: During validation the dependency loops will be resolved by *
2635 * removing offending dependencies. *
2636 * *
2637 ******************************************************************************/
lld_trigger_dependencies_validate(zbx_vector_ptr_t * triggers,char ** error)2638 static void lld_trigger_dependencies_validate(zbx_vector_ptr_t *triggers, char **error)
2639 {
2640 const char *__function_name = "lld_trigger_dependencies_validate";
2641
2642 zbx_hashset_t cache;
2643 zbx_hashset_iter_t iter;
2644 zbx_lld_trigger_node_t *trigger_node, *trigger_node_up;
2645 zbx_lld_trigger_node_iter_t node_iter = {0};
2646 zbx_vector_ptr_t nodes;
2647 int i;
2648
2649 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2650
2651 lld_trigger_cache_init(&cache, triggers);
2652
2653 /* Perform dependency validation in the order of trigger ids and starting with parentless triggers. */
2654 /* This will give some consistency in choosing what dependencies should be deleted in the case of */
2655 /* recursion. */
2656 zbx_vector_ptr_create(&nodes);
2657 zbx_vector_ptr_reserve(&nodes, cache.num_data);
2658
2659 zbx_hashset_iter_reset(&cache, &iter);
2660 while (NULL != (trigger_node = zbx_hashset_iter_next(&iter)))
2661 {
2662 for (i = 0; i < trigger_node->dependencies.values_num; i++)
2663 {
2664 if (NULL == (trigger_node_up = zbx_hashset_search(&cache,
2665 trigger_node->dependencies.values[i])))
2666 {
2667 THIS_SHOULD_NEVER_HAPPEN;
2668 continue;
2669 }
2670
2671 trigger_node_up->parents++;
2672 }
2673 zbx_vector_ptr_append(&nodes, trigger_node);
2674 }
2675
2676 zbx_vector_ptr_sort(&nodes, zbx_lld_trigger_node_compare_func);
2677
2678 for (i = 0; i < nodes.values_num; i++)
2679 {
2680 if (NULL == (trigger_node = zbx_hashset_search(&cache, (zbx_lld_trigger_node_t *)nodes.values[i])))
2681 {
2682 THIS_SHOULD_NEVER_HAPPEN;
2683 continue;
2684 }
2685
2686 /* If dependency iterator returns false it means that dependency loop was detected */
2687 /* (and resolved). In this case we have to validate dependencies for this trigger */
2688 /* again. */
2689 do
2690 {
2691 node_iter.iter_num++;
2692 node_iter.ref_from = NULL;
2693 node_iter.ref_to = NULL;
2694 }
2695 while (SUCCEED != lld_trigger_dependencies_iter(&cache, triggers, trigger_node, &node_iter, 0, error));
2696 }
2697
2698 zbx_vector_ptr_destroy(&nodes);
2699 zbx_trigger_cache_clean(&cache);
2700
2701 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2702 }
2703
2704 /******************************************************************************
2705 * *
2706 * Function: lld_update_triggers *
2707 * *
2708 * Purpose: add or update triggers for discovered items *
2709 * *
2710 * Return value: SUCCEED - if triggers were successfully added/updated or *
2711 * adding/updating was not necessary *
2712 * FAIL - triggers cannot be added/updated *
2713 * *
2714 ******************************************************************************/
lld_update_triggers(zbx_uint64_t hostid,zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,char ** error)2715 int lld_update_triggers(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows, char **error)
2716 {
2717 const char *__function_name = "lld_update_triggers";
2718
2719 zbx_vector_ptr_t trigger_prototypes;
2720 zbx_vector_ptr_t triggers;
2721 zbx_vector_ptr_t items;
2722 zbx_lld_trigger_t *trigger;
2723 zbx_lld_trigger_prototype_t *trigger_prototype;
2724 int ret = SUCCEED, i;
2725
2726 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2727
2728 zbx_vector_ptr_create(&trigger_prototypes);
2729
2730 lld_trigger_prototypes_get(lld_ruleid, &trigger_prototypes);
2731
2732 if (0 == trigger_prototypes.values_num)
2733 goto out;
2734
2735 zbx_vector_ptr_create(&triggers); /* list of triggers which were created or will be created or */
2736 /* updated by the trigger prototype */
2737 zbx_vector_ptr_create(&items); /* list of items which are related to the trigger prototypes */
2738
2739 lld_triggers_get(&trigger_prototypes, &triggers);
2740 lld_functions_get(&trigger_prototypes, &triggers);
2741 lld_dependencies_get(&trigger_prototypes, &triggers);
2742 lld_items_get(&trigger_prototypes, &items);
2743
2744 /* simplifying trigger expressions */
2745
2746 for (i = 0; i < trigger_prototypes.values_num; i++)
2747 {
2748 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes.values[i];
2749
2750 lld_expression_simplify(&trigger_prototype->expression, &trigger_prototype->functions);
2751 }
2752
2753 for (i = 0; i < triggers.values_num; i++)
2754 {
2755 trigger = (zbx_lld_trigger_t *)triggers.values[i];
2756
2757 lld_expression_simplify(&trigger->expression, &trigger->functions);
2758 }
2759
2760 /* making triggers */
2761
2762 lld_triggers_make(&trigger_prototypes, &triggers, &items, lld_rows, error);
2763 lld_triggers_validate(hostid, &triggers, error);
2764 lld_trigger_dependencies_make(&trigger_prototypes, &triggers, &items, lld_rows, error);
2765 lld_trigger_dependencies_validate(&triggers, error);
2766 ret = lld_triggers_save(hostid, &trigger_prototypes, &triggers);
2767
2768 /* cleaning */
2769
2770 zbx_vector_ptr_clear_ext(&items, (zbx_mem_free_func_t)lld_item_free);
2771 zbx_vector_ptr_clear_ext(&triggers, (zbx_mem_free_func_t)lld_trigger_free);
2772 zbx_vector_ptr_destroy(&items);
2773 zbx_vector_ptr_destroy(&triggers);
2774 out:
2775 zbx_vector_ptr_clear_ext(&trigger_prototypes, (zbx_mem_free_func_t)lld_trigger_prototype_free);
2776 zbx_vector_ptr_destroy(&trigger_prototypes);
2777
2778 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2779
2780 return ret;
2781 }
2782