diff options
Diffstat (limited to 'src/libs/zbxcacheconfig/dbconfig_maintenance.c')
-rw-r--r-- | src/libs/zbxcacheconfig/dbconfig_maintenance.c | 1608 |
1 files changed, 1608 insertions, 0 deletions
diff --git a/src/libs/zbxcacheconfig/dbconfig_maintenance.c b/src/libs/zbxcacheconfig/dbconfig_maintenance.c new file mode 100644 index 00000000000..ff84f2563cf --- /dev/null +++ b/src/libs/zbxcacheconfig/dbconfig_maintenance.c @@ -0,0 +1,1608 @@ +/* +** 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 "zbxcacheconfig.h" +#include "dbconfig.h" + +#include "log.h" +#include "zbxalgo.h" +#include "dbsync.h" +#include "zbxnum.h" +#include "zbxtime.h" + +extern int CONFIG_TIMER_FORKS; + +typedef struct +{ + zbx_uint64_t hostid; + const zbx_dc_maintenance_t *maintenance; +} +zbx_host_maintenance_t; + +typedef struct +{ + zbx_uint64_t hostid; + zbx_vector_ptr_t maintenances; +} +zbx_host_event_maintenance_t; + +/****************************************************************************** + * * + * Purpose: Updates maintenances in configuration cache * + * * + * Parameters: sync - [IN] the db synchronization data * + * * + * Comments: The result contains the following fields: * + * 0 - maintenanceid * + * 1 - maintenance_type * + * 2 - active_since * + * 3 - active_till * + * 4 - tags_evaltype * + * * + ******************************************************************************/ +void DCsync_maintenances(zbx_dbsync_t *sync) +{ + char **row; + zbx_uint64_t rowid; + unsigned char tag; + zbx_uint64_t maintenanceid; + zbx_dc_maintenance_t *maintenance; + int found, ret; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag))) + { + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE; + + /* removed rows will be always added at the end */ + if (ZBX_DBSYNC_ROW_REMOVE == tag) + break; + + ZBX_STR2UINT64(maintenanceid, row[0]); + + maintenance = (zbx_dc_maintenance_t *)DCfind_id(&config->maintenances, maintenanceid, + sizeof(zbx_dc_maintenance_t), &found); + + if (0 == found) + { + maintenance->state = ZBX_MAINTENANCE_IDLE; + maintenance->running_since = 0; + maintenance->running_until = 0; + + zbx_vector_uint64_create_ext(&maintenance->groupids, config->maintenances.mem_malloc_func, + config->maintenances.mem_realloc_func, config->maintenances.mem_free_func); + zbx_vector_uint64_create_ext(&maintenance->hostids, config->maintenances.mem_malloc_func, + config->maintenances.mem_realloc_func, config->maintenances.mem_free_func); + zbx_vector_ptr_create_ext(&maintenance->tags, config->maintenances.mem_malloc_func, + config->maintenances.mem_realloc_func, config->maintenances.mem_free_func); + zbx_vector_ptr_create_ext(&maintenance->periods, config->maintenances.mem_malloc_func, + config->maintenances.mem_realloc_func, config->maintenances.mem_free_func); + } + + ZBX_STR2UCHAR(maintenance->type, row[1]); + ZBX_STR2UCHAR(maintenance->tags_evaltype, row[4]); + maintenance->active_since = atoi(row[2]); + maintenance->active_until = atoi(row[3]); + } + + /* remove deleted maintenances */ + + for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag)) + { + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, &rowid))) + continue; + + zbx_vector_uint64_destroy(&maintenance->groupids); + zbx_vector_uint64_destroy(&maintenance->hostids); + zbx_vector_ptr_destroy(&maintenance->tags); + zbx_vector_ptr_destroy(&maintenance->periods); + + zbx_hashset_remove_direct(&config->maintenances, maintenance); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: compare maintenance tags by tag name for sorting * + * * + ******************************************************************************/ +static int dc_compare_maintenance_tags(const void *d1, const void *d2) +{ + const zbx_dc_maintenance_tag_t *tag1 = *(const zbx_dc_maintenance_tag_t **)d1; + const zbx_dc_maintenance_tag_t *tag2 = *(const zbx_dc_maintenance_tag_t **)d2; + + return strcmp(tag1->tag, tag2->tag); +} + +/****************************************************************************** + * * + * Purpose: Updates maintenance tags in configuration cache * + * * + * Parameters: sync - [IN] the db synchronization data * + * * + * Comments: The result contains the following fields: * + * 0 - maintenancetagid * + * 1 - maintenanceid * + * 2 - operator * + * 3 - tag * + * 4 - value * + * * + ******************************************************************************/ +void DCsync_maintenance_tags(zbx_dbsync_t *sync) +{ + char **row; + zbx_uint64_t rowid; + unsigned char tag; + zbx_uint64_t maintenancetagid, maintenanceid; + zbx_dc_maintenance_tag_t *maintenance_tag; + zbx_dc_maintenance_t *maintenance; + zbx_vector_ptr_t maintenances; + int found, ret, index, i; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(&maintenances); + + while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag))) + { + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE; + + /* removed rows will be always added at the end */ + if (ZBX_DBSYNC_ROW_REMOVE == tag) + break; + + ZBX_STR2UINT64(maintenanceid, row[1]); + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + + ZBX_STR2UINT64(maintenancetagid, row[0]); + maintenance_tag = (zbx_dc_maintenance_tag_t *)DCfind_id(&config->maintenance_tags, maintenancetagid, + sizeof(zbx_dc_maintenance_tag_t), &found); + + maintenance_tag->maintenanceid = maintenanceid; + ZBX_STR2UCHAR(maintenance_tag->op, row[2]); + dc_strpool_replace(found, &maintenance_tag->tag, row[3]); + dc_strpool_replace(found, &maintenance_tag->value, row[4]); + + if (0 == found) + zbx_vector_ptr_append(&maintenance->tags, maintenance_tag); + + zbx_vector_ptr_append(&maintenances, maintenance); + } + + /* remove deleted maintenance tags */ + + for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag)) + { + if (NULL == (maintenance_tag = (zbx_dc_maintenance_tag_t *)zbx_hashset_search(&config->maintenance_tags, + &rowid))) + { + continue; + } + + if (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenance_tag->maintenanceid))) + { + index = zbx_vector_ptr_search(&maintenance->tags, &maintenance_tag->maintenancetagid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + + if (FAIL != index) + zbx_vector_ptr_remove_noorder(&maintenance->tags, index); + + zbx_vector_ptr_append(&maintenances, maintenance); + } + + dc_strpool_release(maintenance_tag->tag); + dc_strpool_release(maintenance_tag->value); + + zbx_hashset_remove_direct(&config->maintenance_tags, maintenance_tag); + } + + /* sort maintenance tags */ + + zbx_vector_ptr_sort(&maintenances, ZBX_DEFAULT_PTR_COMPARE_FUNC); + zbx_vector_ptr_uniq(&maintenances, ZBX_DEFAULT_PTR_COMPARE_FUNC); + + for (i = 0; i < maintenances.values_num; i++) + { + maintenance = (zbx_dc_maintenance_t *)maintenances.values[i]; + zbx_vector_ptr_sort(&maintenance->tags, dc_compare_maintenance_tags); + } + + zbx_vector_ptr_destroy(&maintenances); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: Updates maintenance period in configuration cache * + * * + * Parameters: sync - [IN] the db synchronization data * + * * + * Comments: The result contains the following fields: * + * 0 - timeperiodid * + * 1 - timeperiod_type * + * 2 - every * + * 3 - month * + * 4 - dayofweek * + * 5 - day * + * 6 - start_time * + * 7 - period * + * 8 - start_date * + * 9 - maintenanceid * + * * + ******************************************************************************/ +void DCsync_maintenance_periods(zbx_dbsync_t *sync) +{ + char **row; + zbx_uint64_t rowid; + unsigned char tag; + zbx_uint64_t periodid, maintenanceid; + zbx_dc_maintenance_period_t *period; + zbx_dc_maintenance_t *maintenance; + int found, ret, index; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag))) + { + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE; + + /* removed rows will be always added at the end */ + if (ZBX_DBSYNC_ROW_REMOVE == tag) + break; + + ZBX_STR2UINT64(maintenanceid, row[9]); + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + + ZBX_STR2UINT64(periodid, row[0]); + period = (zbx_dc_maintenance_period_t *)DCfind_id(&config->maintenance_periods, periodid, + sizeof(zbx_dc_maintenance_period_t), &found); + + period->maintenanceid = maintenanceid; + ZBX_STR2UCHAR(period->type, row[1]); + period->every = atoi(row[2]); + period->month = atoi(row[3]); + period->dayofweek = atoi(row[4]); + period->day = atoi(row[5]); + period->start_time = atoi(row[6]); + period->period = atoi(row[7]); + period->start_date = atoi(row[8]); + + if (0 == found) + zbx_vector_ptr_append(&maintenance->periods, period); + } + + /* remove deleted maintenance tags */ + + for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag)) + { + if (NULL == (period = (zbx_dc_maintenance_period_t *)zbx_hashset_search(&config->maintenance_periods, + &rowid))) + { + continue; + } + + if (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &period->maintenanceid))) + { + index = zbx_vector_ptr_search(&maintenance->periods, &period->timeperiodid, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + + if (FAIL != index) + zbx_vector_ptr_remove_noorder(&maintenance->periods, index); + } + + zbx_hashset_remove_direct(&config->maintenance_periods, period); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: Updates maintenance groups in configuration cache * + * * + * Parameters: sync - [IN] the db synchronization data * + * * + * Comments: The result contains the following fields: * + * 0 - maintenanceid * + * 1 - groupid * + * * + ******************************************************************************/ +void DCsync_maintenance_groups(zbx_dbsync_t *sync) +{ + char **row; + zbx_uint64_t rowid; + unsigned char tag; + zbx_dc_maintenance_t *maintenance = NULL; + int index, ret; + zbx_uint64_t last_maintenanceid = 0, maintenanceid, groupid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag))) + { + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE; + + /* removed rows will be always added at the end */ + if (ZBX_DBSYNC_ROW_REMOVE == tag) + break; + + ZBX_STR2UINT64(maintenanceid, row[0]); + + if (last_maintenanceid != maintenanceid || 0 == last_maintenanceid) + { + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + last_maintenanceid = maintenanceid; + } + + ZBX_STR2UINT64(groupid, row[1]); + + zbx_vector_uint64_append(&maintenance->groupids, groupid); + } + + /* remove deleted maintenance groupids from cache */ + for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag)) + { + ZBX_STR2UINT64(maintenanceid, row[0]); + + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + ZBX_STR2UINT64(groupid, row[1]); + + if (FAIL == (index = zbx_vector_uint64_search(&maintenance->groupids, groupid, + ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + continue; + } + + zbx_vector_uint64_remove_noorder(&maintenance->groupids, index); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: Updates maintenance hosts in configuration cache * + * * + * Parameters: sync - [IN] the db synchronization data * + * * + * Comments: The result contains the following fields: * + * 0 - maintenanceid * + * 1 - hostid * + * * + ******************************************************************************/ +void DCsync_maintenance_hosts(zbx_dbsync_t *sync) +{ + char **row; + zbx_uint64_t rowid; + unsigned char tag; + zbx_vector_ptr_t maintenances; + zbx_dc_maintenance_t *maintenance = NULL; + int index, ret, i; + zbx_uint64_t last_maintenanceid, maintenanceid, hostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(&maintenances); + + while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag))) + { + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE; + + /* removed rows will be always added at the end */ + if (ZBX_DBSYNC_ROW_REMOVE == tag) + break; + + ZBX_STR2UINT64(maintenanceid, row[0]); + + if (NULL == maintenance || last_maintenanceid != maintenanceid) + { + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + last_maintenanceid = maintenanceid; + } + + ZBX_STR2UINT64(hostid, row[1]); + + zbx_vector_uint64_append(&maintenance->hostids, hostid); + zbx_vector_ptr_append(&maintenances, maintenance); + } + + /* remove deleted maintenance hostids from cache */ + for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag)) + { + ZBX_STR2UINT64(maintenanceid, row[0]); + + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceid))) + { + continue; + } + ZBX_STR2UINT64(hostid, row[1]); + + if (FAIL == (index = zbx_vector_uint64_search(&maintenance->hostids, hostid, + ZBX_DEFAULT_UINT64_COMPARE_FUNC))) + { + continue; + } + + zbx_vector_uint64_remove_noorder(&maintenance->hostids, index); + zbx_vector_ptr_append(&maintenances, maintenance); + } + + zbx_vector_ptr_sort(&maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + zbx_vector_ptr_uniq(&maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + + for (i = 0; i < maintenances.values_num; i++) + { + maintenance = (zbx_dc_maintenance_t *)maintenances.values[i]; + zbx_vector_uint64_sort(&maintenance->hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + } + + zbx_vector_ptr_destroy(&maintenances); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Purpose: subtract two local times with DST correction * + * * + * Parameter: minuend - [IN] the minuend time * + * subtrahend - [IN] the subtrahend time (may be negative) * + * tm - [OUT] the struct tm * + * * + * Return value: the resulting time difference in seconds * + * * + ******************************************************************************/ +static time_t dc_subtract_time(time_t minuend, int subtrahend, struct tm *tm) +{ + time_t diff, offset_min, offset_diff; + + offset_min = zbx_get_timezone_offset(minuend, tm); + diff = minuend - subtrahend; + offset_diff = zbx_get_timezone_offset(diff, tm); + diff -= offset_diff - offset_min; + + return diff; +} + +/****************************************************************************** + * * + * Purpose: calculate start time for the specified maintenance period * + * * + * Parameter: maintenance - [IN] the maintenance * + * period - [IN] the maintenance period * + * start_date - [IN] the period starting timestamp based on * + * current time * + * running_since - [OUT] the actual period starting timestamp * + * running_until - [OUT] the actual period ending timestamp * + * * + * Return value: SUCCEED - a valid period was found * + * FAIL - period started before maintenance activation time * + * * + ******************************************************************************/ +static int dc_calculate_maintenance_period(const zbx_dc_maintenance_t *maintenance, + const zbx_dc_maintenance_period_t *period, time_t start_date, time_t *running_since, + time_t *running_until) +{ + int day, wday, week; + struct tm tm; + time_t active_since = maintenance->active_since; + + if (TIMEPERIOD_TYPE_ONETIME == period->type) + { + *running_since = (period->start_date < active_since ? active_since : period->start_date); + *running_until = period->start_date + period->period; + if (maintenance->active_until < *running_until) + *running_until = maintenance->active_until; + + return SUCCEED; + } + + switch (period->type) + { + case TIMEPERIOD_TYPE_DAILY: + if (start_date < active_since) + return FAIL; + + tm = *localtime(&active_since); + active_since = dc_subtract_time(active_since, + tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec, &tm); + + day = (start_date - active_since) / SEC_PER_DAY; + start_date = dc_subtract_time(start_date, SEC_PER_DAY * (day % period->every), &tm); + break; + case TIMEPERIOD_TYPE_WEEKLY: + if (start_date < active_since) + return FAIL; + + tm = *localtime(&active_since); + wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1; + active_since = dc_subtract_time(active_since, wday * SEC_PER_DAY + + tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec, &tm); + + for (; start_date >= active_since; start_date = dc_subtract_time(start_date, SEC_PER_DAY, &tm)) + { + /* check for every x week(s) */ + week = (start_date - active_since) / SEC_PER_WEEK; + if (0 != week % period->every) + continue; + + /* check for day of the week */ + tm = *localtime(&start_date); + wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1; + if (0 == (period->dayofweek & (1 << wday))) + continue; + + break; + } + break; + case TIMEPERIOD_TYPE_MONTHLY: + for (; start_date >= active_since; start_date = dc_subtract_time(start_date, SEC_PER_DAY, &tm)) + { + /* check for month */ + tm = *localtime(&start_date); + if (0 == (period->month & (1 << tm.tm_mon))) + continue; + + if (0 != period->day) + { + /* check for day of the month */ + if (period->day != tm.tm_mday) + continue; + } + else + { + /* check for day of the week */ + wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1; + if (0 == (period->dayofweek & (1 << wday))) + continue; + + /* check for number of day (first, second, third, fourth or last) */ + day = (tm.tm_mday - 1) / 7 + 1; + if (5 == period->every && 4 == day) + { + if (tm.tm_mday + 7 <= zbx_day_in_month(1900 + tm.tm_year, + tm.tm_mon + 1)) + { + continue; + } + } + else if (period->every != day) + continue; + } + + if (start_date < active_since) + return FAIL; + + break; + } + break; + default: + return FAIL; + } + + *running_since = start_date; + *running_until = start_date + period->period; + if (maintenance->active_until < *running_until) + *running_until = maintenance->active_until; + + return SUCCEED; +} + +/****************************************************************************** + * * + * Purpose: calculates start time for the specified maintenance period and * + * checks if we are inside the maintenance period * + * * + * Parameter: maintenance - [IN] the maintenance * + * period - [IN] the maintenance period * + * now - [IN] current time * + * running_since - [OUT] the actual period starting timestamp * + * running_until - [OUT] the actual period ending timestamp * + * * + * Return value: SUCCEED - current time is inside valid maintenance period * + * FAIL - current time is outside valid maintenance period * + * * + ******************************************************************************/ +static int dc_check_maintenance_period(const zbx_dc_maintenance_t *maintenance, + const zbx_dc_maintenance_period_t *period, time_t now, time_t *running_since, time_t *running_until) +{ + struct tm tm; + int seconds, rc, ret = FAIL; + time_t period_start, period_end; + + tm = *localtime(&now); + seconds = tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec; + period_start = dc_subtract_time(now, seconds, &tm); + period_start = dc_subtract_time(period_start, -period->start_time, &tm); + + tm = *localtime(&period_start); + + /* skip maintenance if the time does not exist due to DST */ + if (period->start_time != (tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec)) + { + goto out; + } + + if (now < period_start) + period_start = dc_subtract_time(period_start, SEC_PER_DAY, &tm); + + rc = dc_calculate_maintenance_period(maintenance, period, period_start, &period_start, &period_end); + + if (SUCCEED == rc && period_start <= now && now < period_end) + { + *running_since = period_start; + *running_until = period_end; + ret = SUCCEED; + } +out: + return ret; +} + +/****************************************************************************** + * * + * Purpose: sets maintenance update flags for all timers * + * * + ******************************************************************************/ +void zbx_dc_maintenance_set_update_flags(void) +{ + int slots_num = ZBX_MAINTENANCE_UPDATE_FLAGS_NUM(), timers_left; + + WRLOCK_CACHE; + + memset(config->maintenance_update_flags, 0xff, sizeof(zbx_uint64_t) * slots_num); + + if (0 != (timers_left = (CONFIG_TIMER_FORKS % (sizeof(uint64_t) * 8)))) + config->maintenance_update_flags[slots_num - 1] >>= (sizeof(zbx_uint64_t) * 8 - timers_left); + + UNLOCK_CACHE; +} + +/****************************************************************************** + * * + * Purpose: resets maintenance update flags for the specified timer * + * * + * Parameters: timer - [IN] the timer process number * + * * + ******************************************************************************/ +void zbx_dc_maintenance_reset_update_flag(int timer) +{ + int slot, bit; + zbx_uint64_t mask; + + timer--; + slot = timer / (sizeof(uint64_t) * 8); + bit = timer % (sizeof(uint64_t) * 8); + + mask = ~(__UINT64_C(1) << bit); + + WRLOCK_CACHE; + + config->maintenance_update_flags[slot] &= mask; + + UNLOCK_CACHE; +} + +/****************************************************************************** + * * + * Purpose: checks if the maintenance update flag is set for the specified * + * timer * + * * + * Parameters: timer - [IN] the timer process number * + * * + * Return value: SUCCEED - maintenance update flag is set * + * FAIL - otherwise * + ******************************************************************************/ +int zbx_dc_maintenance_check_update_flag(int timer) +{ + int slot, bit, ret; + zbx_uint64_t mask; + + timer--; + slot = timer / (sizeof(uint64_t) * 8); + bit = timer % (sizeof(uint64_t) * 8); + + mask = __UINT64_C(1) << bit; + + RDLOCK_CACHE; + + ret = (0 == (config->maintenance_update_flags[slot] & mask) ? FAIL : SUCCEED); + + UNLOCK_CACHE; + + return ret; +} + +/****************************************************************************** + * * + * Purpose: checks if at least one maintenance update flag is set * + * * + * Return value: SUCCEED - a maintenance update flag is set * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_dc_maintenance_check_update_flags(void) +{ + int slots_num = ZBX_MAINTENANCE_UPDATE_FLAGS_NUM(), ret = SUCCEED; + + RDLOCK_CACHE; + + if (0 != config->maintenance_update_flags[0]) + goto out; + + if (1 != slots_num) + { + if (0 != memcmp(config->maintenance_update_flags, config->maintenance_update_flags + 1, slots_num - 1)) + goto out; + } + + ret = FAIL; +out: + UNLOCK_CACHE; + + return ret; +} + +/****************************************************************************** + * * + * Purpose: update maintenance state depending on maintenance periods * + * * + * Return value: SUCCEED - maintenance status was changed, host/event update * + * must be performed * + * FAIL - otherwise * + * * + * Comments: This function calculates if any maintenance period is running * + * and based on that sets current maintenance state - running/idle * + * and period start/end time. * + * * + ******************************************************************************/ +int zbx_dc_update_maintenances(void) +{ + zbx_dc_maintenance_t *maintenance; + zbx_dc_maintenance_period_t *period; + zbx_hashset_iter_t iter; + int i, running_num = 0, started_num = 0, stopped_num = 0, ret = FAIL; + unsigned char state; + time_t now, period_start, period_end, running_since, running_until; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + now = time(NULL); + + WRLOCK_CACHE; + + if (ZBX_MAINTENANCE_UPDATE_TRUE == config->maintenance_update) + { + ret = SUCCEED; + config->maintenance_update = ZBX_MAINTENANCE_UPDATE_FALSE; + } + + zbx_hashset_iter_reset(&config->maintenances, &iter); + while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter))) + { + state = ZBX_MAINTENANCE_IDLE; + running_since = 0; + running_until = 0; + + if (now >= maintenance->active_since && now < maintenance->active_until) + { + /* find the longest running maintenance period */ + for (i = 0; i < maintenance->periods.values_num; i++) + { + period = (zbx_dc_maintenance_period_t *)maintenance->periods.values[i]; + + if (SUCCEED == dc_check_maintenance_period(maintenance, period, now, &period_start, + &period_end)) + { + state = ZBX_MAINTENANCE_RUNNING; + if (period_end > running_until) + { + running_since = period_start; + running_until = period_end; + } + } + } + } + + if (state == ZBX_MAINTENANCE_RUNNING) + { + if (ZBX_MAINTENANCE_IDLE == maintenance->state) + { + maintenance->running_since = running_since; + maintenance->state = ZBX_MAINTENANCE_RUNNING; + started_num++; + + /* Precache nested host groups for started maintenances. */ + /* Nested host groups for running maintenances are already */ + /* precached during configuration cache synchronization. */ + for (i = 0; i < maintenance->groupids.values_num; i++) + { + zbx_dc_hostgroup_t *group; + + if (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_search( + &config->hostgroups, &maintenance->groupids.values[i]))) + { + dc_hostgroup_cache_nested_groupids(group); + } + } + ret = SUCCEED; + } + + if (maintenance->running_until != running_until) + { + maintenance->running_until = running_until; + ret = SUCCEED; + } + running_num++; + } + else + { + if (ZBX_MAINTENANCE_RUNNING == maintenance->state) + { + maintenance->running_since = 0; + maintenance->running_until = 0; + maintenance->state = ZBX_MAINTENANCE_IDLE; + stopped_num++; + ret = SUCCEED; + } + } + } + + UNLOCK_CACHE; + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() started:%d stopped:%d running:%d", __func__, + started_num, stopped_num, running_num); + + return ret; +} + +/****************************************************************************** + * * + * Purpose: assign maintenance to a host, host can only be in one maintenance * + * * + * Parameters: host_maintenances - [OUT] host with maintenance * + * maintenance - [IN] maintenance that host is in * + * hostid - [IN] ID of the host * + * * + ******************************************************************************/ +static void dc_assign_maintenance_to_host(zbx_hashset_t *host_maintenances, zbx_dc_maintenance_t *maintenance, + zbx_uint64_t hostid) +{ + zbx_host_maintenance_t *host_maintenance, host_maintenance_local; + + if (NULL == (host_maintenance = (zbx_host_maintenance_t *)zbx_hashset_search(host_maintenances, &hostid))) + { + host_maintenance_local.hostid = hostid; + host_maintenance_local.maintenance = maintenance; + + zbx_hashset_insert(host_maintenances, &host_maintenance_local, sizeof(host_maintenance_local)); + } + else if (MAINTENANCE_TYPE_NORMAL == host_maintenance->maintenance->type && + MAINTENANCE_TYPE_NODATA == maintenance->type) + { + host_maintenance->maintenance = maintenance; + } +} + +/****************************************************************************** + * * + * Purpose: assign maintenance to a host that event belongs to, events can be * + * in multiple maintenances at a time * + * * + * Parameters: host_event_maintenances - [OUT] host with maintenances * + * maintenance - [IN] maintenance that host is in * + * hostid - [IN] ID of the host * + * * + ******************************************************************************/ +static void dc_assign_event_maintenance_to_host(zbx_hashset_t *host_event_maintenances, + zbx_dc_maintenance_t *maintenance, zbx_uint64_t hostid) +{ + zbx_host_event_maintenance_t *host_event_maintenance, host_event_maintenance_local; + + if (NULL == (host_event_maintenance = (zbx_host_event_maintenance_t *)zbx_hashset_search( + host_event_maintenances, &hostid))) + { + host_event_maintenance_local.hostid = hostid; + zbx_vector_ptr_create(&host_event_maintenance_local.maintenances); + zbx_vector_ptr_append(&host_event_maintenance_local.maintenances, maintenance); + + zbx_hashset_insert(host_event_maintenances, &host_event_maintenance_local, + sizeof(host_event_maintenance_local)); + return; + } + + zbx_vector_ptr_append(&host_event_maintenance->maintenances, maintenance); +} + +typedef void (*assign_maintenance_to_host_f)(zbx_hashset_t *host_maintenances, + zbx_dc_maintenance_t *maintenance, zbx_uint64_t hostid); + +/****************************************************************************** + * * + * Purpose: get hosts and their maintenances * + * * + * Parameters: maintenanceids - [IN] the maintenance ids * + * host_maintenances - [OUT] the maintenances running on hosts * + * cb - [IN] callback function * + * * + ******************************************************************************/ +static void dc_get_host_maintenances_by_ids(const zbx_vector_uint64_t *maintenanceids, + zbx_hashset_t *host_maintenances, assign_maintenance_to_host_f cb) +{ + zbx_dc_maintenance_t *maintenance; + int i, j; + zbx_vector_uint64_t groupids; + + zbx_vector_uint64_create(&groupids); + + for (i = 0; i < maintenanceids->values_num; i++) + { + if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, + &maintenanceids->values[i]))) + { + continue; + } + + for (j = 0; j < maintenance->hostids.values_num; j++) + cb(host_maintenances, maintenance, maintenance->hostids.values[j]); + + if (0 != maintenance->groupids.values_num) /* hosts groups */ + { + zbx_dc_hostgroup_t *group; + + for (j = 0; j < maintenance->groupids.values_num; j++) + dc_get_nested_hostgroupids(maintenance->groupids.values[j], &groupids); + + zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + for (j = 0; j < groupids.values_num; j++) + { + zbx_hashset_iter_t iter; + zbx_uint64_t *phostid; + + if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, + &groupids.values[j]))) + { + continue; + } + + zbx_hashset_iter_reset(&group->hostids, &iter); + + while (NULL != (phostid = (zbx_uint64_t *)zbx_hashset_iter_next(&iter))) + cb(host_maintenances, maintenance, *phostid); + } + + zbx_vector_uint64_clear(&groupids); + } + } + + zbx_vector_uint64_destroy(&groupids); +} + +/****************************************************************************** + * * + * Purpose: gets maintenance updates for all hosts * + * * + * Parameters: host_maintenances - [IN] the maintenances running on hosts * + * updates - [OUT] updates to be applied * + * * + ******************************************************************************/ +static void dc_get_host_maintenance_updates(zbx_hashset_t *host_maintenances, zbx_vector_ptr_t *updates) +{ + zbx_hashset_iter_t iter; + ZBX_DC_HOST *host; + int maintenance_from; + unsigned char maintenance_status, maintenance_type; + zbx_uint64_t maintenanceid; + zbx_host_maintenance_diff_t *diff; + unsigned int flags; + const zbx_host_maintenance_t *host_maintenance; + + zbx_hashset_iter_reset(&config->hosts, &iter); + while (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter))) + { + if (HOST_STATUS_PROXY_ACTIVE == host->status || HOST_STATUS_PROXY_PASSIVE == host->status) + continue; + + if (NULL != (host_maintenance = zbx_hashset_search(host_maintenances, &host->hostid))) + { + maintenance_status = HOST_MAINTENANCE_STATUS_ON; + maintenance_type = host_maintenance->maintenance->type; + maintenanceid = host_maintenance->maintenance->maintenanceid; + maintenance_from = host_maintenance->maintenance->running_since; + } + else + { + maintenance_status = HOST_MAINTENANCE_STATUS_OFF; + maintenance_type = MAINTENANCE_TYPE_NORMAL; + maintenanceid = 0; + maintenance_from = 0; + } + + flags = 0; + + if (maintenanceid != host->maintenanceid) + flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID; + + if (maintenance_status != host->maintenance_status) + flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS; + + if (maintenance_from != host->maintenance_from) + flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM; + + if (maintenance_type != host->maintenance_type) + flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE; + + if (0 != flags) + { + diff = (zbx_host_maintenance_diff_t *)zbx_malloc(0, sizeof(zbx_host_maintenance_diff_t)); + diff->flags = flags; + diff->hostid = host->hostid; + diff->maintenanceid = maintenanceid; + diff->maintenance_status = maintenance_status; + diff->maintenance_from = maintenance_from; + diff->maintenance_type = maintenance_type; + zbx_vector_ptr_append(updates, diff); + } + } +} + +/****************************************************************************** + * * + * Purpose: flush host maintenance updates to configuration cache * + * * + * Parameters: updates - [IN] the updates to flush * + * * + ******************************************************************************/ +void zbx_dc_flush_host_maintenance_updates(const zbx_vector_ptr_t *updates) +{ + int i; + const zbx_host_maintenance_diff_t *diff; + ZBX_DC_HOST *host; + int now; + + now = time(NULL); + + WRLOCK_CACHE; + + for (i = 0; i < updates->values_num; i++) + { + int maintenance_without_data = 0; + + diff = (zbx_host_maintenance_diff_t *)updates->values[i]; + + if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &diff->hostid))) + continue; + + if (HOST_MAINTENANCE_STATUS_ON == host->maintenance_status && + MAINTENANCE_TYPE_NODATA == host->maintenance_type) + { + maintenance_without_data = 1; + } + + if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID)) + host->maintenanceid = diff->maintenanceid; + + if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE)) + host->maintenance_type = diff->maintenance_type; + + if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS)) + host->maintenance_status = diff->maintenance_status; + + if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM)) + host->maintenance_from = diff->maintenance_from; + + if (1 == maintenance_without_data && (HOST_MAINTENANCE_STATUS_ON != host->maintenance_status || + MAINTENANCE_TYPE_NODATA != host->maintenance_type)) + { + /* Store time at which no-data maintenance ended for the host (either */ + /* because no-data maintenance ended or because maintenance type was */ + /* changed to normal), this is needed for nodata() trigger function. */ + host->data_expected_from = now; + } + } + + UNLOCK_CACHE; +} + +/****************************************************************************** + * * + * Purpose: calculates required host maintenance updates based on specified * + * maintenances * + * * + * Parameters: maintenanceids - [IN] identifiers of the maintenances to * + * process * + * updates - [OUT] pending updates * + * * + * Comments: This function must be called after zbx_dc_update_maintenances() * + * function has updated maintenance state in configuration cache. * + * To be able to work with lazy nested group caching and read locks * + * all nested groups used in maintenances must be already precached * + * before calling this function. * + * * + ******************************************************************************/ +void zbx_dc_get_host_maintenance_updates(const zbx_vector_uint64_t *maintenanceids, zbx_vector_ptr_t *updates) +{ + zbx_hashset_t host_maintenances; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_hashset_create(&host_maintenances, maintenanceids->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC, + ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + RDLOCK_CACHE; + + dc_get_host_maintenances_by_ids(maintenanceids, &host_maintenances, dc_assign_maintenance_to_host); + + /* host maintenance update must be performed even without running maintenances */ + /* to reset host maintenances status for stopped maintenances */ + dc_get_host_maintenance_updates(&host_maintenances, updates); + + UNLOCK_CACHE; + + zbx_hashset_destroy(&host_maintenances); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() updates:%d", __func__, updates->values_num); +} + +/****************************************************************************** + * * + * Purpose: perform maintenance tag comparison using maintenance tag operator * + * * + ******************************************************************************/ +static int dc_maintenance_tag_value_match(const zbx_dc_maintenance_tag_t *mt, const zbx_tag_t *tag) +{ + switch (mt->op) + { + case ZBX_MAINTENANCE_TAG_OPERATOR_LIKE: + return (NULL != strstr(tag->value, mt->value) ? SUCCEED : FAIL); + case ZBX_MAINTENANCE_TAG_OPERATOR_EQUAL: + return (0 == strcmp(tag->value, mt->value) ? SUCCEED : FAIL); + default: + THIS_SHOULD_NEVER_HAPPEN; + return FAIL; + } +} + +/****************************************************************************** + * * + * Purpose: matches tags with [*mt_pos] maintenance tag name * + * * + * Parameters: mtags - [IN] the maintenance tags, sorted by tag names * + * etags - [IN] the event tags, sorted by tag names * + * mt_pos - [IN/OUT] the next maintenance tag index * + * et_pos - [IN/OUT] the next event tag index * + * * + * Return value: SUCCEED - found matching tag * + * FAIL - no matching tags found * + * * + ******************************************************************************/ +static int dc_maintenance_match_tag_range(const zbx_vector_ptr_t *mtags, const zbx_vector_ptr_t *etags, + int *mt_pos, int *et_pos) +{ + const zbx_dc_maintenance_tag_t *mtag; + const zbx_tag_t *etag; + const char *name; + int i, j, ret, mt_start, mt_end, et_start, et_end; + + /* get the maintenance tag name */ + mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[*mt_pos]; + name = mtag->tag; + + /* find maintenance and event tag ranges matching the first maintenance tag name */ + /* (maintenance tag range [mt_start,mt_end], event tag range [et_start,et_end]) */ + + mt_start = *mt_pos; + et_start = *et_pos; + + /* find last maintenance tag with the required name */ + + for (i = mt_start + 1; i < mtags->values_num; i++) + { + mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[i]; + if (0 != strcmp(mtag->tag, name)) + break; + } + mt_end = i - 1; + *mt_pos = i; + + /* find first event tag with the required name */ + + for (i = et_start; i < etags->values_num; i++) + { + etag = (const zbx_tag_t *)etags->values[i]; + if (0 < (ret = strcmp(etag->tag, name))) + { + *et_pos = i; + return FAIL; + } + + if (0 == ret) + break; + } + + if (i == etags->values_num) + { + *et_pos = i; + return FAIL; + } + + et_start = i++; + + /* find last event tag with the required name */ + + for (; i < etags->values_num; i++) + { + etag = (const zbx_tag_t *)etags->values[i]; + if (0 != strcmp(etag->tag, name)) + break; + } + + et_end = i - 1; + *et_pos = i; + + /* cross-compare maintenance and event tags within the found ranges */ + + for (i = mt_start; i <= mt_end; i++) + { + mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[i]; + + for (j = et_start; j <= et_end; j++) + { + etag = (const zbx_tag_t *)etags->values[j]; + if (SUCCEED == dc_maintenance_tag_value_match(mtag, etag)) + return SUCCEED; + } + } + + return FAIL; +} + +/****************************************************************************** + * * + * Purpose: matches maintenance and event tags using OR eval type * + * * + * Parameters: mtags - [IN] the maintenance tags, sorted by tag names * + * etags - [IN] the event tags, sorted by tag names * + * * + * Return value: SUCCEED - event tags matches maintenance * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int dc_maintenance_match_tags_or(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags) +{ + int mt_pos = 0, et_pos = 0; + + while (mt_pos < maintenance->tags.values_num && et_pos < tags->values_num) + { + if (SUCCEED == dc_maintenance_match_tag_range(&maintenance->tags, tags, &mt_pos, &et_pos)) + return SUCCEED; + } + + return FAIL; +} + +/****************************************************************************** + * * + * Purpose: matches maintenance and event tags using AND/OR eval type * + * * + * Parameters: mtags - [IN] the maintenance tags, sorted by tag names * + * etags - [IN] the event tags, sorted by tag names * + * * + * Return value: SUCCEED - event tags matches maintenance * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int dc_maintenance_match_tags_andor(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags) +{ + int mt_pos = 0, et_pos = 0; + + while (mt_pos < maintenance->tags.values_num && et_pos < tags->values_num) + { + if (FAIL == dc_maintenance_match_tag_range(&maintenance->tags, tags, &mt_pos, &et_pos)) + return FAIL; + } + + if (mt_pos != maintenance->tags.values_num) + return FAIL; + + return SUCCEED; +} + +/****************************************************************************** + * * + * Purpose: check if the tags must be processed by the specified maintenance * + * * + * Parameters: maintenance - [IN] the maintenance * + * tags - [IN] the tags to check * + * * + * Return value: SUCCEED - the tags must be processed by the maintenance * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int dc_maintenance_match_tags(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags) +{ + switch (maintenance->tags_evaltype) + { + case ZBX_MAINTENANCE_TAG_EVAL_TYPE_AND_OR: + /* break; is not missing here */ + case ZBX_MAINTENANCE_TAG_EVAL_TYPE_OR: + if (0 == maintenance->tags.values_num) + return SUCCEED; + + if (0 == tags->values_num) + return FAIL; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + return FAIL; + } + + if (ZBX_MAINTENANCE_TAG_EVAL_TYPE_AND_OR == maintenance->tags_evaltype) + return dc_maintenance_match_tags_andor(maintenance, tags); + else + return dc_maintenance_match_tags_or(maintenance, tags); +} + +/****************************************************************************** + * * + * Purpose: compare maintenance tags by tag name for sorting * + * * + ******************************************************************************/ +static int dc_compare_tags(const void *d1, const void *d2) +{ + const zbx_tag_t *tag1 = *(const zbx_tag_t **)d1; + const zbx_tag_t *tag2 = *(const zbx_tag_t **)d2; + + return strcmp(tag1->tag, tag2->tag); +} + +static void host_event_maintenance_clean(zbx_host_event_maintenance_t *host_event_maintenance) +{ + zbx_vector_ptr_destroy(&host_event_maintenance->maintenances); +} + +/****************************************************************************** + * * + * Purpose: get maintenance data for events * + * * + * Parameters: event_queries - [IN/OUT] in - event data * + * out - running maintenances for each * + * event * + * maintenanceids - [IN] the maintenances to process * + * * + * Return value: SUCCEED - at least one matching maintenance was found * + * * + ******************************************************************************/ +int zbx_dc_get_event_maintenances(zbx_vector_ptr_t *event_queries, const zbx_vector_uint64_t *maintenanceids) +{ + zbx_hashset_t host_event_maintenances; + int i, j, k, ret = FAIL; + zbx_event_suppress_query_t *query; + ZBX_DC_ITEM *item; + ZBX_DC_FUNCTION *function; + zbx_vector_uint64_t hostids; + zbx_hashset_iter_t iter; + zbx_host_event_maintenance_t *host_event_maintenance; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&hostids); + + zbx_hashset_create_ext(&host_event_maintenances, maintenanceids->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC, + ZBX_DEFAULT_UINT64_COMPARE_FUNC, (zbx_clean_func_t)host_event_maintenance_clean, + ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC); + /* event tags must be sorted by name to perform maintenance tag matching */ + + for (i = 0; i < event_queries->values_num; i++) + { + query = (zbx_event_suppress_query_t *)event_queries->values[i]; + if (0 != query->tags.values_num) + zbx_vector_ptr_sort(&query->tags, dc_compare_tags); + } + + RDLOCK_CACHE; + + dc_get_host_maintenances_by_ids(maintenanceids, &host_event_maintenances, dc_assign_event_maintenance_to_host); + + if (0 == host_event_maintenances.num_data) + goto unlock; + + zbx_hashset_iter_reset(&host_event_maintenances, &iter); + + while (NULL != (host_event_maintenance = (zbx_host_event_maintenance_t *)zbx_hashset_iter_next(&iter))) + { + zbx_vector_ptr_sort(&host_event_maintenance->maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + zbx_vector_ptr_uniq(&host_event_maintenance->maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); + } + + for (i = 0; i < event_queries->values_num; i++) + { + query = (zbx_event_suppress_query_t *)event_queries->values[i]; + + /* find hostids of items used in event trigger expressions */ + + /* Some processes do not have trigger data at hand and create event queries */ + /* without filling query functionids. Do it here if necessary. */ + if (0 == query->functionids.values_num) + { + ZBX_DC_TRIGGER *trigger; + + if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, + &query->triggerid))) + { + continue; + } + + zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin, + &query->functionids); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode) + { + zbx_get_serialized_expression_functionids(trigger->recovery_expression, + trigger->recovery_expression_bin, &query->functionids); + } + } + + for (j = 0; j < query->functionids.values_num; j++) + { + ZBX_DC_HOST *dc_host; + + if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, + &query->functionids.values[j]))) + { + continue; + } + + if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid))) + continue; + + if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->hostid))) + continue; + + if (HOST_MAINTENANCE_STATUS_OFF == dc_host->maintenance_status) + goto skip; + + zbx_vector_uint64_append(&hostids, item->hostid); + } + + zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + /* find matching maintenances */ + for (j = 0; j < hostids.values_num; j++) + { + const zbx_dc_maintenance_t *maintenance; + + if (NULL == (host_event_maintenance = zbx_hashset_search(&host_event_maintenances, + &hostids.values[j]))) + { + continue; + } + + for (k = 0; k < host_event_maintenance->maintenances.values_num; k++) + { + zbx_uint64_pair_t pair; + + maintenance = (zbx_dc_maintenance_t *)host_event_maintenance->maintenances.values[k]; + + if (ZBX_MAINTENANCE_RUNNING != maintenance->state) + continue; + + pair.first = maintenance->maintenanceid; + + if (FAIL != zbx_vector_uint64_pair_search(&query->maintenances, pair, + ZBX_DEFAULT_UINT64_COMPARE_FUNC)) + { + continue; + } + + if (SUCCEED != dc_maintenance_match_tags(maintenance, &query->tags)) + continue; + + pair.second = maintenance->running_until; + zbx_vector_uint64_pair_append(&query->maintenances, pair); + ret = SUCCEED; + } + } +skip: + zbx_vector_uint64_clear(&hostids); + } +unlock: + UNLOCK_CACHE; + + zbx_vector_uint64_destroy(&hostids); + zbx_hashset_destroy(&host_event_maintenances); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); + + return ret; +} + +/****************************************************************************** + * * + * Purpose: free event suppress query structure * + * * + ******************************************************************************/ +void zbx_event_suppress_query_free(zbx_event_suppress_query_t *query) +{ + zbx_vector_uint64_destroy(&query->functionids); + zbx_vector_uint64_pair_destroy(&query->maintenances); + zbx_vector_ptr_clear_ext(&query->tags, (zbx_clean_func_t)zbx_free_tag); + zbx_vector_ptr_destroy(&query->tags); + zbx_free(query); +} + +/****************************************************************************** + * * + * Purpose: get identifiers of the running maintenances * + * * + * Return value: SUCCEED - at least one running maintenance was found * + * FAIL - no running maintenances were found * + * * + ******************************************************************************/ +int zbx_dc_get_running_maintenanceids(zbx_vector_uint64_t *maintenanceids) +{ + zbx_dc_maintenance_t *maintenance; + zbx_hashset_iter_t iter; + + RDLOCK_CACHE; + + zbx_hashset_iter_reset(&config->maintenances, &iter); + while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter))) + { + if (ZBX_MAINTENANCE_RUNNING == maintenance->state) + zbx_vector_uint64_append(maintenanceids, maintenance->maintenanceid); + } + + UNLOCK_CACHE; + + return (0 != maintenanceids->values_num ? SUCCEED : FAIL); +} + +#ifdef HAVE_TESTS +# include "../../../tests/libs/zbxdbcache/dbconfig_maintenance_test.c" +#endif |