![]() |
Icinga-core 1.4.0
next gen monitoring
|
00001 /***************************************************************************** 00002 * 00003 * NOTIFICATIONS.C - Service and host notification functions for Icinga 00004 * 00005 * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org) 00006 * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors 00007 * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org) 00008 * 00009 * License: 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License version 2 as 00013 * published by the Free Software Foundation. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 * 00024 *****************************************************************************/ 00025 00026 #include "../include/config.h" 00027 #include "../include/common.h" 00028 #include "../include/objects.h" 00029 #include "../include/statusdata.h" 00030 #include "../include/macros.h" 00031 #include "../include/icinga.h" 00032 #include "../include/broker.h" 00033 #include "../include/neberrors.h" 00034 00035 extern notification *notification_list; 00036 extern contact *contact_list; 00037 extern serviceescalation *serviceescalation_list; 00038 extern hostescalation *hostescalation_list; 00039 00040 extern time_t program_start; 00041 00042 extern int interval_length; 00043 extern int log_notifications; 00044 00045 extern int enable_notifications; 00046 00047 extern int notification_timeout; 00048 00049 extern unsigned long next_notification_id; 00050 00051 extern char *generic_summary; 00052 00053 int check_escalation_condition(escalation_condition*); 00054 00055 int dummy; /* reduce compiler warnings */ 00056 00057 /******************************************************************/ 00058 /***************** SERVICE NOTIFICATION FUNCTIONS *****************/ 00059 /******************************************************************/ 00060 00061 00062 /* notify contacts about a service problem or recovery */ 00063 int service_notification(service *svc, int type, char *not_author, char *not_data, int options){ 00064 host *temp_host=NULL; 00065 notification *temp_notification=NULL; 00066 contact *temp_contact=NULL; 00067 time_t current_time; 00068 struct timeval start_time; 00069 struct timeval end_time; 00070 int escalated=FALSE; 00071 int result=OK; 00072 int contacts_notified=0; 00073 int increment_notification_number=FALSE; 00074 icinga_macros *mac; /* XXX: global macros */ 00075 int neb_result; 00076 00077 mac = get_global_macros(); 00078 00079 log_debug_info(DEBUGL_FUNCTIONS,0,"service_notification()\n"); 00080 00081 /* get the current time */ 00082 time(¤t_time); 00083 gettimeofday(&start_time,NULL); 00084 00085 log_debug_info(DEBUGL_NOTIFICATIONS,0,"** Service Notification Attempt ** Host: '%s', Service: '%s', Type: %d, Options: %d, Current State: %d, Last Notification: %s",svc->host_name,svc->description,type,options,svc->current_state,ctime(&svc->last_notification)); 00086 00087 /* if we couldn't find the host, return an error */ 00088 if((temp_host=svc->host_ptr)==NULL){ 00089 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Couldn't find the host associated with this service, so we won't send a notification!\n"); 00090 return ERROR; 00091 } 00092 00093 /* check the viability of sending out a service notification */ 00094 if(check_service_notification_viability(svc,type,options)==ERROR){ 00095 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test failed. No notification will be sent out.\n"); 00096 return OK; 00097 } 00098 00099 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test passed.\n"); 00100 00101 /* should the notification number be increased? */ 00102 if(type==NOTIFICATION_NORMAL || (options & NOTIFICATION_OPTION_INCREMENT)){ 00103 svc->current_notification_number++; 00104 00105 #ifdef USE_ST_BASED_ESCAL_RANGES 00106 /* also increment the warning/critical/unknown state counter */ 00107 if (svc->current_state == STATE_WARNING) { 00108 svc->current_warning_notification_number++; 00109 } 00110 if (svc->current_state == STATE_CRITICAL) { 00111 svc->current_critical_notification_number++; 00112 } 00113 if (svc->current_state == STATE_UNKNOWN) { 00114 svc->current_unknown_notification_number++; 00115 } 00116 #endif 00117 increment_notification_number=TRUE; 00118 } 00119 00120 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current notification number: %d (%s)\n",svc->current_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged"); 00121 00122 #ifdef USE_ST_BASED_ESCAL_RANGES 00123 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current warning notification number: %d (%s)\n",svc->current_warning_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged"); 00124 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current critical notification number: %d (%s)\n",svc->current_critical_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged"); 00125 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current unknown notification number: %d (%s)\n",svc->current_unknown_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged"); 00126 #endif 00127 00128 /* save and increase the current notification id */ 00129 svc->current_notification_id=next_notification_id; 00130 next_notification_id++; 00131 00132 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Creating list of contacts to be notified.\n"); 00133 00134 /* create the contact notification list for this service */ 00135 create_notification_list_from_service(mac, svc,options,&escalated); 00136 00137 #ifdef USE_EVENT_BROKER 00138 /* send data to event broker */ 00139 end_time.tv_sec=0L; 00140 end_time.tv_usec=0L; 00141 neb_result=broker_notification_data(NEBTYPE_NOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,not_author,not_data,escalated,0,NULL); 00142 if(NEBERROR_CALLBACKCANCEL==neb_result) 00143 return ERROR; 00144 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 00145 return OK; 00146 #endif 00147 00148 /* XXX: crazy indent */ 00149 /* we have contacts to notify... */ 00150 if(notification_list!=NULL){ 00151 00152 /* grab the macro variables */ 00153 grab_host_macros_r(mac, temp_host); 00154 grab_service_macros_r(mac, svc); 00155 00156 /* if this notification has an author, attempt to lookup the associated contact */ 00157 if(not_author!=NULL){ 00158 00159 /* see if we can find the contact - first by name, then by alias */ 00160 if((temp_contact=find_contact(not_author))==NULL){ 00161 for(temp_contact=contact_list;temp_contact!=NULL;temp_contact=temp_contact->next){ 00162 if(!strcmp(temp_contact->alias,not_author)) 00163 break; 00164 } 00165 } 00166 00167 } 00168 00169 /* get author and comment macros */ 00170 my_free(mac->x[MACRO_NOTIFICATIONAUTHOR]); 00171 if(not_author) 00172 mac->x[MACRO_NOTIFICATIONAUTHOR]=(char *)strdup(not_author); 00173 my_free(mac->x[MACRO_NOTIFICATIONAUTHORNAME]); 00174 my_free(mac->x[MACRO_NOTIFICATIONAUTHORALIAS]); 00175 if(temp_contact!=NULL){ 00176 mac->x[MACRO_NOTIFICATIONAUTHORNAME]=(char *)strdup(temp_contact->name); 00177 mac->x[MACRO_NOTIFICATIONAUTHORALIAS]=(char *)strdup(temp_contact->alias); 00178 } 00179 my_free(mac->x[MACRO_NOTIFICATIONCOMMENT]); 00180 if(not_data) 00181 mac->x[MACRO_NOTIFICATIONCOMMENT]=(char *)strdup(not_data); 00182 00183 /* NOTE: these macros are deprecated and will likely disappear in future major releases */ 00184 /* if this is an acknowledgement, get author and comment macros */ 00185 if(type==NOTIFICATION_ACKNOWLEDGEMENT){ 00186 00187 my_free(mac->x[MACRO_SERVICEACKAUTHOR]); 00188 if(not_author) 00189 mac->x[MACRO_SERVICEACKAUTHOR]=(char *)strdup(not_author); 00190 00191 my_free(mac->x[MACRO_SERVICEACKCOMMENT]); 00192 if(not_data) 00193 mac->x[MACRO_SERVICEACKCOMMENT]=(char *)strdup(not_data); 00194 my_free(mac->x[MACRO_SERVICEACKAUTHORNAME]); 00195 my_free(mac->x[MACRO_SERVICEACKAUTHORALIAS]); 00196 if(temp_contact!=NULL){ 00197 mac->x[MACRO_SERVICEACKAUTHORNAME]=(char *)strdup(temp_contact->name); 00198 mac->x[MACRO_SERVICEACKAUTHORALIAS]=(char *)strdup(temp_contact->alias); 00199 } 00200 } 00201 00202 /* set the notification type macro */ 00203 my_free(mac->x[MACRO_NOTIFICATIONTYPE]); 00204 if(type==NOTIFICATION_ACKNOWLEDGEMENT) 00205 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("ACKNOWLEDGEMENT"); 00206 else if(type==NOTIFICATION_FLAPPINGSTART) 00207 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTART"); 00208 else if(type==NOTIFICATION_FLAPPINGSTOP) 00209 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTOP"); 00210 else if(type==NOTIFICATION_FLAPPINGDISABLED) 00211 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGDISABLED"); 00212 else if(type==NOTIFICATION_DOWNTIMESTART) 00213 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMESTART"); 00214 else if(type==NOTIFICATION_DOWNTIMEEND) 00215 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMEEND"); 00216 else if(type==NOTIFICATION_DOWNTIMECANCELLED) 00217 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMECANCELLED"); 00218 else if(type==NOTIFICATION_CUSTOM) 00219 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("CUSTOM"); 00220 else if(svc->current_state==STATE_OK) 00221 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("RECOVERY"); 00222 else 00223 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("PROBLEM"); 00224 00225 /* set the notification number macro */ 00226 my_free(mac->x[MACRO_SERVICENOTIFICATIONNUMBER]); 00227 dummy=asprintf(&mac->x[MACRO_SERVICENOTIFICATIONNUMBER],"%d",svc->current_notification_number); 00228 00229 /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */ 00230 my_free(mac->x[MACRO_NOTIFICATIONNUMBER]); 00231 mac->x[MACRO_NOTIFICATIONNUMBER]=(char *)strdup((mac->x[MACRO_SERVICENOTIFICATIONNUMBER]==NULL)?"":mac->x[MACRO_SERVICENOTIFICATIONNUMBER]); 00232 00233 /* set the notification id macro */ 00234 my_free(mac->x[MACRO_SERVICENOTIFICATIONID]); 00235 dummy=asprintf(&mac->x[MACRO_SERVICENOTIFICATIONID],"%lu",svc->current_notification_id); 00236 00237 /* notify each contact (duplicates have been removed) */ 00238 for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){ 00239 00240 /* grab the macro variables for this contact */ 00241 grab_contact_macros_r(mac, temp_notification->contact); 00242 00243 /* clear summary macros (they are customized for each contact) */ 00244 clear_summary_macros_r(mac); 00245 00246 /* notify this contact */ 00247 result=notify_contact_of_service(mac, temp_notification->contact,svc,type,not_author,not_data,options,escalated); 00248 00249 /* keep track of how many contacts were notified */ 00250 if(result==OK) 00251 contacts_notified++; 00252 } 00253 00254 /* free memory allocated to the notification list */ 00255 free_notification_list(); 00256 00257 /* clear summary macros so they will be regenerated without contact filters when needed next */ 00258 clear_summary_macros_r(mac); 00259 00260 if(type==NOTIFICATION_NORMAL){ 00261 00262 /* adjust last/next notification time and notification flags if we notified someone */ 00263 if(contacts_notified>0){ 00264 00265 /* calculate the next acceptable re-notification time */ 00266 svc->next_notification=get_next_service_notification_time(svc,current_time); 00267 00268 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified. Next possible notification time: %s",contacts_notified,ctime(&svc->next_notification)); 00269 00270 /* update the last notification time for this service (this is needed for rescheduling later notifications) */ 00271 svc->last_notification=current_time; 00272 00273 /* update notifications flags */ 00274 if(svc->current_state==STATE_UNKNOWN) 00275 svc->notified_on_unknown=TRUE; 00276 else if(svc->current_state==STATE_WARNING) 00277 svc->notified_on_warning=TRUE; 00278 else if(svc->current_state==STATE_CRITICAL) 00279 svc->notified_on_critical=TRUE; 00280 } 00281 00282 /* we didn't end up notifying anyone */ 00283 else if(increment_notification_number==TRUE){ 00284 00285 /* adjust current notification number */ 00286 svc->current_notification_number--; 00287 00288 #ifdef USE_ST_BASED_ESCAL_RANGES 00289 if (svc->current_state == STATE_WARNING) { 00290 svc->current_warning_notification_number--; 00291 } 00292 if (svc->current_state == STATE_CRITICAL) { 00293 svc->current_critical_notification_number--; 00294 } 00295 if (svc->current_state == STATE_UNKNOWN) { 00296 svc->current_unknown_notification_number--; 00297 } 00298 #endif 00299 00300 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were notified. Next possible notification time: %s",ctime(&svc->next_notification)); 00301 } 00302 00303 } 00304 00305 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.\n",contacts_notified); 00306 } 00307 00308 /* there were no contacts, so no notification really occurred... */ 00309 else{ 00310 00311 /* readjust current notification number, since one didn't go out */ 00312 if(increment_notification_number==TRUE) { 00313 svc->current_notification_number--; 00314 00315 #ifdef USE_ST_BASED_ESCAL_RANGES 00316 if (svc->current_state == STATE_WARNING) { 00317 svc->current_warning_notification_number--; 00318 } 00319 if (svc->current_state == STATE_CRITICAL) { 00320 svc->current_critical_notification_number--; 00321 } 00322 if (svc->current_state == STATE_UNKNOWN) { 00323 svc->current_unknown_notification_number--; 00324 } 00325 #endif 00326 } 00327 00328 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were found for notification purposes. No notification was sent out.\n"); 00329 } 00330 00331 /* get the time we finished */ 00332 gettimeofday(&end_time,NULL); 00333 00334 #ifdef USE_EVENT_BROKER 00335 /* send data to event broker */ 00336 broker_notification_data(NEBTYPE_NOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,not_author,not_data,escalated,contacts_notified,NULL); 00337 #endif 00338 00339 /* update the status log with the service information */ 00340 update_service_status(svc,FALSE); 00341 00342 return OK; 00343 } 00344 00345 00346 00347 /* checks the viability of sending out a service alert (top level filters) */ 00348 int check_service_notification_viability(service *svc, int type, int options){ 00349 host *temp_host=NULL; 00350 timeperiod *temp_period=NULL; 00351 time_t current_time; 00352 time_t timeperiod_start; 00353 time_t first_problem_time; 00354 00355 log_debug_info(DEBUGL_FUNCTIONS,0,"check_service_notification_viability()\n"); 00356 00357 /* forced notifications bust through everything */ 00358 if(options & NOTIFICATION_OPTION_FORCED){ 00359 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced service notification, so we'll send it out.\n"); 00360 return OK; 00361 } 00362 00363 /* get current time */ 00364 time(¤t_time); 00365 00366 /* are notifications enabled? */ 00367 if(enable_notifications==FALSE){ 00368 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are disabled, so service notifications will not be sent out.\n"); 00369 return ERROR; 00370 } 00371 00372 /* find the host this service is associated with */ 00373 if((temp_host=(host *)svc->host_ptr)==NULL) 00374 return ERROR; 00375 00376 /* if we couldn't find the host, return an error */ 00377 if(temp_host==NULL){ 00378 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Couldn't find the host associated with this service, so we won't send a notification.\n"); 00379 return ERROR; 00380 } 00381 00382 /* if the service has no notification period, inherit one from the host */ 00383 temp_period = svc->notification_period_ptr; 00384 if(temp_period == NULL){ 00385 temp_period = temp_host->notification_period_ptr; 00386 } 00387 00388 /* see if the service can have notifications sent out at this time */ 00389 if(check_time_against_period(current_time,temp_period)==ERROR){ 00390 00391 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service shouldn't have notifications sent out at this time.\n"); 00392 00393 /* calculate the next acceptable notification time, once the next valid time range arrives... */ 00394 if(type==NOTIFICATION_NORMAL){ 00395 00396 get_next_valid_time(current_time,&timeperiod_start,svc->notification_period_ptr); 00397 00398 /* looks like there are no valid notification times defined, so schedule the next one far into the future (one year)... */ 00399 if(timeperiod_start==(time_t)0) 00400 svc->next_notification=(time_t)(current_time+(60*60*24*365)); 00401 00402 /* else use the next valid notification time */ 00403 else 00404 svc->next_notification=timeperiod_start; 00405 00406 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next possible notification time: %s\n",ctime(&svc->next_notification)); 00407 } 00408 00409 return ERROR; 00410 } 00411 00412 /* are notifications temporarily disabled for this service? */ 00413 if(svc->notifications_enabled==FALSE){ 00414 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are temporarily disabled for this service, so we won't send one out.\n"); 00415 return ERROR; 00416 } 00417 00418 00419 /*********************************************/ 00420 /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/ 00421 /*********************************************/ 00422 00423 /* custom notifications are good to go at this point... */ 00424 if(type==NOTIFICATION_CUSTOM) { 00425 if(svc->scheduled_downtime_depth>0 || temp_host->scheduled_downtime_depth>0){ 00426 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't send custom notification during scheduled downtime.\n"); 00427 return ERROR; 00428 } 00429 return OK; 00430 } 00431 00432 00433 /****************************************/ 00434 /*** SPECIAL CASE FOR ACKNOWLEGEMENTS ***/ 00435 /****************************************/ 00436 00437 /* acknowledgements only have to pass three general filters, although they have another test of their own... */ 00438 if(type==NOTIFICATION_ACKNOWLEDGEMENT){ 00439 00440 /* don't send an acknowledgement if there isn't a problem... */ 00441 if(svc->current_state==STATE_OK){ 00442 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The service is currently OK, so we won't send an acknowledgement.\n"); 00443 return ERROR; 00444 } 00445 00446 /* acknowledgement viability test passed, so the notification can be sent out */ 00447 return OK; 00448 } 00449 00450 00451 /****************************************/ 00452 /*** SPECIAL CASE FOR FLAPPING ALERTS ***/ 00453 /****************************************/ 00454 00455 /* flapping notifications only have to pass three general filters */ 00456 if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){ 00457 00458 /* don't send a notification if we're not supposed to... */ 00459 if(svc->notify_on_flapping==FALSE){ 00460 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events for this service.\n"); 00461 return ERROR; 00462 } 00463 00464 /* don't send notifications during scheduled downtime */ 00465 if(svc->scheduled_downtime_depth>0 || temp_host->scheduled_downtime_depth>0){ 00466 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events during scheduled downtime.\n"); 00467 return ERROR; 00468 } 00469 00470 /* flapping viability test passed, so the notification can be sent out */ 00471 return OK; 00472 } 00473 00474 00475 /****************************************/ 00476 /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/ 00477 /****************************************/ 00478 00479 /* downtime notifications only have to pass three general filters */ 00480 if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){ 00481 00482 /* don't send a notification if we're not supposed to... */ 00483 if(svc->notify_on_downtime==FALSE){ 00484 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events for this service.\n"); 00485 return ERROR; 00486 } 00487 00488 /* don't send notifications during scheduled downtime (for service only, not host) */ 00489 if(svc->scheduled_downtime_depth>0){ 00490 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events during scheduled downtime.\n"); 00491 return ERROR; 00492 } 00493 00494 /* downtime viability test passed, so the notification can be sent out */ 00495 return OK; 00496 } 00497 00498 00499 /****************************************/ 00500 /*** NORMAL NOTIFICATIONS ***************/ 00501 /****************************************/ 00502 00503 /* is this a hard problem/recovery? */ 00504 if(svc->state_type==SOFT_STATE){ 00505 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is in a soft state, so we won't send a notification out.\n"); 00506 return ERROR; 00507 } 00508 00509 /* has this problem already been acknowledged? */ 00510 if(svc->problem_has_been_acknowledged==TRUE){ 00511 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service problem has already been acknowledged, so we won't send a notification out.\n"); 00512 return ERROR; 00513 } 00514 00515 /* check service notification dependencies */ 00516 if(check_service_dependencies(svc,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){ 00517 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification dependencies for this service have failed, so we won't sent a notification out.\n"); 00518 return ERROR; 00519 } 00520 00521 /* check host notification dependencies */ 00522 if(check_host_dependencies(temp_host,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){ 00523 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Host notification dependencies for this service have failed, so we won't sent a notification out.\n"); 00524 return ERROR; 00525 } 00526 00527 /* see if we should notify about problems with this service */ 00528 if(svc->current_state==STATE_UNKNOWN && svc->notify_on_unknown==FALSE){ 00529 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about UNKNOWN states for this service.\n"); 00530 return ERROR; 00531 } 00532 if(svc->current_state==STATE_WARNING && svc->notify_on_warning==FALSE){ 00533 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about WARNING states for this service.\n"); 00534 return ERROR; 00535 } 00536 if(svc->current_state==STATE_CRITICAL && svc->notify_on_critical==FALSE){ 00537 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about CRITICAL states for this service.\n"); 00538 return ERROR; 00539 } 00540 if(svc->current_state==STATE_OK){ 00541 if(svc->notify_on_recovery==FALSE){ 00542 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about RECOVERY states for this service.\n"); 00543 return ERROR; 00544 } 00545 if(!(svc->notified_on_unknown==TRUE || svc->notified_on_warning==TRUE || svc->notified_on_critical==TRUE)){ 00546 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about this recovery.\n"); 00547 return ERROR; 00548 } 00549 } 00550 00551 /* see if enough time has elapsed for first notification (Mathias Sundman) */ 00552 /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time ok (or program start) in calculation */ 00553 /* it is reasonable to assume that if the host was never up, the program start time should be used in this calculation */ 00554 if(type==NOTIFICATION_NORMAL && svc->current_notification_number==0 && svc->current_state!=STATE_OK){ 00555 00556 /* determine the time to use of the first problem point */ 00557 first_problem_time=svc->last_time_ok; /* not accurate, but its the earliest time we could use in the comparison */ 00558 00559 if((svc->last_time_warning < first_problem_time) && (svc->last_time_warning > svc->last_time_ok)) 00560 first_problem_time=svc->last_time_warning; 00561 if((svc->last_time_unknown < first_problem_time) && (svc->last_time_unknown > svc->last_time_ok)) 00562 first_problem_time=svc->last_time_unknown; 00563 if((svc->last_time_critical < first_problem_time) && (svc->last_time_critical > svc->last_time_ok)) 00564 first_problem_time=svc->last_time_critical; 00565 00566 if(current_time < (time_t)((first_problem_time==(time_t)0L)?program_start:first_problem_time) + (time_t)(svc->first_notification_delay*interval_length)){ 00567 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Not enough time has elapsed since the service changed to a non-OK state, so we should not notify about this problem yet\n"); 00568 return ERROR; 00569 } 00570 } 00571 00572 /* if this service is currently flapping, don't send the notification */ 00573 if(svc->is_flapping==TRUE){ 00574 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is currently flapping, so we won't send notifications.\n"); 00575 return ERROR; 00576 } 00577 00578 /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/ 00579 if(svc->current_state==STATE_OK) 00580 return OK; 00581 00582 /* don't notify contacts about this service problem again if the notification interval is set to 0 */ 00583 if(svc->no_more_notifications==TRUE){ 00584 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't re-notify contacts about this service problem.\n"); 00585 return ERROR; 00586 } 00587 00588 /* if the host is down or unreachable, don't notify contacts about service failures */ 00589 if(temp_host->current_state!=HOST_UP){ 00590 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host is either down or unreachable, so we won't notify contacts about this service.\n"); 00591 return ERROR; 00592 } 00593 00594 /* don't notify if we haven't waited long enough since the last time (and the service is not marked as being volatile) */ 00595 if((current_time < svc->next_notification)){ 00596 if (svc->is_volatile==FALSE || svc->is_volatile==VOLATILE_WITH_RENOTIFICATION_INTERVAL) { 00597 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We haven't waited long enough to re-notify contacts about this service.\n"); 00598 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next valid notification time: %s",ctime(&svc->next_notification)); 00599 return ERROR; 00600 } 00601 } 00602 00603 /* if this service is currently in a scheduled downtime period, don't send the notification */ 00604 if(svc->scheduled_downtime_depth>0){ 00605 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is currently in a scheduled downtime, so we won't send notifications.\n"); 00606 return ERROR; 00607 } 00608 00609 /* if this host is currently in a scheduled downtime period, don't send the notification */ 00610 if(temp_host->scheduled_downtime_depth>0){ 00611 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host this service is associated with is currently in a scheduled downtime, so we won't send notifications.\n"); 00612 return ERROR; 00613 } 00614 00615 return OK; 00616 } 00617 00618 00619 00620 /* check viability of sending out a service notification to a specific contact (contact-specific filters) */ 00621 int check_contact_service_notification_viability(contact *cntct, service *svc, int type, int options){ 00622 00623 log_debug_info(DEBUGL_FUNCTIONS,0,"check_contact_service_notification_viability()\n"); 00624 00625 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Checking service notification viability for contact '%s'...\n",cntct->name); 00626 00627 /* forced notifications bust through everything */ 00628 if(options & NOTIFICATION_OPTION_FORCED){ 00629 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced service notification, so we'll send it out to this contact.\n"); 00630 return OK; 00631 } 00632 00633 /* are notifications enabled? */ 00634 if(cntct->service_notifications_enabled==FALSE){ 00635 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Service notifications are disabled for this contact.\n"); 00636 return ERROR; 00637 } 00638 00639 /* see if the contact can be notified at this time */ 00640 if(check_time_against_period(time(NULL),cntct->service_notification_period_ptr)==ERROR){ 00641 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This contact shouldn't be notified at this time.\n"); 00642 return ERROR; 00643 } 00644 00645 /*********************************************/ 00646 /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/ 00647 /*********************************************/ 00648 00649 /* custom notifications are good to go at this point... */ 00650 if(type==NOTIFICATION_CUSTOM) 00651 return OK; 00652 00653 00654 /****************************************/ 00655 /*** SPECIAL CASE FOR FLAPPING ALERTS ***/ 00656 /****************************************/ 00657 00658 if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){ 00659 00660 if(cntct->notify_on_service_flapping==FALSE){ 00661 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about FLAPPING service events.\n"); 00662 return ERROR; 00663 } 00664 00665 return OK; 00666 } 00667 00668 /****************************************/ 00669 /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/ 00670 /****************************************/ 00671 00672 if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){ 00673 00674 if(cntct->notify_on_service_downtime==FALSE){ 00675 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWNTIME service events.\n"); 00676 return ERROR; 00677 } 00678 00679 return OK; 00680 } 00681 00682 /*************************************/ 00683 /*** ACKS AND NORMAL NOTIFICATIONS ***/ 00684 /*************************************/ 00685 00686 /* see if we should notify about problems with this service */ 00687 if(svc->current_state==STATE_UNKNOWN && cntct->notify_on_service_unknown==FALSE){ 00688 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about UNKNOWN service states.\n"); 00689 return ERROR; 00690 } 00691 00692 if(svc->current_state==STATE_WARNING && cntct->notify_on_service_warning==FALSE){ 00693 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about WARNING service states.\n"); 00694 return ERROR; 00695 } 00696 00697 if(svc->current_state==STATE_CRITICAL && cntct->notify_on_service_critical==FALSE){ 00698 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about CRITICAL service states.\n"); 00699 return ERROR; 00700 } 00701 00702 if(svc->current_state==STATE_OK){ 00703 00704 if(cntct->notify_on_service_recovery==FALSE){ 00705 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about RECOVERY service states.\n"); 00706 return ERROR; 00707 } 00708 00709 if(!((svc->notified_on_unknown==TRUE && cntct->notify_on_service_unknown==TRUE) || (svc->notified_on_warning==TRUE && cntct->notify_on_service_warning==TRUE) || (svc->notified_on_critical==TRUE && cntct->notify_on_service_critical==TRUE))){ 00710 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify about this recovery.\n"); 00711 return ERROR; 00712 } 00713 } 00714 00715 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Service notification viability for contact '%s' PASSED.\n",cntct->name); 00716 00717 return OK; 00718 } 00719 00720 00721 00722 /* notify a specific contact about a service problem or recovery */ 00723 int notify_contact_of_service(icinga_macros *mac, contact *cntct, service *svc, int type, char *not_author, char *not_data, int options, int escalated){ 00724 commandsmember *temp_commandsmember=NULL; 00725 char *command_name=NULL; 00726 char *command_name_ptr=NULL; 00727 char *raw_command=NULL; 00728 char *processed_command=NULL; 00729 char *temp_buffer=NULL; 00730 char *processed_buffer=NULL; 00731 int early_timeout=FALSE; 00732 double exectime; 00733 struct timeval start_time,end_time; 00734 struct timeval method_start_time,method_end_time; 00735 int macro_options=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS; 00736 int neb_result; 00737 00738 log_debug_info(DEBUGL_FUNCTIONS,0,"notify_contact_of_service()\n"); 00739 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Attempting to notifying contact '%s'...\n",cntct->name); 00740 00741 /* check viability of notifying this user */ 00742 /* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */ 00743 if(check_contact_service_notification_viability(cntct,svc,type,options)==ERROR) 00744 return ERROR; 00745 00746 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Notifying contact '%s'\n",cntct->name); 00747 00748 /* get start time */ 00749 gettimeofday(&start_time,NULL); 00750 00751 #ifdef USE_EVENT_BROKER 00752 /* send data to event broker */ 00753 end_time.tv_sec=0L; 00754 end_time.tv_usec=0L; 00755 neb_result=broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,cntct,not_author,not_data,escalated,NULL); 00756 if(NEBERROR_CALLBACKCANCEL==neb_result) 00757 return ERROR; 00758 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 00759 return OK; 00760 #endif 00761 00762 /* process all the notification commands this user has */ 00763 for(temp_commandsmember=cntct->service_notification_commands;temp_commandsmember!=NULL;temp_commandsmember=temp_commandsmember->next){ 00764 00765 /* get start time */ 00766 gettimeofday(&method_start_time,NULL); 00767 00768 #ifdef USE_EVENT_BROKER 00769 /* send data to event broker */ 00770 method_end_time.tv_sec=0L; 00771 method_end_time.tv_usec=0L; 00772 neb_result=broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,method_start_time,method_end_time,(void *)svc,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL); 00773 if(NEBERROR_CALLBACKCANCEL==neb_result) 00774 break ; 00775 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 00776 continue ; 00777 #endif 00778 00779 /* get the raw command line */ 00780 get_raw_command_line_r(mac, temp_commandsmember->command_ptr,temp_commandsmember->command,&raw_command,macro_options); 00781 if(raw_command==NULL) 00782 continue; 00783 00784 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Raw notification command: %s\n",raw_command); 00785 00786 /* process any macros contained in the argument */ 00787 process_macros_r(mac, raw_command,&processed_command,macro_options); 00788 if(processed_command==NULL) 00789 continue; 00790 00791 /* get the command name */ 00792 command_name=(char *)strdup(temp_commandsmember->command); 00793 command_name_ptr=strtok(command_name,"!"); 00794 00795 /* run the notification command... */ 00796 00797 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Processed notification command: %s\n",processed_command); 00798 00799 /* log the notification to program log file */ 00800 if(log_notifications==TRUE){ 00801 switch(type){ 00802 case NOTIFICATION_CUSTOM: 00803 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;CUSTOM ($SERVICESTATE$);%s;$SERVICEOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00804 break; 00805 case NOTIFICATION_ACKNOWLEDGEMENT: 00806 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;ACKNOWLEDGEMENT ($SERVICESTATE$);%s;$SERVICEOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00807 break; 00808 case NOTIFICATION_FLAPPINGSTART: 00809 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGSTART ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00810 break; 00811 case NOTIFICATION_FLAPPINGSTOP: 00812 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGSTOP ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00813 break; 00814 case NOTIFICATION_FLAPPINGDISABLED: 00815 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGDISABLED ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00816 break; 00817 case NOTIFICATION_DOWNTIMESTART: 00818 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMESTART ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00819 break; 00820 case NOTIFICATION_DOWNTIMEEND: 00821 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMEEND ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00822 break; 00823 case NOTIFICATION_DOWNTIMECANCELLED: 00824 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMECANCELLED ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00825 break; 00826 default: 00827 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;$SERVICESTATE$;%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr); 00828 break; 00829 } 00830 00831 process_macros_r(mac, temp_buffer,&processed_buffer,0); 00832 write_to_all_logs(processed_buffer,NSLOG_SERVICE_NOTIFICATION); 00833 00834 my_free(temp_buffer); 00835 my_free(processed_buffer); 00836 } 00837 00838 /* run the notification command */ 00839 my_system_r(mac, processed_command,notification_timeout,&early_timeout,&exectime,NULL,0); 00840 00841 /* check to see if the notification command timed out */ 00842 if(early_timeout==TRUE){ 00843 logit(NSLOG_SERVICE_NOTIFICATION | NSLOG_RUNTIME_WARNING,TRUE,"Warning: Contact '%s' service notification command '%s' timed out after %d seconds\n",cntct->name,processed_command,notification_timeout); 00844 } 00845 00846 /* free memory */ 00847 my_free(command_name); 00848 my_free(raw_command); 00849 my_free(processed_command); 00850 00851 /* get end time */ 00852 gettimeofday(&method_end_time,NULL); 00853 00854 #ifdef USE_EVENT_BROKER 00855 /* send data to event broker */ 00856 broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,method_start_time,method_end_time,(void *)svc,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL); 00857 #endif 00858 } 00859 00860 /* get end time */ 00861 gettimeofday(&end_time,NULL); 00862 00863 /* update the contact's last service notification time */ 00864 cntct->last_service_notification=start_time.tv_sec; 00865 00866 #ifdef USE_EVENT_BROKER 00867 /* send data to event broker */ 00868 broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,cntct,not_author,not_data,escalated,NULL); 00869 #endif 00870 00871 return OK; 00872 } 00873 00874 00875 /* checks to see if a service escalation entry is a match for the current service notification */ 00876 int is_valid_escalation_for_service_notification(service *svc, serviceescalation *se, int options){ 00877 int notification_number=0; 00878 #ifdef USE_ST_BASED_ESCAL_RANGES 00879 int warning_notification_number=0; 00880 int critical_notification_number=0; 00881 int unknown_notification_number=0; 00882 int widematch=1; 00883 #endif 00884 time_t current_time=0L; 00885 service *temp_service=NULL; 00886 00887 log_debug_info(DEBUGL_FUNCTIONS,0,"is_valid_escalation_for_service_notification()\n"); 00888 00889 /* get the current time */ 00890 time(¤t_time); 00891 00892 /* if this is a recovery, really we check for who got notified about a previous problem */ 00893 if(svc->current_state==STATE_OK) 00894 notification_number=svc->current_notification_number-1; 00895 else 00896 notification_number=svc->current_notification_number; 00897 00898 #ifdef USE_ST_BASED_ESCAL_RANGES 00899 /* These will not be incremented in the case of a recovery, so use the current values regardless of the state */ 00900 warning_notification_number=svc->current_warning_notification_number; 00901 critical_notification_number=svc->current_critical_notification_number; 00902 unknown_notification_number=svc->current_unknown_notification_number; 00903 #endif 00904 00905 /* this entry if it is not for this service */ 00906 temp_service=se->service_ptr; 00907 if(temp_service==NULL || temp_service!=svc) 00908 return FALSE; 00909 00910 /*** EXCEPTION ***/ 00911 /* broadcast options go to everyone, so this escalation is valid */ 00912 if(options & NOTIFICATION_OPTION_BROADCAST) 00913 return TRUE; 00914 00915 #ifndef USE_ST_BASED_ESCAL_RANGES 00916 /* skip this escalation if it happens later */ 00917 if(se->first_notification > notification_number) 00918 return FALSE; 00919 #else 00920 /* skip this escalation if it happens later 00921 * Only skip if none of the notifications numbers match */ 00922 00923 if(se->first_notification == -2 || se->first_notification > notification_number) 00924 widematch=0; 00925 00926 if (!widematch){ 00927 switch (svc->current_state){ 00928 case STATE_WARNING:{ 00929 if (se->first_warning_notification == -2 || se->first_warning_notification > warning_notification_number) 00930 return FALSE; 00931 break; 00932 } 00933 case STATE_CRITICAL:{ 00934 if (se->first_critical_notification == -2 || se->first_critical_notification > critical_notification_number) 00935 return FALSE; 00936 break; 00937 } 00938 case STATE_UNKNOWN:{ 00939 if (se->first_unknown_notification == -2 || se->first_unknown_notification > unknown_notification_number) 00940 return FALSE; 00941 break; 00942 } 00943 } 00944 } 00945 #endif 00946 00947 00948 #ifndef USE_ST_BASED_ESCAL_RANGES 00949 /* skip this escalation if it has already passed */ 00950 if(se->last_notification!=0 && se->last_notification < notification_number) 00951 return FALSE; 00952 #else 00953 /* skip this escalation if it has already passed 00954 * only skip if none of the notifications numbers match */ 00955 00956 widematch=1; 00957 if(se->last_notification == -2 || ((se->last_notification!=0) && (se->last_notification < notification_number))) 00958 widematch=0; 00959 00960 00961 if (!widematch){ 00962 switch (svc->current_state){ 00963 case STATE_WARNING:{ 00964 if (se->last_warning_notification == -2 || ((se->last_warning_notification!=0) && (se->last_warning_notification < warning_notification_number))) 00965 return FALSE; 00966 break; 00967 } 00968 case STATE_CRITICAL:{ 00969 if (se->last_critical_notification == -2 || ((se->last_critical_notification!=0) && (se->last_critical_notification < critical_notification_number))) 00970 return FALSE; 00971 break; 00972 } 00973 case STATE_UNKNOWN:{ 00974 if (se->last_unknown_notification == -2 || ((se->last_unknown_notification!=0) && (se->last_unknown_notification < unknown_notification_number))) 00975 return FALSE; 00976 break; 00977 } 00978 } 00979 } 00980 #endif 00981 00982 /* skip this escalation if it has a timeperiod and the current time isn't valid */ 00983 if(se->escalation_period!=NULL && check_time_against_period(current_time,se->escalation_period_ptr)==ERROR) 00984 return FALSE; 00985 00986 /* skip this escalation if the state options don't match */ 00987 if(svc->current_state==STATE_OK && se->escalate_on_recovery==FALSE) 00988 return FALSE; 00989 else if(svc->current_state==STATE_WARNING && se->escalate_on_warning==FALSE) 00990 return FALSE; 00991 else if(svc->current_state==STATE_UNKNOWN && se->escalate_on_unknown==FALSE) 00992 return FALSE; 00993 else if(svc->current_state==STATE_CRITICAL && se->escalate_on_critical==FALSE) 00994 return FALSE; 00995 00996 /* skip this escalation if the conditions don't match */ 00997 else if(check_escalation_condition(se->condition)==FALSE) 00998 return FALSE; 00999 01000 return TRUE; 01001 } 01002 01003 /* internal help function checks if all conditions in an escalation condition list match the status of hosts/services */ 01004 int check_escalation_condition(escalation_condition *cond){ 01005 int resultAll = TRUE; 01006 int connector = EC_CONNECTOR_NO; 01007 escalation_condition *cnd = cond; // first condition in list 01008 01009 log_debug_info(DEBUGL_FUNCTIONS,0,"check_escalation_condition()"); 01010 01011 while(cnd!=NULL) { 01012 int result = TRUE; 01013 01014 /* service condition */ 01015 if(cnd->service_description!=NULL && strcmp(cnd->service_description,"") 01016 && cnd->host_name!=NULL && strcmp(cnd->host_name,"")) { 01017 01018 /* try to find the service */ 01019 service *svc = find_service(cnd->host_name, cnd->service_description); 01020 if (svc == NULL) { 01021 result = FALSE; 01022 } 01023 else { 01024 if(svc->current_state==STATE_OK && cnd->escalate_on_ok==FALSE) 01025 result = FALSE; 01026 else if(svc->current_state==STATE_WARNING && cnd->escalate_on_warning==FALSE) 01027 result = FALSE; 01028 else if(svc->current_state==STATE_UNKNOWN && cnd->escalate_on_unknown==FALSE) 01029 result = FALSE; 01030 else if(svc->current_state==STATE_CRITICAL && cnd->escalate_on_critical==FALSE) 01031 result = FALSE; 01032 } 01033 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Check service escalation condition %s.%s = %d.\n", svc->host_name, svc->description, result); 01034 } 01035 01036 /* host condition */ 01037 else if(cnd->host_name!=NULL && strcmp(cnd->host_name,"")) { 01038 01039 /* try to find the host */ 01040 host *hst = find_host(cnd->host_name); 01041 if (hst==NULL) { 01042 result = FALSE; 01043 } 01044 else { 01045 if(hst->current_state==HOST_UP && cnd->escalate_on_ok==FALSE) 01046 result = FALSE; 01047 else if(hst->current_state==HOST_DOWN && cnd->escalate_on_down==FALSE) 01048 result = FALSE; 01049 else if(hst->current_state==HOST_UNREACHABLE && cnd->escalate_on_unreachable==FALSE) 01050 result = FALSE; 01051 } 01052 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Check host escalation condition %s = %d.\n", hst->name, result); 01053 } 01054 01055 /* connect the result with the result of previous conditions */ 01056 switch(connector) { 01057 case EC_CONNECTOR_NO: 01058 // goes here when looking at the first condition! 01059 resultAll = result; 01060 break; 01061 case EC_CONNECTOR_AND: 01062 resultAll = resultAll && result; 01063 break; 01064 case EC_CONNECTOR_OR: 01065 resultAll = resultAll || result; 01066 break; 01067 default: 01068 // this should not happen 01069 return FALSE; 01070 break; 01071 } 01072 connector = cnd->connector; 01073 cnd = cnd->next; 01074 } 01075 return resultAll; 01076 } 01077 01078 /* checks to see whether a service notification should be escalation */ 01079 int should_service_notification_be_escalated(service *svc){ 01080 serviceescalation *temp_se=NULL; 01081 void *ptr=NULL; 01082 01083 log_debug_info(DEBUGL_FUNCTIONS,0,"should_service_notification_be_escalated()\n"); 01084 01085 /* search the service escalation list */ 01086 for(temp_se=get_first_serviceescalation_by_service(svc->host_name,svc->description,&ptr);temp_se!=NULL;temp_se=get_next_serviceescalation_by_service(svc->host_name,svc->description,&ptr)){ 01087 01088 /* we found a matching entry, so escalate this notification! */ 01089 if(is_valid_escalation_for_service_notification(svc,temp_se,NOTIFICATION_OPTION_NONE)==TRUE){ 01090 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification WILL be escalated.\n"); 01091 return TRUE; 01092 } 01093 } 01094 01095 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification will NOT be escalated.\n"); 01096 01097 return FALSE; 01098 } 01099 01100 01101 /* given a service, create a list of contacts to be notified, removing duplicates */ 01102 int create_notification_list_from_service(icinga_macros *mac, service *svc, int options, int *escalated){ 01103 serviceescalation *temp_se=NULL; 01104 contactsmember *temp_contactsmember=NULL; 01105 contact *temp_contact=NULL; 01106 contactgroupsmember *temp_contactgroupsmember=NULL; 01107 contactgroup *temp_contactgroup=NULL; 01108 int escalate_notification=FALSE; 01109 void *ptr=NULL; 01110 01111 log_debug_info(DEBUGL_FUNCTIONS,0,"create_notification_list_from_service()\n"); 01112 01113 /* see if this notification should be escalated */ 01114 escalate_notification=should_service_notification_be_escalated(svc); 01115 01116 /* set the escalation flag */ 01117 *escalated=escalate_notification; 01118 01119 /* set the escalation macro */ 01120 my_free(mac->x[MACRO_NOTIFICATIONISESCALATED]); 01121 dummy=asprintf(&mac->x[MACRO_NOTIFICATIONISESCALATED],"%d",escalate_notification); 01122 01123 if(options & NOTIFICATION_OPTION_BROADCAST) 01124 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This notification will be BROADCAST to all (escalated and normal) contacts...\n"); 01125 01126 /* use escalated contacts for this notification */ 01127 if(escalate_notification==TRUE || (options & NOTIFICATION_OPTION_BROADCAST)){ 01128 01129 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding contacts from service escalation(s) to notification list.\n"); 01130 01131 /* search all the escalation entries for valid matches */ 01132 for(temp_se=get_first_serviceescalation_by_service(svc->host_name,svc->description,&ptr);temp_se!=NULL;temp_se=get_next_serviceescalation_by_service(svc->host_name,svc->description,&ptr)){ 01133 01134 /* skip this entry if it isn't appropriate */ 01135 if(is_valid_escalation_for_service_notification(svc,temp_se,options)==FALSE) 01136 continue; 01137 01138 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts from service escalation(s) to notification list.\n"); 01139 01140 /* add all individual contacts for this escalation entry */ 01141 for(temp_contactsmember=temp_se->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 01142 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 01143 continue; 01144 add_notification(mac, temp_contact); 01145 } 01146 01147 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups from service escalation(s) to notification list.\n"); 01148 01149 /* add all contacts that belong to contactgroups for this escalation */ 01150 for(temp_contactgroupsmember=temp_se->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){ 01151 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for service escalation to notification list.\n",temp_contactgroupsmember->group_name); 01152 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL) 01153 continue; 01154 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 01155 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 01156 continue; 01157 add_notification(mac, temp_contact); 01158 } 01159 } 01160 } 01161 } 01162 01163 /* else use normal, non-escalated contacts */ 01164 if(escalate_notification==FALSE || (options & NOTIFICATION_OPTION_BROADCAST)){ 01165 01166 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding normal contacts for service to notification list.\n"); 01167 01168 /* add all individual contacts for this service */ 01169 for(temp_contactsmember=svc->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 01170 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 01171 continue; 01172 add_notification(mac, temp_contact); 01173 } 01174 01175 /* add all contacts that belong to contactgroups for this service */ 01176 for(temp_contactgroupsmember=svc->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){ 01177 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for service to notification list.\n",temp_contactgroupsmember->group_name); 01178 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL) 01179 continue; 01180 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 01181 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 01182 continue; 01183 add_notification(mac, temp_contact); 01184 } 01185 } 01186 } 01187 01188 return OK; 01189 } 01190 01191 01192 01193 01194 /******************************************************************/ 01195 /******************* HOST NOTIFICATION FUNCTIONS ******************/ 01196 /******************************************************************/ 01197 01198 01199 01200 /* notify all contacts for a host that the entire host is down or up */ 01201 int host_notification(host *hst, int type, char *not_author, char *not_data, int options){ 01202 notification *temp_notification=NULL; 01203 contact *temp_contact=NULL; 01204 time_t current_time; 01205 struct timeval start_time; 01206 struct timeval end_time; 01207 int escalated=FALSE; 01208 int result=OK; 01209 int contacts_notified=0; 01210 int increment_notification_number=FALSE; 01211 icinga_macros *mac; /* XXX: global macros */ 01212 int neb_result; 01213 01214 /* get the current time */ 01215 time(¤t_time); 01216 gettimeofday(&start_time,NULL); 01217 01218 log_debug_info(DEBUGL_NOTIFICATIONS,0,"** Host Notification Attempt ** Host: '%s', Type: %d, Options: %d, Current State: %d, Last Notification: %s",hst->name,type,options,hst->current_state,ctime(&hst->last_host_notification)); 01219 01220 01221 /* check viability of sending out a host notification */ 01222 if(check_host_notification_viability(hst,type,options)==ERROR){ 01223 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test failed. No notification will be sent out.\n"); 01224 return OK; 01225 } 01226 01227 /* clear volatile macros */ 01228 mac = get_global_macros(); 01229 clear_volatile_macros_r(mac); 01230 01231 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test passed.\n"); 01232 01233 /* should the notification number be increased? */ 01234 if(type==NOTIFICATION_NORMAL || (options & NOTIFICATION_OPTION_INCREMENT)){ 01235 hst->current_notification_number++; 01236 01237 #ifdef USE_ST_BASED_ESCAL_RANGES 01238 /* also increment down/unreachable state counter */ 01239 if (hst->current_state == HOST_DOWN) { 01240 hst->current_down_notification_number++; 01241 } 01242 if (hst->current_state == HOST_UNREACHABLE) { 01243 hst->current_unreachable_notification_number++; 01244 } 01245 #endif 01246 increment_notification_number=TRUE; 01247 } 01248 01249 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current notification number: %d (%s)\n",hst->current_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged"); 01250 01251 /* save and increase the current notification id */ 01252 hst->current_notification_id=next_notification_id; 01253 next_notification_id++; 01254 01255 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Creating list of contacts to be notified.\n"); 01256 01257 /* create the contact notification list for this host */ 01258 create_notification_list_from_host(mac, hst,options,&escalated); 01259 01260 #ifdef USE_EVENT_BROKER 01261 /* send data to event broker */ 01262 end_time.tv_sec=0L; 01263 end_time.tv_usec=0L; 01264 neb_result=broker_notification_data(NEBTYPE_NOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,not_author,not_data,escalated,0,NULL); 01265 if(NEBERROR_CALLBACKCANCEL==neb_result) 01266 return ERROR; 01267 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 01268 return OK; 01269 #endif 01270 01271 /* XXX: crazy indent */ 01272 /* there are contacts to be notified... */ 01273 if(notification_list!=NULL){ 01274 01275 /* grab the macro variables */ 01276 grab_host_macros_r(mac, hst); 01277 01278 /* if this notification has an author, attempt to lookup the associated contact */ 01279 if(not_author!=NULL){ 01280 01281 /* see if we can find the contact - first by name, then by alias */ 01282 if((temp_contact=find_contact(not_author))==NULL){ 01283 for(temp_contact=contact_list;temp_contact!=NULL;temp_contact=temp_contact->next){ 01284 if(!strcmp(temp_contact->alias,not_author)) 01285 break; 01286 } 01287 } 01288 01289 } 01290 01291 /* get author and comment macros */ 01292 my_free(mac->x[MACRO_NOTIFICATIONAUTHOR]); 01293 if(not_author) 01294 mac->x[MACRO_NOTIFICATIONAUTHOR]=(char *)strdup(not_author); 01295 my_free(mac->x[MACRO_NOTIFICATIONAUTHORNAME]); 01296 my_free(mac->x[MACRO_NOTIFICATIONAUTHORALIAS]); 01297 if(temp_contact!=NULL){ 01298 mac->x[MACRO_NOTIFICATIONAUTHORNAME]=(char *)strdup(temp_contact->name); 01299 mac->x[MACRO_NOTIFICATIONAUTHORALIAS]=(char *)strdup(temp_contact->alias); 01300 } 01301 my_free(mac->x[MACRO_NOTIFICATIONCOMMENT]); 01302 if(not_data) 01303 mac->x[MACRO_NOTIFICATIONCOMMENT]=(char *)strdup(not_data); 01304 01305 /* NOTE: these macros are deprecated and will likely disappear in Icinga 4.x */ 01306 /* if this is an acknowledgement, get author and comment macros */ 01307 if(type==NOTIFICATION_ACKNOWLEDGEMENT){ 01308 01309 my_free(mac->x[MACRO_HOSTACKAUTHOR]); 01310 if(not_author) 01311 mac->x[MACRO_HOSTACKAUTHOR]=(char *)strdup(not_author); 01312 01313 my_free(mac->x[MACRO_HOSTACKCOMMENT]); 01314 if(not_data) 01315 mac->x[MACRO_HOSTACKCOMMENT]=(char *)strdup(not_data); 01316 01317 my_free(mac->x[MACRO_SERVICEACKAUTHORNAME]); 01318 my_free(mac->x[MACRO_SERVICEACKAUTHORALIAS]); 01319 if(temp_contact!=NULL){ 01320 mac->x[MACRO_SERVICEACKAUTHORNAME]=(char *)strdup(temp_contact->name); 01321 mac->x[MACRO_SERVICEACKAUTHORALIAS]=(char *)strdup(temp_contact->alias); 01322 } 01323 } 01324 01325 /* set the notification type macro */ 01326 my_free(mac->x[MACRO_NOTIFICATIONTYPE]); 01327 if(type==NOTIFICATION_ACKNOWLEDGEMENT) 01328 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("ACKNOWLEDGEMENT"); 01329 else if(type==NOTIFICATION_FLAPPINGSTART) 01330 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTART"); 01331 else if(type==NOTIFICATION_FLAPPINGSTOP) 01332 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTOP"); 01333 else if(type==NOTIFICATION_FLAPPINGDISABLED) 01334 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGDISABLED"); 01335 else if(type==NOTIFICATION_DOWNTIMESTART) 01336 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMESTART"); 01337 else if(type==NOTIFICATION_DOWNTIMEEND) 01338 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMEEND"); 01339 else if(type==NOTIFICATION_DOWNTIMECANCELLED) 01340 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMECANCELLED"); 01341 else if(type==NOTIFICATION_CUSTOM) 01342 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("CUSTOM"); 01343 else if(hst->current_state==HOST_UP) 01344 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("RECOVERY"); 01345 else 01346 mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("PROBLEM"); 01347 01348 /* set the notification number macro */ 01349 my_free(mac->x[MACRO_HOSTNOTIFICATIONNUMBER]); 01350 dummy=asprintf(&mac->x[MACRO_HOSTNOTIFICATIONNUMBER],"%d",hst->current_notification_number); 01351 01352 /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */ 01353 my_free(mac->x[MACRO_NOTIFICATIONNUMBER]); 01354 mac->x[MACRO_NOTIFICATIONNUMBER]=(char *)strdup((mac->x[MACRO_HOSTNOTIFICATIONNUMBER]==NULL)?"":mac->x[MACRO_HOSTNOTIFICATIONNUMBER]); 01355 01356 /* set the notification id macro */ 01357 my_free(mac->x[MACRO_HOSTNOTIFICATIONID]); 01358 dummy=asprintf(&mac->x[MACRO_HOSTNOTIFICATIONID],"%lu",hst->current_notification_id); 01359 01360 /* notify each contact (duplicates have been removed) */ 01361 for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){ 01362 01363 /* grab the macro variables for this contact */ 01364 grab_contact_macros_r(mac, temp_notification->contact); 01365 01366 /* clear summary macros (they are customized for each contact) */ 01367 clear_summary_macros_r(mac); 01368 01369 /* notify this contact */ 01370 result=notify_contact_of_host(mac, temp_notification->contact,hst,type,not_author,not_data,options,escalated); 01371 01372 /* keep track of how many contacts were notified */ 01373 if(result==OK) 01374 contacts_notified++; 01375 } 01376 01377 /* free memory allocated to the notification list */ 01378 free_notification_list(); 01379 01380 /* clear summary macros so they will be regenerated without contact filters when needednext */ 01381 clear_summary_macros_r(mac); 01382 01383 if(type==NOTIFICATION_NORMAL){ 01384 01385 /* adjust last/next notification time and notification flags if we notified someone */ 01386 if(contacts_notified>0){ 01387 01388 /* calculate the next acceptable re-notification time */ 01389 hst->next_host_notification=get_next_host_notification_time(hst,current_time); 01390 01391 /* update the last notification time for this host (this is needed for scheduling the next problem notification) */ 01392 hst->last_host_notification=current_time; 01393 01394 /* update notifications flags */ 01395 if(hst->current_state==HOST_DOWN) 01396 hst->notified_on_down=TRUE; 01397 else if(hst->current_state==HOST_UNREACHABLE) 01398 hst->notified_on_unreachable=TRUE; 01399 01400 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified. Next possible notification time: %s",contacts_notified,ctime(&hst->next_host_notification)); 01401 } 01402 01403 /* we didn't end up notifying anyone */ 01404 else if(increment_notification_number==TRUE){ 01405 01406 /* adjust current notification number */ 01407 hst->current_notification_number--; 01408 01409 #ifdef USE_ST_BASED_ESCAL_RANGES 01410 if (hst->current_state == HOST_DOWN) { 01411 hst->current_down_notification_number--; 01412 } 01413 if (hst->current_state == HOST_UNREACHABLE) { 01414 hst->current_unreachable_notification_number--; 01415 } 01416 #endif 01417 01418 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were notified. Next possible notification time: %s",ctime(&hst->next_host_notification)); 01419 } 01420 } 01421 01422 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.\n",contacts_notified); 01423 } 01424 01425 /* there were no contacts, so no notification really occurred... */ 01426 else{ 01427 01428 /* adjust notification number, since no notification actually went out */ 01429 if(increment_notification_number==TRUE) { 01430 hst->current_notification_number--; 01431 01432 #ifdef USE_ST_BASED_ESCAL_RANGES 01433 if (hst->current_state == HOST_DOWN) { 01434 hst->current_down_notification_number--; 01435 } 01436 if (hst->current_state == HOST_UNREACHABLE) { 01437 hst->current_unreachable_notification_number--; 01438 } 01439 #endif 01440 } 01441 01442 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were found for notification purposes. No notification was sent out.\n"); 01443 } 01444 01445 /* get the time we finished */ 01446 gettimeofday(&end_time,NULL); 01447 01448 #ifdef USE_EVENT_BROKER 01449 /* send data to event broker */ 01450 broker_notification_data(NEBTYPE_NOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,not_author,not_data,escalated,contacts_notified,NULL); 01451 #endif 01452 01453 /* update the status log with the host info */ 01454 update_host_status(hst,FALSE); 01455 01456 return OK; 01457 } 01458 01459 01460 01461 /* checks viability of sending a host notification */ 01462 int check_host_notification_viability(host *hst, int type, int options){ 01463 time_t current_time; 01464 time_t timeperiod_start; 01465 time_t first_problem_time; 01466 01467 log_debug_info(DEBUGL_FUNCTIONS,0,"check_host_notification_viability()\n"); 01468 01469 /* forced notifications bust through everything */ 01470 if(options & NOTIFICATION_OPTION_FORCED){ 01471 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced host notification, so we'll send it out.\n"); 01472 return OK; 01473 } 01474 01475 /* get current time */ 01476 time(¤t_time); 01477 01478 /* are notifications enabled? */ 01479 if(enable_notifications==FALSE){ 01480 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are disabled, so host notifications will not be sent out.\n"); 01481 return ERROR; 01482 } 01483 01484 /* see if the host can have notifications sent out at this time */ 01485 if(check_time_against_period(current_time,hst->notification_period_ptr)==ERROR){ 01486 01487 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host shouldn't have notifications sent out at this time.\n"); 01488 01489 /* if this is a normal notification, calculate the next acceptable notification time, once the next valid time range arrives... */ 01490 if(type==NOTIFICATION_NORMAL){ 01491 01492 get_next_valid_time(current_time,&timeperiod_start,hst->notification_period_ptr); 01493 01494 /* it looks like there is no notification time defined, so schedule next one far into the future (one year)... */ 01495 if(timeperiod_start==(time_t)0) 01496 hst->next_host_notification=(time_t)(current_time+(60*60*24*365)); 01497 01498 /* else use the next valid notification time */ 01499 else 01500 hst->next_host_notification=timeperiod_start; 01501 01502 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next possible notification time: %s\n",ctime(&hst->next_host_notification)); 01503 } 01504 01505 return ERROR; 01506 } 01507 01508 /* are notifications temporarily disabled for this host? */ 01509 if(hst->notifications_enabled==FALSE){ 01510 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are temporarily disabled for this host, so we won't send one out.\n"); 01511 return ERROR; 01512 } 01513 01514 01515 /*********************************************/ 01516 /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/ 01517 /*********************************************/ 01518 01519 /* custom notifications are good to go at this point... */ 01520 if(type==NOTIFICATION_CUSTOM) 01521 return OK; 01522 01523 01524 /****************************************/ 01525 /*** SPECIAL CASE FOR ACKNOWLEGEMENTS ***/ 01526 /****************************************/ 01527 01528 /* acknowledgements only have to pass three general filters, although they have another test of their own... */ 01529 if(type==NOTIFICATION_ACKNOWLEDGEMENT){ 01530 01531 /* don't send an acknowledgement if there isn't a problem... */ 01532 if(hst->current_state==HOST_UP){ 01533 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host is currently UP, so we won't send an acknowledgement.\n"); 01534 return ERROR; 01535 } 01536 01537 /* acknowledgement viability test passed, so the notification can be sent out */ 01538 return OK; 01539 } 01540 01541 01542 /*****************************************/ 01543 /*** SPECIAL CASE FOR FLAPPING ALERTS ***/ 01544 /*****************************************/ 01545 01546 /* flapping notifications only have to pass three general filters */ 01547 if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){ 01548 01549 /* don't send a notification if we're not supposed to... */ 01550 if(hst->notify_on_flapping==FALSE){ 01551 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events for this host.\n"); 01552 return ERROR; 01553 } 01554 01555 /* don't send notifications during scheduled downtime */ 01556 if(hst->scheduled_downtime_depth>0){ 01557 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events during scheduled downtime.\n"); 01558 return ERROR; 01559 } 01560 01561 /* flapping viability test passed, so the notification can be sent out */ 01562 return OK; 01563 } 01564 01565 01566 /*****************************************/ 01567 /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/ 01568 /*****************************************/ 01569 01570 /* flapping notifications only have to pass three general filters */ 01571 if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){ 01572 01573 /* don't send a notification if we're not supposed to... */ 01574 if(hst->notify_on_downtime==FALSE){ 01575 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events for this host.\n"); 01576 return ERROR; 01577 } 01578 01579 /* don't send notifications during scheduled downtime */ 01580 if(hst->scheduled_downtime_depth>0){ 01581 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events during scheduled downtime!\n"); 01582 return ERROR; 01583 } 01584 01585 /* downtime viability test passed, so the notification can be sent out */ 01586 return OK; 01587 } 01588 01589 01590 /****************************************/ 01591 /*** NORMAL NOTIFICATIONS ***************/ 01592 /****************************************/ 01593 01594 /* is this a hard problem/recovery? */ 01595 if(hst->state_type==SOFT_STATE){ 01596 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is in a soft state, so we won't send a notification out.\n"); 01597 return ERROR; 01598 } 01599 01600 /* has this problem already been acknowledged? */ 01601 if(hst->problem_has_been_acknowledged==TRUE){ 01602 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host problem has already been acknowledged, so we won't send a notification out!\n"); 01603 return ERROR; 01604 } 01605 01606 /* check notification dependencies */ 01607 if(check_host_dependencies(hst,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){ 01608 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notification dependencies for this host have failed, so we won't sent a notification out!\n"); 01609 return ERROR; 01610 } 01611 01612 /* see if we should notify about problems with this host */ 01613 if(hst->current_state==HOST_UNREACHABLE && hst->notify_on_unreachable==FALSE){ 01614 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about UNREACHABLE status for this host.\n"); 01615 return ERROR; 01616 } 01617 if(hst->current_state==HOST_DOWN && hst->notify_on_down==FALSE){ 01618 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWN states for this host.\n"); 01619 return ERROR; 01620 } 01621 if(hst->current_state==HOST_UP){ 01622 01623 if(hst->notify_on_recovery==FALSE){ 01624 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about RECOVERY states for this host.\n"); 01625 return ERROR; 01626 } 01627 if(!(hst->notified_on_down==TRUE || hst->notified_on_unreachable==TRUE)){ 01628 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about this recovery.\n"); 01629 return ERROR; 01630 } 01631 01632 } 01633 01634 /* see if enough time has elapsed for first notification (Mathias Sundman) */ 01635 /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time up (or program start) in calculation */ 01636 /* it is reasonable to assume that if the host was never up, the program start time should be used in this calculation */ 01637 if(type==NOTIFICATION_NORMAL && hst->current_notification_number==0 && hst->current_state!=HOST_UP){ 01638 01639 /* determine the time to use of the first problem point */ 01640 first_problem_time=hst->last_time_up; /* not accurate, but its the earliest time we could use in the comparison */ 01641 01642 if((hst->last_time_down < first_problem_time) && (hst->last_time_down > hst->last_time_up)) 01643 first_problem_time=hst->last_time_down; 01644 if((hst->last_time_unreachable < first_problem_time) && (hst->last_time_unreachable > hst->last_time_unreachable)) 01645 first_problem_time=hst->last_time_unreachable; 01646 01647 if(current_time < (time_t)((first_problem_time==(time_t)0L)?program_start:first_problem_time) + (time_t)(hst->first_notification_delay*interval_length)){ 01648 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Not enough time has elapsed since the host changed to a non-UP state (or since program start), so we shouldn't notify about this problem yet.\n"); 01649 return ERROR; 01650 } 01651 } 01652 01653 /* if this host is currently flapping, don't send the notification */ 01654 if(hst->is_flapping==TRUE){ 01655 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is currently flapping, so we won't send notifications.\n"); 01656 return ERROR; 01657 } 01658 01659 /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/ 01660 if(hst->current_state==HOST_UP) 01661 return OK; 01662 01663 /* if this host is currently in a scheduled downtime period, don't send the notification */ 01664 if(hst->scheduled_downtime_depth>0){ 01665 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is currently in a scheduled downtime, so we won't send notifications.\n"); 01666 return ERROR; 01667 } 01668 01669 /* check if we shouldn't renotify contacts about the host problem */ 01670 if(hst->no_more_notifications==TRUE){ 01671 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't re-notify contacts about this host problem.\n"); 01672 return ERROR; 01673 } 01674 01675 /* check if its time to re-notify the contacts about the host... */ 01676 if(current_time < hst->next_host_notification){ 01677 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Its not yet time to re-notify the contacts about this host problem...\n"); 01678 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next acceptable notification time: %s",ctime(&hst->next_host_notification)); 01679 return ERROR; 01680 } 01681 01682 return OK; 01683 } 01684 01685 01686 01687 /* checks the viability of notifying a specific contact about a host */ 01688 int check_contact_host_notification_viability(contact *cntct, host *hst, int type, int options){ 01689 01690 log_debug_info(DEBUGL_FUNCTIONS,0,"check_contact_host_notification_viability()\n"); 01691 01692 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Checking host notification viability for contact '%s'...\n",cntct->name); 01693 01694 /* forced notifications bust through everything */ 01695 if(options & NOTIFICATION_OPTION_FORCED){ 01696 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This is a forced host notification, so we'll send it out for this contact.\n"); 01697 return OK; 01698 } 01699 01700 /* are notifications enabled? */ 01701 if(cntct->host_notifications_enabled==FALSE){ 01702 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Host notifications are disabled for this contact.\n"); 01703 return ERROR; 01704 } 01705 01706 /* see if the contact can be notified at this time */ 01707 if(check_time_against_period(time(NULL),cntct->host_notification_period_ptr)==ERROR){ 01708 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This contact shouldn't be notified at this time.\n"); 01709 return ERROR; 01710 } 01711 01712 01713 /*********************************************/ 01714 /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/ 01715 /*********************************************/ 01716 01717 /* custom notifications are good to go at this point... */ 01718 if(type==NOTIFICATION_CUSTOM) 01719 return OK; 01720 01721 01722 /****************************************/ 01723 /*** SPECIAL CASE FOR FLAPPING ALERTS ***/ 01724 /****************************************/ 01725 01726 if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){ 01727 01728 if(cntct->notify_on_host_flapping==FALSE){ 01729 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about FLAPPING host events.\n"); 01730 return ERROR; 01731 } 01732 01733 return OK; 01734 } 01735 01736 01737 /****************************************/ 01738 /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/ 01739 /****************************************/ 01740 01741 if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){ 01742 01743 if(cntct->notify_on_host_downtime==FALSE){ 01744 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWNTIME host events.\n"); 01745 return ERROR; 01746 } 01747 01748 return OK; 01749 } 01750 01751 01752 /*************************************/ 01753 /*** ACKS AND NORMAL NOTIFICATIONS ***/ 01754 /*************************************/ 01755 01756 /* see if we should notify about problems with this host */ 01757 if(hst->current_state==HOST_DOWN && cntct->notify_on_host_down==FALSE){ 01758 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWN states.\n"); 01759 return ERROR; 01760 } 01761 01762 if(hst->current_state==HOST_UNREACHABLE && cntct->notify_on_host_unreachable==FALSE){ 01763 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about UNREACHABLE states,\n"); 01764 return ERROR; 01765 } 01766 01767 if(hst->current_state==HOST_UP){ 01768 01769 if(cntct->notify_on_host_recovery==FALSE){ 01770 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about RECOVERY states.\n"); 01771 return ERROR; 01772 } 01773 01774 if(!((hst->notified_on_down==TRUE && cntct->notify_on_host_down==TRUE) || (hst->notified_on_unreachable==TRUE && cntct->notify_on_host_unreachable==TRUE))){ 01775 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify about this recovery.\n"); 01776 return ERROR; 01777 } 01778 01779 } 01780 01781 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Host notification viability for contact '%s' PASSED.\n",cntct->name); 01782 01783 return OK; 01784 } 01785 01786 01787 01788 /* notify a specific contact that an entire host is down or up */ 01789 int notify_contact_of_host(icinga_macros *mac, contact *cntct, host *hst, int type, char *not_author, char *not_data, int options, int escalated){ 01790 commandsmember *temp_commandsmember=NULL; 01791 char *command_name=NULL; 01792 char *command_name_ptr=NULL; 01793 char *temp_buffer=NULL; 01794 char *processed_buffer=NULL; 01795 char *raw_command=NULL; 01796 char *processed_command=NULL; 01797 int early_timeout=FALSE; 01798 double exectime; 01799 struct timeval start_time; 01800 struct timeval end_time; 01801 struct timeval method_start_time; 01802 struct timeval method_end_time; 01803 int macro_options=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS; 01804 int neb_result; 01805 01806 log_debug_info(DEBUGL_FUNCTIONS,0,"notify_contact_of_host()\n"); 01807 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Attempting to notifying contact '%s'...\n",cntct->name); 01808 01809 /* check viability of notifying this user about the host */ 01810 /* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */ 01811 if(check_contact_host_notification_viability(cntct,hst,type,options)==ERROR) 01812 return ERROR; 01813 01814 log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Notifying contact '%s'\n",cntct->name); 01815 01816 /* get start time */ 01817 gettimeofday(&start_time,NULL); 01818 01819 #ifdef USE_EVENT_BROKER 01820 /* send data to event broker */ 01821 end_time.tv_sec=0L; 01822 end_time.tv_usec=0L; 01823 neb_result=broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,cntct,not_author,not_data,escalated,NULL); 01824 if(NEBERROR_CALLBACKCANCEL==neb_result) 01825 return ERROR; 01826 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 01827 return OK; 01828 #endif 01829 01830 /* process all the notification commands this user has */ 01831 for(temp_commandsmember=cntct->host_notification_commands;temp_commandsmember!=NULL;temp_commandsmember=temp_commandsmember->next){ 01832 01833 /* get start time */ 01834 gettimeofday(&method_start_time,NULL); 01835 01836 #ifdef USE_EVENT_BROKER 01837 /* send data to event broker */ 01838 method_end_time.tv_sec=0L; 01839 method_end_time.tv_usec=0L; 01840 neb_result=broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,method_start_time,method_end_time,(void *)hst,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL); 01841 if(NEBERROR_CALLBACKCANCEL==neb_result) 01842 break; 01843 else if(NEBERROR_CALLBACKOVERRIDE==neb_result) 01844 continue; 01845 #endif 01846 01847 /* get the raw command line */ 01848 get_raw_command_line_r(mac, temp_commandsmember->command_ptr,temp_commandsmember->command,&raw_command,macro_options); 01849 if(raw_command==NULL) 01850 continue; 01851 01852 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Raw notification command: %s\n",raw_command); 01853 01854 /* process any macros contained in the argument */ 01855 process_macros_r(mac, raw_command,&processed_command,macro_options); 01856 if(processed_command==NULL) 01857 continue; 01858 01859 /* get the command name */ 01860 command_name=(char *)strdup(temp_commandsmember->command); 01861 command_name_ptr=strtok(command_name,"!"); 01862 01863 /* run the notification command... */ 01864 01865 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Processed notification command: %s\n",processed_command); 01866 01867 /* log the notification to program log file */ 01868 if(log_notifications==TRUE){ 01869 switch(type){ 01870 case NOTIFICATION_CUSTOM: 01871 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;CUSTOM ($HOSTSTATE$);%s;$HOSTOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,hst->name,command_name_ptr); 01872 break; 01873 case NOTIFICATION_ACKNOWLEDGEMENT: 01874 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;ACKNOWLEDGEMENT ($HOSTSTATE$);%s;$HOSTOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,hst->name,command_name_ptr); 01875 break; 01876 case NOTIFICATION_FLAPPINGSTART: 01877 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGSTART ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01878 break; 01879 case NOTIFICATION_FLAPPINGSTOP: 01880 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGSTOP ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01881 break; 01882 case NOTIFICATION_FLAPPINGDISABLED: 01883 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGDISABLED ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01884 break; 01885 case NOTIFICATION_DOWNTIMESTART: 01886 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMESTART ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01887 break; 01888 case NOTIFICATION_DOWNTIMEEND: 01889 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMEEND ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01890 break; 01891 case NOTIFICATION_DOWNTIMECANCELLED: 01892 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMECANCELLED ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01893 break; 01894 default: 01895 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;$HOSTSTATE$;%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr); 01896 break; 01897 } 01898 01899 process_macros_r(mac, temp_buffer,&processed_buffer,0); 01900 write_to_all_logs(processed_buffer,NSLOG_HOST_NOTIFICATION); 01901 01902 my_free(temp_buffer); 01903 my_free(processed_buffer); 01904 } 01905 01906 /* run the notification command */ 01907 my_system_r(mac, processed_command,notification_timeout,&early_timeout,&exectime,NULL,0); 01908 01909 /* check to see if the notification timed out */ 01910 if(early_timeout==TRUE){ 01911 logit(NSLOG_HOST_NOTIFICATION | NSLOG_RUNTIME_WARNING,TRUE,"Warning: Contact '%s' host notification command '%s' timed out after %d seconds\n", cntct->name,processed_command,notification_timeout); 01912 } 01913 01914 /* free memory */ 01915 my_free(command_name); 01916 my_free(raw_command); 01917 my_free(processed_command); 01918 01919 /* get end time */ 01920 gettimeofday(&method_end_time,NULL); 01921 01922 #ifdef USE_EVENT_BROKER 01923 /* send data to event broker */ 01924 broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,method_start_time,method_end_time,(void *)hst,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL); 01925 #endif 01926 } 01927 01928 /* get end time */ 01929 gettimeofday(&end_time,NULL); 01930 01931 /* update the contact's last host notification time */ 01932 cntct->last_host_notification=start_time.tv_sec; 01933 01934 #ifdef USE_EVENT_BROKER 01935 /* send data to event broker */ 01936 broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,cntct,not_author,not_data,escalated,NULL); 01937 #endif 01938 01939 return OK; 01940 } 01941 01942 01943 /* checks to see if a host escalation entry is a match for the current host notification */ 01944 int is_valid_escalation_for_host_notification(host *hst, hostescalation *he, int options){ 01945 int notification_number=0; 01946 01947 #ifdef USE_ST_BASED_ESCAL_RANGES 01948 int down_notification_number=0; 01949 int unreachable_notification_number=0; 01950 int widematch=1; 01951 #endif 01952 01953 time_t current_time=0L; 01954 host *temp_host=NULL; 01955 01956 log_debug_info(DEBUGL_FUNCTIONS,0,"is_valid_escalation_for_host_notification()\n"); 01957 01958 /* get the current time */ 01959 time(¤t_time); 01960 01961 /* if this is a recovery, really we check for who got notified about a previous problem */ 01962 if(hst->current_state==HOST_UP) 01963 notification_number=hst->current_notification_number-1; 01964 else 01965 notification_number=hst->current_notification_number; 01966 01967 #ifdef USE_ST_BASED_ESCAL_RANGES 01968 /* these are not incremented in the case of recovery, so don't need special handling */ 01969 down_notification_number=hst->current_down_notification_number; 01970 unreachable_notification_number=hst->current_unreachable_notification_number; 01971 #endif 01972 01973 /* find the host this escalation entry is associated with */ 01974 temp_host=he->host_ptr; 01975 if(temp_host==NULL || temp_host!=hst) 01976 return FALSE; 01977 01978 /*** EXCEPTION ***/ 01979 /* broadcast options go to everyone, so this escalation is valid */ 01980 if(options & NOTIFICATION_OPTION_BROADCAST) 01981 return TRUE; 01982 01983 #ifndef USE_ST_BASED_ESCAL_RANGES 01984 if(he->first_notification > notification_number) 01985 return FALSE; 01986 #else 01987 /* skip this escalation if it happens later */ 01988 if(he->first_notification == -2 || he->first_notification > notification_number) 01989 widematch=0; 01990 01991 if (!widematch){ 01992 switch (hst->current_state){ 01993 case HOST_DOWN:{ 01994 if (he->first_down_notification == -2 || he->first_down_notification > down_notification_number) 01995 return FALSE; 01996 break; 01997 } 01998 case HOST_UNREACHABLE:{ 01999 if (he->first_unreachable_notification == -2 || he->first_unreachable_notification > unreachable_notification_number) 02000 return FALSE; 02001 break; 02002 } 02003 } 02004 } 02005 #endif 02006 02007 #ifndef USE_ST_BASED_ESCAL_RANGES 02008 /* skip this escalation if it has already passed */ 02009 if(he->last_notification!=0 && he->last_notification < notification_number) 02010 return FALSE; 02011 #else 02012 /* skip this escalation if it has already passed. only skip if none match */ 02013 widematch=1; 02014 if((he->last_notification == -2) || ((he->last_notification!=0) && (he->last_notification < notification_number))) 02015 widematch=0; 02016 02017 if (!widematch){ 02018 switch (hst->current_state){ 02019 case HOST_DOWN:{ 02020 if ((he->last_down_notification == -2) || ((he->last_down_notification!=0) && (he->last_down_notification < down_notification_number))) 02021 return FALSE; 02022 break; 02023 } 02024 case HOST_UNREACHABLE:{ 02025 if ((he->last_unreachable_notification == -2) || ((he->last_unreachable_notification) && (he->last_unreachable_notification < unreachable_notification_number))) 02026 return FALSE; 02027 break; 02028 } 02029 } 02030 } 02031 #endif 02032 /* skip this escalation if it has a timeperiod and the current time isn't valid */ 02033 if(he->escalation_period!=NULL && check_time_against_period(current_time,he->escalation_period_ptr)==ERROR) 02034 return FALSE; 02035 02036 /* skip this escalation if the state options don't match */ 02037 if(hst->current_state==HOST_UP && he->escalate_on_recovery==FALSE) 02038 return FALSE; 02039 else if(hst->current_state==HOST_DOWN && he->escalate_on_down==FALSE) 02040 return FALSE; 02041 else if(hst->current_state==HOST_UNREACHABLE && he->escalate_on_unreachable==FALSE) 02042 return FALSE; 02043 02044 /* skip this escalation if the conditions don't match */ 02045 else if(check_escalation_condition(he->condition)==FALSE) 02046 return FALSE; 02047 02048 return TRUE; 02049 } 02050 02051 02052 02053 /* checks to see whether a host notification should be escalation */ 02054 int should_host_notification_be_escalated(host *hst){ 02055 hostescalation *temp_he=NULL; 02056 void *ptr=NULL; 02057 02058 log_debug_info(DEBUGL_FUNCTIONS,0,"should_host_notification_be_escalated()\n"); 02059 02060 if(hst==NULL) 02061 return FALSE; 02062 02063 /* search the host escalation list */ 02064 for(temp_he=get_first_hostescalation_by_host(hst->name,&ptr);temp_he!=NULL;temp_he=get_next_hostescalation_by_host(hst->name,&ptr)){ 02065 02066 /* we found a matching entry, so escalate this notification! */ 02067 if(is_valid_escalation_for_host_notification(hst,temp_he,NOTIFICATION_OPTION_NONE)==TRUE) 02068 return TRUE; 02069 } 02070 02071 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Host notification will NOT be escalated.\n"); 02072 02073 return FALSE; 02074 } 02075 02076 02077 /* given a host, create a list of contacts to be notified, removing duplicates */ 02078 int create_notification_list_from_host(icinga_macros *mac, host *hst, int options, int *escalated){ 02079 hostescalation *temp_he=NULL; 02080 contactsmember *temp_contactsmember=NULL; 02081 contact *temp_contact=NULL; 02082 contactgroupsmember *temp_contactgroupsmember=NULL; 02083 contactgroup *temp_contactgroup=NULL; 02084 int escalate_notification=FALSE; 02085 void *ptr=NULL; 02086 02087 log_debug_info(DEBUGL_FUNCTIONS,0,"create_notification_list_from_host()\n"); 02088 02089 /* see if this notification should be escalated */ 02090 escalate_notification=should_host_notification_be_escalated(hst); 02091 02092 /* set the escalation flag */ 02093 *escalated=escalate_notification; 02094 02095 /* set the escalation macro */ 02096 my_free(mac->x[MACRO_NOTIFICATIONISESCALATED]); 02097 dummy=asprintf(&mac->x[MACRO_NOTIFICATIONISESCALATED],"%d",escalate_notification); 02098 02099 if(options & NOTIFICATION_OPTION_BROADCAST) 02100 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This notification will be BROADCAST to all (escalated and normal) contacts...\n"); 02101 02102 /* use escalated contacts for this notification */ 02103 if(escalate_notification==TRUE || (options & NOTIFICATION_OPTION_BROADCAST)){ 02104 02105 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding contacts from host escalation(s) to notification list.\n"); 02106 02107 /* check all the host escalation entries */ 02108 for(temp_he=get_first_hostescalation_by_host(hst->name,&ptr);temp_he!=NULL;temp_he=get_next_hostescalation_by_host(hst->name,&ptr)){ 02109 02110 /* see if this escalation if valid for this notification */ 02111 if(is_valid_escalation_for_host_notification(hst,temp_he,options)==FALSE) 02112 continue; 02113 02114 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts from host escalation(s) to notification list.\n"); 02115 02116 /* add all individual contacts for this escalation */ 02117 for(temp_contactsmember=temp_he->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 02118 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 02119 continue; 02120 add_notification(mac, temp_contact); 02121 } 02122 02123 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups from host escalation(s) to notification list.\n"); 02124 02125 /* add all contacts that belong to contactgroups for this escalation */ 02126 for(temp_contactgroupsmember=temp_he->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){ 02127 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for host escalation to notification list.\n",temp_contactgroupsmember->group_name); 02128 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL) 02129 continue; 02130 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 02131 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 02132 continue; 02133 add_notification(mac, temp_contact); 02134 } 02135 } 02136 } 02137 } 02138 02139 /* use normal, non-escalated contacts for this notification */ 02140 if(escalate_notification==FALSE || (options & NOTIFICATION_OPTION_BROADCAST)){ 02141 02142 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding normal contacts for host to notification list.\n"); 02143 02144 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts for host to notification list.\n"); 02145 02146 /* add all individual contacts for this host */ 02147 for(temp_contactsmember=hst->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 02148 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 02149 continue; 02150 add_notification(mac, temp_contact); 02151 } 02152 02153 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups for host to notification list.\n"); 02154 02155 /* add all contacts that belong to contactgroups for this host */ 02156 for(temp_contactgroupsmember=hst->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){ 02157 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for host to notification list.\n",temp_contactgroupsmember->group_name); 02158 02159 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL) 02160 continue; 02161 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){ 02162 if((temp_contact=temp_contactsmember->contact_ptr)==NULL) 02163 continue; 02164 add_notification(mac, temp_contact); 02165 } 02166 } 02167 } 02168 02169 return OK; 02170 } 02171 02172 02173 02174 02175 /******************************************************************/ 02176 /***************** NOTIFICATION TIMING FUNCTIONS ******************/ 02177 /******************************************************************/ 02178 02179 02180 /* calculates next acceptable re-notification time for a service */ 02181 time_t get_next_service_notification_time(service *svc, time_t offset){ 02182 time_t next_notification=0L; 02183 double interval_to_use=0.0; 02184 serviceescalation *temp_se=NULL; 02185 int have_escalated_interval=FALSE; 02186 02187 log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_service_notification_time()\n"); 02188 02189 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Calculating next valid notification time...\n"); 02190 02191 /* default notification interval */ 02192 interval_to_use=svc->notification_interval; 02193 02194 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Default interval: %f\n",interval_to_use); 02195 02196 /* search all the escalation entries for valid matches for this service (at its current notification number) */ 02197 for(temp_se=serviceescalation_list;temp_se!=NULL;temp_se=temp_se->next){ 02198 02199 /* interval < 0 means to use non-escalated interval */ 02200 if(temp_se->notification_interval<0.0) 02201 continue; 02202 02203 /* skip this entry if it isn't appropriate */ 02204 if(is_valid_escalation_for_service_notification(svc,temp_se,NOTIFICATION_OPTION_NONE)==FALSE) 02205 continue; 02206 02207 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Found a valid escalation w/ interval of %f\n",temp_se->notification_interval); 02208 02209 /* if we haven't used a notification interval from an escalation yet, use this one */ 02210 if(have_escalated_interval==FALSE){ 02211 have_escalated_interval=TRUE; 02212 interval_to_use=temp_se->notification_interval; 02213 } 02214 02215 /* else use the shortest of all valid escalation intervals */ 02216 else if(temp_se->notification_interval<interval_to_use) 02217 interval_to_use=temp_se->notification_interval; 02218 02219 log_debug_info(DEBUGL_NOTIFICATIONS,2,"New interval: %f\n",interval_to_use); 02220 } 02221 02222 /* if notification interval is 0, we shouldn't send any more problem notifications (unless service is volatile) */ 02223 if(interval_to_use==0.0 && svc->is_volatile==FALSE) 02224 svc->no_more_notifications=TRUE; 02225 else 02226 svc->no_more_notifications=FALSE; 02227 02228 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Interval used for calculating next valid notification time: %f\n",interval_to_use); 02229 02230 /* calculate next notification time */ 02231 next_notification=offset+(interval_to_use*interval_length); 02232 02233 return next_notification; 02234 } 02235 02236 02237 02238 /* calculates next acceptable re-notification time for a host */ 02239 time_t get_next_host_notification_time(host *hst, time_t offset){ 02240 time_t next_notification=0L; 02241 double interval_to_use=0.0; 02242 hostescalation *temp_he=NULL; 02243 int have_escalated_interval=FALSE; 02244 02245 02246 log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_host_notification_time()\n"); 02247 02248 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Calculating next valid notification time...\n"); 02249 02250 /* default notification interval */ 02251 interval_to_use=hst->notification_interval; 02252 02253 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Default interval: %f\n",interval_to_use); 02254 02255 /* check all the host escalation entries for valid matches for this host (at its current notification number) */ 02256 for(temp_he=hostescalation_list;temp_he!=NULL;temp_he=temp_he->next){ 02257 02258 /* interval < 0 means to use non-escalated interval */ 02259 if(temp_he->notification_interval<0.0) 02260 continue; 02261 02262 /* skip this entry if it isn't appropriate */ 02263 if(is_valid_escalation_for_host_notification(hst,temp_he,NOTIFICATION_OPTION_NONE)==FALSE) 02264 continue; 02265 02266 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Found a valid escalation w/ interval of %f\n",temp_he->notification_interval); 02267 02268 /* if we haven't used a notification interval from an escalation yet, use this one */ 02269 if(have_escalated_interval==FALSE){ 02270 have_escalated_interval=TRUE; 02271 interval_to_use=temp_he->notification_interval; 02272 } 02273 02274 /* else use the shortest of all valid escalation intervals */ 02275 else if(temp_he->notification_interval<interval_to_use) 02276 interval_to_use=temp_he->notification_interval; 02277 02278 log_debug_info(DEBUGL_NOTIFICATIONS,2,"New interval: %f\n",interval_to_use); 02279 } 02280 02281 /* if interval is 0, no more notifications should be sent */ 02282 if(interval_to_use==0.0) 02283 hst->no_more_notifications=TRUE; 02284 else 02285 hst->no_more_notifications=FALSE; 02286 02287 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Interval used for calculating next valid notification time: %f\n",interval_to_use); 02288 02289 /* calculate next notification time */ 02290 next_notification=offset+(interval_to_use*interval_length); 02291 02292 return next_notification; 02293 } 02294 02295 02296 02297 /******************************************************************/ 02298 /***************** NOTIFICATION OBJECT FUNCTIONS ******************/ 02299 /******************************************************************/ 02300 02301 02302 /* given a contact name, find the notification entry for them for the list in memory */ 02303 notification * find_notification(contact *cntct){ 02304 notification *temp_notification=NULL; 02305 02306 log_debug_info(DEBUGL_FUNCTIONS,0,"find_notification() start\n"); 02307 02308 if(cntct==NULL) 02309 return NULL; 02310 02311 for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){ 02312 if(temp_notification->contact==cntct) 02313 return temp_notification; 02314 } 02315 02316 /* we couldn't find the contact in the notification list */ 02317 return NULL; 02318 } 02319 02320 02321 02322 /* add a new notification to the list in memory */ 02323 int add_notification(icinga_macros *mac, contact *cntct){ 02324 notification *new_notification=NULL; 02325 notification *temp_notification=NULL; 02326 02327 log_debug_info(DEBUGL_FUNCTIONS,0,"add_notification() start\n"); 02328 02329 if(cntct==NULL) 02330 return ERROR; 02331 02332 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding contact '%s' to notification list.\n",cntct->name); 02333 02334 /* don't add anything if this contact is already on the notification list */ 02335 if((temp_notification=find_notification(cntct))!=NULL) 02336 return OK; 02337 02338 /* allocate memory for a new contact in the notification list */ 02339 if((new_notification=malloc(sizeof(notification)))==NULL) 02340 return ERROR; 02341 02342 /* fill in the contact info */ 02343 new_notification->contact=cntct; 02344 02345 /* add new notification to head of list */ 02346 new_notification->next=notification_list; 02347 notification_list=new_notification; 02348 02349 /* add contact to notification recipients macro */ 02350 if(mac->x[MACRO_NOTIFICATIONRECIPIENTS]==NULL) 02351 mac->x[MACRO_NOTIFICATIONRECIPIENTS]=(char *)strdup(cntct->name); 02352 else{ 02353 if((mac->x[MACRO_NOTIFICATIONRECIPIENTS]=(char *)realloc(mac->x[MACRO_NOTIFICATIONRECIPIENTS],strlen(mac->x[MACRO_NOTIFICATIONRECIPIENTS])+strlen(cntct->name)+2))){ 02354 strcat(mac->x[MACRO_NOTIFICATIONRECIPIENTS],","); 02355 strcat(mac->x[MACRO_NOTIFICATIONRECIPIENTS],cntct->name); 02356 } 02357 } 02358 02359 return OK; 02360 } 02361