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 *recovery_expression;
32 char *comments;
33 char *url;
34 char *correlation_tag;
35 char *opdata;
36 unsigned char status;
37 unsigned char type;
38 unsigned char priority;
39 unsigned char recovery_mode;
40 unsigned char correlation_mode;
41 unsigned char manual_close;
42 unsigned char discover;
43 zbx_vector_ptr_t functions;
44 zbx_vector_ptr_t dependencies;
45 zbx_vector_ptr_t tags;
46 }
47 zbx_lld_trigger_prototype_t;
48
49 typedef struct
50 {
51 zbx_uint64_t triggerid;
52 zbx_uint64_t parent_triggerid;
53 char *description;
54 char *description_orig;
55 char *expression;
56 char *expression_orig;
57 char *recovery_expression;
58 char *recovery_expression_orig;
59 char *comments;
60 char *comments_orig;
61 char *url;
62 char *url_orig;
63 char *correlation_tag;
64 char *correlation_tag_orig;
65 char *opdata;
66 char *opdata_orig;
67 zbx_vector_ptr_t functions;
68 zbx_vector_ptr_t dependencies;
69 zbx_vector_ptr_t dependents;
70 zbx_vector_ptr_t tags;
71 zbx_vector_ptr_pair_t override_tags;
72 #define ZBX_FLAG_LLD_TRIGGER_UNSET __UINT64_C(0x0000)
73 #define ZBX_FLAG_LLD_TRIGGER_DISCOVERED __UINT64_C(0x0001)
74 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION __UINT64_C(0x0002)
75 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION __UINT64_C(0x0004)
76 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE __UINT64_C(0x0008)
77 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY __UINT64_C(0x0010)
78 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS __UINT64_C(0x0020)
79 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_URL __UINT64_C(0x0040)
80 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION __UINT64_C(0x0080)
81 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE __UINT64_C(0x0100)
82 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE __UINT64_C(0x0200)
83 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG __UINT64_C(0x0400)
84 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE __UINT64_C(0x0800)
85 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA __UINT64_C(0x1000)
86 #define ZBX_FLAG_LLD_TRIGGER_UPDATE \
87 (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION | \
88 ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE | ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY | \
89 ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS | ZBX_FLAG_LLD_TRIGGER_UPDATE_URL | \
90 ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION | ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE | \
91 ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE | ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG | \
92 ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE | ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA)
93 zbx_uint64_t flags;
94 int lastcheck;
95 int ts_delete;
96 unsigned char status;
97 unsigned char priority;
98 }
99 zbx_lld_trigger_t;
100
101 typedef struct
102 {
103 zbx_uint64_t functionid;
104 zbx_uint64_t index;
105 zbx_uint64_t itemid;
106 zbx_uint64_t itemid_orig;
107 char *function;
108 char *function_orig;
109 char *parameter;
110 char *parameter_orig;
111 #define ZBX_FLAG_LLD_FUNCTION_UNSET __UINT64_C(0x00)
112 #define ZBX_FLAG_LLD_FUNCTION_DISCOVERED __UINT64_C(0x01)
113 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID __UINT64_C(0x02)
114 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION __UINT64_C(0x04)
115 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER __UINT64_C(0x08)
116 #define ZBX_FLAG_LLD_FUNCTION_UPDATE \
117 (ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID | ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION | \
118 ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER)
119 #define ZBX_FLAG_LLD_FUNCTION_DELETE __UINT64_C(0x10)
120 zbx_uint64_t flags;
121 }
122 zbx_lld_function_t;
123
124 typedef struct
125 {
126 zbx_uint64_t triggerdepid;
127 zbx_uint64_t triggerid_up; /* generic trigger */
128 zbx_lld_trigger_t *trigger_up; /* lld-created trigger; (null) if trigger depends on generic trigger */
129 #define ZBX_FLAG_LLD_DEPENDENCY_UNSET __UINT64_C(0x00)
130 #define ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED __UINT64_C(0x01)
131 #define ZBX_FLAG_LLD_DEPENDENCY_DELETE __UINT64_C(0x02)
132 zbx_uint64_t flags;
133 }
134 zbx_lld_dependency_t;
135
136 typedef struct
137 {
138 zbx_uint64_t triggertagid;
139 char *tag;
140 char *value;
141 #define ZBX_FLAG_LLD_TAG_UNSET __UINT64_C(0x00)
142 #define ZBX_FLAG_LLD_TAG_DISCOVERED __UINT64_C(0x01)
143 #define ZBX_FLAG_LLD_TAG_UPDATE_TAG __UINT64_C(0x02)
144 #define ZBX_FLAG_LLD_TAG_UPDATE_VALUE __UINT64_C(0x04)
145 #define ZBX_FLAG_LLD_TAG_UPDATE \
146 (ZBX_FLAG_LLD_TAG_UPDATE_TAG | ZBX_FLAG_LLD_TAG_UPDATE_VALUE)
147 #define ZBX_FLAG_LLD_TAG_DELETE __UINT64_C(0x08)
148 zbx_uint64_t flags;
149 }
150 zbx_lld_tag_t;
151
152 typedef struct
153 {
154 zbx_uint64_t parent_triggerid;
155 zbx_uint64_t itemid;
156 zbx_lld_trigger_t *trigger;
157 }
158 zbx_lld_item_trigger_t;
159
160 typedef struct
161 {
162 zbx_uint64_t itemid;
163 unsigned char flags;
164 }
165 zbx_lld_item_t;
166
167 /* a reference to trigger which could be either existing trigger in database or */
168 /* a just discovered trigger stored in memory */
169 typedef struct
170 {
171 /* trigger id, 0 for newly discovered triggers */
172 zbx_uint64_t triggerid;
173
174 /* trigger data, NULL for non-discovered triggers */
175 zbx_lld_trigger_t *trigger;
176
177 /* flags to mark trigger dependencies during trigger dependency validation */
178 #define ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL 0
179 #define ZBX_LLD_TRIGGER_DEPENDENCY_NEW 1
180 #define ZBX_LLD_TRIGGER_DEPENDENCY_DELETE 2
181
182 /* flags used to mark dependencies when trigger reference is use to store dependency links */
183 int flags;
184 }
185 zbx_lld_trigger_ref_t;
186
187 /* a trigger node used to build trigger tree for dependency validation */
188 typedef struct
189 {
190 /* trigger reference */
191 zbx_lld_trigger_ref_t trigger_ref;
192
193 /* the current iteration number, used during dependency validation */
194 int iter_num;
195
196 /* the number of dependents */
197 int parents;
198
199 /* trigger dependency list */
200 zbx_vector_ptr_t dependencies;
201 }
202 zbx_lld_trigger_node_t;
203
204 /* a structure to keep information about current iteration during trigger dependencies validation */
205 typedef struct
206 {
207 /* iteration number */
208 int iter_num;
209
210 /* the dependency (from->to) that should be removed in the case of recursive loop */
211 zbx_lld_trigger_ref_t *ref_from;
212 zbx_lld_trigger_ref_t *ref_to;
213 }
214 zbx_lld_trigger_node_iter_t;
215
216
lld_tag_free(zbx_lld_tag_t * tag)217 static void lld_tag_free(zbx_lld_tag_t *tag)
218 {
219 zbx_free(tag->tag);
220 zbx_free(tag->value);
221 zbx_free(tag);
222 }
223
lld_item_free(zbx_lld_item_t * item)224 static void lld_item_free(zbx_lld_item_t *item)
225 {
226 zbx_free(item);
227 }
228
lld_function_free(zbx_lld_function_t * function)229 static void lld_function_free(zbx_lld_function_t *function)
230 {
231 zbx_free(function->parameter_orig);
232 zbx_free(function->parameter);
233 zbx_free(function->function_orig);
234 zbx_free(function->function);
235 zbx_free(function);
236 }
237
lld_trigger_prototype_free(zbx_lld_trigger_prototype_t * trigger_prototype)238 static void lld_trigger_prototype_free(zbx_lld_trigger_prototype_t *trigger_prototype)
239 {
240 zbx_vector_ptr_clear_ext(&trigger_prototype->tags, (zbx_clean_func_t)lld_tag_free);
241 zbx_vector_ptr_destroy(&trigger_prototype->tags);
242 zbx_vector_ptr_clear_ext(&trigger_prototype->dependencies, zbx_ptr_free);
243 zbx_vector_ptr_destroy(&trigger_prototype->dependencies);
244 zbx_vector_ptr_clear_ext(&trigger_prototype->functions, (zbx_mem_free_func_t)lld_function_free);
245 zbx_vector_ptr_destroy(&trigger_prototype->functions);
246 zbx_free(trigger_prototype->opdata);
247 zbx_free(trigger_prototype->correlation_tag);
248 zbx_free(trigger_prototype->url);
249 zbx_free(trigger_prototype->comments);
250 zbx_free(trigger_prototype->recovery_expression);
251 zbx_free(trigger_prototype->expression);
252 zbx_free(trigger_prototype->description);
253 zbx_free(trigger_prototype);
254 }
255
lld_trigger_free(zbx_lld_trigger_t * trigger)256 static void lld_trigger_free(zbx_lld_trigger_t *trigger)
257 {
258 zbx_vector_ptr_clear_ext(&trigger->tags, (zbx_clean_func_t)lld_tag_free);
259 zbx_vector_ptr_pair_destroy(&trigger->override_tags);
260 zbx_vector_ptr_destroy(&trigger->tags);
261 zbx_vector_ptr_destroy(&trigger->dependents);
262 zbx_vector_ptr_clear_ext(&trigger->dependencies, zbx_ptr_free);
263 zbx_vector_ptr_destroy(&trigger->dependencies);
264 zbx_vector_ptr_clear_ext(&trigger->functions, (zbx_clean_func_t)lld_function_free);
265 zbx_vector_ptr_destroy(&trigger->functions);
266 zbx_free(trigger->opdata_orig);
267 zbx_free(trigger->opdata);
268 zbx_free(trigger->correlation_tag_orig);
269 zbx_free(trigger->correlation_tag);
270 zbx_free(trigger->url_orig);
271 zbx_free(trigger->url);
272 zbx_free(trigger->comments_orig);
273 zbx_free(trigger->comments);
274 zbx_free(trigger->recovery_expression_orig);
275 zbx_free(trigger->recovery_expression);
276 zbx_free(trigger->expression_orig);
277 zbx_free(trigger->expression);
278 zbx_free(trigger->description_orig);
279 zbx_free(trigger->description);
280 zbx_free(trigger);
281 }
282
283 /******************************************************************************
284 * *
285 * Function: lld_trigger_prototypes_get *
286 * *
287 * Purpose: retrieve trigger prototypes which are inherited from the *
288 * discovery rule *
289 * *
290 * Parameters: lld_ruleid - [IN] discovery rule id *
291 * trigger_prototypes - [OUT] sorted list of trigger prototypes *
292 * *
293 ******************************************************************************/
lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * trigger_prototypes)294 static void lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *trigger_prototypes)
295 {
296 DB_RESULT result;
297 DB_ROW row;
298 zbx_lld_trigger_prototype_t *trigger_prototype;
299
300 result = DBselect(
301 "select distinct t.triggerid,t.description,t.expression,t.status,t.type,t.priority,t.comments,"
302 "t.url,t.recovery_expression,t.recovery_mode,t.correlation_mode,t.correlation_tag,"
303 "t.manual_close,t.opdata,t.discover"
304 " from triggers t,functions f,items i,item_discovery id"
305 " where t.triggerid=f.triggerid"
306 " and f.itemid=i.itemid"
307 " and i.itemid=id.itemid"
308 " and id.parent_itemid=" ZBX_FS_UI64,
309 lld_ruleid);
310
311 /* run through trigger prototypes */
312 while (NULL != (row = DBfetch(result)))
313 {
314 trigger_prototype = (zbx_lld_trigger_prototype_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_prototype_t));
315
316 ZBX_STR2UINT64(trigger_prototype->triggerid, row[0]);
317 trigger_prototype->description = zbx_strdup(NULL, row[1]);
318 trigger_prototype->expression = zbx_strdup(NULL, row[2]);
319 trigger_prototype->recovery_expression = zbx_strdup(NULL, row[8]);
320 ZBX_STR2UCHAR(trigger_prototype->status, row[3]);
321 ZBX_STR2UCHAR(trigger_prototype->type, row[4]);
322 ZBX_STR2UCHAR(trigger_prototype->priority, row[5]);
323 ZBX_STR2UCHAR(trigger_prototype->recovery_mode, row[9]);
324 trigger_prototype->comments = zbx_strdup(NULL, row[6]);
325 trigger_prototype->url = zbx_strdup(NULL, row[7]);
326 ZBX_STR2UCHAR(trigger_prototype->correlation_mode, row[10]);
327 trigger_prototype->correlation_tag = zbx_strdup(NULL, row[11]);
328 ZBX_STR2UCHAR(trigger_prototype->manual_close, row[12]);
329 trigger_prototype->opdata = zbx_strdup(NULL, row[13]);
330 ZBX_STR2UCHAR(trigger_prototype->discover, row[14]);
331
332 zbx_vector_ptr_create(&trigger_prototype->functions);
333 zbx_vector_ptr_create(&trigger_prototype->dependencies);
334 zbx_vector_ptr_create(&trigger_prototype->tags);
335
336 zbx_vector_ptr_append(trigger_prototypes, trigger_prototype);
337 }
338 DBfree_result(result);
339
340 zbx_vector_ptr_sort(trigger_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
341 }
342
343 /******************************************************************************
344 * *
345 * Function: lld_triggers_get *
346 * *
347 * Purpose: retrieve triggers which were created by the specified trigger *
348 * prototypes *
349 * *
350 * Parameters: trigger_prototypes - [IN] sorted list of trigger prototypes *
351 * triggers - [OUT] sorted list of triggers *
352 * *
353 ******************************************************************************/
lld_triggers_get(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)354 static void lld_triggers_get(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
355 {
356 DB_RESULT result;
357 DB_ROW row;
358 zbx_vector_uint64_t parent_triggerids;
359 char *sql = NULL;
360 size_t sql_alloc = 256, sql_offset = 0;
361 int i;
362
363 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
364
365 zbx_vector_uint64_create(&parent_triggerids);
366 zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
367
368 for (i = 0; i < trigger_prototypes->values_num; i++)
369 {
370 const zbx_lld_trigger_prototype_t *trigger_prototype;
371
372 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
373
374 zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
375 }
376
377 sql = (char *)zbx_malloc(sql, sql_alloc);
378
379 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
380 "select td.parent_triggerid,t.triggerid,t.description,t.expression,t.type,t.priority,"
381 "t.comments,t.url,t.recovery_expression,t.recovery_mode,t.correlation_mode,"
382 "t.correlation_tag,t.manual_close,t.opdata,td.lastcheck,td.ts_delete"
383 " from triggers t,trigger_discovery td"
384 " where t.triggerid=td.triggerid"
385 " and");
386 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.parent_triggerid",
387 parent_triggerids.values, parent_triggerids.values_num);
388
389 zbx_vector_uint64_destroy(&parent_triggerids);
390
391 result = DBselect("%s", sql);
392
393 zbx_free(sql);
394
395 while (NULL != (row = DBfetch(result)))
396 {
397 zbx_uint64_t parent_triggerid;
398 const zbx_lld_trigger_prototype_t *trigger_prototype;
399 zbx_lld_trigger_t *trigger;
400 int index;
401
402 ZBX_STR2UINT64(parent_triggerid, row[0]);
403
404 if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_prototypes, &parent_triggerid,
405 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
406 {
407 THIS_SHOULD_NEVER_HAPPEN;
408 continue;
409 }
410
411 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
412
413 trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
414
415 ZBX_STR2UINT64(trigger->triggerid, row[1]);
416 trigger->parent_triggerid = parent_triggerid;
417 trigger->description = zbx_strdup(NULL, row[2]);
418 trigger->description_orig = NULL;
419 trigger->expression = zbx_strdup(NULL, row[3]);
420 trigger->expression_orig = NULL;
421 trigger->recovery_expression = zbx_strdup(NULL, row[8]);
422 trigger->recovery_expression_orig = NULL;
423
424 trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
425
426 if ((unsigned char)atoi(row[4]) != trigger_prototype->type)
427 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE;
428
429 trigger->priority = (unsigned char)atoi(row[5]);
430
431 if ((unsigned char)atoi(row[9]) != trigger_prototype->recovery_mode)
432 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE;
433
434 if ((unsigned char)atoi(row[10]) != trigger_prototype->correlation_mode)
435 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE;
436
437 if ((unsigned char)atoi(row[12]) != trigger_prototype->manual_close)
438 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE;
439
440 trigger->comments = zbx_strdup(NULL, row[6]);
441 trigger->comments_orig = NULL;
442 trigger->url = zbx_strdup(NULL, row[7]);
443 trigger->url_orig = NULL;
444 trigger->correlation_tag = zbx_strdup(NULL, row[11]);
445 trigger->correlation_tag_orig = NULL;
446 trigger->opdata = zbx_strdup(NULL, row[13]);
447 trigger->opdata_orig = NULL;
448 trigger->lastcheck = atoi(row[14]);
449 trigger->ts_delete = atoi(row[15]);
450
451 zbx_vector_ptr_create(&trigger->functions);
452 zbx_vector_ptr_create(&trigger->dependencies);
453 zbx_vector_ptr_create(&trigger->dependents);
454 zbx_vector_ptr_create(&trigger->tags);
455 zbx_vector_ptr_pair_create(&trigger->override_tags);
456
457 zbx_vector_ptr_append(triggers, trigger);
458 }
459 DBfree_result(result);
460
461 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
462
463 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
464 }
465
466 /******************************************************************************
467 * *
468 * Function: lld_functions_get *
469 * *
470 * Purpose: retrieve functions which are used by all triggers in the host of *
471 * the trigger prototype *
472 * *
473 ******************************************************************************/
lld_functions_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)474 static void lld_functions_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
475 {
476 int i;
477 zbx_lld_trigger_prototype_t *trigger_prototype;
478 zbx_lld_trigger_t *trigger;
479 zbx_vector_uint64_t triggerids;
480
481 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
482
483 zbx_vector_uint64_create(&triggerids);
484
485 if (NULL != trigger_prototypes)
486 {
487 for (i = 0; i < trigger_prototypes->values_num; i++)
488 {
489 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
490
491 zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
492 }
493 }
494
495 for (i = 0; i < triggers->values_num; i++)
496 {
497 trigger = (zbx_lld_trigger_t *)triggers->values[i];
498
499 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
500 }
501
502 if (0 != triggerids.values_num)
503 {
504 DB_RESULT result;
505 DB_ROW row;
506 zbx_lld_function_t *function;
507 zbx_uint64_t triggerid;
508 char *sql = NULL;
509 size_t sql_alloc = 256, sql_offset = 0;
510 int index;
511
512 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
513
514 sql = (char *)zbx_malloc(sql, sql_alloc);
515
516 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
517 "select functionid,triggerid,itemid,name,parameter"
518 " from functions"
519 " where");
520 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
521 triggerids.values, triggerids.values_num);
522
523 result = DBselect("%s", sql);
524
525 zbx_free(sql);
526
527 while (NULL != (row = DBfetch(result)))
528 {
529 function = (zbx_lld_function_t *)zbx_malloc(NULL, sizeof(zbx_lld_function_t));
530
531 function->index = 0;
532 ZBX_STR2UINT64(function->functionid, row[0]);
533 ZBX_STR2UINT64(triggerid, row[1]);
534 ZBX_STR2UINT64(function->itemid, row[2]);
535 function->itemid_orig = 0;
536 function->function = zbx_strdup(NULL, row[3]);
537 function->function_orig = NULL;
538 function->parameter = zbx_strdup(NULL, row[4]);
539 function->parameter_orig = NULL;
540 function->flags = ZBX_FLAG_LLD_FUNCTION_UNSET;
541
542 if (NULL != trigger_prototypes && FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes,
543 &triggerid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
544 {
545 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
546
547 zbx_vector_ptr_append(&trigger_prototype->functions, function);
548 }
549 else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
550 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
551 {
552 trigger = (zbx_lld_trigger_t *)triggers->values[index];
553
554 zbx_vector_ptr_append(&trigger->functions, function);
555 }
556 else
557 {
558 THIS_SHOULD_NEVER_HAPPEN;
559 lld_function_free(function);
560 }
561 }
562 DBfree_result(result);
563
564 if (NULL != trigger_prototypes)
565 {
566 for (i = 0; i < trigger_prototypes->values_num; i++)
567 {
568 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
569
570 zbx_vector_ptr_sort(&trigger_prototype->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
571 }
572 }
573
574 for (i = 0; i < triggers->values_num; i++)
575 {
576 trigger = (zbx_lld_trigger_t *)triggers->values[i];
577
578 zbx_vector_ptr_sort(&trigger->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
579 }
580 }
581
582 zbx_vector_uint64_destroy(&triggerids);
583
584 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
585 }
586
587 /******************************************************************************
588 * *
589 * Function: lld_dependencies_get *
590 * *
591 * Purpose: retrieve trigger dependencies *
592 * *
593 ******************************************************************************/
lld_dependencies_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)594 static void lld_dependencies_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
595 {
596 DB_RESULT result;
597 DB_ROW row;
598 zbx_lld_trigger_prototype_t *trigger_prototype;
599 zbx_lld_trigger_t *trigger;
600 zbx_lld_dependency_t *dependency;
601 zbx_vector_uint64_t triggerids;
602 zbx_uint64_t triggerid_down;
603 char *sql = NULL;
604 size_t sql_alloc = 256, sql_offset = 0;
605 int i, index;
606
607 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
608
609 zbx_vector_uint64_create(&triggerids);
610
611 for (i = 0; i < trigger_prototypes->values_num; i++)
612 {
613 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
614
615 zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
616 }
617
618 for (i = 0; i < triggers->values_num; i++)
619 {
620 trigger = (zbx_lld_trigger_t *)triggers->values[i];
621
622 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
623 }
624
625 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
626
627 sql = (char *)zbx_malloc(sql, sql_alloc);
628
629 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
630 "select triggerdepid,triggerid_down,triggerid_up"
631 " from trigger_depends"
632 " where");
633 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid_down",
634 triggerids.values, triggerids.values_num);
635
636 zbx_vector_uint64_destroy(&triggerids);
637
638 result = DBselect("%s", sql);
639
640 zbx_free(sql);
641
642 while (NULL != (row = DBfetch(result)))
643 {
644 dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
645
646 ZBX_STR2UINT64(dependency->triggerdepid, row[0]);
647 ZBX_STR2UINT64(triggerid_down, row[1]);
648 ZBX_STR2UINT64(dependency->triggerid_up, row[2]);
649 dependency->trigger_up = NULL;
650 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
651
652 if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_down,
653 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
654 {
655 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
656
657 zbx_vector_ptr_append(&trigger_prototype->dependencies, dependency);
658 }
659 else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid_down,
660 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
661 {
662 trigger = (zbx_lld_trigger_t *)triggers->values[index];
663
664 zbx_vector_ptr_append(&trigger->dependencies, dependency);
665 }
666 else
667 {
668 THIS_SHOULD_NEVER_HAPPEN;
669 zbx_ptr_free(dependency);
670 }
671 }
672 DBfree_result(result);
673
674 for (i = 0; i < trigger_prototypes->values_num; i++)
675 {
676 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
677
678 zbx_vector_ptr_sort(&trigger_prototype->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
679 }
680
681 for (i = 0; i < triggers->values_num; i++)
682 {
683 trigger = (zbx_lld_trigger_t *)triggers->values[i];
684
685 zbx_vector_ptr_sort(&trigger->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
686 }
687
688 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
689 }
690
691 /******************************************************************************
692 * *
693 * Function: lld_tags_get *
694 * *
695 * Purpose: retrieve trigger tags *
696 * *
697 ******************************************************************************/
lld_tags_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)698 static void lld_tags_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
699 {
700 DB_RESULT result;
701 DB_ROW row;
702 zbx_vector_uint64_t triggerids;
703 int i, index;
704 zbx_lld_trigger_prototype_t *trigger_prototype;
705 zbx_lld_trigger_t *trigger;
706 zbx_lld_tag_t *tag;
707 char *sql = NULL;
708 size_t sql_alloc = 256, sql_offset = 0;
709 zbx_uint64_t triggerid;
710
711 zbx_vector_uint64_create(&triggerids);
712
713 for (i = 0; i < trigger_prototypes->values_num; i++)
714 {
715 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
716
717 zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
718 }
719
720 for (i = 0; i < triggers->values_num; i++)
721 {
722 trigger = (zbx_lld_trigger_t *)triggers->values[i];
723
724 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
725 }
726
727 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
728
729 sql = (char *)zbx_malloc(sql, sql_alloc);
730
731 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
732 "select triggertagid,triggerid,tag,value"
733 " from trigger_tag"
734 " where");
735 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
736 triggerids.values, triggerids.values_num);
737
738 zbx_vector_uint64_destroy(&triggerids);
739
740 result = DBselect("%s", sql);
741
742 zbx_free(sql);
743
744 while (NULL != (row = DBfetch(result)))
745 {
746 tag = (zbx_lld_tag_t *)zbx_malloc(NULL, sizeof(zbx_lld_tag_t));
747
748 ZBX_STR2UINT64(tag->triggertagid, row[0]);
749 ZBX_STR2UINT64(triggerid, row[1]);
750 tag->tag = zbx_strdup(NULL, row[2]);
751 tag->value = zbx_strdup(NULL, row[3]);
752 tag->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
753
754 if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid,
755 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
756 {
757 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
758
759 zbx_vector_ptr_append(&trigger_prototype->tags, tag);
760 }
761 else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
762 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
763 {
764 trigger = (zbx_lld_trigger_t *)triggers->values[index];
765
766 zbx_vector_ptr_append(&trigger->tags, tag);
767 }
768 else
769 {
770 THIS_SHOULD_NEVER_HAPPEN;
771 zbx_ptr_free(tag);
772 }
773
774 }
775 DBfree_result(result);
776
777 for (i = 0; i < trigger_prototypes->values_num; i++)
778 {
779 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
780
781 zbx_vector_ptr_sort(&trigger_prototype->tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
782 }
783
784 for (i = 0; i < triggers->values_num; i++)
785 {
786 trigger = (zbx_lld_trigger_t *)triggers->values[i];
787
788 zbx_vector_ptr_sort(&trigger->tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
789 }
790
791 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
792 }
793
794 /******************************************************************************
795 * *
796 * Function: lld_items_get *
797 * *
798 * Purpose: returns the list of items which are related to the trigger *
799 * prototypes *
800 * *
801 * Parameters: trigger_prototypes - [IN] a vector of trigger prototypes *
802 * items - [OUT] sorted list of items *
803 * *
804 ******************************************************************************/
lld_items_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * items)805 static void lld_items_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *items)
806 {
807 DB_RESULT result;
808 DB_ROW row;
809 zbx_lld_item_t *item;
810 zbx_vector_uint64_t parent_triggerids;
811 char *sql = NULL;
812 size_t sql_alloc = 256, sql_offset = 0;
813 int i;
814
815 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
816
817 zbx_vector_uint64_create(&parent_triggerids);
818 zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
819
820 for (i = 0; i < trigger_prototypes->values_num; i++)
821 {
822 zbx_lld_trigger_prototype_t *trigger_prototype;
823
824 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
825
826 zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
827 }
828 sql = (char *)zbx_malloc(sql, sql_alloc);
829
830 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
831 "select distinct i.itemid,i.flags"
832 " from items i,functions f"
833 " where i.itemid=f.itemid"
834 " and");
835 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "f.triggerid",
836 parent_triggerids.values, parent_triggerids.values_num);
837
838 zbx_vector_uint64_destroy(&parent_triggerids);
839
840 result = DBselect("%s", sql);
841
842 zbx_free(sql);
843
844 while (NULL != (row = DBfetch(result)))
845 {
846 item = (zbx_lld_item_t *)zbx_malloc(NULL, sizeof(zbx_lld_item_t));
847
848 ZBX_STR2UINT64(item->itemid, row[0]);
849 ZBX_STR2UCHAR(item->flags, row[1]);
850
851 zbx_vector_ptr_append(items, item);
852 }
853 DBfree_result(result);
854
855 zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
856
857 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
858 }
859
860 /******************************************************************************
861 * *
862 * Function: lld_trigger_get *
863 * *
864 * Purpose: finds already existing trigger, using an item prototype and items *
865 * already created by it *
866 * *
867 * Return value: upon successful completion return pointer to the trigger *
868 * *
869 ******************************************************************************/
lld_trigger_get(zbx_uint64_t parent_triggerid,zbx_hashset_t * items_triggers,const zbx_vector_ptr_t * item_links)870 static zbx_lld_trigger_t *lld_trigger_get(zbx_uint64_t parent_triggerid, zbx_hashset_t *items_triggers,
871 const zbx_vector_ptr_t *item_links)
872 {
873 int i;
874
875 for (i = 0; i < item_links->values_num; i++)
876 {
877 zbx_lld_item_trigger_t *item_trigger, item_trigger_local;
878 const zbx_lld_item_link_t *item_link = (zbx_lld_item_link_t *)item_links->values[i];
879
880 item_trigger_local.parent_triggerid = parent_triggerid;
881 item_trigger_local.itemid = item_link->itemid;
882
883 if (NULL != (item_trigger = (zbx_lld_item_trigger_t *)zbx_hashset_search(items_triggers, &item_trigger_local)))
884 return item_trigger->trigger;
885 }
886
887 return NULL;
888 }
889
lld_expression_simplify(char ** expression,zbx_vector_ptr_t * functions,zbx_uint64_t * function_index)890 static void lld_expression_simplify(char **expression, zbx_vector_ptr_t *functions, zbx_uint64_t *function_index)
891 {
892 size_t l, r;
893 int index;
894 zbx_uint64_t functionid;
895 zbx_lld_function_t *function;
896 char buffer[ZBX_MAX_UINT64_LEN];
897
898 for (l = 0; '\0' != (*expression)[l]; l++)
899 {
900 if ('{' != (*expression)[l])
901 continue;
902
903 if ('$' == (*expression)[l + 1])
904 {
905 int macro_r, context_l, context_r;
906
907 if (SUCCEED == zbx_user_macro_parse(*expression + l, ¯o_r, &context_l, &context_r, NULL))
908 l += macro_r;
909 else
910 l++;
911
912 continue;
913 }
914
915 for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
916 ;
917
918 if ('}' != (*expression)[r])
919 continue;
920
921 /* ... > 0 | {12345} + ... */
922 /* l r */
923
924 if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &functionid))
925 continue;
926
927 if (FAIL != (index = zbx_vector_ptr_bsearch(functions, &functionid,
928 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
929 {
930 function = (zbx_lld_function_t *)functions->values[index];
931
932 if (0 == function->index)
933 function->index = ++(*function_index);
934
935 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->index);
936
937 r--;
938 zbx_replace_string(expression, l + 1, &r, buffer);
939 r++;
940 }
941
942 l = r;
943 }
944 }
945
lld_expressions_simplify(char ** expression,char ** recovery_expression,zbx_vector_ptr_t * functions)946 static void lld_expressions_simplify(char **expression, char **recovery_expression, zbx_vector_ptr_t *functions)
947 {
948 zbx_uint64_t function_index = 0;
949
950 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s' recovery_expression:'%s'", __func__,
951 *expression, *recovery_expression);
952
953 lld_expression_simplify(expression, functions, &function_index);
954 lld_expression_simplify(recovery_expression, functions, &function_index);
955
956 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s' recovery_expression:'%s'", __func__,
957 *expression, *recovery_expression);
958 }
959
lld_expression_expand(const char * expression,const zbx_vector_ptr_t * functions)960 static char *lld_expression_expand(const char *expression, const zbx_vector_ptr_t *functions)
961 {
962 size_t l, r;
963 int i;
964 zbx_uint64_t index;
965 char *buffer = NULL;
966 size_t buffer_alloc = 64, buffer_offset = 0;
967
968 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression);
969
970 buffer = (char *)zbx_malloc(buffer, buffer_alloc);
971
972 *buffer = '\0';
973
974 for (l = 0; '\0' != expression[l]; l++)
975 {
976 zbx_chrcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, expression[l]);
977
978 if ('{' != expression[l])
979 continue;
980
981 if ('$' == expression[l + 1])
982 {
983 int macro_r, context_l, context_r;
984
985 if (SUCCEED == zbx_user_macro_parse(expression + l, ¯o_r, &context_l, &context_r, NULL))
986 l += macro_r;
987 else
988 l++;
989
990 continue;
991 }
992
993 for (r = l + 1; '\0' != expression[r] && '}' != expression[r]; r++)
994 ;
995
996 if ('}' != expression[r])
997 continue;
998
999 /* ... > 0 | {1} + ... */
1000 /* l r */
1001
1002 if (SUCCEED != is_uint64_n(expression + l + 1, r - l - 1, &index))
1003 continue;
1004
1005 for (i = 0; i < functions->values_num; i++)
1006 {
1007 const zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
1008
1009 if (function->index != index)
1010 continue;
1011
1012 zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, ZBX_FS_UI64 ":%s(%s)",
1013 function->itemid, function->function, function->parameter);
1014
1015 break;
1016 }
1017
1018 l = r - 1;
1019 }
1020
1021 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():'%s'", __func__, buffer);
1022
1023 return buffer;
1024 }
1025
lld_parameter_make(const char * e,char ** exp,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1026 static int lld_parameter_make(const char *e, char **exp, const struct zbx_json_parse *jp_row,
1027 const zbx_vector_ptr_t *lld_macros, char **error)
1028 {
1029 int ret;
1030 size_t exp_alloc = 0, exp_offset = 0;
1031 size_t length;
1032 char err[64];
1033
1034 if (FAIL == zbx_function_validate_parameters(e, &length))
1035 {
1036 *error = zbx_dsprintf(*error, "Invalid parameter \"%s\"", e);
1037 return FAIL;
1038 }
1039
1040 if (FAIL == (ret = substitute_function_lld_param(e, length, 0, exp, &exp_alloc, &exp_offset, jp_row, lld_macros,
1041 err, sizeof(err))))
1042 {
1043 *error = zbx_strdup(*error, err);
1044 }
1045
1046 return ret;
1047 }
1048
lld_function_make(const zbx_lld_function_t * function_proto,zbx_vector_ptr_t * functions,zbx_uint64_t itemid,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1049 static int lld_function_make(const zbx_lld_function_t *function_proto, zbx_vector_ptr_t *functions,
1050 zbx_uint64_t itemid, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros,
1051 char **error)
1052 {
1053 int i, ret, function_found = 0;
1054 zbx_lld_function_t *function = NULL;
1055 char *proto_parameter = NULL;
1056
1057 for (i = 0; i < functions->values_num; i++)
1058 {
1059 function = (zbx_lld_function_t *)functions->values[i];
1060
1061 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1062 continue;
1063
1064 if (function->index == function_proto->index)
1065 {
1066 function_found = 1;
1067 break;
1068 }
1069 }
1070
1071 if (FAIL == (ret = lld_parameter_make(function_proto->parameter, &proto_parameter, jp_row, lld_macros, error)))
1072 goto clean;
1073
1074 if (0 == function_found)
1075 {
1076 function = (zbx_lld_function_t *)zbx_malloc(NULL, sizeof(zbx_lld_function_t));
1077
1078 function->index = function_proto->index;
1079 function->functionid = 0;
1080 function->itemid = itemid;
1081 function->itemid_orig = 0;
1082 function->function = zbx_strdup(NULL, function_proto->function);
1083 function->function_orig = NULL;
1084 function->parameter = proto_parameter;
1085 proto_parameter = NULL;
1086 function->parameter_orig = NULL;
1087 function->flags = ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1088
1089 zbx_vector_ptr_append(functions, function);
1090 }
1091 else
1092 {
1093 if (function->itemid != itemid)
1094 {
1095 function->itemid_orig = function->itemid;
1096 function->itemid = itemid;
1097 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID;
1098 }
1099
1100 if (0 != strcmp(function->function, function_proto->function))
1101 {
1102 function->function_orig = function->function;
1103 function->function = zbx_strdup(NULL, function_proto->function);
1104 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION;
1105 }
1106
1107 if (0 != strcmp(function->parameter, proto_parameter))
1108 {
1109 function->parameter_orig = function->parameter;
1110 function->parameter = proto_parameter;
1111 proto_parameter = NULL;
1112 function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER;
1113 }
1114
1115 function->flags |= ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1116 }
1117 clean:
1118 zbx_free(proto_parameter);
1119
1120 return ret;
1121 }
1122
lld_functions_delete(zbx_vector_ptr_t * functions)1123 static void lld_functions_delete(zbx_vector_ptr_t *functions)
1124 {
1125 int i;
1126
1127 for (i = 0; i < functions->values_num; i++)
1128 {
1129 zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
1130
1131 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1132 continue;
1133
1134 function->flags |= ZBX_FLAG_LLD_FUNCTION_DELETE;
1135 }
1136 }
1137
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,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1138 static int lld_functions_make(const zbx_vector_ptr_t *functions_proto, zbx_vector_ptr_t *functions,
1139 const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *item_links, const struct zbx_json_parse *jp_row,
1140 const zbx_vector_ptr_t *lld_macros, char **error)
1141 {
1142 int i, index, ret = FAIL;
1143 const zbx_lld_function_t *function_proto;
1144 const zbx_lld_item_t *item_proto;
1145 const zbx_lld_item_link_t *item_link;
1146 zbx_uint64_t itemid;
1147
1148 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1149
1150 for (i = 0; i < functions_proto->values_num; i++)
1151 {
1152 function_proto = (zbx_lld_function_t *)functions_proto->values[i];
1153
1154 index = zbx_vector_ptr_bsearch(items, &function_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1155
1156 if (FAIL == index)
1157 goto out;
1158
1159 item_proto = (zbx_lld_item_t *)items->values[index];
1160
1161 if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
1162 {
1163 index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid,
1164 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1165
1166 if (FAIL == index)
1167 goto out;
1168
1169 item_link = (zbx_lld_item_link_t *)item_links->values[index];
1170
1171 itemid = item_link->itemid;
1172 }
1173 else
1174 itemid = item_proto->itemid;
1175
1176 if (FAIL == lld_function_make(function_proto, functions, itemid, jp_row, lld_macros, error))
1177 goto out;
1178 }
1179
1180 lld_functions_delete(functions);
1181
1182 ret = SUCCEED;
1183 out:
1184 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1185
1186 return ret;
1187 }
1188
1189 /******************************************************************************
1190 * *
1191 * Function: lld_trigger_make *
1192 * *
1193 * Purpose: create a trigger based on lld rule and add it to the list *
1194 * *
1195 ******************************************************************************/
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,const zbx_vector_ptr_t * lld_macros,char ** error)1196 static void lld_trigger_make(const zbx_lld_trigger_prototype_t *trigger_prototype, zbx_vector_ptr_t *triggers,
1197 const zbx_vector_ptr_t *items, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row,
1198 const zbx_vector_ptr_t *lld_macros, char **error)
1199 {
1200 zbx_lld_trigger_t *trigger;
1201 char *buffer = NULL, *expression = NULL, *recovery_expression = NULL, err[64];
1202 char *err_msg = NULL;
1203 const char *operation_msg;
1204 const struct zbx_json_parse *jp_row = &lld_row->jp_row;
1205 unsigned char discover;
1206
1207 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1208
1209 trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links);
1210 operation_msg = NULL != trigger ? "update" : "create";
1211
1212 expression = zbx_strdup(expression, trigger_prototype->expression);
1213 recovery_expression = zbx_strdup(recovery_expression, trigger_prototype->recovery_expression);
1214
1215 if (SUCCEED != substitute_lld_macros(&expression, jp_row, lld_macros, ZBX_MACRO_ANY | ZBX_TOKEN_TRIGGER,
1216 err, sizeof(err)) ||
1217 SUCCEED != substitute_lld_macros(&recovery_expression, jp_row, lld_macros,
1218 ZBX_MACRO_ANY | ZBX_TOKEN_TRIGGER, err, sizeof(err)))
1219 {
1220 *error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", operation_msg, err);
1221 goto out;
1222 }
1223
1224 discover = trigger_prototype->discover;
1225
1226 if (NULL != trigger)
1227 {
1228 unsigned char priority;
1229
1230 buffer = zbx_strdup(buffer, trigger_prototype->description);
1231 substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1232 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1233 priority = trigger_prototype->priority;
1234
1235 lld_override_trigger(&lld_row->overrides, buffer, &priority, &trigger->override_tags, NULL, &discover);
1236
1237 if (ZBX_PROTOTYPE_NO_DISCOVER == discover)
1238 goto out;
1239
1240 if (0 != strcmp(trigger->description, buffer))
1241 {
1242 trigger->description_orig = trigger->description;
1243 trigger->description = buffer;
1244 buffer = NULL;
1245 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION;
1246 }
1247
1248 if (trigger->priority != priority)
1249 {
1250 trigger->priority = priority;
1251 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY;
1252 }
1253
1254 if (0 != strcmp(trigger->expression, expression))
1255 {
1256 trigger->expression_orig = trigger->expression;
1257 trigger->expression = expression;
1258 expression = NULL;
1259 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION;
1260 }
1261
1262 if (0 != strcmp(trigger->recovery_expression, recovery_expression))
1263 {
1264 trigger->recovery_expression_orig = trigger->recovery_expression;
1265 trigger->recovery_expression = recovery_expression;
1266 recovery_expression = NULL;
1267 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION;
1268 }
1269
1270 buffer = zbx_strdup(buffer, trigger_prototype->comments);
1271 substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1272 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1273 if (0 != strcmp(trigger->comments, buffer))
1274 {
1275 trigger->comments_orig = trigger->comments;
1276 trigger->comments = buffer;
1277 buffer = NULL;
1278 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS;
1279 }
1280
1281 buffer = zbx_strdup(buffer, trigger_prototype->url);
1282 substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1283 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1284 if (0 != strcmp(trigger->url, buffer))
1285 {
1286 trigger->url_orig = trigger->url;
1287 trigger->url = buffer;
1288 buffer = NULL;
1289 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_URL;
1290 }
1291
1292 buffer = zbx_strdup(buffer, trigger_prototype->correlation_tag);
1293 substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1294 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1295 if (0 != strcmp(trigger->correlation_tag, buffer))
1296 {
1297 trigger->correlation_tag_orig = trigger->correlation_tag;
1298 trigger->correlation_tag = buffer;
1299 buffer = NULL;
1300 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG;
1301 }
1302
1303 buffer = zbx_strdup(buffer, trigger_prototype->opdata);
1304 substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1305 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1306 if (0 != strcmp(trigger->opdata, buffer))
1307 {
1308 trigger->opdata_orig = trigger->opdata;
1309 trigger->opdata = buffer;
1310 buffer = NULL;
1311 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA;
1312 }
1313 }
1314 else
1315 {
1316 trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1317
1318 trigger->triggerid = 0;
1319 trigger->lastcheck = 0;
1320 trigger->ts_delete = 0;
1321 trigger->parent_triggerid = trigger_prototype->triggerid;
1322
1323 trigger->description = zbx_strdup(NULL, trigger_prototype->description);
1324 trigger->description_orig = NULL;
1325 substitute_lld_macros(&trigger->description, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1326 zbx_lrtrim(trigger->description, ZBX_WHITESPACE);
1327
1328 trigger->status = trigger_prototype->status;
1329 trigger->priority = trigger_prototype->priority;
1330
1331 zbx_vector_ptr_pair_create(&trigger->override_tags);
1332
1333 lld_override_trigger(&lld_row->overrides, trigger->description, &trigger->priority,
1334 &trigger->override_tags, &trigger->status, &discover);
1335
1336 if (ZBX_PROTOTYPE_NO_DISCOVER == discover)
1337 {
1338 zbx_vector_ptr_pair_destroy(&trigger->override_tags);
1339 zbx_free(trigger->description);
1340 zbx_free(trigger);
1341 goto out;
1342 }
1343
1344 trigger->expression = expression;
1345 trigger->expression_orig = NULL;
1346 expression = NULL;
1347
1348 trigger->recovery_expression = recovery_expression;
1349 trigger->recovery_expression_orig = NULL;
1350 recovery_expression = NULL;
1351
1352 trigger->comments = zbx_strdup(NULL, trigger_prototype->comments);
1353 trigger->comments_orig = NULL;
1354 substitute_lld_macros(&trigger->comments, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1355 zbx_lrtrim(trigger->comments, ZBX_WHITESPACE);
1356
1357 trigger->url = zbx_strdup(NULL, trigger_prototype->url);
1358 trigger->url_orig = NULL;
1359 substitute_lld_macros(&trigger->url, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1360 zbx_lrtrim(trigger->url, ZBX_WHITESPACE);
1361
1362 trigger->correlation_tag = zbx_strdup(NULL, trigger_prototype->correlation_tag);
1363 trigger->correlation_tag_orig = NULL;
1364 substitute_lld_macros(&trigger->correlation_tag, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1365 zbx_lrtrim(trigger->correlation_tag, ZBX_WHITESPACE);
1366
1367 trigger->opdata = zbx_strdup(NULL, trigger_prototype->opdata);
1368 trigger->opdata_orig = NULL;
1369 substitute_lld_macros(&trigger->opdata, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1370 zbx_lrtrim(trigger->opdata, ZBX_WHITESPACE);
1371
1372 zbx_vector_ptr_create(&trigger->functions);
1373 zbx_vector_ptr_create(&trigger->dependencies);
1374 zbx_vector_ptr_create(&trigger->dependents);
1375 zbx_vector_ptr_create(&trigger->tags);
1376
1377 trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1378
1379 zbx_vector_ptr_append(triggers, trigger);
1380 }
1381
1382 if (SUCCEED != lld_functions_make(&trigger_prototype->functions, &trigger->functions, items,
1383 &lld_row->item_links, jp_row, lld_macros, &err_msg))
1384 {
1385 if (err_msg)
1386 {
1387 *error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", operation_msg, err_msg);
1388 zbx_free(err_msg);
1389 }
1390 goto out;
1391 }
1392
1393 trigger->flags |= ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1394 out:
1395 zbx_free(recovery_expression);
1396 zbx_free(expression);
1397 zbx_free(buffer);
1398
1399 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1400 }
1401
items_triggers_hash_func(const void * data)1402 static zbx_hash_t items_triggers_hash_func(const void *data)
1403 {
1404 const zbx_lld_item_trigger_t *item_trigger = (zbx_lld_item_trigger_t *)data;
1405 zbx_hash_t hash;
1406
1407 hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_trigger->parent_triggerid);
1408 hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&item_trigger->itemid, sizeof(zbx_uint64_t), hash);
1409
1410 return hash;
1411 }
1412
items_triggers_compare_func(const void * d1,const void * d2)1413 static int items_triggers_compare_func(const void *d1, const void *d2)
1414 {
1415 const zbx_lld_item_trigger_t *item_trigger1 = (zbx_lld_item_trigger_t *)d1, *item_trigger2 = (zbx_lld_item_trigger_t *)d2;
1416
1417 ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->parent_triggerid, item_trigger2->parent_triggerid);
1418 ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->itemid, item_trigger2->itemid);
1419
1420 return 0;
1421 }
1422
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,const zbx_vector_ptr_t * lld_macro_paths,char ** error)1423 static void lld_triggers_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1424 const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows,
1425 const zbx_vector_ptr_t *lld_macro_paths, char **error)
1426 {
1427 const zbx_lld_trigger_prototype_t *trigger_prototype;
1428 int i, j;
1429 zbx_hashset_t items_triggers;
1430 zbx_lld_trigger_t *trigger;
1431 const zbx_lld_function_t *function;
1432 zbx_lld_item_trigger_t item_trigger;
1433
1434 /* used for fast search of trigger by item prototype */
1435 zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1436
1437 for (i = 0; i < triggers->values_num; i++)
1438 {
1439 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1440
1441 for (j = 0; j < trigger->functions.values_num; j++)
1442 {
1443 function = (zbx_lld_function_t *)trigger->functions.values[j];
1444
1445 item_trigger.parent_triggerid = trigger->parent_triggerid;
1446 item_trigger.itemid = function->itemid;
1447 item_trigger.trigger = trigger;
1448 zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1449 }
1450 }
1451
1452 for (i = 0; i < trigger_prototypes->values_num; i++)
1453 {
1454 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1455
1456 for (j = 0; j < lld_rows->values_num; j++)
1457 {
1458 zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1459
1460 lld_trigger_make(trigger_prototype, triggers, items, &items_triggers, lld_row, lld_macro_paths,
1461 error);
1462 }
1463 }
1464
1465 zbx_hashset_destroy(&items_triggers);
1466
1467 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1468 }
1469
1470 /******************************************************************************
1471 * *
1472 * Function: lld_trigger_dependency_make *
1473 * *
1474 * Purpose: create a trigger dependencies *
1475 * *
1476 ******************************************************************************/
lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t * trigger_prototype,const zbx_vector_ptr_t * trigger_prototypes,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)1477 static void lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t *trigger_prototype,
1478 const zbx_vector_ptr_t *trigger_prototypes, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row,
1479 char **error)
1480 {
1481 zbx_lld_trigger_t *trigger, *dep_trigger;
1482 const zbx_lld_trigger_prototype_t *dep_trigger_prototype;
1483 zbx_lld_dependency_t *dependency;
1484 zbx_uint64_t triggerid_up;
1485 int i, j, index;
1486
1487 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1488
1489 if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1490 goto out;
1491
1492 for (i = 0; i < trigger_prototype->dependencies.values_num; i++)
1493 {
1494 triggerid_up = ((zbx_lld_dependency_t *)trigger_prototype->dependencies.values[i])->triggerid_up;
1495
1496 index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_up, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1497
1498 if (FAIL != index)
1499 {
1500 /* creating trigger dependency based on trigger prototype */
1501
1502 dep_trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1503
1504 dep_trigger = lld_trigger_get(dep_trigger_prototype->triggerid, items_triggers,
1505 &lld_row->item_links);
1506
1507 if (NULL != dep_trigger)
1508 {
1509 if (0 == dep_trigger->triggerid)
1510 {
1511 dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1512
1513 dependency->triggerdepid = 0;
1514 dependency->triggerid_up = 0;
1515
1516 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1517 }
1518 else
1519 {
1520 int dependency_found = 0;
1521
1522 for (j = 0; j < trigger->dependencies.values_num; j++)
1523 {
1524 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1525
1526 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1527 continue;
1528
1529 if (dependency->triggerid_up == dep_trigger->triggerid)
1530 {
1531 dependency_found = 1;
1532 break;
1533 }
1534 }
1535
1536 if (0 == dependency_found)
1537 {
1538 dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1539
1540 dependency->triggerdepid = 0;
1541 dependency->triggerid_up = dep_trigger->triggerid;
1542
1543 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1544 }
1545 }
1546
1547 zbx_vector_ptr_append(&dep_trigger->dependents, trigger);
1548
1549 dependency->trigger_up = dep_trigger;
1550 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1551 }
1552 else
1553 {
1554 *error = zbx_strdcatf(*error, "Cannot create dependency on trigger \"%s\".\n",
1555 trigger->description);
1556 }
1557 }
1558 else
1559 {
1560 /* creating trigger dependency based on generic trigger */
1561
1562 for (j = 0; j < trigger->dependencies.values_num; j++)
1563 {
1564 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1565
1566 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1567 continue;
1568
1569 if (dependency->triggerid_up == triggerid_up)
1570 break;
1571 }
1572
1573 if (j == trigger->dependencies.values_num)
1574 {
1575 dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1576
1577 dependency->triggerdepid = 0;
1578 dependency->triggerid_up = triggerid_up;
1579 dependency->trigger_up = NULL;
1580
1581 zbx_vector_ptr_append(&trigger->dependencies, dependency);
1582 }
1583
1584 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1585 }
1586 }
1587 out:
1588 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1589 }
1590
lld_trigger_dependencies_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * lld_rows,char ** error)1591 static void lld_trigger_dependencies_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1592 const zbx_vector_ptr_t *lld_rows, char **error)
1593 {
1594 const zbx_lld_trigger_prototype_t *trigger_prototype;
1595 int i, j;
1596 zbx_hashset_t items_triggers;
1597 zbx_lld_trigger_t *trigger;
1598 zbx_lld_function_t *function;
1599 zbx_lld_item_trigger_t item_trigger;
1600 zbx_lld_dependency_t *dependency;
1601
1602 for (i = 0; i < trigger_prototypes->values_num; i++)
1603 {
1604 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1605
1606 if (0 != trigger_prototype->dependencies.values_num)
1607 break;
1608 }
1609
1610 for (j = 0; j < triggers->values_num; j++)
1611 {
1612 trigger = (zbx_lld_trigger_t *)triggers->values[j];
1613
1614 if (0 != trigger->dependencies.values_num)
1615 break;
1616 }
1617
1618 /* all trigger prototypes and triggers have no dependencies */
1619 if (i == trigger_prototypes->values_num && j == triggers->values_num)
1620 return;
1621
1622 /* used for fast search of trigger by item prototype */
1623 zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1624
1625 for (i = 0; i < triggers->values_num; i++)
1626 {
1627 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1628
1629 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1630 continue;
1631
1632 for (j = 0; j < trigger->functions.values_num; j++)
1633 {
1634 function = (zbx_lld_function_t *)trigger->functions.values[j];
1635
1636 item_trigger.parent_triggerid = trigger->parent_triggerid;
1637 item_trigger.itemid = function->itemid;
1638 item_trigger.trigger = trigger;
1639 zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1640 }
1641 }
1642
1643 for (i = 0; i < trigger_prototypes->values_num; i++)
1644 {
1645 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1646
1647 for (j = 0; j < lld_rows->values_num; j++)
1648 {
1649 zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1650
1651 lld_trigger_dependency_make(trigger_prototype, trigger_prototypes,
1652 &items_triggers, lld_row, error);
1653 }
1654 }
1655
1656 /* marking dependencies which will be deleted */
1657 for (i = 0; i < triggers->values_num; i++)
1658 {
1659 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1660
1661 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1662 continue;
1663
1664 for (j = 0; j < trigger->dependencies.values_num; j++)
1665 {
1666 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1667
1668 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1669 dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DELETE;
1670 }
1671 }
1672
1673 zbx_hashset_destroy(&items_triggers);
1674
1675 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1676 }
1677
ptr_pair_compare_func(const void * d1,const void * d2)1678 static int ptr_pair_compare_func(const void *d1, const void *d2)
1679 {
1680 const zbx_ptr_pair_t *pair1 = (const zbx_ptr_pair_t *)d1;
1681 const zbx_ptr_pair_t *pair2 = (const zbx_ptr_pair_t *)d2;
1682 int ret;
1683
1684 if (0 != (ret = strcmp((char *)pair1->first, (char *)pair2->first)))
1685 return ret;
1686
1687 return strcmp((char *)pair1->second, (char *)pair2->second);
1688 }
1689
1690 /******************************************************************************
1691 * *
1692 * Function: lld_trigger_tag_make *
1693 * *
1694 * Purpose: create a trigger tag *
1695 * *
1696 ******************************************************************************/
lld_trigger_tag_make(zbx_lld_trigger_prototype_t * trigger_prototype,zbx_hashset_t * items_triggers,zbx_lld_row_t * lld_row,const zbx_vector_ptr_t * lld_macro_paths)1697 static void lld_trigger_tag_make(zbx_lld_trigger_prototype_t *trigger_prototype,
1698 zbx_hashset_t *items_triggers, zbx_lld_row_t *lld_row, const zbx_vector_ptr_t *lld_macro_paths)
1699 {
1700 zbx_lld_trigger_t *trigger;
1701 int i;
1702 zbx_lld_tag_t *tag;
1703 char *buffer = NULL;
1704 const char *key, *value;
1705
1706 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1707
1708 if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1709 goto out;
1710
1711 zbx_vector_ptr_pair_sort(&trigger->override_tags, ptr_pair_compare_func);
1712
1713 for (i = 0; i < trigger_prototype->tags.values_num + trigger->override_tags.values_num; i++)
1714 {
1715 if (i < trigger_prototype->tags.values_num)
1716 {
1717 zbx_lld_tag_t *tag_proto;
1718
1719 tag_proto = (zbx_lld_tag_t *)trigger_prototype->tags.values[i];
1720 key = tag_proto->tag;
1721 value = tag_proto->value;
1722 }
1723 else
1724 {
1725 zbx_ptr_pair_t pair;
1726
1727 pair = trigger->override_tags.values[i - trigger_prototype->tags.values_num];
1728 key = pair.first;
1729 value = pair.second;
1730 }
1731
1732 if (i < trigger->tags.values_num)
1733 {
1734 tag = (zbx_lld_tag_t *)trigger->tags.values[i];
1735
1736 buffer = zbx_strdup(buffer, key);
1737 substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1738 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1739 if (0 != strcmp(buffer, tag->tag))
1740 {
1741 zbx_free(tag->tag);
1742 tag->tag = buffer;
1743 buffer = NULL;
1744 tag->flags |= ZBX_FLAG_LLD_TAG_UPDATE_TAG;
1745 }
1746
1747 buffer = zbx_strdup(buffer, value);
1748 substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1749 zbx_lrtrim(buffer, ZBX_WHITESPACE);
1750 if (0 != strcmp(buffer, tag->value))
1751 {
1752 zbx_free(tag->value);
1753 tag->value = buffer;
1754 buffer = NULL;
1755 tag->flags |= ZBX_FLAG_LLD_TAG_UPDATE_VALUE;
1756 }
1757 }
1758 else
1759 {
1760 tag = (zbx_lld_tag_t *)zbx_malloc(NULL, sizeof(zbx_lld_tag_t));
1761
1762 tag->triggertagid = 0;
1763
1764 tag->tag = zbx_strdup(NULL, key);
1765 substitute_lld_macros(&tag->tag, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1766 zbx_lrtrim(tag->tag, ZBX_WHITESPACE);
1767
1768 tag->value = zbx_strdup(NULL, value);
1769 substitute_lld_macros(&tag->value, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1770 zbx_lrtrim(tag->value, ZBX_WHITESPACE);
1771
1772 tag->flags = ZBX_FLAG_LLD_TAG_UNSET;
1773
1774 zbx_vector_ptr_append(&trigger->tags, tag);
1775
1776 }
1777
1778 tag->flags |= ZBX_FLAG_LLD_TAG_DISCOVERED;
1779 }
1780 out:
1781 zbx_free(buffer);
1782
1783 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1784 }
1785
1786 /******************************************************************************
1787 * *
1788 * Function: lld_trigger_tags_make *
1789 * *
1790 * Purpose: create a trigger tags *
1791 * *
1792 ******************************************************************************/
lld_trigger_tags_make(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths)1793 static void lld_trigger_tags_make(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1794 const zbx_vector_ptr_t *lld_rows, const zbx_vector_ptr_t *lld_macro_paths)
1795 {
1796 zbx_lld_trigger_prototype_t *trigger_prototype;
1797 int i, j;
1798 zbx_hashset_t items_triggers;
1799 zbx_lld_trigger_t *trigger;
1800 zbx_lld_function_t *function;
1801 zbx_lld_item_trigger_t item_trigger;
1802 zbx_lld_tag_t *tag;
1803
1804 /* used for fast search of trigger by item prototype */
1805 zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1806
1807 for (i = 0; i < triggers->values_num; i++)
1808 {
1809 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1810
1811 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1812 continue;
1813
1814 for (j = 0; j < trigger->functions.values_num; j++)
1815 {
1816 function = (zbx_lld_function_t *)trigger->functions.values[j];
1817
1818 item_trigger.parent_triggerid = trigger->parent_triggerid;
1819 item_trigger.itemid = function->itemid;
1820 item_trigger.trigger = trigger;
1821 zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1822 }
1823 }
1824
1825 for (i = 0; i < trigger_prototypes->values_num; i++)
1826 {
1827 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1828
1829 for (j = 0; j < lld_rows->values_num; j++)
1830 {
1831 zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1832
1833 lld_trigger_tag_make(trigger_prototype, &items_triggers, lld_row, lld_macro_paths);
1834 }
1835 }
1836
1837 /* marking tags which will be deleted */
1838 for (i = 0; i < triggers->values_num; i++)
1839 {
1840 trigger = (zbx_lld_trigger_t *)triggers->values[i];
1841
1842 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1843 continue;
1844
1845 for (j = 0; j < trigger->tags.values_num; j++)
1846 {
1847 tag = (zbx_lld_tag_t *)trigger->tags.values[j];
1848
1849 if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
1850 tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
1851 }
1852 }
1853
1854 zbx_hashset_destroy(&items_triggers);
1855
1856 zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1857 }
1858
1859 /******************************************************************************
1860 * *
1861 * Function: lld_validate_trigger_field *
1862 * *
1863 ******************************************************************************/
lld_validate_trigger_field(zbx_lld_trigger_t * trigger,char ** field,char ** field_orig,zbx_uint64_t flag,size_t field_len,char ** error)1864 static void lld_validate_trigger_field(zbx_lld_trigger_t *trigger, char **field, char **field_orig,
1865 zbx_uint64_t flag, size_t field_len, char **error)
1866 {
1867 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1868 return;
1869
1870 /* only new triggers or triggers with changed data will be validated */
1871 if (0 != trigger->triggerid && 0 == (trigger->flags & flag))
1872 return;
1873
1874 if (SUCCEED != zbx_is_utf8(*field))
1875 {
1876 zbx_replace_invalid_utf8(*field);
1877 *error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" has invalid UTF-8 sequence.\n",
1878 (0 != trigger->triggerid ? "update" : "create"), *field);
1879 }
1880 else if (zbx_strlen_utf8(*field) > field_len)
1881 {
1882 *error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" is too long.\n",
1883 (0 != trigger->triggerid ? "update" : "create"), *field);
1884 }
1885 else if (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION == flag && '\0' == **field)
1886 {
1887 *error = zbx_strdcatf(*error, "Cannot %s trigger: name is empty.\n",
1888 (0 != trigger->triggerid ? "update" : "create"));
1889 }
1890 else
1891 return;
1892
1893 if (0 != trigger->triggerid)
1894 lld_field_str_rollback(field, field_orig, &trigger->flags, flag);
1895 else
1896 trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1897 }
1898
1899 /******************************************************************************
1900 * *
1901 * Function: lld_trigger_changed *
1902 * *
1903 * Return value: returns SUCCEED if a trigger description or expression has *
1904 * been changed; FAIL - otherwise *
1905 * *
1906 ******************************************************************************/
lld_trigger_changed(const zbx_lld_trigger_t * trigger)1907 static int lld_trigger_changed(const zbx_lld_trigger_t *trigger)
1908 {
1909 int i;
1910 zbx_lld_function_t *function;
1911
1912 if (0 == trigger->triggerid)
1913 return SUCCEED;
1914
1915 if (0 != (trigger->flags & (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION |
1916 ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION)))
1917 {
1918 return SUCCEED;
1919 }
1920
1921 for (i = 0; i < trigger->functions.values_num; i++)
1922 {
1923 function = (zbx_lld_function_t *)trigger->functions.values[i];
1924
1925 if (0 == function->functionid)
1926 {
1927 THIS_SHOULD_NEVER_HAPPEN;
1928 return SUCCEED;
1929 }
1930
1931 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1932 return SUCCEED;
1933 }
1934
1935 return FAIL;
1936 }
1937
1938 /******************************************************************************
1939 * *
1940 * Function: lld_triggers_equal *
1941 * *
1942 * Return value: returns SUCCEED if descriptions and expressions of *
1943 * the triggers are identical; FAIL - otherwise *
1944 * *
1945 ******************************************************************************/
lld_triggers_equal(const zbx_lld_trigger_t * trigger,const zbx_lld_trigger_t * trigger_b)1946 static int lld_triggers_equal(const zbx_lld_trigger_t *trigger, const zbx_lld_trigger_t *trigger_b)
1947 {
1948 int ret = FAIL;
1949
1950 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1951
1952 if (0 == strcmp(trigger->description, trigger_b->description))
1953 {
1954 char *expression, *expression_b;
1955
1956 expression = lld_expression_expand(trigger->expression, &trigger->functions);
1957 expression_b = lld_expression_expand(trigger_b->expression, &trigger_b->functions);
1958
1959 if (0 == strcmp(expression, expression_b))
1960 {
1961 zbx_free(expression);
1962 zbx_free(expression_b);
1963
1964 expression = lld_expression_expand(trigger->recovery_expression, &trigger->functions);
1965 expression_b = lld_expression_expand(trigger_b->recovery_expression, &trigger_b->functions);
1966
1967 if (0 == strcmp(expression, expression_b))
1968 ret = SUCCEED;
1969 }
1970
1971 zbx_free(expression);
1972 zbx_free(expression_b);
1973 }
1974
1975 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1976
1977 return ret;
1978 }
1979
1980 /******************************************************************************
1981 * *
1982 * Function: lld_triggers_validate *
1983 * *
1984 * Parameters: triggers - [IN] sorted list of triggers *
1985 * *
1986 ******************************************************************************/
lld_triggers_validate(zbx_uint64_t hostid,zbx_vector_ptr_t * triggers,char ** error)1987 static void lld_triggers_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *triggers, char **error)
1988 {
1989 int i, j, k;
1990 zbx_lld_trigger_t *trigger;
1991 zbx_lld_function_t *function;
1992 zbx_vector_uint64_t triggerids;
1993 zbx_vector_str_t descriptions;
1994
1995 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1996
1997 zbx_vector_uint64_create(&triggerids);
1998 zbx_vector_str_create(&descriptions);
1999
2000 /* checking a validity of the fields */
2001
2002 for (i = 0; i < triggers->values_num; i++)
2003 {
2004 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2005
2006 lld_validate_trigger_field(trigger, &trigger->description, &trigger->description_orig,
2007 ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION, TRIGGER_DESCRIPTION_LEN, error);
2008 lld_validate_trigger_field(trigger, &trigger->comments, &trigger->comments_orig,
2009 ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS, TRIGGER_COMMENTS_LEN, error);
2010 lld_validate_trigger_field(trigger, &trigger->url, &trigger->url_orig,
2011 ZBX_FLAG_LLD_TRIGGER_UPDATE_URL, TRIGGER_URL_LEN, error);
2012 lld_validate_trigger_field(trigger, &trigger->correlation_tag, &trigger->correlation_tag_orig,
2013 ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG, TAG_NAME_LEN, error);
2014 lld_validate_trigger_field(trigger, &trigger->opdata, &trigger->opdata_orig,
2015 ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA, TRIGGER_OPDATA_LEN, error);
2016 }
2017
2018 /* checking duplicated triggers in DB */
2019
2020 for (i = 0; i < triggers->values_num; i++)
2021 {
2022 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2023
2024 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2025 continue;
2026
2027 if (0 != trigger->triggerid)
2028 {
2029 zbx_vector_uint64_append(&triggerids, trigger->triggerid);
2030
2031 if (SUCCEED != lld_trigger_changed(trigger))
2032 continue;
2033 }
2034
2035 zbx_vector_str_append(&descriptions, trigger->description);
2036 }
2037
2038 if (0 != descriptions.values_num)
2039 {
2040 char *sql = NULL;
2041 size_t sql_alloc = 256, sql_offset = 0;
2042 DB_RESULT result;
2043 DB_ROW row;
2044 zbx_vector_ptr_t db_triggers;
2045 zbx_lld_trigger_t *db_trigger;
2046
2047 zbx_vector_ptr_create(&db_triggers);
2048
2049 zbx_vector_str_sort(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
2050 zbx_vector_str_uniq(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
2051
2052 sql = (char *)zbx_malloc(sql, sql_alloc);
2053
2054 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2055 "select distinct t.triggerid,t.description,t.expression,t.recovery_expression"
2056 " from triggers t,functions f,items i"
2057 " where t.triggerid=f.triggerid"
2058 " and f.itemid=i.itemid"
2059 " and i.hostid=" ZBX_FS_UI64
2060 " and",
2061 hostid);
2062 DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.description",
2063 (const char **)descriptions.values, descriptions.values_num);
2064
2065 if (0 != triggerids.values_num)
2066 {
2067 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2068 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
2069 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid",
2070 triggerids.values, triggerids.values_num);
2071 }
2072
2073 result = DBselect("%s", sql);
2074
2075 while (NULL != (row = DBfetch(result)))
2076 {
2077 db_trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
2078
2079 ZBX_STR2UINT64(db_trigger->triggerid, row[0]);
2080 db_trigger->description = zbx_strdup(NULL, row[1]);
2081 db_trigger->description_orig = NULL;
2082 db_trigger->expression = zbx_strdup(NULL, row[2]);
2083 db_trigger->expression_orig = NULL;
2084 db_trigger->recovery_expression = zbx_strdup(NULL, row[3]);
2085 db_trigger->recovery_expression_orig = NULL;
2086 db_trigger->comments = NULL;
2087 db_trigger->comments_orig = NULL;
2088 db_trigger->url = NULL;
2089 db_trigger->url_orig = NULL;
2090 db_trigger->correlation_tag = NULL;
2091 db_trigger->correlation_tag_orig = NULL;
2092 db_trigger->opdata = NULL;
2093 db_trigger->opdata_orig = NULL;
2094 db_trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
2095
2096 zbx_vector_ptr_create(&db_trigger->functions);
2097 zbx_vector_ptr_create(&db_trigger->dependencies);
2098 zbx_vector_ptr_create(&db_trigger->dependents);
2099 zbx_vector_ptr_create(&db_trigger->tags);
2100 zbx_vector_ptr_pair_create(&db_trigger->override_tags);
2101
2102 zbx_vector_ptr_append(&db_triggers, db_trigger);
2103 }
2104 DBfree_result(result);
2105
2106 zbx_vector_ptr_sort(&db_triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2107
2108 lld_functions_get(NULL, &db_triggers);
2109
2110 for (i = 0; i < db_triggers.values_num; i++)
2111 {
2112 db_trigger = (zbx_lld_trigger_t *)db_triggers.values[i];
2113
2114 lld_expressions_simplify(&db_trigger->expression, &db_trigger->recovery_expression,
2115 &db_trigger->functions);
2116
2117 for (j = 0; j < triggers->values_num; j++)
2118 {
2119 trigger = (zbx_lld_trigger_t *)triggers->values[j];
2120
2121 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2122 continue;
2123
2124 if (SUCCEED != lld_triggers_equal(trigger, db_trigger))
2125 continue;
2126
2127 *error = zbx_strdcatf(*error, "Cannot %s trigger: trigger \"%s\" already exists.\n",
2128 (0 != trigger->triggerid ? "update" : "create"), trigger->description);
2129
2130 if (0 != trigger->triggerid)
2131 {
2132 lld_field_str_rollback(&trigger->description, &trigger->description_orig,
2133 &trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION);
2134
2135 lld_field_str_rollback(&trigger->expression, &trigger->expression_orig,
2136 &trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION);
2137
2138 lld_field_str_rollback(&trigger->recovery_expression,
2139 &trigger->recovery_expression_orig, &trigger->flags,
2140 ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION);
2141
2142 for (k = 0; k < trigger->functions.values_num; k++)
2143 {
2144 function = (zbx_lld_function_t *)trigger->functions.values[k];
2145
2146 if (0 != function->functionid)
2147 {
2148 lld_field_uint64_rollback(&function->itemid,
2149 &function->itemid_orig,
2150 &function->flags,
2151 ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID);
2152
2153 lld_field_str_rollback(&function->function,
2154 &function->function_orig,
2155 &function->flags,
2156 ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION);
2157
2158 lld_field_str_rollback(&function->parameter,
2159 &function->parameter_orig,
2160 &function->flags,
2161 ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER);
2162
2163 function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DELETE;
2164 }
2165 else
2166 function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
2167 }
2168 }
2169 else
2170 trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
2171
2172 break; /* only one same trigger can be here */
2173 }
2174 }
2175
2176 zbx_vector_ptr_clear_ext(&db_triggers, (zbx_clean_func_t)lld_trigger_free);
2177 zbx_vector_ptr_destroy(&db_triggers);
2178
2179 zbx_free(sql);
2180 }
2181
2182 zbx_vector_str_destroy(&descriptions);
2183 zbx_vector_uint64_destroy(&triggerids);
2184
2185 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2186 }
2187
2188 /******************************************************************************
2189 * *
2190 * Function: lld_validate_trigger_tag_field *
2191 * *
2192 ******************************************************************************/
lld_validate_trigger_tag_field(zbx_lld_tag_t * tag,const char * field,zbx_uint64_t flag,size_t field_len,char ** error)2193 static void lld_validate_trigger_tag_field(zbx_lld_tag_t *tag, const char *field, zbx_uint64_t flag,
2194 size_t field_len, char **error)
2195 {
2196 size_t len;
2197
2198 if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2199 return;
2200
2201 /* only new trigger tags or tags with changed data will be validated */
2202 if (0 != tag->triggertagid && 0 == (tag->flags & flag))
2203 return;
2204
2205 if (SUCCEED != zbx_is_utf8(field))
2206 {
2207 char *field_utf8;
2208
2209 field_utf8 = zbx_strdup(NULL, field);
2210 zbx_replace_invalid_utf8(field_utf8);
2211 *error = zbx_strdcatf(*error, "Cannot create trigger tag: value \"%s\" has invalid UTF-8 sequence.\n",
2212 field_utf8);
2213 zbx_free(field_utf8);
2214 }
2215 else if ((len = zbx_strlen_utf8(field)) > field_len)
2216 *error = zbx_strdcatf(*error, "Cannot create trigger tag: value \"%s\" is too long.\n", field);
2217 else if (0 != (flag & ZBX_FLAG_LLD_TAG_UPDATE_TAG) && 0 == len)
2218 *error = zbx_strdcatf(*error, "Cannot create trigger tag: empty tag name.\n");
2219 else
2220 return;
2221
2222 if (0 != tag->triggertagid)
2223 tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
2224 else
2225 tag->flags &= ~ZBX_FLAG_LLD_TAG_DISCOVERED;
2226 }
2227
2228 /******************************************************************************
2229 * *
2230 * Function: lld_trigger_tags_validate *
2231 * *
2232 * Purpose: validate created or updated trigger tags *
2233 * *
2234 ******************************************************************************/
lld_trigger_tags_validate(zbx_vector_ptr_t * triggers,char ** error)2235 static void lld_trigger_tags_validate(zbx_vector_ptr_t *triggers, char **error)
2236 {
2237 int i, j, k;
2238 zbx_lld_trigger_t *trigger;
2239 zbx_lld_tag_t *tag, *tag_tmp;
2240
2241 for (i = 0; i < triggers->values_num; i++)
2242 {
2243 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2244
2245 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2246 continue;
2247
2248 for (j = 0; j < trigger->tags.values_num; j++)
2249 {
2250 tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2251
2252 lld_validate_trigger_tag_field(tag, tag->tag, ZBX_FLAG_LLD_TAG_UPDATE_TAG,
2253 TAG_NAME_LEN, error);
2254 lld_validate_trigger_tag_field(tag, tag->value, ZBX_FLAG_LLD_TAG_UPDATE_VALUE,
2255 TAG_VALUE_LEN, error);
2256
2257 if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2258 continue;
2259
2260 /* check for duplicated tag,values pairs */
2261 for (k = 0; k < j; k++)
2262 {
2263 tag_tmp = (zbx_lld_tag_t *)trigger->tags.values[k];
2264
2265 if (0 == strcmp(tag->tag, tag_tmp->tag) && 0 == strcmp(tag->value, tag_tmp->value))
2266 {
2267 *error = zbx_strdcatf(*error, "Cannot create trigger tag: tag \"%s\","
2268 "\"%s\" already exists.\n", tag->tag, tag->value);
2269
2270 if (0 != tag->triggertagid)
2271 tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
2272 else
2273 tag->flags &= ~ZBX_FLAG_LLD_TAG_DISCOVERED;
2274 }
2275 }
2276
2277 /* reset trigger discovery flags for new trigger if tag discovery failed */
2278 if (0 == trigger->triggerid && 0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2279 {
2280 trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
2281 break;
2282 }
2283 }
2284 }
2285 }
2286
2287 /******************************************************************************
2288 * *
2289 * Function: lld_expression_create *
2290 * *
2291 * Purpose: transforms the simple trigger expression to the DB format *
2292 * *
2293 * Example: *
2294 * *
2295 * "{1} > 5" => "{84756} > 5" *
2296 * ^ ^ *
2297 * | functionid from the database *
2298 * internal function index *
2299 * *
2300 ******************************************************************************/
lld_expression_create(char ** expression,const zbx_vector_ptr_t * functions)2301 static void lld_expression_create(char **expression, const zbx_vector_ptr_t *functions)
2302 {
2303 size_t l, r;
2304 int i;
2305 zbx_uint64_t function_index;
2306 char buffer[ZBX_MAX_UINT64_LEN];
2307
2308 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, *expression);
2309
2310 for (l = 0; '\0' != (*expression)[l]; l++)
2311 {
2312 if ('{' != (*expression)[l])
2313 continue;
2314
2315 if ('$' == (*expression)[l + 1])
2316 {
2317 int macro_r, context_l, context_r;
2318
2319 if (SUCCEED == zbx_user_macro_parse(*expression + l, ¯o_r, &context_l, &context_r, NULL))
2320 l += macro_r;
2321 else
2322 l++;
2323
2324 continue;
2325 }
2326
2327 for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
2328 ;
2329
2330 if ('}' != (*expression)[r])
2331 continue;
2332
2333 /* ... > 0 | {1} + ... */
2334 /* l r */
2335
2336 if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &function_index))
2337 continue;
2338
2339 for (i = 0; i < functions->values_num; i++)
2340 {
2341 const zbx_lld_function_t *function = (zbx_lld_function_t *)functions->values[i];
2342
2343 if (function->index != function_index)
2344 continue;
2345
2346 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->functionid);
2347
2348 r--;
2349 zbx_replace_string(expression, l + 1, &r, buffer);
2350 r++;
2351
2352 break;
2353 }
2354
2355 l = r;
2356 }
2357
2358 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __func__, *expression);
2359 }
2360
2361 /******************************************************************************
2362 * *
2363 * Function: lld_triggers_save *
2364 * *
2365 * Purpose: add or update triggers in database based on discovery rule *
2366 * *
2367 * Parameters: hostid - [IN] parent host id *
2368 * lld_triggers_save - [IN] trigger prototypes *
2369 * triggers - [IN/OUT] triggers to save *
2370 * *
2371 * Return value: SUCCEED - if triggers was successfully saved or saving *
2372 * was not necessary *
2373 * FAIL - triggers cannot be saved *
2374 * *
2375 ******************************************************************************/
lld_triggers_save(zbx_uint64_t hostid,const zbx_vector_ptr_t * trigger_prototypes,const zbx_vector_ptr_t * triggers)2376 static int lld_triggers_save(zbx_uint64_t hostid, const zbx_vector_ptr_t *trigger_prototypes,
2377 const zbx_vector_ptr_t *triggers)
2378 {
2379 int ret = SUCCEED, i, j, new_triggers = 0, upd_triggers = 0, new_functions = 0,
2380 new_dependencies = 0, new_tags = 0, upd_tags = 0;
2381 const zbx_lld_trigger_prototype_t *trigger_prototype;
2382 zbx_lld_trigger_t *trigger;
2383 zbx_lld_function_t *function;
2384 zbx_lld_dependency_t *dependency;
2385 zbx_lld_tag_t *tag;
2386 zbx_vector_ptr_t upd_functions; /* the ordered list of functions which will be updated */
2387 zbx_vector_uint64_t del_functionids, del_triggerdepids, del_triggertagids, trigger_protoids;
2388 zbx_uint64_t triggerid = 0, functionid = 0, triggerdepid = 0, triggerid_up, triggertagid;
2389 char *sql = NULL, *function_esc, *parameter_esc;
2390 size_t sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
2391 zbx_db_insert_t db_insert, db_insert_tdiscovery, db_insert_tfunctions, db_insert_tdepends,
2392 db_insert_ttags;
2393
2394 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2395
2396 zbx_vector_ptr_create(&upd_functions);
2397 zbx_vector_uint64_create(&del_functionids);
2398 zbx_vector_uint64_create(&del_triggerdepids);
2399 zbx_vector_uint64_create(&del_triggertagids);
2400 zbx_vector_uint64_create(&trigger_protoids);
2401
2402 for (i = 0; i < triggers->values_num; i++)
2403 {
2404 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2405
2406 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2407 continue;
2408
2409 if (0 == trigger->triggerid)
2410 new_triggers++;
2411 else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
2412 upd_triggers++;
2413
2414 for (j = 0; j < trigger->functions.values_num; j++)
2415 {
2416 function = (zbx_lld_function_t *)trigger->functions.values[j];
2417
2418 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
2419 {
2420 zbx_vector_uint64_append(&del_functionids, function->functionid);
2421 continue;
2422 }
2423
2424 if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
2425 continue;
2426
2427 if (0 == function->functionid)
2428 new_functions++;
2429 else if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
2430 zbx_vector_ptr_append(&upd_functions, function);
2431 }
2432
2433 for (j = 0; j < trigger->dependencies.values_num; j++)
2434 {
2435 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2436
2437 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
2438 {
2439 zbx_vector_uint64_append(&del_triggerdepids, dependency->triggerdepid);
2440 continue;
2441 }
2442
2443 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2444 continue;
2445
2446 if (0 == dependency->triggerdepid)
2447 new_dependencies++;
2448 }
2449
2450 for (j = 0; j < trigger->tags.values_num; j++)
2451 {
2452 tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2453
2454 if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_DELETE))
2455 {
2456 zbx_vector_uint64_append(&del_triggertagids, tag->triggertagid);
2457 continue;
2458 }
2459
2460 if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2461 continue;
2462
2463 if (0 == tag->triggertagid)
2464 new_tags++;
2465 else if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE))
2466 upd_tags++;
2467 }
2468 }
2469
2470 if (0 == new_triggers && 0 == new_functions && 0 == new_dependencies && 0 == upd_triggers &&
2471 0 == upd_functions.values_num && 0 == del_functionids.values_num &&
2472 0 == del_triggerdepids.values_num && 0 == new_tags && 0 == upd_tags &&
2473 0 == del_triggertagids.values_num)
2474 {
2475 goto out;
2476 }
2477
2478 DBbegin();
2479
2480 for (i = 0; i < trigger_prototypes->values_num; i++)
2481 {
2482 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
2483 zbx_vector_uint64_append(&trigger_protoids, trigger_prototype->triggerid);
2484 }
2485
2486 if (SUCCEED != DBlock_hostid(hostid) || SUCCEED != DBlock_triggerids(&trigger_protoids))
2487 {
2488 /* the host or trigger prototype was removed while processing lld rule */
2489 DBrollback();
2490 ret = FAIL;
2491 goto out;
2492 }
2493
2494 if (0 != new_triggers)
2495 {
2496 triggerid = DBget_maxid_num("triggers", new_triggers);
2497
2498 zbx_db_insert_prepare(&db_insert, "triggers", "triggerid", "description", "expression", "priority",
2499 "status", "comments", "url", "type", "value", "state", "flags", "recovery_mode",
2500 "recovery_expression", "correlation_mode", "correlation_tag", "manual_close", "opdata",
2501 NULL);
2502
2503 zbx_db_insert_prepare(&db_insert_tdiscovery, "trigger_discovery", "triggerid", "parent_triggerid",
2504 NULL);
2505 }
2506
2507 if (0 != new_functions)
2508 {
2509 functionid = DBget_maxid_num("functions", new_functions);
2510
2511 zbx_db_insert_prepare(&db_insert_tfunctions, "functions", "functionid", "itemid", "triggerid",
2512 "name", "parameter", NULL);
2513 }
2514
2515 if (0 != new_dependencies)
2516 {
2517 triggerdepid = DBget_maxid_num("trigger_depends", new_dependencies);
2518
2519 zbx_db_insert_prepare(&db_insert_tdepends, "trigger_depends", "triggerdepid", "triggerid_down",
2520 "triggerid_up", NULL);
2521 }
2522
2523 if (0 != new_tags)
2524 {
2525 triggertagid = DBget_maxid_num("trigger_tag", new_tags);
2526
2527 zbx_db_insert_prepare(&db_insert_ttags, "trigger_tag", "triggertagid", "triggerid", "tag", "value",
2528 NULL);
2529 }
2530
2531 if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2532 0 != del_triggerdepids.values_num || 0 != upd_tags || 0 != del_triggertagids.values_num)
2533 {
2534 sql = (char *)zbx_malloc(sql, sql_alloc);
2535 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2536 }
2537
2538 for (i = 0; i < triggers->values_num; i++)
2539 {
2540 char *description_esc, *expression_esc, *comments_esc, *url_esc, *value_esc, *opdata_esc;
2541 int index;
2542
2543 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2544
2545 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2546 continue;
2547
2548 index = zbx_vector_ptr_bsearch(trigger_prototypes, &trigger->parent_triggerid,
2549 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2550
2551 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
2552
2553 for (j = 0; j < trigger->functions.values_num; j++)
2554 {
2555 function = (zbx_lld_function_t *)trigger->functions.values[j];
2556
2557 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
2558 continue;
2559
2560 if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
2561 continue;
2562
2563 if (0 == function->functionid)
2564 {
2565 zbx_db_insert_add_values(&db_insert_tfunctions, functionid, function->itemid,
2566 (0 == trigger->triggerid ? triggerid : trigger->triggerid),
2567 function->function, function->parameter);
2568
2569 function->functionid = functionid++;
2570 }
2571 }
2572
2573 if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
2574 lld_expression_create(&trigger->expression, &trigger->functions);
2575
2576 if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION))
2577 lld_expression_create(&trigger->recovery_expression, &trigger->functions);
2578
2579 if (0 == trigger->triggerid)
2580 {
2581 zbx_db_insert_add_values(&db_insert, triggerid, trigger->description, trigger->expression,
2582 (int)trigger->priority, (int)trigger->status,
2583 trigger->comments, trigger->url, (int)trigger_prototype->type,
2584 (int)TRIGGER_VALUE_OK, (int)TRIGGER_STATE_NORMAL,
2585 (int)ZBX_FLAG_DISCOVERY_CREATED, (int)trigger_prototype->recovery_mode,
2586 trigger->recovery_expression, (int)trigger_prototype->correlation_mode,
2587 trigger->correlation_tag, (int)trigger_prototype->manual_close,
2588 trigger->opdata);
2589
2590 zbx_db_insert_add_values(&db_insert_tdiscovery, triggerid, trigger->parent_triggerid);
2591
2592 trigger->triggerid = triggerid++;
2593 }
2594 else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
2595 {
2596 const char *d = "";
2597
2598 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set ");
2599
2600 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION))
2601 {
2602 description_esc = DBdyn_escape_string(trigger->description);
2603 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "description='%s'",
2604 description_esc);
2605 zbx_free(description_esc);
2606 d = ",";
2607 }
2608
2609 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
2610 {
2611 expression_esc = DBdyn_escape_string(trigger->expression);
2612 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sexpression='%s'", d,
2613 expression_esc);
2614 zbx_free(expression_esc);
2615 d = ",";
2616 }
2617
2618 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION))
2619 {
2620 expression_esc = DBdyn_escape_string(trigger->recovery_expression);
2621 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%srecovery_expression='%s'", d,
2622 expression_esc);
2623 zbx_free(expression_esc);
2624 d = ",";
2625 }
2626
2627 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE))
2628 {
2629 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%srecovery_mode=%d", d,
2630 (int)trigger_prototype->recovery_mode);
2631 d = ",";
2632 }
2633
2634 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE))
2635 {
2636 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d,
2637 (int)trigger_prototype->type);
2638 d = ",";
2639 }
2640
2641 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY))
2642 {
2643 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spriority=%d", d,
2644 (int)trigger->priority);
2645 d = ",";
2646 }
2647
2648 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS))
2649 {
2650 comments_esc = DBdyn_escape_string(trigger->comments);
2651 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scomments='%s'", d, comments_esc);
2652 zbx_free(comments_esc);
2653 d = ",";
2654 }
2655
2656 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_URL))
2657 {
2658 url_esc = DBdyn_escape_string(trigger->url);
2659 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl='%s'", d, url_esc);
2660 zbx_free(url_esc);
2661 d = ",";
2662 }
2663
2664 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE))
2665 {
2666 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_mode=%d", d,
2667 (int)trigger_prototype->correlation_mode);
2668 d = ",";
2669 }
2670
2671 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG))
2672 {
2673 value_esc = DBdyn_escape_string(trigger->correlation_tag);
2674 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_tag='%s'", d,
2675 value_esc);
2676 zbx_free(value_esc);
2677 d = ",";
2678 }
2679
2680 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE))
2681 {
2682 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%smanual_close=%d", d,
2683 (int)trigger_prototype->manual_close);
2684 d = ",";
2685 }
2686
2687 if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA))
2688 {
2689 opdata_esc = DBdyn_escape_string(trigger->opdata);
2690 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sopdata='%s'", d, opdata_esc);
2691 zbx_free(opdata_esc);
2692 }
2693
2694 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2695 " where triggerid=" ZBX_FS_UI64 ";\n", trigger->triggerid);
2696 }
2697 }
2698
2699 for (i = 0; i < triggers->values_num; i++)
2700 {
2701 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2702
2703 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2704 continue;
2705
2706 for (j = 0; j < trigger->dependencies.values_num; j++)
2707 {
2708 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2709
2710 if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
2711 continue;
2712
2713 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2714 continue;
2715
2716 if (0 == dependency->triggerdepid)
2717 {
2718 triggerid_up = (NULL == dependency->trigger_up ? dependency->triggerid_up :
2719 dependency->trigger_up->triggerid);
2720
2721 zbx_db_insert_add_values(&db_insert_tdepends, triggerdepid, trigger->triggerid,
2722 triggerid_up);
2723
2724 dependency->triggerdepid = triggerdepid++;
2725 }
2726 }
2727 }
2728
2729 /* create/update trigger tags */
2730 for (i = 0; i < triggers->values_num; i++)
2731 {
2732 trigger = (zbx_lld_trigger_t *)triggers->values[i];
2733
2734 if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2735 continue;
2736
2737 for (j = 0; j < trigger->tags.values_num; j++)
2738 {
2739 char *value_esc;
2740
2741 tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2742
2743 if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_DELETE))
2744 continue;
2745
2746 if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2747 continue;
2748
2749 if (0 == tag->triggertagid)
2750 {
2751 tag->triggertagid = triggertagid++;
2752 zbx_db_insert_add_values(&db_insert_ttags, tag->triggertagid, trigger->triggerid,
2753 tag->tag, tag->value);
2754 }
2755 else if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE))
2756 {
2757 const char *d = "";
2758
2759 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update trigger_tag set ");
2760
2761 if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE_TAG))
2762 {
2763 value_esc = DBdyn_escape_string(tag->tag);
2764 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "tag='%s'", value_esc);
2765 zbx_free(value_esc);
2766 d = ",";
2767 }
2768
2769 if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE_VALUE))
2770 {
2771 value_esc = DBdyn_escape_string(tag->value);
2772 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%svalue='%s'", d, value_esc);
2773 zbx_free(value_esc);
2774 }
2775
2776 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2777 " where triggertagid=" ZBX_FS_UI64 ";\n", tag->triggertagid);
2778 }
2779 }
2780 }
2781
2782 zbx_vector_ptr_sort(&upd_functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2783
2784 for (i = 0; i < upd_functions.values_num; i++)
2785 {
2786 const char *d = "";
2787
2788 function = (zbx_lld_function_t *)upd_functions.values[i];
2789
2790 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update functions set ");
2791
2792 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID))
2793 {
2794 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64,
2795 function->itemid);
2796 d = ",";
2797 }
2798
2799 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION))
2800 {
2801 function_esc = DBdyn_escape_string(function->function);
2802 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sname='%s'", d,
2803 function_esc);
2804 zbx_free(function_esc);
2805 d = ",";
2806 }
2807
2808 if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER))
2809 {
2810 parameter_esc = DBdyn_escape_string(function->parameter);
2811 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sparameter='%s'", d,
2812 parameter_esc);
2813 zbx_free(parameter_esc);
2814 }
2815
2816 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2817 " where functionid=" ZBX_FS_UI64 ";\n", function->functionid);
2818 }
2819
2820 if (0 != del_functionids.values_num)
2821 {
2822 zbx_vector_uint64_sort(&del_functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2823
2824 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where");
2825 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "functionid",
2826 del_functionids.values, del_functionids.values_num);
2827 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2828 }
2829
2830 if (0 != del_triggerdepids.values_num)
2831 {
2832 zbx_vector_uint64_sort(&del_triggerdepids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2833
2834 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_depends where");
2835 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerdepid",
2836 del_triggerdepids.values, del_triggerdepids.values_num);
2837 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2838 }
2839
2840 if (0 != del_triggertagids.values_num)
2841 {
2842 zbx_vector_uint64_sort(&del_triggertagids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2843
2844 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_tag where");
2845 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggertagid",
2846 del_triggertagids.values, del_triggertagids.values_num);
2847 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2848 }
2849
2850 if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2851 0 != del_triggerdepids.values_num || 0 != upd_tags || 0 != del_triggertagids.values_num)
2852 {
2853 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2854 DBexecute("%s", sql);
2855 zbx_free(sql);
2856 }
2857
2858 if (0 != new_triggers)
2859 {
2860 zbx_db_insert_execute(&db_insert);
2861 zbx_db_insert_clean(&db_insert);
2862
2863 zbx_db_insert_execute(&db_insert_tdiscovery);
2864 zbx_db_insert_clean(&db_insert_tdiscovery);
2865 }
2866
2867 if (0 != new_functions)
2868 {
2869 zbx_db_insert_execute(&db_insert_tfunctions);
2870 zbx_db_insert_clean(&db_insert_tfunctions);
2871 }
2872
2873 if (0 != new_dependencies)
2874 {
2875 zbx_db_insert_execute(&db_insert_tdepends);
2876 zbx_db_insert_clean(&db_insert_tdepends);
2877 }
2878
2879 if (0 != new_tags)
2880 {
2881 zbx_db_insert_execute(&db_insert_ttags);
2882 zbx_db_insert_clean(&db_insert_ttags);
2883 }
2884
2885 DBcommit();
2886 out:
2887
2888 zbx_vector_uint64_destroy(&trigger_protoids);
2889 zbx_vector_uint64_destroy(&del_triggertagids);
2890 zbx_vector_uint64_destroy(&del_triggerdepids);
2891 zbx_vector_uint64_destroy(&del_functionids);
2892 zbx_vector_ptr_destroy(&upd_functions);
2893
2894 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2895
2896 return ret;
2897 }
2898
2899 /* hash/comparison functions to support cache/vector lookups by trigger reference */
zbx_lld_trigger_ref_hash_func(const void * data)2900 static zbx_hash_t zbx_lld_trigger_ref_hash_func(const void *data)
2901 {
2902 zbx_hash_t hash;
2903 const zbx_lld_trigger_node_t *trigger_node = (const zbx_lld_trigger_node_t *)data;
2904 void *ptr = NULL;
2905
2906 hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&trigger_node->trigger_ref.triggerid,
2907 sizeof(trigger_node->trigger_ref.triggerid), ZBX_DEFAULT_HASH_SEED);
2908
2909 if (0 == trigger_node->trigger_ref.triggerid)
2910 ptr = trigger_node->trigger_ref.trigger;
2911
2912 return ZBX_DEFAULT_PTR_HASH_ALGO(&ptr, sizeof(trigger_node->trigger_ref.trigger), hash);
2913 }
2914
zbx_lld_trigger_ref_compare_func(const void * d1,const void * d2)2915 static int zbx_lld_trigger_ref_compare_func(const void *d1, const void *d2)
2916 {
2917 const zbx_lld_trigger_node_t *n1 = (const zbx_lld_trigger_node_t *)d1;
2918 const zbx_lld_trigger_node_t *n2 = (const zbx_lld_trigger_node_t *)d2;
2919
2920 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2921
2922 /* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2923 if (0 != n1->trigger_ref.triggerid)
2924 return 0;
2925
2926 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2927
2928 return 0;
2929 }
2930
2931 /* comparison function to determine trigger dependency validation order */
zbx_lld_trigger_node_compare_func(const void * d1,const void * d2)2932 static int zbx_lld_trigger_node_compare_func(const void *d1, const void *d2)
2933 {
2934 const zbx_lld_trigger_node_t *n1 = *(const zbx_lld_trigger_node_t **)d1;
2935 const zbx_lld_trigger_node_t *n2 = *(const zbx_lld_trigger_node_t **)d2;
2936
2937 /* sort in ascending order, but ensure that existing triggers are first */
2938 if (0 != n1->trigger_ref.triggerid && 0 == n2->trigger_ref.triggerid)
2939 return -1;
2940
2941 /* give priority to nodes with less parents */
2942 ZBX_RETURN_IF_NOT_EQUAL(n1->parents, n2->parents);
2943
2944 /* compare ids */
2945 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2946
2947 /* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2948 if (0 != n1->trigger_ref.triggerid)
2949 return 0;
2950
2951 ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2952
2953 return 0;
2954 }
2955
2956 /******************************************************************************
2957 * *
2958 * Function: lld_trigger_cache_append *
2959 * *
2960 * Purpose: adds a node to trigger cache *
2961 * *
2962 * Parameters: cache - [IN] the trigger cache *
2963 * triggerid - [IN] the trigger id *
2964 * trigger - [IN] the trigger data for new triggers *
2965 * *
2966 * Return value: the added node *
2967 * *
2968 ******************************************************************************/
lld_trigger_cache_append(zbx_hashset_t * cache,zbx_uint64_t triggerid,zbx_lld_trigger_t * trigger)2969 static zbx_lld_trigger_node_t *lld_trigger_cache_append(zbx_hashset_t *cache, zbx_uint64_t triggerid,
2970 zbx_lld_trigger_t *trigger)
2971 {
2972 zbx_lld_trigger_node_t node_local;
2973
2974 node_local.trigger_ref.triggerid = triggerid;
2975 node_local.trigger_ref.trigger = trigger;
2976 node_local.trigger_ref.flags = 0;
2977 node_local.iter_num = 0;
2978 node_local.parents = 0;
2979
2980 zbx_vector_ptr_create(&node_local.dependencies);
2981
2982 return (zbx_lld_trigger_node_t *)zbx_hashset_insert(cache, &node_local, sizeof(node_local));
2983 }
2984
2985 /******************************************************************************
2986 * *
2987 * Function: lld_trigger_cache_add_trigger_node *
2988 * *
2989 * Purpose: add trigger and all triggers related to it to trigger dependency *
2990 * validation cache. *
2991 * *
2992 * Parameters: cache - [IN] the trigger cache *
2993 * trigger - [IN] the trigger to add *
2994 * triggerids_up - [OUT] identifiers of generic trigger *
2995 * dependents *
2996 * triggerids_down - [OUT] identifiers of generic trigger *
2997 * dependencies *
2998 * *
2999 ******************************************************************************/
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)3000 static void lld_trigger_cache_add_trigger_node(zbx_hashset_t *cache, zbx_lld_trigger_t *trigger,
3001 zbx_vector_uint64_t *triggerids_up, zbx_vector_uint64_t *triggerids_down)
3002 {
3003 zbx_lld_trigger_ref_t *trigger_ref;
3004 zbx_lld_trigger_node_t *trigger_node, trigger_node_local;
3005 zbx_lld_dependency_t *dependency;
3006 int i;
3007
3008 trigger_node_local.trigger_ref.triggerid = trigger->triggerid;
3009 trigger_node_local.trigger_ref.trigger = trigger;
3010
3011 if (NULL != zbx_hashset_search(cache, &trigger_node_local))
3012 return;
3013
3014 trigger_node = lld_trigger_cache_append(cache, trigger->triggerid, trigger);
3015
3016 for (i = 0; i < trigger->dependencies.values_num; i++)
3017 {
3018 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3019
3020 if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
3021 continue;
3022
3023 trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_ref_t));
3024
3025 trigger_ref->triggerid = dependency->triggerid_up;
3026 trigger_ref->trigger = dependency->trigger_up;
3027 trigger_ref->flags = (0 == dependency->triggerdepid ? ZBX_LLD_TRIGGER_DEPENDENCY_NEW :
3028 ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL);
3029
3030 zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
3031
3032 if (NULL == trigger_ref->trigger)
3033 {
3034 trigger_node_local.trigger_ref.triggerid = trigger_ref->triggerid;
3035 trigger_node_local.trigger_ref.trigger = NULL;
3036
3037 if (NULL == zbx_hashset_search(cache, &trigger_node_local))
3038 {
3039 zbx_vector_uint64_append(triggerids_up, trigger_ref->triggerid);
3040 zbx_vector_uint64_append(triggerids_down, trigger_ref->triggerid);
3041
3042 lld_trigger_cache_append(cache, trigger_ref->triggerid, NULL);
3043 }
3044 }
3045 }
3046
3047 if (0 != trigger->triggerid)
3048 zbx_vector_uint64_append(triggerids_up, trigger->triggerid);
3049
3050 for (i = 0; i < trigger->dependents.values_num; i++)
3051 {
3052 lld_trigger_cache_add_trigger_node(cache, (zbx_lld_trigger_t *)trigger->dependents.values[i], triggerids_up,
3053 triggerids_down);
3054 }
3055
3056 for (i = 0; i < trigger->dependencies.values_num; i++)
3057 {
3058 dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3059
3060 if (NULL != dependency->trigger_up)
3061 {
3062 lld_trigger_cache_add_trigger_node(cache, dependency->trigger_up, triggerids_up,
3063 triggerids_down);
3064 }
3065 }
3066 }
3067
3068 /******************************************************************************
3069 * *
3070 * Function: lld_trigger_cache_init *
3071 * *
3072 * Purpose: initializes trigger cache used to perform trigger dependency *
3073 * validation *
3074 * *
3075 * Parameters: cache - [IN] the trigger cache *
3076 * triggers - [IN] the discovered triggers *
3077 * *
3078 * Comments: Triggers with new dependencies and.all triggers related to them *
3079 * are added to cache. *
3080 * *
3081 ******************************************************************************/
lld_trigger_cache_init(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers)3082 static void lld_trigger_cache_init(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers)
3083 {
3084 zbx_vector_uint64_t triggerids_up, triggerids_down;
3085 int i, j;
3086 char *sql = NULL;
3087 size_t sql_alloc = 0, sql_offset;
3088 DB_RESULT result;
3089 DB_ROW row;
3090 zbx_lld_trigger_ref_t *trigger_ref;
3091 zbx_lld_trigger_node_t *trigger_node, trigger_node_local;
3092
3093 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3094
3095 zbx_hashset_create(cache, triggers->values_num, zbx_lld_trigger_ref_hash_func,
3096 zbx_lld_trigger_ref_compare_func);
3097
3098 zbx_vector_uint64_create(&triggerids_down);
3099 zbx_vector_uint64_create(&triggerids_up);
3100
3101 /* add all triggers with new dependencies to trigger cache */
3102 for (i = 0; i < triggers->values_num; i++)
3103 {
3104 zbx_lld_trigger_t *trigger = (zbx_lld_trigger_t *)triggers->values[i];
3105
3106 for (j = 0; j < trigger->dependencies.values_num; j++)
3107 {
3108 zbx_lld_dependency_t *dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
3109
3110 if (0 == dependency->triggerdepid)
3111 break;
3112 }
3113
3114 if (j != trigger->dependencies.values_num)
3115 lld_trigger_cache_add_trigger_node(cache, trigger, &triggerids_up, &triggerids_down);
3116 }
3117
3118 /* keep trying to load generic dependents/dependencies until there are nothing to load */
3119 while (0 != triggerids_up.values_num || 0 != triggerids_down.values_num)
3120 {
3121 /* load dependents */
3122 if (0 != triggerids_down.values_num)
3123 {
3124 sql_offset = 0;
3125 zbx_vector_uint64_sort(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3126 zbx_vector_uint64_uniq(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3127
3128 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3129 "select td.triggerid_down,td.triggerid_up"
3130 " from trigger_depends td"
3131 " left join triggers t"
3132 " on td.triggerid_up=t.triggerid"
3133 " where t.flags<>%d"
3134 " and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
3135 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_down",
3136 triggerids_down.values, triggerids_down.values_num);
3137
3138 zbx_vector_uint64_clear(&triggerids_down);
3139
3140 result = DBselect("%s", sql);
3141
3142 while (NULL != (row = DBfetch(result)))
3143 {
3144 int new_node = 0;
3145 zbx_lld_trigger_node_t *trigger_node_up;
3146
3147 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[1]);
3148
3149 if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, &trigger_node_local)))
3150 {
3151 trigger_node_up = lld_trigger_cache_append(cache,
3152 trigger_node_local.trigger_ref.triggerid, NULL);
3153 new_node = 1;
3154 }
3155
3156 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
3157
3158 if (NULL == (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, &trigger_node_local)))
3159 {
3160 THIS_SHOULD_NEVER_HAPPEN;
3161 continue;
3162 }
3163
3164 /* check if the dependency is not already registered in cache */
3165 for (i = 0; i < trigger_node->dependencies.values_num; i++)
3166 {
3167 trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
3168
3169 /* references to generic triggers will always have valid id value */
3170 if (trigger_ref->triggerid == trigger_node_up->trigger_ref.triggerid)
3171 break;
3172 }
3173
3174 /* if the dependency was not found - add it */
3175 if (i == trigger_node->dependencies.values_num)
3176 {
3177 trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL,
3178 sizeof(zbx_lld_trigger_ref_t));
3179
3180 trigger_ref->triggerid = trigger_node_up->trigger_ref.triggerid;
3181 trigger_ref->trigger = NULL;
3182 trigger_ref->flags = ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL;
3183
3184 zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
3185
3186 trigger_node_up->parents++;
3187 }
3188
3189 if (1 == new_node)
3190 {
3191 /* if the trigger was added to cache, we must check its dependencies */
3192 zbx_vector_uint64_append(&triggerids_up,
3193 trigger_node_up->trigger_ref.triggerid);
3194 zbx_vector_uint64_append(&triggerids_down,
3195 trigger_node_up->trigger_ref.triggerid);
3196 }
3197 }
3198
3199 DBfree_result(result);
3200 }
3201
3202 /* load dependencies */
3203 if (0 != triggerids_up.values_num)
3204 {
3205 sql_offset = 0;
3206 zbx_vector_uint64_sort(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3207 zbx_vector_uint64_uniq(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3208
3209 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3210 "select td.triggerid_down"
3211 " from trigger_depends td"
3212 " left join triggers t"
3213 " on t.triggerid=td.triggerid_down"
3214 " where t.flags<>%d"
3215 " and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
3216 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_up", triggerids_up.values,
3217 triggerids_up.values_num);
3218
3219 zbx_vector_uint64_clear(&triggerids_up);
3220
3221 result = DBselect("%s", sql);
3222
3223 while (NULL != (row = DBfetch(result)))
3224 {
3225 ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
3226
3227 if (NULL != zbx_hashset_search(cache, &trigger_node_local))
3228 continue;
3229
3230 lld_trigger_cache_append(cache, trigger_node_local.trigger_ref.triggerid, NULL);
3231
3232 zbx_vector_uint64_append(&triggerids_up, trigger_node_local.trigger_ref.triggerid);
3233 zbx_vector_uint64_append(&triggerids_down, trigger_node_local.trigger_ref.triggerid);
3234 }
3235
3236 DBfree_result(result);
3237 }
3238
3239 }
3240
3241 zbx_free(sql);
3242
3243 zbx_vector_uint64_destroy(&triggerids_up);
3244 zbx_vector_uint64_destroy(&triggerids_down);
3245
3246 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3247 }
3248
3249 /******************************************************************************
3250 * *
3251 * Function: zbx_trigger_cache_clean *
3252 * *
3253 * Purpose: releases resources allocated by trigger cache *
3254 * validation *
3255 * *
3256 * Parameters: cache - [IN] the trigger cache *
3257 * *
3258 ******************************************************************************/
zbx_trigger_cache_clean(zbx_hashset_t * cache)3259 static void zbx_trigger_cache_clean(zbx_hashset_t *cache)
3260 {
3261 zbx_hashset_iter_t iter;
3262 zbx_lld_trigger_node_t *trigger_node;
3263
3264 zbx_hashset_iter_reset(cache, &iter);
3265 while (NULL != (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_iter_next(&iter)))
3266 {
3267 zbx_vector_ptr_clear_ext(&trigger_node->dependencies, zbx_ptr_free);
3268 zbx_vector_ptr_destroy(&trigger_node->dependencies);
3269 }
3270
3271 zbx_hashset_destroy(cache);
3272 }
3273
3274 /******************************************************************************
3275 * *
3276 * Function: lld_trigger_dependency_delete *
3277 * *
3278 * Purpose: removes trigger dependency *
3279 * *
3280 * Parameters: from - [IN] the reference to dependent trigger *
3281 * to - [IN] the reference to trigger the from depends on *
3282 * error - [OUT] the error message *
3283 * *
3284 * Comments: If possible (the dependency loop was introduced by discovered *
3285 * dependencies) the last dependency in the loop will be removed. *
3286 * Otherwise (the triggers in database already had dependency loop) *
3287 * the last dependency in the loop will be marked as removed, *
3288 * however the dependency in database will be left intact. *
3289 * *
3290 ******************************************************************************/
lld_trigger_dependency_delete(zbx_lld_trigger_ref_t * from,zbx_lld_trigger_ref_t * to,char ** error)3291 static void lld_trigger_dependency_delete(zbx_lld_trigger_ref_t *from, zbx_lld_trigger_ref_t *to, char **error)
3292 {
3293 zbx_lld_trigger_t *trigger;
3294 int i;
3295 char *trigger_desc;
3296
3297 if (ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == to->flags)
3298 {
3299 /* When old dependency loop has been detected mark it as deleted to avoid */
3300 /* infinite recursion during dependency validation, but don't really delete */
3301 /* it because only new dependencies can be deleted. */
3302
3303 /* in old dependency loop there are no new triggers, so all involved */
3304 /* triggers have valid identifiers */
3305 zabbix_log(LOG_LEVEL_CRIT, "existing recursive dependency loop detected for trigger \""
3306 ZBX_FS_UI64 "\"", to->triggerid);
3307 return;
3308 }
3309
3310 trigger = from->trigger;
3311
3312 /* remove the dependency */
3313 for (i = 0; i < trigger->dependencies.values_num; i++)
3314 {
3315 zbx_lld_dependency_t *dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3316
3317 if ((NULL != dependency->trigger_up && dependency->trigger_up == to->trigger) ||
3318 (0 != dependency->triggerid_up && dependency->triggerid_up == to->triggerid))
3319 {
3320 zbx_free(dependency);
3321 zbx_vector_ptr_remove(&trigger->dependencies, i);
3322
3323 break;
3324 }
3325 }
3326
3327 if (0 != from->triggerid)
3328 trigger_desc = zbx_dsprintf(NULL, ZBX_FS_UI64, from->triggerid);
3329 else
3330 trigger_desc = zbx_strdup(NULL, from->trigger->description);
3331
3332 *error = zbx_strdcatf(*error, "Cannot create all trigger \"%s\" dependencies:"
3333 " recursion too deep.\n", trigger_desc);
3334
3335 zbx_free(trigger_desc);
3336 }
3337
3338 /******************************************************************************
3339 * *
3340 * Function: lld_trigger_dependencies_iter *
3341 * *
3342 * Purpose: iterates through trigger dependencies to find dependency loops *
3343 * *
3344 * Parameters: cache - [IN] the trigger cache *
3345 * triggers - [IN] the discovered triggers *
3346 * trigger_node - [IN] the trigger to check *
3347 * iter - [IN] the dependency iterator *
3348 * level - [IN] the dependency level *
3349 * error - [OUT] the error message *
3350 * *
3351 * Return value: SUCCEED - the trigger's dependency chain in valid *
3352 * FAIL - a dependency loop was detected *
3353 * *
3354 * Comments: If the validation fails the offending dependency is removed. *
3355 * *
3356 ******************************************************************************/
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)3357 static int lld_trigger_dependencies_iter(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers,
3358 zbx_lld_trigger_node_t *trigger_node, zbx_lld_trigger_node_iter_t *iter, int level, char **error)
3359 {
3360 int i;
3361 zbx_lld_trigger_ref_t *trigger_ref;
3362 zbx_lld_trigger_node_t *trigger_node_up;
3363 zbx_lld_trigger_node_iter_t child_iter, *piter;
3364
3365 if (trigger_node->iter_num == iter->iter_num || ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
3366 {
3367 /* dependency loop detected, resolve it by deleting corresponding dependency */
3368 lld_trigger_dependency_delete(iter->ref_from, iter->ref_to, error);
3369
3370 /* mark the dependency as removed */
3371 iter->ref_to->flags = ZBX_LLD_TRIGGER_DEPENDENCY_DELETE;
3372
3373 return FAIL;
3374 }
3375
3376 trigger_node->iter_num = iter->iter_num;
3377
3378 for (i = 0; i < trigger_node->dependencies.values_num; i++)
3379 {
3380 trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
3381
3382 /* skip dependencies marked as deleted */
3383 if (ZBX_LLD_TRIGGER_DEPENDENCY_DELETE == trigger_ref->flags)
3384 continue;
3385
3386 if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, trigger_ref)))
3387 {
3388 THIS_SHOULD_NEVER_HAPPEN;
3389 continue;
3390 }
3391
3392 /* Remember last dependency that could be cut. */
3393 /* It should be either a last new dependency or just a last dependency */
3394 /* if no new dependencies were encountered. */
3395 if (ZBX_LLD_TRIGGER_DEPENDENCY_NEW == trigger_ref->flags || NULL == iter->ref_to ||
3396 ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == iter->ref_to->flags)
3397 {
3398 child_iter.ref_from = &trigger_node->trigger_ref;
3399 child_iter.ref_to = trigger_ref;
3400 child_iter.iter_num = iter->iter_num;
3401
3402 piter = &child_iter;
3403 }
3404 else
3405 piter = iter;
3406
3407 if (FAIL == lld_trigger_dependencies_iter(cache, triggers, trigger_node_up, piter, level + 1, error))
3408 return FAIL;
3409 }
3410
3411 trigger_node->iter_num = 0;
3412
3413 return SUCCEED;
3414 }
3415
3416 /******************************************************************************
3417 * *
3418 * Function: lld_trigger_dependencies_validate *
3419 * *
3420 * Purpose: validate discovered trigger dependencies *
3421 * *
3422 * Parameters: triggers - [IN] the discovered triggers *
3423 * error - [OUT] the error message *
3424 * triggers - [IN] the discovered triggers *
3425 * trigger - [IN] the trigger to check *
3426 * iter - [IN] the dependency iterator *
3427 * level - [IN] the dependency level *
3428 * *
3429 * Comments: During validation the dependency loops will be resolved by *
3430 * removing offending dependencies. *
3431 * *
3432 ******************************************************************************/
lld_trigger_dependencies_validate(zbx_vector_ptr_t * triggers,char ** error)3433 static void lld_trigger_dependencies_validate(zbx_vector_ptr_t *triggers, char **error)
3434 {
3435 zbx_hashset_t cache;
3436 zbx_hashset_iter_t iter;
3437 zbx_lld_trigger_node_t *trigger_node, *trigger_node_up;
3438 zbx_lld_trigger_node_iter_t node_iter = {0};
3439 zbx_vector_ptr_t nodes;
3440 int i;
3441
3442 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3443
3444 lld_trigger_cache_init(&cache, triggers);
3445
3446 /* Perform dependency validation in the order of trigger ids and starting with parentless triggers. */
3447 /* This will give some consistency in choosing what dependencies should be deleted in the case of */
3448 /* recursion. */
3449 zbx_vector_ptr_create(&nodes);
3450 zbx_vector_ptr_reserve(&nodes, cache.num_data);
3451
3452 zbx_hashset_iter_reset(&cache, &iter);
3453 while (NULL != (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_iter_next(&iter)))
3454 {
3455 for (i = 0; i < trigger_node->dependencies.values_num; i++)
3456 {
3457 if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(&cache,
3458 trigger_node->dependencies.values[i])))
3459 {
3460 THIS_SHOULD_NEVER_HAPPEN;
3461 continue;
3462 }
3463
3464 trigger_node_up->parents++;
3465 }
3466 zbx_vector_ptr_append(&nodes, trigger_node);
3467 }
3468
3469 zbx_vector_ptr_sort(&nodes, zbx_lld_trigger_node_compare_func);
3470
3471 for (i = 0; i < nodes.values_num; i++)
3472 {
3473 if (NULL == (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_search(&cache, (zbx_lld_trigger_node_t *)nodes.values[i])))
3474 {
3475 THIS_SHOULD_NEVER_HAPPEN;
3476 continue;
3477 }
3478
3479 /* If dependency iterator returns false it means that dependency loop was detected */
3480 /* (and resolved). In this case we have to validate dependencies for this trigger */
3481 /* again. */
3482 do
3483 {
3484 node_iter.iter_num++;
3485 node_iter.ref_from = NULL;
3486 node_iter.ref_to = NULL;
3487 }
3488 while (SUCCEED != lld_trigger_dependencies_iter(&cache, triggers, trigger_node, &node_iter, 0, error));
3489 }
3490
3491 zbx_vector_ptr_destroy(&nodes);
3492 zbx_trigger_cache_clean(&cache);
3493
3494 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3495 }
3496
get_trigger_info(const void * object,zbx_uint64_t * id,int * discovery_flag,int * lastcheck,int * ts_delete)3497 static void get_trigger_info(const void *object, zbx_uint64_t *id, int *discovery_flag, int *lastcheck,
3498 int *ts_delete)
3499 {
3500 zbx_lld_trigger_t *trigger;
3501
3502 trigger = (zbx_lld_trigger_t *)object;
3503
3504 *id = trigger->triggerid;
3505 *discovery_flag = trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
3506 *lastcheck = trigger->lastcheck;
3507 *ts_delete = trigger->ts_delete;
3508 }
3509
3510 /******************************************************************************
3511 * *
3512 * Function: lld_update_triggers *
3513 * *
3514 * Purpose: add or update triggers for discovered items *
3515 * *
3516 * Return value: SUCCEED - if triggers were successfully added/updated or *
3517 * adding/updating was not necessary *
3518 * FAIL - triggers cannot be added/updated *
3519 * *
3520 ******************************************************************************/
lld_update_triggers(zbx_uint64_t hostid,zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths,char ** error,int lifetime,int lastcheck)3521 int lld_update_triggers(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows,
3522 const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck)
3523 {
3524 zbx_vector_ptr_t trigger_prototypes;
3525 zbx_vector_ptr_t triggers;
3526 zbx_vector_ptr_t items;
3527 zbx_lld_trigger_t *trigger;
3528 zbx_lld_trigger_prototype_t *trigger_prototype;
3529 int ret = SUCCEED, i;
3530
3531 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3532
3533 zbx_vector_ptr_create(&trigger_prototypes);
3534
3535 lld_trigger_prototypes_get(lld_ruleid, &trigger_prototypes);
3536
3537 if (0 == trigger_prototypes.values_num)
3538 goto out;
3539
3540 zbx_vector_ptr_create(&triggers); /* list of triggers which were created or will be created or */
3541 /* updated by the trigger prototype */
3542 zbx_vector_ptr_create(&items); /* list of items which are related to the trigger prototypes */
3543
3544 lld_triggers_get(&trigger_prototypes, &triggers);
3545 lld_functions_get(&trigger_prototypes, &triggers);
3546 lld_dependencies_get(&trigger_prototypes, &triggers);
3547 lld_tags_get(&trigger_prototypes, &triggers);
3548 lld_items_get(&trigger_prototypes, &items);
3549
3550 /* simplifying trigger expressions */
3551
3552 for (i = 0; i < trigger_prototypes.values_num; i++)
3553 {
3554 trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes.values[i];
3555
3556 lld_expressions_simplify(&trigger_prototype->expression, &trigger_prototype->recovery_expression,
3557 &trigger_prototype->functions);
3558 }
3559
3560 for (i = 0; i < triggers.values_num; i++)
3561 {
3562 trigger = (zbx_lld_trigger_t *)triggers.values[i];
3563
3564 lld_expressions_simplify(&trigger->expression, &trigger->recovery_expression, &trigger->functions);
3565 }
3566
3567 /* making triggers */
3568
3569 lld_triggers_make(&trigger_prototypes, &triggers, &items, lld_rows, lld_macro_paths, error);
3570 lld_triggers_validate(hostid, &triggers, error);
3571 lld_trigger_dependencies_make(&trigger_prototypes, &triggers, lld_rows, error);
3572 lld_trigger_dependencies_validate(&triggers, error);
3573 lld_trigger_tags_make(&trigger_prototypes, &triggers, lld_rows, lld_macro_paths);
3574 lld_trigger_tags_validate(&triggers, error);
3575 ret = lld_triggers_save(hostid, &trigger_prototypes, &triggers);
3576
3577 lld_remove_lost_objects("trigger_discovery", "triggerid", &triggers, lifetime, lastcheck, DBdelete_triggers,
3578 get_trigger_info);
3579 /* cleaning */
3580
3581 zbx_vector_ptr_clear_ext(&items, (zbx_mem_free_func_t)lld_item_free);
3582 zbx_vector_ptr_clear_ext(&triggers, (zbx_mem_free_func_t)lld_trigger_free);
3583 zbx_vector_ptr_destroy(&items);
3584 zbx_vector_ptr_destroy(&triggers);
3585 out:
3586 zbx_vector_ptr_clear_ext(&trigger_prototypes, (zbx_mem_free_func_t)lld_trigger_prototype_free);
3587 zbx_vector_ptr_destroy(&trigger_prototypes);
3588
3589 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3590
3591 return ret;
3592 }
3593