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
20 #include "common.h"
21
22 #include "db.h"
23 #include "log.h"
24 #include "mutexs.h"
25
26 #define LOCK_ITSERVICES zbx_mutex_lock(&itservices_lock)
27 #define UNLOCK_ITSERVICES zbx_mutex_unlock(&itservices_lock)
28
29 static ZBX_MUTEX itservices_lock = ZBX_MUTEX_NULL;
30
31 /* status update queue items */
32 typedef struct
33 {
34 /* the update source id */
35 zbx_uint64_t sourceid;
36 /* the new status */
37 int status;
38 /* timestamp */
39 int clock;
40 }
41 zbx_status_update_t;
42
43 /* IT service node */
44 typedef struct
45 {
46 /* service id */
47 zbx_uint64_t serviceid;
48 /* trigger id of leaf nodes */
49 zbx_uint64_t triggerid;
50 /* the initial service status */
51 int old_status;
52 /* the calculated service status */
53 int status;
54 /* the service status calculation algorithm, see SERVICE_ALGORITHM_* defines */
55 int algorithm;
56 /* the parent nodes */
57 zbx_vector_ptr_t parents;
58 /* the child nodes */
59 zbx_vector_ptr_t children;
60 }
61 zbx_itservice_t;
62
63 /* index of services by triggerid */
64 typedef struct
65 {
66 zbx_uint64_t triggerid;
67 zbx_vector_ptr_t itservices;
68 }
69 zbx_itservice_index_t;
70
71 /* a set of IT services used during update session */
72 /* */
73 /* All services are stored into hashset accessed by serviceid. The services */
74 /* also are indexed by triggerid. */
75 /* The following types of services are loaded during update session: */
76 /* 1) services directly linked to the triggers with values changed */
77 /* during update session. */
78 /* 2) direct or indirect parent services of (1) */
79 /* 3) services required to calculate status of (2) and not already loaded */
80 /* as (1) or (2). */
81 /* */
82 /* In this schema: */
83 /* (1) can't have children services */
84 /* (2) will have children services */
85 /* (1) and (2) will have parent services unless it's the root service */
86 /* (3) will have neither children or parent services */
87 /* */
88 typedef struct
89 {
90 /* loaded IT services */
91 zbx_hashset_t itservices;
92 /* service index by triggerid */
93 zbx_hashset_t index;
94 }
95 zbx_itservices_t;
96
97 /******************************************************************************
98 * *
99 * Function: its_itservices_init *
100 * *
101 * Purpose: initializes IT services data set to store services during update *
102 * session *
103 * *
104 * Parameters: set - [IN] the data set to initialize *
105 * *
106 ******************************************************************************/
its_itservices_init(zbx_itservices_t * itservices)107 static void its_itservices_init(zbx_itservices_t *itservices)
108 {
109 zbx_hashset_create(&itservices->itservices, 512, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
110 zbx_hashset_create(&itservices->index, 128, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
111 }
112
113 /******************************************************************************
114 * *
115 * Function: its_itservices_clean *
116 * *
117 * Purpose: cleans IT services data set by releasing allocated memory *
118 * *
119 * Parameters: set - [IN] the data set to clean *
120 * *
121 ******************************************************************************/
its_itservices_clean(zbx_itservices_t * itservices)122 static void its_itservices_clean(zbx_itservices_t *itservices)
123 {
124 zbx_hashset_iter_t iter;
125 zbx_itservice_t *itservice;
126 zbx_itservice_index_t *index;
127
128 zbx_hashset_iter_reset(&itservices->index, &iter);
129
130 while (NULL != (index = zbx_hashset_iter_next(&iter)))
131 zbx_vector_ptr_destroy(&index->itservices);
132
133 zbx_hashset_destroy(&itservices->index);
134
135 zbx_hashset_iter_reset(&itservices->itservices, &iter);
136
137 while (NULL != (itservice = zbx_hashset_iter_next(&iter)))
138 {
139 zbx_vector_ptr_destroy(&itservice->children);
140 zbx_vector_ptr_destroy(&itservice->parents);
141 }
142
143 zbx_hashset_destroy(&itservices->itservices);
144 }
145
146 /******************************************************************************
147 * *
148 * Function: its_itservice_create *
149 * *
150 * Purpose: creates a new IT service node *
151 * *
152 * Parameters: itservices - [IN] the IT services data *
153 * serviceid - [IN] the service id *
154 * algorithm - [IN] the service status calculation mode *
155 * triggerid - [IN] the source trigger id for leaf nodes *
156 * status - [IN] the initial service status *
157 * *
158 * Return value: the created IT service node *
159 * *
160 ******************************************************************************/
its_itservice_create(zbx_itservices_t * itservices,zbx_uint64_t serviceid,zbx_uint64_t triggerid,int status,int algorithm)161 static zbx_itservice_t *its_itservice_create(zbx_itservices_t *itservices, zbx_uint64_t serviceid,
162 zbx_uint64_t triggerid, int status, int algorithm)
163 {
164 zbx_itservice_t itservice = {serviceid, triggerid, status, status, algorithm}, *pitservice;
165 zbx_itservice_index_t *pindex;
166
167 zbx_vector_ptr_create(&itservice.children);
168 zbx_vector_ptr_create(&itservice.parents);
169
170 pitservice = zbx_hashset_insert(&itservices->itservices, &itservice, sizeof(itservice));
171
172 if (0 != triggerid)
173 {
174 if (NULL == (pindex = zbx_hashset_search(&itservices->index, &triggerid)))
175 {
176 zbx_itservice_index_t index = {triggerid};
177
178 zbx_vector_ptr_create(&index.itservices);
179
180 pindex = zbx_hashset_insert(&itservices->index, &index, sizeof(index));
181 }
182
183 zbx_vector_ptr_append(&pindex->itservices, pitservice);
184 }
185
186 return pitservice;
187 }
188
189 /******************************************************************************
190 * *
191 * Function: its_updates_append *
192 * *
193 * Purpose: adds an update to the queue *
194 * *
195 * Parameters: updates - [OUT] the update queue *
196 * sourceid - [IN] the update source id *
197 * status - [IN] the update status *
198 * clock - [IN] the update timestamp *
199 * *
200 ******************************************************************************/
its_updates_append(zbx_vector_ptr_t * updates,zbx_uint64_t sourceid,int status,int clock)201 static void its_updates_append(zbx_vector_ptr_t *updates, zbx_uint64_t sourceid, int status, int clock)
202 {
203 zbx_status_update_t *update;
204
205 update = zbx_malloc(NULL, sizeof(zbx_status_update_t));
206
207 update->sourceid = sourceid;
208 update->status = status;
209 update->clock = clock;
210
211 zbx_vector_ptr_append(updates, update);
212 }
213
zbx_status_update_free(zbx_status_update_t * update)214 static void zbx_status_update_free(zbx_status_update_t *update)
215 {
216 zbx_free(update);
217 }
218
219 /******************************************************************************
220 * *
221 * Function: its_itservices_load_children *
222 * *
223 * Purpose: loads all missing children of the specified services *
224 * *
225 * Parameters: itservices - [IN] the IT services data *
226 * *
227 ******************************************************************************/
its_itservices_load_children(zbx_itservices_t * itservices)228 static void its_itservices_load_children(zbx_itservices_t *itservices)
229 {
230 const char *__function_name = "its_itservices_load_children";
231
232 char *sql = NULL;
233 size_t sql_alloc = 0, sql_offset = 0;
234 DB_RESULT result;
235 DB_ROW row;
236 zbx_itservice_t *itservice, *parent;
237 zbx_uint64_t serviceid, parentid;
238 zbx_vector_uint64_t serviceids;
239 zbx_hashset_iter_t iter;
240
241 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
242
243 zbx_vector_uint64_create(&serviceids);
244
245 zbx_hashset_iter_reset(&itservices->itservices, &iter);
246
247 while (NULL != (itservice = zbx_hashset_iter_next(&iter)))
248 {
249 if (0 == itservice->triggerid)
250 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
251 }
252
253 /* check for extreme case when there are only leaf nodes */
254 if (0 == serviceids.values_num)
255 goto out;
256
257 zbx_vector_uint64_sort(&serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
258
259 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
260 "select s.serviceid,s.status,s.algorithm,sl.serviceupid"
261 " from services s,services_links sl"
262 " where s.serviceid=sl.servicedownid"
263 " and");
264 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.serviceupid", serviceids.values,
265 serviceids.values_num);
266
267 result = DBselect("%s", sql);
268
269 while (NULL != (row = DBfetch(result)))
270 {
271 ZBX_STR2UINT64(serviceid, row[0]);
272 ZBX_STR2UINT64(parentid, row[3]);
273
274 if (NULL == (parent = zbx_hashset_search(&itservices->itservices, &parentid)))
275 {
276 THIS_SHOULD_NEVER_HAPPEN;
277 continue;
278 }
279
280 if (NULL == (itservice = zbx_hashset_search(&itservices->itservices, &serviceid)))
281 itservice = its_itservice_create(itservices, serviceid, 0, atoi(row[1]), atoi(row[2]));
282
283 if (FAIL == zbx_vector_ptr_search(&parent->children, itservice, ZBX_DEFAULT_PTR_COMPARE_FUNC))
284 zbx_vector_ptr_append(&parent->children, itservice);
285 }
286 DBfree_result(result);
287
288 zbx_free(sql);
289
290 zbx_vector_uint64_destroy(&serviceids);
291 out:
292 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
293 }
294
295 /******************************************************************************
296 * *
297 * Function: its_itservices_load_parents *
298 * *
299 * Purpose: recursively loads parent nodes of the specified service until the *
300 * root node *
301 * *
302 * Parameters: itservices - [IN] the IT services data *
303 * serviceids - [IN] a vector containing ids of services to *
304 * load parents *
305 * *
306 ******************************************************************************/
its_itservices_load_parents(zbx_itservices_t * itservices,zbx_vector_uint64_t * serviceids)307 static void its_itservices_load_parents(zbx_itservices_t *itservices, zbx_vector_uint64_t *serviceids)
308 {
309 const char *__function_name = "its_itservices_load_parents";
310
311 DB_RESULT result;
312 DB_ROW row;
313 char *sql = NULL;
314 size_t sql_alloc = 0, sql_offset = 0;
315 zbx_itservice_t *parent, *itservice;
316 zbx_uint64_t parentid, serviceid;
317
318 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
319
320 zbx_vector_uint64_sort(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
321 zbx_vector_uint64_uniq(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
322
323 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
324 "select s.serviceid,s.status,s.algorithm,sl.servicedownid"
325 " from services s,services_links sl"
326 " where s.serviceid=sl.serviceupid"
327 " and");
328 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.servicedownid", serviceids->values,
329 serviceids->values_num);
330
331 zbx_vector_uint64_clear(serviceids);
332
333 result = DBselect("%s", sql);
334
335 while (NULL != (row = DBfetch(result)))
336 {
337 ZBX_STR2UINT64(parentid, row[0]);
338 ZBX_STR2UINT64(serviceid, row[3]);
339
340 /* find the service */
341 if (NULL == (itservice = zbx_hashset_search(&itservices->itservices, &serviceid)))
342 {
343 THIS_SHOULD_NEVER_HAPPEN;
344 continue;
345 }
346
347 /* find/load the parent service */
348 if (NULL == (parent = zbx_hashset_search(&itservices->itservices, &parentid)))
349 {
350 parent = its_itservice_create(itservices, parentid, 0, atoi(row[1]), atoi(row[2]));
351 zbx_vector_uint64_append(serviceids, parent->serviceid);
352 }
353
354 /* link the service as a parent's child */
355 if (FAIL == zbx_vector_ptr_search(&itservice->parents, parent, ZBX_DEFAULT_PTR_COMPARE_FUNC))
356 zbx_vector_ptr_append(&itservice->parents, parent);
357 }
358 DBfree_result(result);
359
360 zbx_free(sql);
361
362 if (0 != serviceids->values_num)
363 its_itservices_load_parents(itservices, serviceids);
364
365 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
366 }
367
368 /******************************************************************************
369 * *
370 * Function: its_load_services_by_triggerids *
371 * *
372 * Purpose: loads services that might be affected by the specified triggerid *
373 * or are required to calculate status of loaded services *
374 * *
375 * Parameters: itservices - [IN] the IT services data *
376 * triggerids - [IN] the sorted list of trigger ids *
377 * *
378 ******************************************************************************/
its_load_services_by_triggerids(zbx_itservices_t * itservices,const zbx_vector_uint64_t * triggerids)379 static void its_load_services_by_triggerids(zbx_itservices_t *itservices, const zbx_vector_uint64_t *triggerids)
380 {
381 const char *__function_name = "its_load_services_by_triggerids";
382
383 DB_RESULT result;
384 DB_ROW row;
385 zbx_uint64_t serviceid, triggerid;
386 zbx_itservice_t *itservice;
387 char *sql = NULL;
388 size_t sql_alloc = 0, sql_offset = 0;
389 zbx_vector_uint64_t serviceids;
390
391 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
392
393 zbx_vector_uint64_create(&serviceids);
394
395 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
396 "select serviceid,triggerid,status,algorithm"
397 " from services"
398 " where");
399 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num);
400
401 result = DBselect("%s", sql);
402
403 zbx_free(sql);
404
405 while (NULL != (row = DBfetch(result)))
406 {
407 ZBX_STR2UINT64(serviceid, row[0]);
408 ZBX_STR2UINT64(triggerid, row[1]);
409
410 itservice = its_itservice_create(itservices, serviceid, triggerid, atoi(row[2]), atoi(row[3]));
411
412 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
413 }
414 DBfree_result(result);
415
416 if (0 != serviceids.values_num)
417 {
418 its_itservices_load_parents(itservices, &serviceids);
419 its_itservices_load_children(itservices);
420 }
421
422 zbx_vector_uint64_destroy(&serviceids);
423
424 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
425 }
426
427 /******************************************************************************
428 * *
429 * Function: its_itservice_update_status *
430 * *
431 * Purpose: updates service and its parents statuses *
432 * *
433 * Parameters: service - [IN] the service to update *
434 * clock - [IN] the update timestamp *
435 * alarms - [OUT] the alarms update queue *
436 * *
437 * Comments: This function recalculates service status according to the *
438 * algorithm and status of the children services. If the status *
439 * has been changed, an alarm is generated and parent services *
440 * (up until the root service) are updated too. *
441 * *
442 ******************************************************************************/
its_itservice_update_status(zbx_itservice_t * itservice,int clock,zbx_vector_ptr_t * alarms)443 static void its_itservice_update_status(zbx_itservice_t *itservice, int clock, zbx_vector_ptr_t *alarms)
444 {
445 int status, i;
446
447 switch (itservice->algorithm)
448 {
449 case SERVICE_ALGORITHM_MIN:
450 status = TRIGGER_SEVERITY_COUNT;
451 for (i = 0; i < itservice->children.values_num; i++)
452 {
453 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
454
455 if (child->status < status)
456 status = child->status;
457 }
458 break;
459 case SERVICE_ALGORITHM_MAX:
460 status = 0;
461 for (i = 0; i < itservice->children.values_num; i++)
462 {
463 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
464
465 if (child->status > status)
466 status = child->status;
467 }
468 break;
469 case SERVICE_ALGORITHM_NONE:
470 goto out;
471 default:
472 zabbix_log(LOG_LEVEL_ERR, "unknown calculation algorithm of service status [%d]",
473 itservice->algorithm);
474 goto out;
475 }
476
477 if (itservice->status != status)
478 {
479 itservice->status = status;
480
481 its_updates_append(alarms, itservice->serviceid, status, clock);
482
483 /* update parent services */
484 for (i = 0; i < itservice->parents.values_num; i++)
485 its_itservice_update_status(itservice->parents.values[i], clock, alarms);
486 }
487 out:
488 ;
489 }
490
491 /******************************************************************************
492 * *
493 * Function: its_updates_compare *
494 * *
495 * Purpose: used to sort service updates by source id *
496 * *
497 ******************************************************************************/
its_updates_compare(const zbx_status_update_t ** update1,const zbx_status_update_t ** update2)498 static int its_updates_compare(const zbx_status_update_t **update1, const zbx_status_update_t **update2)
499 {
500 ZBX_RETURN_IF_NOT_EQUAL((*update1)->sourceid, (*update2)->sourceid);
501
502 return 0;
503 }
504
505 /******************************************************************************
506 * *
507 * Function: its_write_status_and_alarms *
508 * *
509 * Purpose: writes service status changes and generated service alarms into *
510 * database *
511 * *
512 * Parameters: itservices - [IN] the IT services data *
513 * alarms - [IN] the service alarms update queue *
514 * *
515 * Return value: SUCCEED - the data was written successfully *
516 * FAIL - otherwise *
517 * *
518 ******************************************************************************/
its_write_status_and_alarms(zbx_itservices_t * itservices,zbx_vector_ptr_t * alarms)519 static int its_write_status_and_alarms(zbx_itservices_t *itservices, zbx_vector_ptr_t *alarms)
520 {
521 int i, ret = FAIL;
522 zbx_vector_ptr_t updates;
523 char *sql = NULL;
524 size_t sql_alloc = 0, sql_offset = 0;
525 zbx_uint64_t alarmid;
526 zbx_hashset_iter_t iter;
527 zbx_itservice_t *itservice;
528
529 /* get a list of service status updates that must be written to database */
530 zbx_vector_ptr_create(&updates);
531 zbx_hashset_iter_reset(&itservices->itservices, &iter);
532
533 while (NULL != (itservice = zbx_hashset_iter_next(&iter)))
534 {
535 if (itservice->old_status != itservice->status)
536 its_updates_append(&updates, itservice->serviceid, itservice->status, 0);
537 }
538
539 /* write service status changes into database */
540 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
541
542 if (0 != updates.values_num)
543 {
544 zbx_vector_ptr_sort(&updates, (zbx_compare_func_t)its_updates_compare);
545 zbx_vector_ptr_uniq(&updates, (zbx_compare_func_t)its_updates_compare);
546
547 for (i = 0; i < updates.values_num; i++)
548 {
549 zbx_status_update_t *update = updates.values[i];
550
551 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
552 "update services"
553 " set status=%d"
554 " where serviceid=" ZBX_FS_UI64 ";\n",
555 update->status, update->sourceid);
556
557 if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
558 goto out;
559 }
560 }
561
562 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
563
564 if (16 < sql_offset)
565 {
566 if (ZBX_DB_OK > DBexecute("%s", sql))
567 goto out;
568 }
569
570 ret = SUCCEED;
571
572 /* write generated service alarms into database */
573 if (0 != alarms->values_num)
574 {
575 zbx_db_insert_t db_insert;
576
577 alarmid = DBget_maxid_num("service_alarms", alarms->values_num);
578
579 zbx_db_insert_prepare(&db_insert, "service_alarms", "servicealarmid", "serviceid", "value", "clock",
580 NULL);
581
582 for (i = 0; i < alarms->values_num; i++)
583 {
584 zbx_status_update_t *update = alarms->values[i];
585
586 zbx_db_insert_add_values(&db_insert, alarmid++, update->sourceid, update->status,
587 update->clock);
588 }
589
590 ret = zbx_db_insert_execute(&db_insert);
591
592 zbx_db_insert_clean(&db_insert);
593 }
594 out:
595 zbx_free(sql);
596
597 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
598 zbx_vector_ptr_destroy(&updates);
599
600 return ret;
601 }
602
603 /******************************************************************************
604 * *
605 * Function: its_flush_updates *
606 * *
607 * Purpose: processes the service update queue *
608 * *
609 * Return value: SUCCEED - the data was written successfully *
610 * FAIL - otherwise *
611 * *
612 * Comments: The following steps are taken to process the queue: *
613 * 1) Load all services either directly referenced (with triggerid) *
614 * by update queue or dependent on those services (directly or *
615 * indirectly) or required to calculate status of any loaded *
616 * services. *
617 * 2) Apply updates to the loaded service tree. Queue new service *
618 * alarms whenever service status changes. *
619 * 3) Write the final service status changes and the generated *
620 * service alarm queue into database. *
621 * *
622 ******************************************************************************/
its_flush_updates(const zbx_vector_ptr_t * updates)623 static int its_flush_updates(const zbx_vector_ptr_t *updates)
624 {
625 const char *__function_name = "its_flush_updates";
626
627 int i, j, k, ret = FAIL;
628 const zbx_status_update_t *update;
629 zbx_itservices_t itservices;
630 zbx_vector_ptr_t alarms;
631 zbx_itservice_index_t *index;
632 zbx_vector_uint64_t triggerids;
633
634 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
635
636 its_itservices_init(&itservices);
637
638 zbx_vector_uint64_create(&triggerids);
639
640 for (i = 0; i < updates->values_num; i++)
641 {
642 update = (zbx_status_update_t *)updates->values[i];
643
644 zbx_vector_uint64_append(&triggerids, update->sourceid);
645 }
646
647 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
648
649 /* load all services affected by the trigger status change and */
650 /* the services that are required for resulting status calculations */
651 its_load_services_by_triggerids(&itservices, &triggerids);
652
653 zbx_vector_uint64_destroy(&triggerids);
654
655 if (0 == itservices.itservices.num_data)
656 {
657 ret = SUCCEED;
658 goto out;
659 }
660
661 zbx_vector_ptr_create(&alarms);
662
663 /* apply status updates */
664 for (i = 0; i < updates->values_num; i++)
665 {
666 update = updates->values[i];
667
668 if (NULL == (index = zbx_hashset_search(&itservices.index, update)))
669 continue;
670
671 /* change the status of services based on the update */
672 for (j = 0; j < index->itservices.values_num; j++)
673 {
674 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
675
676 if (SERVICE_ALGORITHM_NONE == itservice->algorithm || itservice->status == update->status)
677 continue;
678
679 its_updates_append(&alarms, itservice->serviceid, update->status, update->clock);
680 itservice->status = update->status;
681 }
682
683 /* recalculate status of the parent services */
684 for (j = 0; j < index->itservices.values_num; j++)
685 {
686 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
687
688 /* update parent services */
689 for (k = 0; k < itservice->parents.values_num; k++)
690 its_itservice_update_status(itservice->parents.values[k], update->clock, &alarms);
691 }
692 }
693
694 ret = its_write_status_and_alarms(&itservices, &alarms);
695
696 zbx_vector_ptr_clear_ext(&alarms, (zbx_clean_func_t)zbx_status_update_free);
697 zbx_vector_ptr_destroy(&alarms);
698 out:
699 its_itservices_clean(&itservices);
700
701 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
702
703 return ret;
704 }
705
706 /*
707 * Public API
708 */
709
710 /******************************************************************************
711 * *
712 * Function: zbx_get_itservices_updates *
713 * *
714 * Purpose: use events to generate list of updates for IT services *
715 * *
716 ******************************************************************************/
zbx_get_itservices_updates(const DB_EVENT * events,size_t events_num,zbx_vector_ptr_t * itservice_updates)717 void zbx_get_itservices_updates(const DB_EVENT *events, size_t events_num, zbx_vector_ptr_t *itservice_updates)
718 {
719 size_t i;
720
721 for (i = 0; i < events_num; i++)
722 {
723 if (EVENT_SOURCE_TRIGGERS != events[i].source)
724 continue;
725
726 its_updates_append(itservice_updates, events[i].objectid, TRIGGER_VALUE_PROBLEM == events[i].value ?
727 events[i].trigger.priority : 0, events[i].clock);
728 }
729 }
730
731 /******************************************************************************
732 * *
733 * Function: DBupdate_itservices *
734 * *
735 * Purpose: apply updates for IT service tree *
736 * *
737 * Return value: SUCCEED - the IT services were updated successfully *
738 * FAIL - otherwise *
739 * *
740 ******************************************************************************/
DBupdate_itservices(const zbx_vector_ptr_t * itservice_updates)741 int DBupdate_itservices(const zbx_vector_ptr_t *itservice_updates)
742 {
743 const char *__function_name = "DBupdate_itservices";
744
745 int ret = SUCCEED;
746
747 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
748
749 if (0 != itservice_updates->values_num)
750 {
751 LOCK_ITSERVICES;
752 DBbegin();
753
754 ret = its_flush_updates(itservice_updates);
755
756 DBcommit();
757 UNLOCK_ITSERVICES;
758 }
759
760 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
761
762 return ret;
763 }
764
765 /******************************************************************************
766 * *
767 * Function: DBremove_itservice_triggers *
768 * *
769 * Purpose: removes specified trigger ids from dependent services and reset *
770 * the status of those services to the default value (0) *
771 * *
772 * Parameters: triggerids - [IN] an array of trigger ids to remove *
773 * triggerids_num - [IN] the number of items in triggerids array *
774 * *
775 * Return value: SUCCEED - the data was written successfully *
776 * FAIL - otherwise *
777 * *
778 ******************************************************************************/
DBremove_triggers_from_itservices(zbx_uint64_t * triggerids,int triggerids_num)779 int DBremove_triggers_from_itservices(zbx_uint64_t *triggerids, int triggerids_num)
780 {
781 char *sql = NULL;
782 size_t sql_alloc = 0, sql_offset = 0;
783 zbx_vector_ptr_t updates;
784 int i, ret = FAIL, now;
785
786 if (0 == triggerids_num)
787 return SUCCEED;
788
789 now = time(NULL);
790
791 zbx_vector_ptr_create(&updates);
792
793 for (i = 0; i < triggerids_num; i++)
794 its_updates_append(&updates, triggerids[i], 0, now);
795
796 LOCK_ITSERVICES;
797
798 if (FAIL == its_flush_updates(&updates))
799 goto out;
800
801 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update services set triggerid=null,showsla=0 where");
802 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids, triggerids_num);
803
804 if (ZBX_DB_OK <= DBexecute("%s", sql))
805 ret = SUCCEED;
806
807 zbx_free(sql);
808 out:
809 UNLOCK_ITSERVICES;
810
811 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
812 zbx_vector_ptr_destroy(&updates);
813
814 return ret;
815 }
816
zbx_create_itservices_lock(void)817 void zbx_create_itservices_lock(void)
818 {
819 if (FAIL == zbx_mutex_create_force(&itservices_lock, ZBX_MUTEX_ITSERVICES))
820 {
821 zbx_error("cannot create mutex for IT services");
822 exit(EXIT_FAILURE);
823 }
824 }
825
zbx_destroy_itservices_lock(void)826 void zbx_destroy_itservices_lock(void)
827 {
828 zbx_mutex_destroy(&itservices_lock);
829 }
830