diff options
Diffstat (limited to 'src/libs/zbxdbwrap/trigger_dep_linking.c')
-rw-r--r-- | src/libs/zbxdbwrap/trigger_dep_linking.c | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/src/libs/zbxdbwrap/trigger_dep_linking.c b/src/libs/zbxdbwrap/trigger_dep_linking.c new file mode 100644 index 00000000000..6bc847ed64b --- /dev/null +++ b/src/libs/zbxdbwrap/trigger_dep_linking.c @@ -0,0 +1,574 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "trigger_dep_linking.h" +#include "zbxdbwrap.h" + +#include "log.h" +#include "audit/zbxaudit_trigger.h" +#include "zbxnum.h" + +typedef struct +{ + zbx_uint64_t triggerid; + int flags; +} +resolve_dependencies_triggers_flags_t; + +static zbx_hash_t triggers_flags_hash_func(const void *data) +{ + const resolve_dependencies_triggers_flags_t *trigger_entry = + (const resolve_dependencies_triggers_flags_t *)data; + + return ZBX_DEFAULT_UINT64_HASH_ALGO(&(trigger_entry->triggerid), sizeof(trigger_entry->triggerid), + ZBX_DEFAULT_HASH_SEED); +} + +static int triggers_flags_compare_func(const void *d1, const void *d2) +{ + const resolve_dependencies_triggers_flags_t *trigger_entry_1 = + (const resolve_dependencies_triggers_flags_t *)d1; + const resolve_dependencies_triggers_flags_t *trigger_entry_2 = + (const resolve_dependencies_triggers_flags_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(trigger_entry_1->triggerid, trigger_entry_2->triggerid); + + return 0; +} + +typedef struct +{ + zbx_uint64_t trigger_dep_id; + zbx_uint64_t trigger_down_id; + zbx_uint64_t trigger_up_id; + int status; + int flags; +} +zbx_trigger_dep_vec_entry_t; + +ZBX_PTR_VECTOR_DECL(trigger_up_entries, zbx_trigger_dep_vec_entry_t *) +ZBX_PTR_VECTOR_IMPL(trigger_up_entries, zbx_trigger_dep_vec_entry_t *) + +typedef struct +{ + zbx_uint64_t trigger_down_id; + zbx_vector_trigger_up_entries_t v; +} +zbx_trigger_dep_entry_t; + +static zbx_hash_t zbx_trigger_dep_entries_hash_func(const void *data) +{ + const zbx_trigger_dep_entry_t *trigger_dep_entry = (const zbx_trigger_dep_entry_t *)data; + + return ZBX_DEFAULT_UINT64_HASH_ALGO(&((trigger_dep_entry)->trigger_down_id), + sizeof(trigger_dep_entry->trigger_down_id), ZBX_DEFAULT_HASH_SEED); +} + +static int zbx_trigger_dep_entries_compare_func(const void *d1, const void *d2) +{ + const zbx_trigger_dep_entry_t *trigger_dep_entry_1 = (const zbx_trigger_dep_entry_t *)d1; + const zbx_trigger_dep_entry_t *trigger_dep_entry_2 = (const zbx_trigger_dep_entry_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(trigger_dep_entry_1->trigger_down_id, trigger_dep_entry_2->trigger_down_id); + + return 0; +} + +static void zbx_trigger_dep_vec_entry_clean(zbx_trigger_dep_vec_entry_t *trigger_dep_entry) +{ + zbx_free(trigger_dep_entry); +} + +static void zbx_triggers_dep_entries_clean(zbx_hashset_t *h) +{ + zbx_hashset_iter_t iter; + zbx_trigger_dep_entry_t *trigger_dep_entry; + + zbx_hashset_iter_reset(h, &iter); + + while (NULL != (trigger_dep_entry = (zbx_trigger_dep_entry_t *)zbx_hashset_iter_next(&iter))) + { + zbx_vector_trigger_up_entries_clear_ext(&(trigger_dep_entry->v), zbx_trigger_dep_vec_entry_clean); + zbx_vector_trigger_up_entries_destroy(&(trigger_dep_entry->v)); + } + + zbx_hashset_destroy(h); +} + +/********************************************************************************* + * * + * Purpose: resolves trigger dependencies for the specified triggers based on * + * host and linked templates * + * * + * Parameters: hostid - [IN] host identifier from database * + * trids - [IN] vector of trigger identifiers from database * + * links - [OUT] pairs of trigger dependencies (down,up) * + * trigger_flags - [OUT] map that lets audit to know if trigger is * + * a prototype or just trigger * + * * + * Return value: upon successful completion return SUCCEED, or FAIL on DB error * + * * + *********************************************************************************/ +static int DBresolve_template_trigger_dependencies(zbx_uint64_t hostid, const zbx_vector_uint64_t *trids, + zbx_vector_uint64_pair_t *links, zbx_hashset_t *triggers_flags) +{ + char *sql = NULL; + int i, res = SUCCEED; + size_t sql_alloc = 512, sql_offset; + DB_RESULT result; + DB_ROW row; + zbx_vector_uint64_pair_t dep_list_ids, map_ids; + zbx_vector_uint64_t all_templ_ids; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&all_templ_ids); + zbx_vector_uint64_pair_create(&dep_list_ids); + zbx_vector_uint64_pair_create(&map_ids); + sql = (char *)zbx_malloc(sql, sql_alloc); + + sql_offset = 0; + + /* get triggerids on which the 'parent template trigger of the new trigger' depends on */ + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select distinct td.triggerid_down,td.triggerid_up" + " from triggers t,trigger_depends td" + " where t.templateid in (td.triggerid_up,td.triggerid_down) and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid", trids->values, trids->values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_pair_t dep_list_id; + + ZBX_STR2UINT64(dep_list_id.first, row[0]); + ZBX_STR2UINT64(dep_list_id.second, row[1]); + zbx_vector_uint64_pair_append(&dep_list_ids, dep_list_id); + zbx_vector_uint64_append(&all_templ_ids, dep_list_id.first); + zbx_vector_uint64_append(&all_templ_ids, dep_list_id.second); + } + + DBfree_result(result); + + if (0 == dep_list_ids.values_num) /* not all trigger templates have a dependency trigger */ + goto clean; + + zbx_vector_uint64_sort(&all_templ_ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&all_templ_ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + + /* find triggers which have a parent template trigger that we have dependency on, */ + /* those are the dependency triggers of interest on our host */ + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t.triggerid,t.templateid,t.flags" + " from triggers t,functions f,items i" + " where t.triggerid=f.triggerid" + " and f.itemid=i.itemid" + " and i.hostid=" ZBX_FS_UI64 + " and", + hostid); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.templateid", all_templ_ids.values, + all_templ_ids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid", trids->values, + trids->values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + zbx_uint64_pair_t map_id; + resolve_dependencies_triggers_flags_t temp_t; + + ZBX_STR2UINT64(temp_t.triggerid, row[0]); + + if (NULL == zbx_hashset_search(triggers_flags, &temp_t)) + { + resolve_dependencies_triggers_flags_t local_temp_t; + + ZBX_STR2UINT64(local_temp_t.triggerid, row[0]); + local_temp_t.flags = atoi(row[2]); + zbx_hashset_insert(triggers_flags, &local_temp_t, sizeof(local_temp_t)); + } + + ZBX_STR2UINT64(map_id.first, row[0]); + ZBX_DBROW2UINT64(map_id.second, row[1]); + + zbx_vector_uint64_pair_append(&map_ids, map_id); + } + + DBfree_result(result); + + for (i = 0; i < dep_list_ids.values_num; i++) + { + zbx_uint64_t templateid_down = dep_list_ids.values[i].first; + zbx_uint64_t templateid_up = dep_list_ids.values[i].second; + + /* Convert template ids to corresponding trigger ids. */ + /* If template trigger depends on host trigger rather than */ + /* template trigger then up id conversion will fail and the */ + /* original value (host trigger id) will be used as intended. */ + zbx_uint64_t triggerid_down = 0; + zbx_uint64_t triggerid_up = templateid_up; + int j; + + for (j = 0; j < map_ids.values_num; j++) + { + zbx_uint64_t hst_triggerid = map_ids.values[j].first; + zbx_uint64_t tpl_triggerid = map_ids.values[j].second; + + if (tpl_triggerid == templateid_down) + triggerid_down = hst_triggerid; + + if (tpl_triggerid == templateid_up) + triggerid_up = hst_triggerid; + } + + if (0 != triggerid_down) + { + zbx_uint64_pair_t link = {triggerid_down, triggerid_up}; + + zbx_vector_uint64_pair_append(links, link); + } + } +clean: + zbx_free(sql); + zbx_vector_uint64_destroy(&all_templ_ids); + + zbx_vector_uint64_pair_destroy(&map_ids); + zbx_vector_uint64_pair_destroy(&dep_list_ids); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +/********************************************************************************************************** + * * + * Purpose: takes a list of pending trigger dependencies (links) and excludes entries that are * + * already present on the target host to generate a new list (links_processed). Also, prepare * + * the list of the trigger dependencies (trigger_dep_ids_del) that need to be deleted on the * + * target host, since they are not present on the template trigger. * + * * + * Parameters: trids - [IN] vector of trigger identifiers from database * + * links - [OUT] pairs of trigger dependencies, list of links_up and links_down * + * links that we want to be present on the target host * + * links_processed - [OUT] processed links with entries that are already present excluded * + * trigger_dep_ids_del - [OUT] list of triggers dependencies that need to be deleted * + * * + * Return value: upon successful completion return SUCCEED, or FAIL on DB error * + * * + *********************************************************************************************************/ +static int prepare_trigger_dependencies_updates_and_deletes(const zbx_vector_uint64_t *trids, + zbx_vector_uint64_pair_t *links, zbx_vector_uint64_pair_t *links_processed, + zbx_vector_uint64_t *trigger_dep_ids_del) +{ + char *sql = NULL; + int i, res = SUCCEED; + size_t sql_alloc = 256, sql_offset = 0; + DB_RESULT result; + DB_ROW row; + zbx_hashset_t h; + zbx_hashset_iter_t iter; + zbx_trigger_dep_entry_t *found; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); +#define TRIGGER_FUNCS_HASHSET_DEF_SIZE 100 + zbx_hashset_create(&h, TRIGGER_FUNCS_HASHSET_DEF_SIZE, zbx_trigger_dep_entries_hash_func, + zbx_trigger_dep_entries_compare_func); +#undef TRIGGER_FUNCS_HASHSET_DEF_SIZE + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select td.triggerdepid,td.triggerid_down,td.triggerid_up,t.flags" + " from trigger_depends td,triggers t " + " where t.triggerid=td.triggerid_down" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_down", trids->values, trids->values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + int flags; + zbx_uint64_t trigger_dep_id, trigger_id_down, trigger_id_up; + zbx_trigger_dep_entry_t temp_t; + zbx_trigger_dep_vec_entry_t *s; + + ZBX_STR2UINT64(trigger_dep_id, row[0]); + ZBX_STR2UINT64(trigger_id_down, row[1]); + ZBX_STR2UINT64(trigger_id_up, row[2]); + flags = atoi(row[3]); + + temp_t.trigger_down_id = trigger_id_down; + + s = (zbx_trigger_dep_vec_entry_t *)zbx_malloc(NULL, sizeof(zbx_trigger_dep_vec_entry_t)); + s->trigger_dep_id = trigger_dep_id; + s->trigger_down_id = trigger_id_down; + s->trigger_up_id = trigger_id_up; + s->status = 0; + s->flags = flags; + + if (NULL != (found = (zbx_trigger_dep_entry_t *)zbx_hashset_search(&h, &temp_t))) + { + zbx_vector_trigger_up_entries_append(&(found->v), s); + } + else + { + zbx_trigger_dep_entry_t local_temp_t; + + zbx_vector_trigger_up_entries_create(&(local_temp_t.v)); + zbx_vector_trigger_up_entries_append(&(local_temp_t.v), s); + local_temp_t.trigger_down_id = trigger_id_down; + zbx_hashset_insert(&h, &local_temp_t, sizeof(local_temp_t)); + } + } + + DBfree_result(result); + + for (i = 0; i < links->values_num; i++) + { + zbx_trigger_dep_entry_t temp_t; + + temp_t.trigger_down_id = links->values[i].first; + + if (NULL != (found = (zbx_trigger_dep_entry_t *) zbx_hashset_search(&h, &temp_t))) + { + int j; + int found_trigger_up = 0; + + for (j = 0; j < found->v.values_num; j++) + { + /* trigger_up are equal */ + if (links->values[i].second == found->v.values[j]->trigger_up_id) + { + found_trigger_up = 1; + /* mark it as 'need to preserve' */ + found->v.values[j]->status = 1; + break; + } + } + + if (0 == found_trigger_up) + { + zbx_uint64_pair_t x; + + x.first = links->values[i].first; + x.second = links->values[i].second; + zbx_vector_uint64_pair_append(links_processed, x); + } + } + else + { + zbx_uint64_pair_t x; + + x.first = links->values[i].first; + x.second = links->values[i].second; + zbx_vector_uint64_pair_append(links_processed, x); + } + } + + zbx_hashset_iter_reset(&h, &iter); + + while (NULL != (found = (zbx_trigger_dep_entry_t *)zbx_hashset_iter_next(&iter))) + { + for (i = 0; i < found->v.values_num; i++) + { + if (0 == found->v.values[i]->status) + { + zbx_vector_uint64_append(trigger_dep_ids_del, + found->v.values[i]->trigger_dep_id); + zbx_audit_trigger_update_json_remove_dependency(found->v.values[i]->flags, + found->v.values[i]->trigger_dep_id, + found->v.values[i]->trigger_down_id); + } + } + } +clean: + zbx_triggers_dep_entries_clean(&h); + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int DBadd_trigger_dependencies(zbx_vector_uint64_pair_t *links, zbx_hashset_t *triggers_flags) +{ + int res = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 < links->values_num) + { + int i; + zbx_uint64_t triggerdepid; + zbx_db_insert_t db_insert; + + triggerdepid = DBget_maxid_num("trigger_depends", links->values_num); + + zbx_db_insert_prepare(&db_insert, "trigger_depends", "triggerdepid", "triggerid_down", "triggerid_up", + NULL); + + for (i = 0; i < links->values_num; i++) + { + resolve_dependencies_triggers_flags_t *found, temp_t; + + zbx_db_insert_add_values(&db_insert, triggerdepid, links->values[i].first, + links->values[i].second); + + temp_t.triggerid = links->values[i].first; + + if (NULL != (found = (resolve_dependencies_triggers_flags_t *)zbx_hashset_search( + triggers_flags, &temp_t))) + { + zbx_audit_trigger_update_json_add_dependency(found->flags, triggerdepid, + links->values[i].first, links->values[i].second); + } + else + { + THIS_SHOULD_NEVER_HAPPEN; + res = FAIL; + + break; + } + + triggerdepid++; + } + + if (SUCCEED == res) + zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int DBadd_and_remove_trigger_dependencies(zbx_vector_uint64_pair_t *links, + const zbx_vector_uint64_t *trids, zbx_hashset_t *triggers_flags) +{ + int res; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + zbx_vector_uint64_pair_t links_processed; + zbx_vector_uint64_t trigger_dep_ids_del; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&trigger_dep_ids_del); + zbx_vector_uint64_pair_create(&links_processed); + + if (FAIL == (res = prepare_trigger_dependencies_updates_and_deletes(trids, links, &links_processed, + &trigger_dep_ids_del))) + { + goto clean; + } + + if (0 < trigger_dep_ids_del.values_num) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_depends where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerdepid", + trigger_dep_ids_del.values, trigger_dep_ids_del.values_num); + + if (ZBX_DB_OK > DBexecute("%s", sql)) + { + res = FAIL; + goto clean; + } + } + + res = DBadd_trigger_dependencies(&links_processed, triggers_flags); +clean: + zbx_free(sql); + zbx_vector_uint64_destroy(&trigger_dep_ids_del); + zbx_vector_uint64_pair_destroy(&links_processed); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +/******************************************************************************** + * * + * Purpose: update trigger dependencies for specified host * + * * + * Parameters: hostid - [IN] host identifier from database * + * trids - [IN] vector of trigger identifiers from database * + * is_update - [IN] flag. Values: * + * TRIGGER_DEP_SYNC_INSERT_OP - 'trids' contains * + * identifiers of new triggers, * + * TRIGGER_DEP_SYNC_UPDATE_OP - 'trids' contains * + * identifiers of already present triggers which * + * need to be updated * + * * + * Return value: upon successful completion return SUCCEED, or FAIL on DB error * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ********************************************************************************/ +int DBsync_template_dependencies_for_triggers(zbx_uint64_t hostid, const zbx_vector_uint64_t *trids, int is_update) +{ + int res = SUCCEED; + zbx_vector_uint64_pair_t links; + zbx_hashset_t triggers_flags; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == trids->values_num) + goto out; + + zbx_vector_uint64_pair_create(&links); +#define TRIGGER_FUNCS_HASHSET_DEF_SIZE 100 + zbx_hashset_create(&triggers_flags, TRIGGER_FUNCS_HASHSET_DEF_SIZE, triggers_flags_hash_func, + triggers_flags_compare_func); +#undef TRIGGER_FUNCS_HASHSET_DEF_SIZE + if (FAIL == (res = DBresolve_template_trigger_dependencies(hostid, trids, &links, &triggers_flags))) + goto clean; + + if (TRIGGER_DEP_SYNC_INSERT_OP == is_update) + { + if (FAIL == (res = DBadd_trigger_dependencies(&links, &triggers_flags))) + goto clean; + } + else if (TRIGGER_DEP_SYNC_UPDATE_OP == is_update) + { + res = DBadd_and_remove_trigger_dependencies(&links, trids, &triggers_flags); + } +clean: + zbx_vector_uint64_pair_destroy(&links); + zbx_hashset_destroy(&triggers_flags); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} |