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