diff --git a/src/naemon/broker.c b/src/naemon/broker.c index 04b124f7..dabcfdf7 100644 --- a/src/naemon/broker.c +++ b/src/naemon/broker.c @@ -847,7 +847,7 @@ void broker_retention_data(int type, int flags, int attr) /* send acknowledgement data to broker */ -void broker_acknowledgement_data(int type, int flags, int attr, int acknowledgement_type, void *data, char *ack_author, char *ack_data, int subtype, int notify_contacts, int persistent_comment) +void broker_acknowledgement_data(int type, int flags, int attr, int acknowledgement_type, void *data, char *ack_author, char *ack_data, int subtype, int notify_contacts, int persistent_comment, time_t end_time) { nebstruct_acknowledgement_data ds; host *temp_host = NULL; @@ -880,6 +880,7 @@ void broker_acknowledgement_data(int type, int flags, int attr, int acknowledgem ds.is_sticky = (subtype == ACKNOWLEDGEMENT_STICKY) ? TRUE : FALSE; ds.notify_contacts = notify_contacts; ds.persistent_comment = persistent_comment; + ds.end_time = end_time; /* make callbacks */ neb_make_callbacks(NEBCALLBACK_ACKNOWLEDGEMENT_DATA, (void *)&ds); diff --git a/src/naemon/broker.h b/src/naemon/broker.h index 47cc7ace..4e7b0b77 100644 --- a/src/naemon/broker.h +++ b/src/naemon/broker.h @@ -191,7 +191,7 @@ void broker_adaptive_contact_data(int, int, int, contact *, int, unsigned long, int broker_external_command(int, int, int, int, time_t, char *, char *); void broker_aggregated_status_data(int, int, int); void broker_retention_data(int, int, int); -void broker_acknowledgement_data(int, int, int, int, void *, char *, char *, int, int, int); +void broker_acknowledgement_data(int, int, int, int, void *, char *, char *, int, int, int, time_t); void broker_statechange_data(int, int, int, int, void *, int, int, int, int); int broker_vault_macro(char *, char **, int *, nagios_macros *); diff --git a/src/naemon/checks_host.c b/src/naemon/checks_host.c index 35f0fdb3..e7f48620 100644 --- a/src/naemon/checks_host.c +++ b/src/naemon/checks_host.c @@ -188,6 +188,9 @@ static void handle_host_check_event(struct nm_event_execution_properties *evprop /* update the status log */ update_host_status(hst, FALSE); } + } else if (evprop->execution_type == EVENT_EXEC_ABORTED) { + /* If the event is destroyed, remove the reference. */ + hst->next_check_event = NULL; } } @@ -969,6 +972,7 @@ static int handle_host_state(host *hst, int *alert_recorded) hst->problem_has_been_acknowledged = FALSE; hst->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + hst->acknowledgement_end_time = (time_t)0; /* remove any non-persistant comments associated with the ack */ delete_host_acknowledgement_comments(hst); @@ -976,6 +980,7 @@ static int handle_host_state(host *hst, int *alert_recorded) hst->problem_has_been_acknowledged = FALSE; hst->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + hst->acknowledgement_end_time = (time_t)0; /* remove any non-persistant comments associated with the ack */ delete_host_acknowledgement_comments(hst); diff --git a/src/naemon/checks_service.c b/src/naemon/checks_service.c index 1031e67a..6d1abc9b 100644 --- a/src/naemon/checks_service.c +++ b/src/naemon/checks_service.c @@ -240,6 +240,9 @@ static void handle_service_check_event(struct nm_event_execution_properties *evp /* Otherwise, run the event */ run_scheduled_service_check(temp_service, options, latency); + } else if (evprop->execution_type == EVENT_EXEC_ABORTED) { + /* If the event is destroyed, remove the reference. */ + temp_service->next_check_event = NULL; } } @@ -636,6 +639,7 @@ int handle_async_service_check_result(service *temp_service, check_result *queue temp_service->problem_has_been_acknowledged = FALSE; temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_service->acknowledgement_end_time = (time_t)0; /* remove any non-persistant comments associated with the ack */ delete_service_acknowledgement_comments(temp_service); @@ -643,6 +647,7 @@ int handle_async_service_check_result(service *temp_service, check_result *queue temp_service->problem_has_been_acknowledged = FALSE; temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_service->acknowledgement_end_time = (time_t)0; /* remove any non-persistant comments associated with the ack */ delete_service_acknowledgement_comments(temp_service); @@ -705,6 +710,7 @@ int handle_async_service_check_result(service *temp_service, check_result *queue /* reset the acknowledgement flag (this should already have been done, but just in case...) */ temp_service->problem_has_been_acknowledged = FALSE; temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_service->acknowledgement_end_time = (time_t)0; /* verify the route to the host and send out host recovery notifications */ if (temp_host->current_state != STATE_UP) { @@ -788,6 +794,7 @@ int handle_async_service_check_result(service *temp_service, check_result *queue temp_service->current_notification_number = 0; temp_service->problem_has_been_acknowledged = FALSE; temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_service->acknowledgement_end_time = (time_t)0; temp_service->notified_on = 0; } diff --git a/src/naemon/commands.c b/src/naemon/commands.c index 88dbe47f..9cd589ba 100644 --- a/src/naemon/commands.c +++ b/src/naemon/commands.c @@ -73,8 +73,8 @@ static void disable_host_notifications(host *); /* disables host notifications static void enable_and_propagate_notifications(host *hst, struct propagation_parameters *params); static void disable_and_propagate_notifications(host *hst, struct propagation_parameters *params); static void schedule_and_propagate_downtime(host *temp_host, struct downtime_parameters *params); -static void acknowledge_host_problem(host *, char *, char *, int, int, int); /* acknowledges a host problem */ -static void acknowledge_service_problem(service *, char *, char *, int, int, int); /* acknowledges a service problem */ +static void acknowledge_host_problem(host *, char *, char *, int, int, int, time_t); /* acknowledges a host problem */ +static void acknowledge_service_problem(service *, char *, char *, int, int, int, time_t); /* acknowledges a service problem */ static void remove_host_acknowledgement(host *); /* removes a host acknowledgement */ static void remove_service_acknowledgement(service *); /* removes a service acknowledgement */ static void start_executing_service_checks(void); /* starts executing service checks */ @@ -1881,7 +1881,11 @@ static int host_command_handler(const struct external_command *ext_command, time return OK; case CMD_ACKNOWLEDGE_HOST_PROBLEM: acknowledge_host_problem(target_host, GV("author"), GV("comment"), GV_INT("sticky"), - GV_BOOL("notify"), GV_BOOL("persistent")); + GV_BOOL("notify"), GV_BOOL("persistent"), (time_t)0); + return OK; + case CMD_ACKNOWLEDGE_HOST_PROBLEM_EXPIRE: + acknowledge_host_problem(target_host, GV("author"), GV("comment"), GV_INT("sticky"), + GV_BOOL("notify"), GV_BOOL("persistent"), GV_TIMESTAMP("end_time")); return OK; case CMD_ENABLE_HOST_EVENT_HANDLER: enable_host_event_handler(target_host); @@ -2257,7 +2261,12 @@ static int service_command_handler(const struct external_command *ext_command, t case CMD_PROCESS_SERVICE_CHECK_RESULT: return process_passive_service_check(entry_time /*entry time as check time*/, target_service->host_name, target_service->description, GV_INT("status_code"), GV("plugin_output")); case CMD_ACKNOWLEDGE_SVC_PROBLEM: - acknowledge_service_problem(target_service, GV("author"), GV("comment"), GV_INT("sticky"), GV_BOOL("notify"), GV_BOOL("persistent")); + acknowledge_service_problem(target_service, GV("author"), GV("comment"), GV_INT("sticky"), + GV_BOOL("notify"), GV_BOOL("persistent"), (time_t)0); + return OK; + case CMD_ACKNOWLEDGE_SVC_PROBLEM_EXPIRE: + acknowledge_service_problem(target_service, GV("author"), GV("comment"), GV_INT("sticky"), + GV_BOOL("notify"), GV_BOOL("persistent"), GV_TIMESTAMP("end_time")); return OK; case CMD_ENABLE_PASSIVE_SVC_CHECKS: enable_passive_service_checks(target_service); @@ -2728,10 +2737,18 @@ void register_core_commands(void) "Allows you to acknowledge the current problem for the specified host. By acknowledging the current problem, future notifications (for the same host state) are disabled. If the 'sticky' option is set to one (1), the acknowledgement will remain until the host returns to an UP state. Otherwise the acknowledgement will automatically be removed when the host changes state. If the 'notify' option is set to one (1), a notification will be sent out to contacts indicating that the current host problem has been acknowledged. If the 'persistent' option is set to one (1), the comment associated with the acknowledgement will remain once the acknowledgement is removed. If not, the comment will be deleted when the acknowledgement is removed.", "host=host_name;int=sticky;bool=notify;bool=persistent;str=author;str=comment"); command_register(core_command, CMD_ACKNOWLEDGE_HOST_PROBLEM); + core_command = command_create("ACKNOWLEDGE_HOST_PROBLEM_EXPIRE", host_command_handler, + "Allows you to acknowledge the current problem for the specified host for a limitied time. By acknowledging the current problem, future notifications (for the same host state) are disabled. The 'end_time' option determines the time after which the acknowledgement is cleared automatically. If the 'sticky' option is set to one (1), the acknowledgement will remain until the host returns to an UP state. Otherwise the acknowledgement will automatically be removed when the host changes state. If the 'notify' option is set to one (1), a notification will be sent out to contacts indicating that the current host problem has been acknowledged. If the 'persistent' option is set to one (1), the comment associated with the acknowledgement will remain once the acknowledgement is removed. If not, the comment will be deleted when the acknowledgement is removed.", "host=host_name;int=sticky;bool=notify;bool=persistent;timestamp=end_time;str=author;str=comment"); + command_register(core_command, CMD_ACKNOWLEDGE_HOST_PROBLEM_EXPIRE); + core_command = command_create("ACKNOWLEDGE_SVC_PROBLEM", service_command_handler, "Allows you to acknowledge the current problem for the specified service. By acknowledging the current problem, future notifications (for the same servicestate) are disabled. If the 'sticky' option is set to one (1), the acknowledgement will remain until the service returns to an OK state. Otherwise the acknowledgement will automatically be removed when the service changes state. If the 'notify' option is set to one (1), a notification will be sent out to contacts indicating that the current service problem has been acknowledged. If the 'persistent' option is set to one (1), the comment associated with the acknowledgement will remain once the acknowledgement is removed. If not, the comment will be deleted when the acknowledgement is removed.", "service=service;int=sticky;bool=notify;bool=persistent;str=author;str=comment"); command_register(core_command, CMD_ACKNOWLEDGE_SVC_PROBLEM); + core_command = command_create("ACKNOWLEDGE_SVC_PROBLEM_EXPIRE", service_command_handler, + "Allows you to acknowledge the current problem for the specified service. By acknowledging the current problem, future notifications (for the same servicestate) are disabled. The 'end_time' option determines the time after which the acknowledgement is cleared automatically. If the 'sticky' option is set to one (1), the acknowledgement will remain until the service returns to an OK state. Otherwise the acknowledgement will automatically be removed when the service changes state. If the 'notify' option is set to one (1), a notification will be sent out to contacts indicating that the current service problem has been acknowledged. If the 'persistent' option is set to one (1), the comment associated with the acknowledgement will remain once the acknowledgement is removed. If not, the comment will be deleted when the acknowledgement is removed.", "service=service;int=sticky;bool=notify;bool=persistent;timestamp=end_time;str=author;str=comment"); + command_register(core_command, CMD_ACKNOWLEDGE_SVC_PROBLEM_EXPIRE); + core_command = command_create("START_EXECUTING_SVC_CHECKS", global_command_handler, "Enables active checks of services on a program-wide basis.", NULL); command_register(core_command, CMD_START_EXECUTING_SVC_CHECKS); @@ -3958,7 +3975,7 @@ static void schedule_and_propagate_downtime(host *temp_host, struct downtime_par /* acknowledges a host problem */ -static void acknowledge_host_problem(host *hst, char *ack_author, char *ack_data, int type, int notify, int persistent) +static void acknowledge_host_problem(host *hst, char *ack_author, char *ack_data, int type, int notify, int persistent, time_t end_time) { time_t current_time = 0L; @@ -3966,7 +3983,15 @@ static void acknowledge_host_problem(host *hst, char *ack_author, char *ack_data if (hst->current_state == STATE_UP) return; - broker_acknowledgement_data(NEBTYPE_ACKNOWLEDGEMENT_ADD, NEBFLAG_NONE, NEBATTR_NONE, HOST_ACKNOWLEDGEMENT, (void *)hst, ack_author, ack_data, type, notify, persistent); + /* get the time */ + time(¤t_time); + + /* if the end time is set but in the past, it has already expired + and we don't need to do anything */ + if (end_time > 0 && end_time <= current_time) + return; + + broker_acknowledgement_data(NEBTYPE_ACKNOWLEDGEMENT_ADD, NEBFLAG_NONE, NEBATTR_NONE, HOST_ACKNOWLEDGEMENT, (void *)hst, ack_author, ack_data, type, notify, persistent, end_time); /* send out an acknowledgement notification */ if (notify == TRUE) @@ -3978,19 +4003,25 @@ static void acknowledge_host_problem(host *hst, char *ack_author, char *ack_data /* set the acknowledgement type */ hst->acknowledgement_type = type ? ACKNOWLEDGEMENT_STICKY : ACKNOWLEDGEMENT_NORMAL; + /* if the ack expires in the future, schedule an event to clear it */ + if (end_time > current_time) + schedule_event(end_time - current_time, handle_host_acknowledgement_expire_event, (void *)hst); + + /* set the acknowledgement expire time */ + hst->acknowledgement_end_time = end_time; + /* update the status log with the host info */ update_host_status(hst, FALSE); /* add a comment for the acknowledgement */ - time(¤t_time); - add_new_host_comment(ACKNOWLEDGEMENT_COMMENT, hst->name, current_time, ack_author, ack_data, persistent, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, NULL); + add_new_host_comment(ACKNOWLEDGEMENT_COMMENT, hst->name, current_time, ack_author, ack_data, persistent, COMMENTSOURCE_INTERNAL, (end_time != 0) ? TRUE : FALSE, end_time, NULL); return; } /* acknowledges a service problem */ -static void acknowledge_service_problem(service *svc, char *ack_author, char *ack_data, int type, int notify, int persistent) +static void acknowledge_service_problem(service *svc, char *ack_author, char *ack_data, int type, int notify, int persistent, time_t end_time) { time_t current_time = 0L; @@ -3998,7 +4029,15 @@ static void acknowledge_service_problem(service *svc, char *ack_author, char *ac if (svc->current_state == STATE_OK) return; - broker_acknowledgement_data(NEBTYPE_ACKNOWLEDGEMENT_ADD, NEBFLAG_NONE, NEBATTR_NONE, SERVICE_ACKNOWLEDGEMENT, (void *)svc, ack_author, ack_data, type, notify, persistent); + /* get the time */ + time(¤t_time); + + /* if the end time is set but in the past, it has already expired + and we don't need to do anything */ + if (end_time > 0 && end_time <= current_time) + return; + + broker_acknowledgement_data(NEBTYPE_ACKNOWLEDGEMENT_ADD, NEBFLAG_NONE, NEBATTR_NONE, SERVICE_ACKNOWLEDGEMENT, (void *)svc, ack_author, ack_data, type, notify, persistent, end_time); /* send out an acknowledgement notification */ if (notify == TRUE) @@ -4010,12 +4049,18 @@ static void acknowledge_service_problem(service *svc, char *ack_author, char *ac /* set the acknowledgement type */ svc->acknowledgement_type = type ? ACKNOWLEDGEMENT_STICKY : ACKNOWLEDGEMENT_NORMAL; + /* if the ack expires in the future, schedule an event to clear it */ + if (end_time > current_time) + schedule_event(end_time - current_time, handle_service_acknowledgement_expire_event, (void *)svc); + + /* set the acknowledgement expire time */ + svc->acknowledgement_end_time = end_time; + /* update the status log with the service info */ update_service_status(svc, FALSE); /* add a comment for the acknowledgement */ - time(¤t_time); - add_new_service_comment(ACKNOWLEDGEMENT_COMMENT, svc->host_name, svc->description, current_time, ack_author, ack_data, persistent, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, NULL); + add_new_service_comment(ACKNOWLEDGEMENT_COMMENT, svc->host_name, svc->description, current_time, ack_author, ack_data, persistent, COMMENTSOURCE_INTERNAL, (end_time != 0) ? TRUE : FALSE, end_time, NULL); return; } @@ -4027,6 +4072,7 @@ static void remove_host_acknowledgement(host *hst) /* set the acknowledgement flag */ hst->problem_has_been_acknowledged = FALSE; + hst->acknowledgement_end_time = (time_t)0; /* update the status log with the host info */ update_host_status(hst, FALSE); @@ -4044,6 +4090,7 @@ static void remove_service_acknowledgement(service *svc) /* set the acknowledgement flag */ svc->problem_has_been_acknowledged = FALSE; + svc->acknowledgement_end_time = (time_t)0; /* update the status log with the service info */ update_service_status(svc, FALSE); @@ -4054,6 +4101,57 @@ static void remove_service_acknowledgement(service *svc) return; } +/* removes an expired host acknowledgement */ +void handle_host_acknowledgement_expire_event(struct nm_event_execution_properties *evprop) +{ + time_t current_time = 0L; + + log_debug_info(DEBUGL_EVENTS, 2, "Running event handler for host acknowledgement expiry\n"); + if (evprop->user_data) { + if (evprop->execution_type == EVENT_EXEC_NORMAL) { + /* get the host */ + host *hst = (host *)evprop->user_data; + + /* get the time */ + time(¤t_time); + + /* if the host ack has an end time now or in the + past, remove the ack */ + if (hst->problem_has_been_acknowledged && + hst->acknowledgement_end_time > 0 && + hst->acknowledgement_end_time <= current_time) { + log_debug_info(DEBUGL_EVENTS, 2, "Removing host acknowledgement for host '%s'\n", hst->name); + remove_host_acknowledgement(hst); + } + } + } +} + +/* removes an expired service acknowledgement */ +void handle_service_acknowledgement_expire_event(struct nm_event_execution_properties *evprop) +{ + time_t current_time = 0L; + + log_debug_info(DEBUGL_EVENTS, 2, "Running event handler for service acknowledgement expiry\n"); + if (evprop->user_data) { + if (evprop->execution_type == EVENT_EXEC_NORMAL) { + /* get the service */ + service *svc = (service *)evprop->user_data; + + /* get the time */ + time(¤t_time); + + /* if the service ack has an end time now or in the + past, remove the ack */ + if (svc->problem_has_been_acknowledged && + svc->acknowledgement_end_time > 0 && + svc->acknowledgement_end_time <= current_time) { + log_debug_info(DEBUGL_EVENTS, 2, "Removing service acknowledgement for service '%s' on host '%s'\n", svc->description, svc->host_name); + remove_service_acknowledgement(svc); + } + } + } +} /* starts executing service checks */ static void start_executing_service_checks(void) diff --git a/src/naemon/commands.h b/src/naemon/commands.h index b7539d99..21db023c 100644 --- a/src/naemon/commands.h +++ b/src/naemon/commands.h @@ -10,6 +10,7 @@ #include "objects_contact.h" #include "objects_host.h" #include "objects_service.h" +#include "events.h" NAGIOS_BEGIN_DECL @@ -220,6 +221,9 @@ int shutdown_command_file_worker(void); int disconnect_command_file_worker(void); int command_worker_get_pid(void); +void handle_host_acknowledgement_expire_event(struct nm_event_execution_properties *evprop); /* removes an expired host acknowledgement */ +void handle_service_acknowledgement_expire_event(struct nm_event_execution_properties *evprop); /* removes an expired service acknowledgement */ + NAGIOS_END_DECL #endif diff --git a/src/naemon/common.h b/src/naemon/common.h index a96c5eb9..44c6038e 100644 --- a/src/naemon/common.h +++ b/src/naemon/common.h @@ -322,6 +322,9 @@ NAGIOS_END_DECL #define CMD_DEL_DOWNTIME_BY_HOSTGROUP_NAME 171 #define CMD_DEL_DOWNTIME_BY_START_TIME_COMMENT 172 +#define CMD_ACKNOWLEDGE_HOST_PROBLEM_EXPIRE 173 +#define CMD_ACKNOWLEDGE_SVC_PROBLEM_EXPIRE 174 + /* custom command introduced in Nagios 3.x */ #define CMD_CUSTOM_COMMAND 999 diff --git a/src/naemon/events.c b/src/naemon/events.c index 8a37a399..f5441bdb 100644 --- a/src/naemon/events.c +++ b/src/naemon/events.c @@ -268,9 +268,20 @@ void init_event_queue(void) event_queue = evheap_create(); } -void destroy_event_queue(void) +void clear_event_queue(void) { struct timed_event *ev; + + if (event_queue == NULL) + return; + + while ((ev = evheap_head(event_queue)) != NULL) { + destroy_event(ev); + } +} + +void destroy_event_queue(void) +{ /* * Since naemon doesn't know if things is started, we can't trust that * destroy event queue actually means we have an event queue to destroy @@ -278,9 +289,7 @@ void destroy_event_queue(void) if (event_queue == NULL) return; - while ((ev = evheap_head(event_queue)) != NULL) { - destroy_event(ev); - } + clear_event_queue(); evheap_destroy(event_queue); event_queue = NULL; } diff --git a/src/naemon/events.h b/src/naemon/events.h index 38682613..b12dba2b 100644 --- a/src/naemon/events.h +++ b/src/naemon/events.h @@ -58,6 +58,7 @@ long get_timed_event_time_left_ms(timed_event *ev); /* Main function */ void init_event_queue(void); /* creates the queue nagios_squeue */ int event_poll(void); /* main monitoring/event handler loop */ +void clear_event_queue(void); /* remove all events from the event queue */ void destroy_event_queue(void); /* destroys the queue nagios_squeue */ NAGIOS_END_DECL diff --git a/src/naemon/nebstructs.h b/src/naemon/nebstructs.h index 68f701e0..76c72cc3 100644 --- a/src/naemon/nebstructs.h +++ b/src/naemon/nebstructs.h @@ -470,6 +470,7 @@ typedef struct nebstruct_acknowledgement_struct { int persistent_comment; int notify_contacts; void *object_ptr; + time_t end_time; } nebstruct_acknowledgement_data; diff --git a/src/naemon/objects_host.c b/src/naemon/objects_host.c index 8b0d8251..ca18d567 100644 --- a/src/naemon/objects_host.c +++ b/src/naemon/objects_host.c @@ -74,6 +74,7 @@ host *create_host(const char *name) new_host->check_type = CHECK_TYPE_ACTIVE; new_host->state_type = HARD_STATE; new_host->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + new_host->acknowledgement_end_time = (time_t)0; new_host->check_options = CHECK_OPTION_NONE; diff --git a/src/naemon/objects_host.h b/src/naemon/objects_host.h index 780a77f7..3609deb4 100644 --- a/src/naemon/objects_host.h +++ b/src/naemon/objects_host.h @@ -77,6 +77,7 @@ struct host { customvariablesmember *custom_variables; int problem_has_been_acknowledged; int acknowledgement_type; + time_t acknowledgement_end_time; int check_type; int current_state; int last_state; diff --git a/src/naemon/objects_service.c b/src/naemon/objects_service.c index 9950592a..020a61ab 100644 --- a/src/naemon/objects_service.c +++ b/src/naemon/objects_service.c @@ -80,6 +80,7 @@ service *create_service(host *hst, const char *description) new_service->description = nm_strdup(description); new_service->display_name = new_service->description; new_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + new_service->acknowledgement_end_time = (time_t)0; new_service->check_type = CHECK_TYPE_ACTIVE; new_service->state_type = HARD_STATE; new_service->check_options = CHECK_OPTION_NONE; diff --git a/src/naemon/objects_service.h b/src/naemon/objects_service.h index d8358ee0..4db85217 100644 --- a/src/naemon/objects_service.h +++ b/src/naemon/objects_service.h @@ -68,6 +68,7 @@ struct service { struct customvariablesmember *custom_variables; int problem_has_been_acknowledged; int acknowledgement_type; + time_t acknowledgement_end_time; int host_problem_at_last_check; int check_type; int current_state; diff --git a/src/naemon/xrddefault.c b/src/naemon/xrddefault.c index 1dc88859..4700597e 100644 --- a/src/naemon/xrddefault.c +++ b/src/naemon/xrddefault.c @@ -14,6 +14,8 @@ #include "defaults.h" #include "nm_alloc.h" #include "broker.h" +#include "events.h" +#include "commands.h" #include /******************************************************************/ @@ -203,6 +205,7 @@ int xrddefault_save_state_information(void) } fprintf(fp, "problem_has_been_acknowledged=%d\n", temp_host->problem_has_been_acknowledged); fprintf(fp, "acknowledgement_type=%d\n", temp_host->acknowledgement_type); + fprintf(fp, "acknowledgement_end_time=%lu\n", temp_host->acknowledgement_end_time); if (conf_host && conf_host->checks_enabled != temp_host->checks_enabled) { fprintf(fp, "config:active_checks_enabled=%d\n", conf_host->checks_enabled); fprintf(fp, "active_checks_enabled=%d\n", temp_host->checks_enabled); @@ -311,6 +314,7 @@ int xrddefault_save_state_information(void) } fprintf(fp, "problem_has_been_acknowledged=%d\n", temp_service->problem_has_been_acknowledged); fprintf(fp, "acknowledgement_type=%d\n", temp_service->acknowledgement_type); + fprintf(fp, "acknowledgement_end_time=%lu\n", temp_service->acknowledgement_end_time); if (conf_svc && conf_svc->flap_detection_enabled != temp_service->flap_detection_enabled) { fprintf(fp, "config:flap_detection_enabled=%d\n", conf_svc->flap_detection_enabled); fprintf(fp, "flap_detection_enabled=%d\n", temp_service->flap_detection_enabled); @@ -634,6 +638,23 @@ int xrddefault_read_state_information(void) if (temp_host->last_hard_state_change == (time_t)0) temp_host->last_hard_state_change = temp_host->last_state_change; + /* if there was an expiring ack */ + if (temp_host->problem_has_been_acknowledged && temp_host->acknowledgement_end_time > 0) { + + /* get the time */ + time(¤t_time); + + /* and if the expiry time is in the future */ + if (temp_host->acknowledgement_end_time > current_time) { + /* schedule the expiry event */ + schedule_event(temp_host->acknowledgement_end_time - current_time, handle_host_acknowledgement_expire_event, (void *)temp_host); + } else { + /* otherwise unacknowledge the problem */ + temp_host->problem_has_been_acknowledged = FALSE; + temp_host->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_host->acknowledgement_end_time = (time_t)0; + } + } /* update host status */ update_host_status(temp_host, FALSE); } @@ -676,6 +697,23 @@ int xrddefault_read_state_information(void) if (temp_service->last_hard_state_change == (time_t)0) temp_service->last_hard_state_change = temp_service->last_state_change; + /* if there was an expiring ack */ + if (temp_service->problem_has_been_acknowledged && temp_service->acknowledgement_end_time > 0) { + + /* get the time */ + time(¤t_time); + + /* and if the expiry time is in the future */ + if (temp_service->acknowledgement_end_time > current_time) { + /* schedule the expiry event */ + schedule_event(temp_service->acknowledgement_end_time - current_time, handle_service_acknowledgement_expire_event, (void *)temp_service); + } else { + /* otherwise unacknowledge the problem */ + temp_service->problem_has_been_acknowledged = FALSE; + temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + temp_service->acknowledgement_end_time = (time_t)0; + } + } /* update service status */ update_service_status(temp_service, FALSE); } @@ -1092,6 +1130,8 @@ int xrddefault_read_state_information(void) temp_host->problem_has_been_acknowledged = (atoi(val) > 0) ? TRUE : FALSE; } else if (!strcmp(var, "acknowledgement_type")) { temp_host->acknowledgement_type = atoi(val); + } else if (!strcmp(var, "acknowledgement_end_time")) { + temp_host->acknowledgement_end_time = strtoul(val, NULL, 10); } else if (!strcmp(var, "notifications_enabled")) { RETAIN_BOOL(host, temp_host, notifications_enabled, MODATTR_NOTIFICATIONS_ENABLED); } else if (!strcmp(var, "active_checks_enabled")) { @@ -1355,6 +1395,8 @@ int xrddefault_read_state_information(void) temp_service->problem_has_been_acknowledged = (atoi(val) > 0) ? TRUE : FALSE; } else if (!strcmp(var, "acknowledgement_type")) { temp_service->acknowledgement_type = atoi(val); + } else if (!strcmp(var, "acknowledgement_end_time")) { + temp_service->acknowledgement_end_time = strtoul(val, NULL, 10); } else if (!strcmp(var, "notifications_enabled")) { RETAIN_BOOL(service, temp_service, notifications_enabled, MODATTR_NOTIFICATIONS_ENABLED); } else if (!strcmp(var, "active_checks_enabled")) { diff --git a/src/naemon/xsddefault.c b/src/naemon/xsddefault.c index c4ee72db..35e8b997 100644 --- a/src/naemon/xsddefault.c +++ b/src/naemon/xsddefault.c @@ -222,6 +222,7 @@ int xsddefault_save_status_data(void) fprintf(fp, "\tnotifications_enabled=%d\n", temp_host->notifications_enabled); fprintf(fp, "\tproblem_has_been_acknowledged=%d\n", temp_host->problem_has_been_acknowledged); fprintf(fp, "\tacknowledgement_type=%d\n", temp_host->acknowledgement_type); + fprintf(fp, "\tacknowledgement_end_time=%lu\n", temp_host->acknowledgement_end_time); fprintf(fp, "\tactive_checks_enabled=%d\n", temp_host->checks_enabled); fprintf(fp, "\tpassive_checks_enabled=%d\n", temp_host->accept_passive_checks); fprintf(fp, "\tevent_handler_enabled=%d\n", temp_host->event_handler_enabled); @@ -292,6 +293,7 @@ int xsddefault_save_status_data(void) fprintf(fp, "\tevent_handler_enabled=%d\n", temp_service->event_handler_enabled); fprintf(fp, "\tproblem_has_been_acknowledged=%d\n", temp_service->problem_has_been_acknowledged); fprintf(fp, "\tacknowledgement_type=%d\n", temp_service->acknowledgement_type); + fprintf(fp, "\tacknowledgement_end_time=%lu\n", temp_service->acknowledgement_end_time); fprintf(fp, "\tflap_detection_enabled=%d\n", temp_service->flap_detection_enabled); fprintf(fp, "\tprocess_performance_data=%d\n", temp_service->process_performance_data); fprintf(fp, "\tobsess=%d\n", temp_service->obsess); diff --git a/t-tap/test_commands.c b/t-tap/test_commands.c index e72d4e38..b8af68fd 100644 --- a/t-tap/test_commands.c +++ b/t-tap/test_commands.c @@ -509,6 +509,29 @@ void test_host_commands(void) ok(!target_host->problem_has_been_acknowledged, "REMOVE_HOST_ACKNOWLEDGEMENT removes a host acknowledgement"); target_host->current_state = STATE_UP; + target_host->current_state = STATE_DOWN; + ok(CMD_ERROR_OK == process_external_command1("[1234567890] ACKNOWLEDGE_HOST_PROBLEM_EXPIRE;host1;2;0;0;4102441200;myself;expire in the future"), "core command: ACKNOWLEDGE_HOST_PROBLEM_EXPIRE"); + ok(target_host->problem_has_been_acknowledged, "ACKNOWLEDGE_HOST_PROBLEM_EXPIRE with future end_time acknowledges a host problem"); + + ok(CMD_ERROR_OK == process_external_command1("[1234567890] REMOVE_HOST_ACKNOWLEDGEMENT;host1"), "core command: REMOVE_HOST_ACKNOWLEDGEMENT"); + ok(!target_host->problem_has_been_acknowledged, "REMOVE_HOST_ACKNOWLEDGEMENT removes a host acknowledgement with expiry"); + target_host->current_state = STATE_UP; + + target_host->current_state = STATE_DOWN; + ok(CMD_ERROR_OK == process_external_command1("[1234567890] ACKNOWLEDGE_HOST_PROBLEM_EXPIRE;host1;2;0;0;946681200;myself;expire in the past"), "core command: ACKNOWLEDGE_HOST_PROBLEM_EXPIRE"); + ok(!target_host->problem_has_been_acknowledged, "ACKNOWLEDGE_HOST_PROBLEM_EXPIRE with past end_time doesn't acknowledge a host problem"); + target_host->current_state = STATE_UP; + + clear_event_queue(); + target_host->current_state = STATE_DOWN; + nm_asprintf(&cmdstr, "[1234567890] ACKNOWLEDGE_HOST_PROBLEM_EXPIRE;host1;2;0;0;%llu;myself;expire in two seconds", (unsigned long long int)time(NULL)+2); + ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: ACKNOWLEDGE_HOST_PROBLEM_EXPIRE"); + ok(target_host->problem_has_been_acknowledged, "ACKNOWLEDGE_HOST_PROBLEM_EXPIRE acknowledgement present before event"); + sleep(3); + event_poll(); + ok(!target_host->problem_has_been_acknowledged, "ACKNOWLEDGE_HOST_PROBLEM_EXPIRE acknowledgement gone after event"); + free(cmdstr); + ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_EVENT_HANDLER;host1"), "core command: DISABLE_HOST_EVENT_HANDLER"); ok(!target_host->event_handler_enabled, "DISABLE_HOST_EVENT_HANDLER disables event handler for a host"); @@ -691,7 +714,7 @@ void test_core_commands(void) int main(int /*@unused@*/ argc, char /*@unused@*/ **arv) { const char *test_config_file = TESTDIR "naemon.cfg"; - plan_tests(510); + plan_tests(519); init_event_queue(); config_file_dir = nspath_absolute_dirname(test_config_file, NULL); @@ -699,6 +722,7 @@ int main(int /*@unused@*/ argc, char /*@unused@*/ **arv) assert(OK == read_all_object_data(test_config_file)); assert(OK == initialize_downtime_data()); assert(OK == initialize_retention_data()); + nagios_iobs = iobroker_create(); test_register(); test_parsing(); test_core_commands();