1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19 #include "common.h"
20 #include "log.h"
21 #include "zbxalgo.h"
22 #include "dbcache.h"
23 #include "mutexs.h"
24
25 #define ZBX_DBCONFIG_IMPL
26 #include "dbconfig.h"
27
28 #include "dbsync.h"
29 #include "zbxserver.h"
30
31 extern int CONFIG_TIMER_FORKS;
32
33 typedef struct
34 {
35 zbx_uint64_t hostid;
36 const zbx_dc_maintenance_t *maintenance;
37 }
38 zbx_host_maintenance_t;
39
40 typedef struct
41 {
42 zbx_uint64_t hostid;
43 zbx_vector_ptr_t maintenances;
44 }
45 zbx_host_event_maintenance_t;
46
47 /******************************************************************************
48 * *
49 * Function: DCsync_maintenances *
50 * *
51 * Purpose: Updates maintenances in configuration cache *
52 * *
53 * Parameters: sync - [IN] the db synchronization data *
54 * *
55 * Comments: The result contains the following fields: *
56 * 0 - maintenanceid *
57 * 1 - maintenance_type *
58 * 2 - active_since *
59 * 3 - active_till *
60 * 4 - tags_evaltype *
61 * *
62 ******************************************************************************/
DCsync_maintenances(zbx_dbsync_t * sync)63 void DCsync_maintenances(zbx_dbsync_t *sync)
64 {
65 char **row;
66 zbx_uint64_t rowid;
67 unsigned char tag;
68 zbx_uint64_t maintenanceid;
69 zbx_dc_maintenance_t *maintenance;
70 int found, ret;
71
72 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
73
74 while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
75 {
76 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
77
78 /* removed rows will be always added at the end */
79 if (ZBX_DBSYNC_ROW_REMOVE == tag)
80 break;
81
82 ZBX_STR2UINT64(maintenanceid, row[0]);
83
84 maintenance = (zbx_dc_maintenance_t *)DCfind_id(&config->maintenances, maintenanceid,
85 sizeof(zbx_dc_maintenance_t), &found);
86
87 if (0 == found)
88 {
89 maintenance->state = ZBX_MAINTENANCE_IDLE;
90 maintenance->running_since = 0;
91 maintenance->running_until = 0;
92
93 zbx_vector_uint64_create_ext(&maintenance->groupids, config->maintenances.mem_malloc_func,
94 config->maintenances.mem_realloc_func, config->maintenances.mem_free_func);
95 zbx_vector_uint64_create_ext(&maintenance->hostids, config->maintenances.mem_malloc_func,
96 config->maintenances.mem_realloc_func, config->maintenances.mem_free_func);
97 zbx_vector_ptr_create_ext(&maintenance->tags, config->maintenances.mem_malloc_func,
98 config->maintenances.mem_realloc_func, config->maintenances.mem_free_func);
99 zbx_vector_ptr_create_ext(&maintenance->periods, config->maintenances.mem_malloc_func,
100 config->maintenances.mem_realloc_func, config->maintenances.mem_free_func);
101 }
102
103 ZBX_STR2UCHAR(maintenance->type, row[1]);
104 ZBX_STR2UCHAR(maintenance->tags_evaltype, row[4]);
105 maintenance->active_since = atoi(row[2]);
106 maintenance->active_until = atoi(row[3]);
107 }
108
109 /* remove deleted maintenances */
110
111 for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
112 {
113 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances, &rowid)))
114 continue;
115
116 zbx_vector_uint64_destroy(&maintenance->groupids);
117 zbx_vector_uint64_destroy(&maintenance->hostids);
118 zbx_vector_ptr_destroy(&maintenance->tags);
119 zbx_vector_ptr_destroy(&maintenance->periods);
120
121 zbx_hashset_remove_direct(&config->maintenances, maintenance);
122 }
123
124 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
125 }
126
127 /******************************************************************************
128 * *
129 * Function: dc_compare_maintenance_tags *
130 * *
131 * Purpose: compare maintenance tags by tag name for sorting *
132 * *
133 ******************************************************************************/
dc_compare_maintenance_tags(const void * d1,const void * d2)134 static int dc_compare_maintenance_tags(const void *d1, const void *d2)
135 {
136 const zbx_dc_maintenance_tag_t *tag1 = *(const zbx_dc_maintenance_tag_t **)d1;
137 const zbx_dc_maintenance_tag_t *tag2 = *(const zbx_dc_maintenance_tag_t **)d2;
138
139 return strcmp(tag1->tag, tag2->tag);
140 }
141
142 /******************************************************************************
143 * *
144 * Function: DCsync_maintenance_tags *
145 * *
146 * Purpose: Updates maintenance tags in configuration cache *
147 * *
148 * Parameters: sync - [IN] the db synchronization data *
149 * *
150 * Comments: The result contains the following fields: *
151 * 0 - maintenancetagid *
152 * 1 - maintenanceid *
153 * 2 - operator *
154 * 3 - tag *
155 * 4 - value *
156 * *
157 ******************************************************************************/
DCsync_maintenance_tags(zbx_dbsync_t * sync)158 void DCsync_maintenance_tags(zbx_dbsync_t *sync)
159 {
160 char **row;
161 zbx_uint64_t rowid;
162 unsigned char tag;
163 zbx_uint64_t maintenancetagid, maintenanceid;
164 zbx_dc_maintenance_tag_t *maintenance_tag;
165 zbx_dc_maintenance_t *maintenance;
166 zbx_vector_ptr_t maintenances;
167 int found, ret, index, i;
168
169 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
170
171 zbx_vector_ptr_create(&maintenances);
172
173 while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
174 {
175 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
176
177 /* removed rows will be always added at the end */
178 if (ZBX_DBSYNC_ROW_REMOVE == tag)
179 break;
180
181 ZBX_STR2UINT64(maintenanceid, row[1]);
182 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
183 &maintenanceid)))
184 {
185 continue;
186 }
187
188 ZBX_STR2UINT64(maintenancetagid, row[0]);
189 maintenance_tag = (zbx_dc_maintenance_tag_t *)DCfind_id(&config->maintenance_tags, maintenancetagid,
190 sizeof(zbx_dc_maintenance_tag_t), &found);
191
192 maintenance_tag->maintenanceid = maintenanceid;
193 ZBX_STR2UCHAR(maintenance_tag->op, row[2]);
194 DCstrpool_replace(found, &maintenance_tag->tag, row[3]);
195 DCstrpool_replace(found, &maintenance_tag->value, row[4]);
196
197 if (0 == found)
198 zbx_vector_ptr_append(&maintenance->tags, maintenance_tag);
199
200 zbx_vector_ptr_append(&maintenances, maintenance);
201 }
202
203 /* remove deleted maintenance tags */
204
205 for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
206 {
207 if (NULL == (maintenance_tag = (zbx_dc_maintenance_tag_t *)zbx_hashset_search(&config->maintenance_tags,
208 &rowid)))
209 {
210 continue;
211 }
212
213 if (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
214 &maintenance_tag->maintenanceid)))
215 {
216 index = zbx_vector_ptr_search(&maintenance->tags, &maintenance_tag->maintenancetagid,
217 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
218
219 if (FAIL != index)
220 zbx_vector_ptr_remove_noorder(&maintenance->tags, index);
221
222 zbx_vector_ptr_append(&maintenances, maintenance);
223 }
224
225 zbx_strpool_release(maintenance_tag->tag);
226 zbx_strpool_release(maintenance_tag->value);
227
228 zbx_hashset_remove_direct(&config->maintenance_tags, maintenance_tag);
229 }
230
231 /* sort maintenance tags */
232
233 zbx_vector_ptr_sort(&maintenances, ZBX_DEFAULT_PTR_COMPARE_FUNC);
234 zbx_vector_ptr_uniq(&maintenances, ZBX_DEFAULT_PTR_COMPARE_FUNC);
235
236 for (i = 0; i < maintenances.values_num; i++)
237 {
238 maintenance = (zbx_dc_maintenance_t *)maintenances.values[i];
239 zbx_vector_ptr_sort(&maintenance->tags, dc_compare_maintenance_tags);
240 }
241
242 zbx_vector_ptr_destroy(&maintenances);
243
244 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
245 }
246
247 /******************************************************************************
248 * *
249 * Function: DCsync_maintenance_periods *
250 * *
251 * Purpose: Updates maintenance period in configuration cache *
252 * *
253 * Parameters: sync - [IN] the db synchronization data *
254 * *
255 * Comments: The result contains the following fields: *
256 * 0 - timeperiodid *
257 * 1 - timeperiod_type *
258 * 2 - every *
259 * 3 - month *
260 * 4 - dayofweek *
261 * 5 - day *
262 * 6 - start_time *
263 * 7 - period *
264 * 8 - start_date *
265 * 9 - maintenanceid *
266 * *
267 ******************************************************************************/
DCsync_maintenance_periods(zbx_dbsync_t * sync)268 void DCsync_maintenance_periods(zbx_dbsync_t *sync)
269 {
270 char **row;
271 zbx_uint64_t rowid;
272 unsigned char tag;
273 zbx_uint64_t periodid, maintenanceid;
274 zbx_dc_maintenance_period_t *period;
275 zbx_dc_maintenance_t *maintenance;
276 int found, ret, index;
277
278 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
279
280 while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
281 {
282 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
283
284 /* removed rows will be always added at the end */
285 if (ZBX_DBSYNC_ROW_REMOVE == tag)
286 break;
287
288 ZBX_STR2UINT64(maintenanceid, row[9]);
289 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
290 &maintenanceid)))
291 {
292 continue;
293 }
294
295 ZBX_STR2UINT64(periodid, row[0]);
296 period = (zbx_dc_maintenance_period_t *)DCfind_id(&config->maintenance_periods, periodid,
297 sizeof(zbx_dc_maintenance_period_t), &found);
298
299 period->maintenanceid = maintenanceid;
300 ZBX_STR2UCHAR(period->type, row[1]);
301 period->every = atoi(row[2]);
302 period->month = atoi(row[3]);
303 period->dayofweek = atoi(row[4]);
304 period->day = atoi(row[5]);
305 period->start_time = atoi(row[6]);
306 period->period = atoi(row[7]);
307 period->start_date = atoi(row[8]);
308
309 if (0 == found)
310 zbx_vector_ptr_append(&maintenance->periods, period);
311 }
312
313 /* remove deleted maintenance tags */
314
315 for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
316 {
317 if (NULL == (period = (zbx_dc_maintenance_period_t *)zbx_hashset_search(&config->maintenance_periods,
318 &rowid)))
319 {
320 continue;
321 }
322
323 if (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
324 &period->maintenanceid)))
325 {
326 index = zbx_vector_ptr_search(&maintenance->periods, &period->timeperiodid,
327 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
328
329 if (FAIL != index)
330 zbx_vector_ptr_remove_noorder(&maintenance->periods, index);
331 }
332
333 zbx_hashset_remove_direct(&config->maintenance_periods, period);
334 }
335
336 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
337 }
338
339 /******************************************************************************
340 * *
341 * Function: DCsync_maintenance_groups *
342 * *
343 * Purpose: Updates maintenance groups in configuration cache *
344 * *
345 * Parameters: sync - [IN] the db synchronization data *
346 * *
347 * Comments: The result contains the following fields: *
348 * 0 - maintenanceid *
349 * 1 - groupid *
350 * *
351 ******************************************************************************/
DCsync_maintenance_groups(zbx_dbsync_t * sync)352 void DCsync_maintenance_groups(zbx_dbsync_t *sync)
353 {
354 char **row;
355 zbx_uint64_t rowid;
356 unsigned char tag;
357 zbx_dc_maintenance_t *maintenance = NULL;
358 int index, ret;
359 zbx_uint64_t last_maintenanceid = 0, maintenanceid, groupid;
360
361 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
362
363 while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
364 {
365 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
366
367 /* removed rows will be always added at the end */
368 if (ZBX_DBSYNC_ROW_REMOVE == tag)
369 break;
370
371 ZBX_STR2UINT64(maintenanceid, row[0]);
372
373 if (last_maintenanceid != maintenanceid || 0 == last_maintenanceid)
374 {
375 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
376 &maintenanceid)))
377 {
378 continue;
379 }
380 last_maintenanceid = maintenanceid;
381 }
382
383 ZBX_STR2UINT64(groupid, row[1]);
384
385 zbx_vector_uint64_append(&maintenance->groupids, groupid);
386 }
387
388 /* remove deleted maintenance groupids from cache */
389 for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
390 {
391 ZBX_STR2UINT64(maintenanceid, row[0]);
392
393 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
394 &maintenanceid)))
395 {
396 continue;
397 }
398 ZBX_STR2UINT64(groupid, row[1]);
399
400 if (FAIL == (index = zbx_vector_uint64_search(&maintenance->groupids, groupid,
401 ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
402 {
403 continue;
404 }
405
406 zbx_vector_uint64_remove_noorder(&maintenance->groupids, index);
407 }
408
409 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
410 }
411
412 /******************************************************************************
413 * *
414 * Function: DCsync_maintenance_hosts *
415 * *
416 * Purpose: Updates maintenance hosts in configuration cache *
417 * *
418 * Parameters: sync - [IN] the db synchronization data *
419 * *
420 * Comments: The result contains the following fields: *
421 * 0 - maintenanceid *
422 * 1 - hostid *
423 * *
424 ******************************************************************************/
DCsync_maintenance_hosts(zbx_dbsync_t * sync)425 void DCsync_maintenance_hosts(zbx_dbsync_t *sync)
426 {
427 char **row;
428 zbx_uint64_t rowid;
429 unsigned char tag;
430 zbx_vector_ptr_t maintenances;
431 zbx_dc_maintenance_t *maintenance = NULL;
432 int index, ret, i;
433 zbx_uint64_t last_maintenanceid, maintenanceid, hostid;
434
435 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
436
437 zbx_vector_ptr_create(&maintenances);
438
439 while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
440 {
441 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
442
443 /* removed rows will be always added at the end */
444 if (ZBX_DBSYNC_ROW_REMOVE == tag)
445 break;
446
447 ZBX_STR2UINT64(maintenanceid, row[0]);
448
449 if (NULL == maintenance || last_maintenanceid != maintenanceid)
450 {
451 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
452 &maintenanceid)))
453 {
454 continue;
455 }
456 last_maintenanceid = maintenanceid;
457 }
458
459 ZBX_STR2UINT64(hostid, row[1]);
460
461 zbx_vector_uint64_append(&maintenance->hostids, hostid);
462 zbx_vector_ptr_append(&maintenances, maintenance);
463 }
464
465 /* remove deleted maintenance hostids from cache */
466 for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
467 {
468 ZBX_STR2UINT64(maintenanceid, row[0]);
469
470 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
471 &maintenanceid)))
472 {
473 continue;
474 }
475 ZBX_STR2UINT64(hostid, row[1]);
476
477 if (FAIL == (index = zbx_vector_uint64_search(&maintenance->hostids, hostid,
478 ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
479 {
480 continue;
481 }
482
483 zbx_vector_uint64_remove_noorder(&maintenance->hostids, index);
484 zbx_vector_ptr_append(&maintenances, maintenance);
485 }
486
487 zbx_vector_ptr_sort(&maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
488 zbx_vector_ptr_uniq(&maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
489
490 for (i = 0; i < maintenances.values_num; i++)
491 {
492 maintenance = (zbx_dc_maintenance_t *)maintenances.values[i];
493 zbx_vector_uint64_sort(&maintenance->hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
494 }
495
496 zbx_vector_ptr_destroy(&maintenances);
497
498 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
499 }
500
501 /******************************************************************************
502 * *
503 * Function: dc_substract_time *
504 * *
505 * Purpose: substract two local times with DST correction *
506 * *
507 * Parameter: minuend - [IN] the minuend time *
508 * subtrahend - [IN] the subtrahend time (may be negative) *
509 * tm - [OUT] the struct tm *
510 * *
511 * Return value: the resulting time difference in seconds *
512 * *
513 ******************************************************************************/
dc_substract_time(time_t minuend,int subtrahend,struct tm * tm)514 static time_t dc_substract_time(time_t minuend, int subtrahend, struct tm *tm)
515 {
516 time_t diff, offset_min, offset_diff;
517
518 offset_min = zbx_get_timezone_offset(minuend, tm);
519 diff = minuend - subtrahend;
520 offset_diff = zbx_get_timezone_offset(diff, tm);
521 diff -= offset_diff - offset_min;
522
523 return diff;
524 }
525
526 /******************************************************************************
527 * *
528 * Function: dc_calculate_maintenance_period *
529 * *
530 * Purpose: calculate start time for the specified maintenance period *
531 * *
532 * Parameter: maintenance - [IN] the maintenance *
533 * period - [IN] the maintenance period *
534 * start_date - [IN] the period starting timestamp based on *
535 * current time *
536 * running_since - [OUT] the actual period starting timestamp *
537 * running_until - [OUT] the actual period ending timestamp *
538 * *
539 * Return value: SUCCEED - a valid period was found *
540 * FAIL - period started before maintenance activation time *
541 * *
542 ******************************************************************************/
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)543 static int dc_calculate_maintenance_period(const zbx_dc_maintenance_t *maintenance,
544 const zbx_dc_maintenance_period_t *period, time_t start_date, time_t *running_since,
545 time_t *running_until)
546 {
547 int day, wday, week;
548 struct tm tm;
549 time_t active_since = maintenance->active_since;
550
551 if (TIMEPERIOD_TYPE_ONETIME == period->type)
552 {
553 *running_since = (period->start_date < active_since ? active_since : period->start_date);
554 *running_until = period->start_date + period->period;
555 if (maintenance->active_until < *running_until)
556 *running_until = maintenance->active_until;
557
558 return SUCCEED;
559 }
560
561 switch (period->type)
562 {
563 case TIMEPERIOD_TYPE_DAILY:
564 if (start_date < active_since)
565 return FAIL;
566
567 tm = *localtime(&active_since);
568 active_since = dc_substract_time(active_since,
569 tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec, &tm);
570
571 day = (start_date - active_since) / SEC_PER_DAY;
572 start_date = dc_substract_time(start_date, SEC_PER_DAY * (day % period->every), &tm);
573 break;
574 case TIMEPERIOD_TYPE_WEEKLY:
575 if (start_date < active_since)
576 return FAIL;
577
578 tm = *localtime(&active_since);
579 wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1;
580 active_since = dc_substract_time(active_since, wday * SEC_PER_DAY +
581 tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec, &tm);
582
583 for (; start_date >= active_since; start_date = dc_substract_time(start_date, SEC_PER_DAY, &tm))
584 {
585 /* check for every x week(s) */
586 week = (start_date - active_since) / SEC_PER_WEEK;
587 if (0 != week % period->every)
588 continue;
589
590 /* check for day of the week */
591 tm = *localtime(&start_date);
592 wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1;
593 if (0 == (period->dayofweek & (1 << wday)))
594 continue;
595
596 break;
597 }
598 break;
599 case TIMEPERIOD_TYPE_MONTHLY:
600 for (; start_date >= active_since; start_date = dc_substract_time(start_date, SEC_PER_DAY, &tm))
601 {
602 /* check for month */
603 tm = *localtime(&start_date);
604 if (0 == (period->month & (1 << tm.tm_mon)))
605 continue;
606
607 if (0 != period->day)
608 {
609 /* check for day of the month */
610 if (period->day != tm.tm_mday)
611 continue;
612 }
613 else
614 {
615 /* check for day of the week */
616 wday = (0 == tm.tm_wday ? 7 : tm.tm_wday) - 1;
617 if (0 == (period->dayofweek & (1 << wday)))
618 continue;
619
620 /* check for number of day (first, second, third, fourth or last) */
621 day = (tm.tm_mday - 1) / 7 + 1;
622 if (5 == period->every && 4 == day)
623 {
624 if (tm.tm_mday + 7 <= zbx_day_in_month(1900 + tm.tm_year,
625 tm.tm_mon + 1))
626 {
627 continue;
628 }
629 }
630 else if (period->every != day)
631 continue;
632 }
633
634 if (start_date < active_since)
635 return FAIL;
636
637 break;
638 }
639 break;
640 default:
641 return FAIL;
642 }
643
644 *running_since = start_date;
645 *running_until = start_date + period->period;
646 if (maintenance->active_until < *running_until)
647 *running_until = maintenance->active_until;
648
649 return SUCCEED;
650 }
651
652 /******************************************************************************
653 * *
654 * Function: dc_check_maintenance_period *
655 * *
656 * Purpose: calculates start time for the specified maintenance period and *
657 * checks if we are inside the maintenance period *
658 * *
659 * Parameter: maintenance - [IN] the maintenance *
660 * period - [IN] the maintenance period *
661 * now - [IN] current time *
662 * running_since - [OUT] the actual period starting timestamp *
663 * running_until - [OUT] the actual period ending timestamp *
664 * *
665 * Return value: SUCCEED - current time is inside valid maintenance period *
666 * FAIL - current time is outside valid maintenance period *
667 * *
668 ******************************************************************************/
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)669 static int dc_check_maintenance_period(const zbx_dc_maintenance_t *maintenance,
670 const zbx_dc_maintenance_period_t *period, time_t now, time_t *running_since, time_t *running_until)
671 {
672 struct tm tm;
673 int seconds, rc, ret = FAIL;
674 time_t period_start, period_end;
675
676 tm = *localtime(&now);
677 seconds = tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec;
678 period_start = dc_substract_time(now, seconds, &tm);
679 period_start = dc_substract_time(period_start, -period->start_time, &tm);
680
681 tm = *localtime(&period_start);
682
683 /* skip maintenance if the time does not exist due to DST */
684 if (period->start_time != (tm.tm_hour * SEC_PER_HOUR + tm.tm_min * SEC_PER_MIN + tm.tm_sec))
685 {
686 goto out;
687 }
688
689 if (now < period_start)
690 period_start = dc_substract_time(period_start, SEC_PER_DAY, &tm);
691
692 rc = dc_calculate_maintenance_period(maintenance, period, period_start, &period_start, &period_end);
693
694 if (SUCCEED == rc && period_start <= now && now < period_end)
695 {
696 *running_since = period_start;
697 *running_until = period_end;
698 ret = SUCCEED;
699 }
700 out:
701 return ret;
702 }
703
704 /******************************************************************************
705 * *
706 * Function: zbx_dc_maintenance_set_update_flags *
707 * *
708 * Purpose: sets maintenance update flags for all timers *
709 * *
710 ******************************************************************************/
zbx_dc_maintenance_set_update_flags(void)711 void zbx_dc_maintenance_set_update_flags(void)
712 {
713 int slots_num = ZBX_MAINTENANCE_UPDATE_FLAGS_NUM(), timers_left;
714
715 WRLOCK_CACHE;
716
717 memset(config->maintenance_update_flags, 0xff, sizeof(zbx_uint64_t) * slots_num);
718
719 if (0 != (timers_left = (CONFIG_TIMER_FORKS % (sizeof(uint64_t) * 8))))
720 config->maintenance_update_flags[slots_num - 1] >>= (sizeof(zbx_uint64_t) * 8 - timers_left);
721
722 UNLOCK_CACHE;
723 }
724
725 /******************************************************************************
726 * *
727 * Function: zbx_dc_maintenance_reset_update_flag *
728 * *
729 * Purpose: resets maintenance update flags for the specified timer *
730 * *
731 * Parameters: timer - [IN] the timer process number *
732 * *
733 ******************************************************************************/
zbx_dc_maintenance_reset_update_flag(int timer)734 void zbx_dc_maintenance_reset_update_flag(int timer)
735 {
736 int slot, bit;
737 zbx_uint64_t mask;
738
739 timer--;
740 slot = timer / (sizeof(uint64_t) * 8);
741 bit = timer % (sizeof(uint64_t) * 8);
742
743 mask = ~(__UINT64_C(1) << bit);
744
745 WRLOCK_CACHE;
746
747 config->maintenance_update_flags[slot] &= mask;
748
749 UNLOCK_CACHE;
750 }
751
752 /******************************************************************************
753 * *
754 * Function: zbx_dc_maintenance_check_update_flag *
755 * *
756 * Purpose: checks if the maintenance update flag is set for the specified *
757 * timer *
758 * *
759 * Parameters: timer - [IN] the timer process number *
760 * *
761 * Return value: SUCCEED - maintenance update flag is set *
762 * FAIL - otherwise *
763 ******************************************************************************/
zbx_dc_maintenance_check_update_flag(int timer)764 int zbx_dc_maintenance_check_update_flag(int timer)
765 {
766 int slot, bit, ret;
767 zbx_uint64_t mask;
768
769 timer--;
770 slot = timer / (sizeof(uint64_t) * 8);
771 bit = timer % (sizeof(uint64_t) * 8);
772
773 mask = __UINT64_C(1) << bit;
774
775 RDLOCK_CACHE;
776
777 ret = (0 == (config->maintenance_update_flags[slot] & mask) ? FAIL : SUCCEED);
778
779 UNLOCK_CACHE;
780
781 return ret;
782 }
783
784 /******************************************************************************
785 * *
786 * Function: zbx_dc_maintenance_check_update_flags *
787 * *
788 * Purpose: checks if at least one maintenance update flag is set *
789 * *
790 * Return value: SUCCEED - a maintenance update flag is set *
791 * FAIL - otherwise *
792 * *
793 ******************************************************************************/
zbx_dc_maintenance_check_update_flags(void)794 int zbx_dc_maintenance_check_update_flags(void)
795 {
796 int slots_num = ZBX_MAINTENANCE_UPDATE_FLAGS_NUM(), ret = SUCCEED;
797
798 RDLOCK_CACHE;
799
800 if (0 != config->maintenance_update_flags[0])
801 goto out;
802
803 if (1 != slots_num)
804 {
805 if (0 != memcmp(config->maintenance_update_flags, config->maintenance_update_flags + 1, slots_num - 1))
806 goto out;
807 }
808
809 ret = FAIL;
810 out:
811 UNLOCK_CACHE;
812
813 return ret;
814 }
815
816 /******************************************************************************
817 * *
818 * Function: zbx_dc_update_maintenances *
819 * *
820 * Purpose: update maintenance state depending on maintenance periods *
821 * *
822 * Return value: SUCCEED - maintenance status was changed, host/event update *
823 * must be performed *
824 * FAIL - otherwise *
825 * *
826 * Comments: This function calculates if any maintenance period is running *
827 * and based on that sets current maintenance state - running/idle *
828 * and period start/end time. *
829 * *
830 ******************************************************************************/
zbx_dc_update_maintenances(void)831 int zbx_dc_update_maintenances(void)
832 {
833 zbx_dc_maintenance_t *maintenance;
834 zbx_dc_maintenance_period_t *period;
835 zbx_hashset_iter_t iter;
836 int i, running_num = 0, started_num = 0, stopped_num = 0, ret = FAIL;
837 unsigned char state;
838 time_t now, period_start, period_end, running_since, running_until;
839
840 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
841
842 now = time(NULL);
843
844 WRLOCK_CACHE;
845
846 if (ZBX_MAINTENANCE_UPDATE_TRUE == config->maintenance_update)
847 {
848 ret = SUCCEED;
849 config->maintenance_update = ZBX_MAINTENANCE_UPDATE_FALSE;
850 }
851
852 zbx_hashset_iter_reset(&config->maintenances, &iter);
853 while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter)))
854 {
855 state = ZBX_MAINTENANCE_IDLE;
856 running_since = 0;
857 running_until = 0;
858
859 if (now >= maintenance->active_since && now < maintenance->active_until)
860 {
861 /* find the longest running maintenance period */
862 for (i = 0; i < maintenance->periods.values_num; i++)
863 {
864 period = (zbx_dc_maintenance_period_t *)maintenance->periods.values[i];
865
866 if (SUCCEED == dc_check_maintenance_period(maintenance, period, now, &period_start,
867 &period_end))
868 {
869 state = ZBX_MAINTENANCE_RUNNING;
870 if (period_end > running_until)
871 {
872 running_since = period_start;
873 running_until = period_end;
874 }
875 }
876 }
877 }
878
879 if (state == ZBX_MAINTENANCE_RUNNING)
880 {
881 if (ZBX_MAINTENANCE_IDLE == maintenance->state)
882 {
883 maintenance->running_since = running_since;
884 maintenance->state = ZBX_MAINTENANCE_RUNNING;
885 started_num++;
886
887 /* Precache nested host groups for started maintenances. */
888 /* Nested host groups for running maintenances are already */
889 /* precached during configuration cache synchronization. */
890 for (i = 0; i < maintenance->groupids.values_num; i++)
891 {
892 zbx_dc_hostgroup_t *group;
893
894 if (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(
895 &config->hostgroups, &maintenance->groupids.values[i])))
896 {
897 dc_hostgroup_cache_nested_groupids(group);
898 }
899 }
900 ret = SUCCEED;
901 }
902
903 if (maintenance->running_until != running_until)
904 {
905 maintenance->running_until = running_until;
906 ret = SUCCEED;
907 }
908 running_num++;
909 }
910 else
911 {
912 if (ZBX_MAINTENANCE_RUNNING == maintenance->state)
913 {
914 maintenance->running_since = 0;
915 maintenance->running_until = 0;
916 maintenance->state = ZBX_MAINTENANCE_IDLE;
917 stopped_num++;
918 ret = SUCCEED;
919 }
920 }
921 }
922
923 UNLOCK_CACHE;
924
925 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() started:%d stopped:%d running:%d", __func__,
926 started_num, stopped_num, running_num);
927
928 return ret;
929 }
930
931 /******************************************************************************
932 * *
933 * Function: dc_assign_maintenance_to_host *
934 * *
935 * Purpose: assign maintenance to a host, host can only be in one maintenance *
936 * *
937 * Parameters: host_maintenances - [OUT] host with maintenance *
938 * maintenance - [IN] maintenance that host is in *
939 * hostid - [IN] ID of the host *
940 * *
941 ******************************************************************************/
dc_assign_maintenance_to_host(zbx_hashset_t * host_maintenances,zbx_dc_maintenance_t * maintenance,zbx_uint64_t hostid)942 static void dc_assign_maintenance_to_host(zbx_hashset_t *host_maintenances, zbx_dc_maintenance_t *maintenance,
943 zbx_uint64_t hostid)
944 {
945 zbx_host_maintenance_t *host_maintenance, host_maintenance_local;
946
947 if (NULL == (host_maintenance = (zbx_host_maintenance_t *)zbx_hashset_search(host_maintenances, &hostid)))
948 {
949 host_maintenance_local.hostid = hostid;
950 host_maintenance_local.maintenance = maintenance;
951
952 zbx_hashset_insert(host_maintenances, &host_maintenance_local, sizeof(host_maintenance_local));
953 }
954 else if (MAINTENANCE_TYPE_NORMAL == host_maintenance->maintenance->type &&
955 MAINTENANCE_TYPE_NODATA == maintenance->type)
956 {
957 host_maintenance->maintenance = maintenance;
958 }
959 }
960
961 /******************************************************************************
962 * *
963 * Function: dc_assign_event_maintenance_to_host *
964 * *
965 * Purpose: assign maintenance to a host that event belongs to, events can be *
966 * in multiple maintenances at a time *
967 * *
968 * Parameters: host_event_maintenances - [OUT] host with maintenances *
969 * maintenance - [IN] maintenance that host is in *
970 * hostid - [IN] ID of the host *
971 * *
972 ******************************************************************************/
dc_assign_event_maintenance_to_host(zbx_hashset_t * host_event_maintenances,zbx_dc_maintenance_t * maintenance,zbx_uint64_t hostid)973 static void dc_assign_event_maintenance_to_host(zbx_hashset_t *host_event_maintenances,
974 zbx_dc_maintenance_t *maintenance, zbx_uint64_t hostid)
975 {
976 zbx_host_event_maintenance_t *host_event_maintenance, host_event_maintenance_local;
977
978 if (NULL == (host_event_maintenance = (zbx_host_event_maintenance_t *)zbx_hashset_search(
979 host_event_maintenances, &hostid)))
980 {
981 host_event_maintenance_local.hostid = hostid;
982 zbx_vector_ptr_create(&host_event_maintenance_local.maintenances);
983 zbx_vector_ptr_append(&host_event_maintenance_local.maintenances, maintenance);
984
985 zbx_hashset_insert(host_event_maintenances, &host_event_maintenance_local,
986 sizeof(host_event_maintenance_local));
987 return;
988 }
989
990 zbx_vector_ptr_append(&host_event_maintenance->maintenances, maintenance);
991 }
992
993 typedef void (*assign_maintenance_to_host_f)(zbx_hashset_t *host_maintenances,
994 zbx_dc_maintenance_t *maintenance, zbx_uint64_t hostid);
995
996 /******************************************************************************
997 * *
998 * Function: dc_get_host_maintenances_by_ids *
999 * *
1000 * Purpose: get hosts and their maintenances *
1001 * *
1002 * Parameters: maintenanceids - [IN] the maintenance ids *
1003 * host_maintenances - [OUT] the maintenances running on hosts *
1004 * cb - [IN] callback function *
1005 * *
1006 ******************************************************************************/
dc_get_host_maintenances_by_ids(const zbx_vector_uint64_t * maintenanceids,zbx_hashset_t * host_maintenances,assign_maintenance_to_host_f cb)1007 static void dc_get_host_maintenances_by_ids(const zbx_vector_uint64_t *maintenanceids,
1008 zbx_hashset_t *host_maintenances, assign_maintenance_to_host_f cb)
1009 {
1010 zbx_dc_maintenance_t *maintenance;
1011 int i, j;
1012 zbx_vector_uint64_t groupids;
1013
1014 zbx_vector_uint64_create(&groupids);
1015
1016 for (i = 0; i < maintenanceids->values_num; i++)
1017 {
1018 if (NULL == (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_search(&config->maintenances,
1019 &maintenanceids->values[i])))
1020 {
1021 continue;
1022 }
1023
1024 for (j = 0; j < maintenance->hostids.values_num; j++)
1025 cb(host_maintenances, maintenance, maintenance->hostids.values[j]);
1026
1027 if (0 != maintenance->groupids.values_num) /* hosts groups */
1028 {
1029 zbx_dc_hostgroup_t *group;
1030
1031 for (j = 0; j < maintenance->groupids.values_num; j++)
1032 dc_get_nested_hostgroupids(maintenance->groupids.values[j], &groupids);
1033
1034 zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1035 zbx_vector_uint64_uniq(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1036
1037 for (j = 0; j < groupids.values_num; j++)
1038 {
1039 zbx_hashset_iter_t iter;
1040 zbx_uint64_t *phostid;
1041
1042 if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups,
1043 &groupids.values[j])))
1044 {
1045 continue;
1046 }
1047
1048 zbx_hashset_iter_reset(&group->hostids, &iter);
1049
1050 while (NULL != (phostid = (zbx_uint64_t *)zbx_hashset_iter_next(&iter)))
1051 cb(host_maintenances, maintenance, *phostid);
1052 }
1053
1054 zbx_vector_uint64_clear(&groupids);
1055 }
1056 }
1057
1058 zbx_vector_uint64_destroy(&groupids);
1059 }
1060
1061 /******************************************************************************
1062 * *
1063 * Function: dc_get_host_maintenance_updates *
1064 * *
1065 * Purpose: gets maintenance updates for all hosts *
1066 * *
1067 * Parameters: host_maintenances - [IN] the maintenances running on hosts *
1068 * updates - [OUT] updates to be applied *
1069 * *
1070 ******************************************************************************/
dc_get_host_maintenance_updates(zbx_hashset_t * host_maintenances,zbx_vector_ptr_t * updates)1071 static void dc_get_host_maintenance_updates(zbx_hashset_t *host_maintenances, zbx_vector_ptr_t *updates)
1072 {
1073 zbx_hashset_iter_t iter;
1074 ZBX_DC_HOST *host;
1075 int maintenance_from;
1076 unsigned char maintenance_status, maintenance_type;
1077 zbx_uint64_t maintenanceid;
1078 zbx_host_maintenance_diff_t *diff;
1079 unsigned int flags;
1080 const zbx_host_maintenance_t *host_maintenance;
1081
1082 zbx_hashset_iter_reset(&config->hosts, &iter);
1083 while (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
1084 {
1085 if (HOST_STATUS_PROXY_ACTIVE == host->status || HOST_STATUS_PROXY_PASSIVE == host->status)
1086 continue;
1087
1088 if (NULL != (host_maintenance = zbx_hashset_search(host_maintenances, &host->hostid)))
1089 {
1090 maintenance_status = HOST_MAINTENANCE_STATUS_ON;
1091 maintenance_type = host_maintenance->maintenance->type;
1092 maintenanceid = host_maintenance->maintenance->maintenanceid;
1093 maintenance_from = host_maintenance->maintenance->running_since;
1094 }
1095 else
1096 {
1097 maintenance_status = HOST_MAINTENANCE_STATUS_OFF;
1098 maintenance_type = MAINTENANCE_TYPE_NORMAL;
1099 maintenanceid = 0;
1100 maintenance_from = 0;
1101 }
1102
1103 flags = 0;
1104
1105 if (maintenanceid != host->maintenanceid)
1106 flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID;
1107
1108 if (maintenance_status != host->maintenance_status)
1109 flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS;
1110
1111 if (maintenance_from != host->maintenance_from)
1112 flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM;
1113
1114 if (maintenance_type != host->maintenance_type)
1115 flags |= ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE;
1116
1117 if (0 != flags)
1118 {
1119 diff = (zbx_host_maintenance_diff_t *)zbx_malloc(0, sizeof(zbx_host_maintenance_diff_t));
1120 diff->flags = flags;
1121 diff->hostid = host->hostid;
1122 diff->maintenanceid = maintenanceid;
1123 diff->maintenance_status = maintenance_status;
1124 diff->maintenance_from = maintenance_from;
1125 diff->maintenance_type = maintenance_type;
1126 zbx_vector_ptr_append(updates, diff);
1127 }
1128 }
1129 }
1130
1131 /******************************************************************************
1132 * *
1133 * Function: zbx_dc_flush_host_maintenance_updates *
1134 * *
1135 * Purpose: flush host maintenance updates to configuration cache *
1136 * *
1137 * Parameters: updates - [IN] the updates to flush *
1138 * *
1139 ******************************************************************************/
zbx_dc_flush_host_maintenance_updates(const zbx_vector_ptr_t * updates)1140 void zbx_dc_flush_host_maintenance_updates(const zbx_vector_ptr_t *updates)
1141 {
1142 int i;
1143 const zbx_host_maintenance_diff_t *diff;
1144 ZBX_DC_HOST *host;
1145 int now;
1146
1147 now = time(NULL);
1148
1149 WRLOCK_CACHE;
1150
1151 for (i = 0; i < updates->values_num; i++)
1152 {
1153 int maintenance_without_data = 0;
1154
1155 diff = (zbx_host_maintenance_diff_t *)updates->values[i];
1156
1157 if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &diff->hostid)))
1158 continue;
1159
1160 if (HOST_MAINTENANCE_STATUS_ON == host->maintenance_status &&
1161 MAINTENANCE_TYPE_NODATA == host->maintenance_type)
1162 {
1163 maintenance_without_data = 1;
1164 }
1165
1166 if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID))
1167 host->maintenanceid = diff->maintenanceid;
1168
1169 if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE))
1170 host->maintenance_type = diff->maintenance_type;
1171
1172 if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS))
1173 host->maintenance_status = diff->maintenance_status;
1174
1175 if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM))
1176 host->maintenance_from = diff->maintenance_from;
1177
1178 if (1 == maintenance_without_data && (HOST_MAINTENANCE_STATUS_ON != host->maintenance_status ||
1179 MAINTENANCE_TYPE_NODATA != host->maintenance_type))
1180 {
1181 /* Store time at which no-data maintenance ended for the host (either */
1182 /* because no-data maintenance ended or because maintenance type was */
1183 /* changed to normal), this is needed for nodata() trigger function. */
1184 host->data_expected_from = now;
1185 }
1186 }
1187
1188 UNLOCK_CACHE;
1189 }
1190
1191 /******************************************************************************
1192 * *
1193 * Function: zbx_dc_get_host_maintenance_updates *
1194 * *
1195 * Purpose: calculates required host maintenance updates based on specified *
1196 * maintenances *
1197 * *
1198 * Parameters: maintenanceids - [IN] identifiers of the maintenances to *
1199 * process *
1200 * updates - [OUT] pending updates *
1201 * *
1202 * Comments: This function must be called after zbx_dc_update_maintenances() *
1203 * function has updated maintenance state in configuration cache. *
1204 * To be able to work with lazy nested group caching and read locks *
1205 * all nested groups used in maintenances must be already precached *
1206 * before calling this function. *
1207 * *
1208 ******************************************************************************/
zbx_dc_get_host_maintenance_updates(const zbx_vector_uint64_t * maintenanceids,zbx_vector_ptr_t * updates)1209 void zbx_dc_get_host_maintenance_updates(const zbx_vector_uint64_t *maintenanceids, zbx_vector_ptr_t *updates)
1210 {
1211 zbx_hashset_t host_maintenances;
1212
1213 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1214
1215 zbx_hashset_create(&host_maintenances, maintenanceids->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC,
1216 ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1217
1218 RDLOCK_CACHE;
1219
1220 dc_get_host_maintenances_by_ids(maintenanceids, &host_maintenances, dc_assign_maintenance_to_host);
1221
1222 /* host maintenance update must be performed even without running maintenances */
1223 /* to reset host maintenances status for stopped maintenances */
1224 dc_get_host_maintenance_updates(&host_maintenances, updates);
1225
1226 UNLOCK_CACHE;
1227
1228 zbx_hashset_destroy(&host_maintenances);
1229
1230 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() updates:%d", __func__, updates->values_num);
1231 }
1232
1233 /******************************************************************************
1234 * *
1235 * Function: dc_maintenance_tag_match *
1236 * *
1237 * Purpose: perform maintenance tag comparison using maintenance tag operator *
1238 * *
1239 ******************************************************************************/
dc_maintenance_tag_value_match(const zbx_dc_maintenance_tag_t * mt,const zbx_tag_t * tag)1240 static int dc_maintenance_tag_value_match(const zbx_dc_maintenance_tag_t *mt, const zbx_tag_t *tag)
1241 {
1242 switch (mt->op)
1243 {
1244 case ZBX_MAINTENANCE_TAG_OPERATOR_LIKE:
1245 return (NULL != strstr(tag->value, mt->value) ? SUCCEED : FAIL);
1246 case ZBX_MAINTENANCE_TAG_OPERATOR_EQUAL:
1247 return (0 == strcmp(tag->value, mt->value) ? SUCCEED : FAIL);
1248 default:
1249 THIS_SHOULD_NEVER_HAPPEN;
1250 return FAIL;
1251 }
1252 }
1253
1254 /******************************************************************************
1255 * *
1256 * Function: dc_maintenance_match_tag_range *
1257 * *
1258 * Purpose: matches tags with [*mt_pos] maintenance tag name *
1259 * *
1260 * Parameters: mtags - [IN] the maintenance tags, sorted by tag names *
1261 * etags - [IN] the event tags, sorted by tag names *
1262 * mt_pos - [IN/OUT] the next maintenance tag index *
1263 * et_pos - [IN/OUT] the next event tag index *
1264 * *
1265 * Return value: SUCCEED - found matching tag *
1266 * FAIL - no matching tags found *
1267 * *
1268 ******************************************************************************/
dc_maintenance_match_tag_range(const zbx_vector_ptr_t * mtags,const zbx_vector_ptr_t * etags,int * mt_pos,int * et_pos)1269 static int dc_maintenance_match_tag_range(const zbx_vector_ptr_t *mtags, const zbx_vector_ptr_t *etags,
1270 int *mt_pos, int *et_pos)
1271 {
1272 const zbx_dc_maintenance_tag_t *mtag;
1273 const zbx_tag_t *etag;
1274 const char *name;
1275 int i, j, ret, mt_start, mt_end, et_start, et_end;
1276
1277 /* get the maintenance tag name */
1278 mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[*mt_pos];
1279 name = mtag->tag;
1280
1281 /* find maintenance and event tag ranges matching the first maintenance tag name */
1282 /* (maintenance tag range [mt_start,mt_end], event tag range [et_start,et_end]) */
1283
1284 mt_start = *mt_pos;
1285 et_start = *et_pos;
1286
1287 /* find last maintenance tag with the required name */
1288
1289 for (i = mt_start + 1; i < mtags->values_num; i++)
1290 {
1291 mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[i];
1292 if (0 != strcmp(mtag->tag, name))
1293 break;
1294 }
1295 mt_end = i - 1;
1296 *mt_pos = i;
1297
1298 /* find first event tag with the required name */
1299
1300 for (i = et_start; i < etags->values_num; i++)
1301 {
1302 etag = (const zbx_tag_t *)etags->values[i];
1303 if (0 < (ret = strcmp(etag->tag, name)))
1304 {
1305 *et_pos = i;
1306 return FAIL;
1307 }
1308
1309 if (0 == ret)
1310 break;
1311 }
1312
1313 if (i == etags->values_num)
1314 {
1315 *et_pos = i;
1316 return FAIL;
1317 }
1318
1319 et_start = i++;
1320
1321 /* find last event tag with the required name */
1322
1323 for (; i < etags->values_num; i++)
1324 {
1325 etag = (const zbx_tag_t *)etags->values[i];
1326 if (0 != strcmp(etag->tag, name))
1327 break;
1328 }
1329
1330 et_end = i - 1;
1331 *et_pos = i;
1332
1333 /* cross-compare maintenance and event tags within the found ranges */
1334
1335 for (i = mt_start; i <= mt_end; i++)
1336 {
1337 mtag = (const zbx_dc_maintenance_tag_t *)mtags->values[i];
1338
1339 for (j = et_start; j <= et_end; j++)
1340 {
1341 etag = (const zbx_tag_t *)etags->values[j];
1342 if (SUCCEED == dc_maintenance_tag_value_match(mtag, etag))
1343 return SUCCEED;
1344 }
1345 }
1346
1347 return FAIL;
1348 }
1349
1350 /******************************************************************************
1351 * *
1352 * Function: dc_maintenance_match_tags_or *
1353 * *
1354 * Purpose: matches maintenance and event tags using OR eval type *
1355 * *
1356 * Parameters: mtags - [IN] the maintenance tags, sorted by tag names *
1357 * etags - [IN] the event tags, sorted by tag names *
1358 * *
1359 * Return value: SUCCEED - event tags matches maintenance *
1360 * FAIL - otherwise *
1361 * *
1362 ******************************************************************************/
dc_maintenance_match_tags_or(const zbx_dc_maintenance_t * maintenance,const zbx_vector_ptr_t * tags)1363 static int dc_maintenance_match_tags_or(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags)
1364 {
1365 int mt_pos = 0, et_pos = 0;
1366
1367 while (mt_pos < maintenance->tags.values_num && et_pos < tags->values_num)
1368 {
1369 if (SUCCEED == dc_maintenance_match_tag_range(&maintenance->tags, tags, &mt_pos, &et_pos))
1370 return SUCCEED;
1371 }
1372
1373 return FAIL;
1374 }
1375
1376 /******************************************************************************
1377 * *
1378 * Function: dc_maintenance_match_tags_andor *
1379 * *
1380 * Purpose: matches maintenance and event tags using AND/OR eval type *
1381 * *
1382 * Parameters: mtags - [IN] the maintenance tags, sorted by tag names *
1383 * etags - [IN] the event tags, sorted by tag names *
1384 * *
1385 * Return value: SUCCEED - event tags matches maintenance *
1386 * FAIL - otherwise *
1387 * *
1388 ******************************************************************************/
dc_maintenance_match_tags_andor(const zbx_dc_maintenance_t * maintenance,const zbx_vector_ptr_t * tags)1389 static int dc_maintenance_match_tags_andor(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags)
1390 {
1391 int mt_pos = 0, et_pos = 0;
1392
1393 while (mt_pos < maintenance->tags.values_num && et_pos < tags->values_num)
1394 {
1395 if (FAIL == dc_maintenance_match_tag_range(&maintenance->tags, tags, &mt_pos, &et_pos))
1396 return FAIL;
1397 }
1398
1399 if (mt_pos != maintenance->tags.values_num)
1400 return FAIL;
1401
1402 return SUCCEED;
1403 }
1404
1405 /******************************************************************************
1406 * *
1407 * Function: dc_maintenance_match_tags *
1408 * *
1409 * Purpose: check if the tags must be processed by the specified maintenance *
1410 * *
1411 * Parameters: maintenance - [IN] the maintenance *
1412 * tags - [IN] the tags to check *
1413 * *
1414 * Return value: SUCCEED - the tags must be processed by the maintenance *
1415 * FAIL - otherwise *
1416 * *
1417 ******************************************************************************/
dc_maintenance_match_tags(const zbx_dc_maintenance_t * maintenance,const zbx_vector_ptr_t * tags)1418 static int dc_maintenance_match_tags(const zbx_dc_maintenance_t *maintenance, const zbx_vector_ptr_t *tags)
1419 {
1420 switch (maintenance->tags_evaltype)
1421 {
1422 case MAINTENANCE_TAG_EVAL_TYPE_AND_OR:
1423 /* break; is not missing here */
1424 case MAINTENANCE_TAG_EVAL_TYPE_OR:
1425 if (0 == maintenance->tags.values_num)
1426 return SUCCEED;
1427
1428 if (0 == tags->values_num)
1429 return FAIL;
1430 break;
1431 default:
1432 THIS_SHOULD_NEVER_HAPPEN;
1433 return FAIL;
1434 }
1435
1436 if (MAINTENANCE_TAG_EVAL_TYPE_AND_OR == maintenance->tags_evaltype)
1437 return dc_maintenance_match_tags_andor(maintenance, tags);
1438 else
1439 return dc_maintenance_match_tags_or(maintenance, tags);
1440 }
1441
1442 /******************************************************************************
1443 * *
1444 * Function: dc_compare_tags *
1445 * *
1446 * Purpose: compare maintenance tags by tag name for sorting *
1447 * *
1448 ******************************************************************************/
dc_compare_tags(const void * d1,const void * d2)1449 static int dc_compare_tags(const void *d1, const void *d2)
1450 {
1451 const zbx_tag_t *tag1 = *(const zbx_tag_t **)d1;
1452 const zbx_tag_t *tag2 = *(const zbx_tag_t **)d2;
1453
1454 return strcmp(tag1->tag, tag2->tag);
1455 }
1456
host_event_maintenance_clean(zbx_host_event_maintenance_t * host_event_maintenance)1457 static void host_event_maintenance_clean(zbx_host_event_maintenance_t *host_event_maintenance)
1458 {
1459 zbx_vector_ptr_destroy(&host_event_maintenance->maintenances);
1460 }
1461
1462 /******************************************************************************
1463 * *
1464 * Function: zbx_dc_get_event_maintenances *
1465 * *
1466 * Purpose: get maintenance data for events *
1467 * *
1468 * Parameters: event_queries - [IN/OUT] in - event data *
1469 * out - running maintenances for each *
1470 * event *
1471 * maintenanceids - [IN] the maintenances to process *
1472 * *
1473 * Return value: SUCCEED - at least one matching maintenance was found *
1474 * *
1475 ******************************************************************************/
zbx_dc_get_event_maintenances(zbx_vector_ptr_t * event_queries,const zbx_vector_uint64_t * maintenanceids)1476 int zbx_dc_get_event_maintenances(zbx_vector_ptr_t *event_queries, const zbx_vector_uint64_t *maintenanceids)
1477 {
1478 zbx_hashset_t host_event_maintenances;
1479 int i, j, k, ret = FAIL;
1480 zbx_event_suppress_query_t *query;
1481 ZBX_DC_ITEM *item;
1482 ZBX_DC_FUNCTION *function;
1483 zbx_vector_uint64_t hostids;
1484 zbx_hashset_iter_t iter;
1485 zbx_host_event_maintenance_t *host_event_maintenance;
1486
1487 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1488
1489 zbx_vector_uint64_create(&hostids);
1490
1491 zbx_hashset_create_ext(&host_event_maintenances, maintenanceids->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC,
1492 ZBX_DEFAULT_UINT64_COMPARE_FUNC, (zbx_clean_func_t)host_event_maintenance_clean,
1493 ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
1494 /* event tags must be sorted by name to perform maintenance tag matching */
1495
1496 for (i = 0; i < event_queries->values_num; i++)
1497 {
1498 query = (zbx_event_suppress_query_t *)event_queries->values[i];
1499 if (0 != query->tags.values_num)
1500 zbx_vector_ptr_sort(&query->tags, dc_compare_tags);
1501 }
1502
1503 RDLOCK_CACHE;
1504
1505 dc_get_host_maintenances_by_ids(maintenanceids, &host_event_maintenances, dc_assign_event_maintenance_to_host);
1506
1507 if (0 == host_event_maintenances.num_data)
1508 goto unlock;
1509
1510 zbx_hashset_iter_reset(&host_event_maintenances, &iter);
1511
1512 while (NULL != (host_event_maintenance = (zbx_host_event_maintenance_t *)zbx_hashset_iter_next(&iter)))
1513 {
1514 zbx_vector_ptr_sort(&host_event_maintenance->maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1515 zbx_vector_ptr_uniq(&host_event_maintenance->maintenances, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1516 }
1517
1518 for (i = 0; i < event_queries->values_num; i++)
1519 {
1520 query = (zbx_event_suppress_query_t *)event_queries->values[i];
1521
1522 /* find hostids of items used in event trigger expressions */
1523
1524 /* Some processes do not have trigger data at hand and create event queries */
1525 /* without filling query functionids. Do it here if necessary. */
1526 if (0 == query->functionids.values_num)
1527 {
1528 ZBX_DC_TRIGGER *trigger;
1529
1530 if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers,
1531 &query->triggerid)))
1532 {
1533 continue;
1534 }
1535
1536 zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin,
1537 &query->functionids);
1538
1539 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode)
1540 {
1541 zbx_get_serialized_expression_functionids(trigger->recovery_expression,
1542 trigger->recovery_expression_bin, &query->functionids);
1543 }
1544 }
1545
1546 for (j = 0; j < query->functionids.values_num; j++)
1547 {
1548 ZBX_DC_HOST *dc_host;
1549
1550 if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
1551 &query->functionids.values[j])))
1552 {
1553 continue;
1554 }
1555
1556 if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
1557 continue;
1558
1559 if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->hostid)))
1560 continue;
1561
1562 if (HOST_MAINTENANCE_STATUS_OFF == dc_host->maintenance_status)
1563 goto skip;
1564
1565 zbx_vector_uint64_append(&hostids, item->hostid);
1566 }
1567
1568 zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1569 zbx_vector_uint64_uniq(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1570
1571 /* find matching maintenances */
1572 for (j = 0; j < hostids.values_num; j++)
1573 {
1574 const zbx_dc_maintenance_t *maintenance;
1575
1576 if (NULL == (host_event_maintenance = zbx_hashset_search(&host_event_maintenances,
1577 &hostids.values[j])))
1578 {
1579 continue;
1580 }
1581
1582 for (k = 0; k < host_event_maintenance->maintenances.values_num; k++)
1583 {
1584 zbx_uint64_pair_t pair;
1585
1586 maintenance = (zbx_dc_maintenance_t *)host_event_maintenance->maintenances.values[k];
1587
1588 if (ZBX_MAINTENANCE_RUNNING != maintenance->state)
1589 continue;
1590
1591 pair.first = maintenance->maintenanceid;
1592
1593 if (FAIL != zbx_vector_uint64_pair_search(&query->maintenances, pair,
1594 ZBX_DEFAULT_UINT64_COMPARE_FUNC))
1595 {
1596 continue;
1597 }
1598
1599 if (SUCCEED != dc_maintenance_match_tags(maintenance, &query->tags))
1600 continue;
1601
1602 pair.second = maintenance->running_until;
1603 zbx_vector_uint64_pair_append(&query->maintenances, pair);
1604 ret = SUCCEED;
1605 }
1606 }
1607 skip:
1608 zbx_vector_uint64_clear(&hostids);
1609 }
1610 unlock:
1611 UNLOCK_CACHE;
1612
1613 zbx_vector_uint64_destroy(&hostids);
1614 zbx_hashset_destroy(&host_event_maintenances);
1615
1616 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1617
1618 return ret;
1619 }
1620
1621 /******************************************************************************
1622 * *
1623 * Function: zbx_event_suppress_query_free *
1624 * *
1625 * Purpose: free event suppress query structure *
1626 * *
1627 ******************************************************************************/
zbx_event_suppress_query_free(zbx_event_suppress_query_t * query)1628 void zbx_event_suppress_query_free(zbx_event_suppress_query_t *query)
1629 {
1630 zbx_vector_uint64_destroy(&query->functionids);
1631 zbx_vector_uint64_pair_destroy(&query->maintenances);
1632 zbx_vector_ptr_clear_ext(&query->tags, (zbx_clean_func_t)zbx_free_tag);
1633 zbx_vector_ptr_destroy(&query->tags);
1634 zbx_free(query);
1635 }
1636
1637 /******************************************************************************
1638 * *
1639 * Function: zbx_dc_get_running_maintenanceids *
1640 * *
1641 * Purpose: get identifiers of the running maintenances *
1642 * *
1643 * Return value: SUCCEED - at least one running maintenance was found *
1644 * FAIL - no running maintenances were found *
1645 * *
1646 ******************************************************************************/
zbx_dc_get_running_maintenanceids(zbx_vector_uint64_t * maintenanceids)1647 int zbx_dc_get_running_maintenanceids(zbx_vector_uint64_t *maintenanceids)
1648 {
1649 zbx_dc_maintenance_t *maintenance;
1650 zbx_hashset_iter_t iter;
1651
1652 RDLOCK_CACHE;
1653
1654 zbx_hashset_iter_reset(&config->maintenances, &iter);
1655 while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter)))
1656 {
1657 if (ZBX_MAINTENANCE_RUNNING == maintenance->state)
1658 zbx_vector_uint64_append(maintenanceids, maintenance->maintenanceid);
1659 }
1660
1661 UNLOCK_CACHE;
1662
1663 return (0 != maintenanceids->values_num ? SUCCEED : FAIL);
1664 }
1665
1666 #ifdef HAVE_TESTS
1667 # include "../../../tests/libs/zbxdbcache/dbconfig_maintenance_test.c"
1668 #endif
1669