Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/zbxcacheconfig/dbconfig_maintenance.c')
-rw-r--r--src/libs/zbxcacheconfig/dbconfig_maintenance.c1608
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