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