Commit 4394714d authored by Alexander Wirt's avatar Alexander Wirt

Imported Upstream version 1.7.2

parent b64d2902
......@@ -4,6 +4,28 @@ Icinga 1.7.x Change Log
Thanks to all contributers, testers and developers. Please read AUTHORS and THANKS for a detailed list :-)
1.7.2 - 27/08/2012
FIXES
* core: fix duplicated events on check scheduling logic for new events (Andreas Ericsson) #2676 #2993 - MF
* core: avoid duplicate events when scheduling forced host|service check (Imri Zvik) #2993 - MF
* core: get rid of the instame macro usage while logging alerts and states (Andreas Ericsson) #2665 - MF
* core: revamp the detection of embedded perl usage directive "# icinga: +epn" (Andreas Ericsson) #2197 - MF
* core: fix whitespaces are not stripped using multiple templates ("use abc, def, ghi") #2701 - MF
* core: add hint on icinga.cfg package location, and tip to read Changelog CHANGES on upgrades #2879 - MF
* core: bail out early with config error if resource.cfg macros contain NULL values #2879 - MF
* core: fix logical bug on icinga.cfg detection on config read #2879 - MF
* core: fsync() files before fclose() (Andreas Ericsson) #2948 - MF
* core: remove weird switch() statement when scanning checkresult queue (Andreas Ericsson) #2950 - MF
* core: fix deleting too old check result files (Andreas Ericsson) #2951 - MF
* idoutils: fix icinga mysql db creation script grants access to all dbs #2917 - MF
* idoutils: fix ignoring mysql password in create_mysqldb.sh #2994 - MF
* icinga.spec: forced update on icinga.cfg change package locations #2923 -MF
* icinga.spec: fix permissions on ido2db.cfg potentially world readable (Aaron Russo) #2897 - MF
1.7.1 - 18/06/2012
FIXES
......
......@@ -78,7 +78,7 @@ MKDIR=/bin/mkdir
###############################
# Global
###############################
ICINGA_VERSION=1.7.1
ICINGA_VERSION=1.7.2
CP=@CP@
......
......@@ -343,3 +343,4 @@ in various ways. If we missed your name, let us know.
* Michal Zimen
* Dennis van Zuijlekom
* Pawel Zuzelski
* Imri Zvik
......@@ -588,13 +588,15 @@ int run_async_service_check(service *svc, int check_options, double latency, int
/* process any macros contained in the argument */
process_macros_r(&mac, raw_command, &processed_command, 0);
my_free(raw_command);
if (processed_command == NULL) {
clear_volatile_macros_r(&mac);
log_debug_info(DEBUGL_CHECKS, 0, "Processed check command for service '%s' on host '%s' was NULL - aborting.\n", svc->description, svc->host_name);
if (preferred_time)
*preferred_time += (svc->check_interval * interval_length);
svc->latency = old_latency;
my_free(raw_command);
return ERROR;
}
......@@ -613,7 +615,6 @@ int run_async_service_check(service *svc, int check_options, double latency, int
clear_volatile_macros_r(&mac);
svc->latency = old_latency;
my_free(processed_command);
my_free(raw_command);
return OK;
}
#endif
......@@ -1881,15 +1882,6 @@ void schedule_service_check(service *svc, time_t check_time, int options) {
return;
}
/* allocate memory for a new event item */
new_event = (timed_event *)malloc(sizeof(timed_event));
if (new_event == NULL) {
logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of service '%s' on host '%s'!\n", svc->description, svc->host_name);
return;
}
/* default is to use the new event */
use_original_event = FALSE;
......@@ -1903,7 +1895,7 @@ void schedule_service_check(service *svc, time_t check_time, int options) {
*/
if (temp_event != NULL) {
log_debug_info(DEBUGL_CHECKS, 2, "Found another service check event for this service @ %s", ctime(&temp_event->run_time));
log_debug_info(DEBUGL_CHECKS, 2, "Found another service check event for service '%s' on host '%s' @ %s", svc->description, svc->host_name, ctime(&temp_event->run_time));
/* use the originally scheduled check unless we decide otherwise */
use_original_event = TRUE;
......@@ -1938,32 +1930,39 @@ void schedule_service_check(service *svc, time_t check_time, int options) {
log_debug_info(DEBUGL_CHECKS, 2, "New service check event occurs after the existing event, so we'll ignore it.\n");
}
}
}
/* the originally queued event won the battle, so keep it */
if (use_original_event == TRUE) {
my_free(new_event);
/*
* we can't use the original event,
* so schedule a new event
*/
if (use_original_event == FALSE) {
log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new service check event for '%s' on host '%s' @ %s", svc->description, svc->host_name, ctime(&check_time));
/* allocate memory for a new event item */
new_event = (timed_event *)malloc(sizeof(timed_event));
if (new_event == NULL) {
logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of service '%s' on host '%s'!\n", svc->description, svc->host_name);
return;
}
/* else we're using the new event, so remove the old one */
else {
/* make sure we kill off the old event */
if (temp_event) {
log_debug_info(DEBUGL_CHECKS, 2, "Removing service check event for service '%s' on host '%s' @ %s", svc->description, svc->host_name, ctime(&temp_event->run_time));
remove_event(temp_event, &event_list_low, &event_list_low_tail);
/* save new event for later */
svc->next_check_event = new_event;
my_free(temp_event);
}
}
/* save check options for retention purposes */
svc->check_options = options;
/* schedule a new event */
if (use_original_event == FALSE) {
log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new service check event.\n");
/* set the next service check time */
/* set the next service check event and time */
svc->next_check_event = new_event;
svc->next_check = check_time;
/* save check options for retention purposes */
svc->check_options = options;
/* place the new event in the event queue */
new_event->event_type = EVENT_SERVICE_CHECK;
new_event->event_data = (void *)svc;
......@@ -2360,14 +2359,6 @@ void schedule_host_check(host *hst, time_t check_time, int options) {
return;
}
/* allocate memory for a new event item */
if ((new_event = (timed_event *)malloc(sizeof(timed_event))) == NULL) {
logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of host '%s'!\n", hst->name);
return;
}
/* default is to use the new event */
use_original_event = FALSE;
......@@ -2381,7 +2372,7 @@ void schedule_host_check(host *hst, time_t check_time, int options) {
*/
if (temp_event != NULL) {
log_debug_info(DEBUGL_CHECKS, 2, "Found another host check event for this host @ %s", ctime(&temp_event->run_time));
log_debug_info(DEBUGL_CHECKS, 2, "Found another host check event for host '%s' @ %s", hst->name, ctime(&temp_event->run_time));
/* use the originally scheduled check unless we decide otherwise */
use_original_event = TRUE;
......@@ -2416,32 +2407,35 @@ void schedule_host_check(host *hst, time_t check_time, int options) {
log_debug_info(DEBUGL_CHECKS, 2, "New host check event occurs after the existing event, so we'll ignore it.\n");
}
}
}
/* the originally queued event won the battle, so keep it */
if (use_original_event == TRUE) {
my_free(new_event);
/*
* we can't use the original event,
* so schedule a new event
*/
if (use_original_event == FALSE) {
log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new host check event for '%s' @ %s", hst->name, ctime(&check_time));
/* allocate memory for a new event item */
if((new_event = (timed_event *)malloc(sizeof(timed_event))) == NULL) {
logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of host '%s'!\n", hst->name);
return;
}
/* else use the new event, so remove the old */
else {
if (temp_event) {
log_debug_info(DEBUGL_CHECKS, 2, "Removing host check event for host '%s' @ %s", hst->name, ctime(&temp_event->run_time));
remove_event(temp_event, &event_list_low, &event_list_low_tail);
/* save new event for later */
hst->next_check_event = new_event;
my_free(temp_event);
}
}
/* save check options for retention purposes */
hst->check_options = options;
/* use the new event */
if (use_original_event == FALSE) {
log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new host check event.\n");
/* set the next host check time */
/* set the next host check event and time */
hst->next_check_event = new_event;
hst->next_check = check_time;
/* save check options for retention purposes */
hst->check_options = options;
/* place the new event in the event queue */
new_event->event_type = EVENT_HOST_CHECK;
new_event->event_data = (void *)hst;
......@@ -2922,6 +2916,7 @@ int execute_sync_host_check_3x(host *hst) {
/* process any macros contained in the argument */
process_macros_r(&mac, raw_command, &processed_command, 0);
if (processed_command == NULL) {
my_free(raw_command);
clear_volatile_macros_r(&mac);
return ERROR;
}
......@@ -2938,6 +2933,7 @@ int execute_sync_host_check_3x(host *hst) {
log_debug_info(DEBUGL_COMMANDS, 1, "Raw host check command: %s\n", raw_command);
log_debug_info(DEBUGL_COMMANDS, 0, "Processed host check ommand: %s\n", processed_command);
my_free(raw_command);
/* clear plugin output and performance data buffers */
my_free(hst->plugin_output);
......@@ -2969,7 +2965,6 @@ int execute_sync_host_check_3x(host *hst) {
/* free memory */
my_free(temp_plugin_output);
my_free(raw_command);
my_free(processed_command);
/* a NULL host check command means we should assume the host is UP */
......@@ -3191,6 +3186,9 @@ int run_async_host_check_3x(host *hst, int check_options, double latency, int sc
/* process any macros contained in the argument */
process_macros_r(&mac, raw_command, &processed_command, 0);
my_free(raw_command);
if (processed_command == NULL) {
clear_volatile_macros_r(&mac);
log_debug_info(DEBUGL_CHECKS, 0, "Processed check command for host '%s' was NULL - aborting.\n", hst->name);
......
......@@ -346,7 +346,11 @@ int read_main_config_file(char *main_config_file) {
mac->x[MACRO_RESOURCEFILE] = (char *)strdup(value);
/* process the resource file */
read_resource_file(value);
if(read_resource_file(value) == ERROR) {
dummy = asprintf(&error_message, "Resource file parsing failed");
error = TRUE;
break;
}
}
else if (!strcmp(variable, "log_file")) {
......
......@@ -929,6 +929,22 @@ int schedule_new_event(int event_type, int high_priority, time_t run_time, int r
new_event->event_interval = event_interval;
new_event->timing_func = timing_func;
new_event->compensate_for_time_change = compensate_for_time_change;
/*
* we need to keep the reverse link from the (service|host *)event_data->next_check_event
* to the new_event in order to stay sane on schedule_host|service_check() checks
* later on, already having a new event assigned to host/service, not rescheduling a new event.
* see #2993 for deeper analysis
*/
if (event_type == EVENT_SERVICE_CHECK) {
service *temp_service = (service *)event_data;
temp_service->next_check_event = new_event;
log_debug_info(DEBUGL_CHECKS, 2, "Service '%s' on Host '%s' next_check_event populated\n", temp_service->description, temp_service->host_name);
}
if (event_type == EVENT_HOST_CHECK) {
host *temp_host = (host *)event_data;
temp_host->next_check_event = new_event;
log_debug_info(DEBUGL_CHECKS, 2, "Host '%s' next_check_event populated\n", temp_host->name);
}
} else
return ERROR;
......
......@@ -521,12 +521,13 @@ int main(int argc, char **argv, char **env) {
if (result != OK) {
/* if the config filename looks fishy, warn the user */
if (!strstr(config_file, "nagios.cfg") || !strstr(config_file, "icinga.cfg")) {
if (!strstr(config_file, "nagios.cfg") && !strstr(config_file, "icinga.cfg")) {
printf("\n***> The name of the main configuration file looks suspicious...\n");
printf("\n");
printf(" Make sure you are specifying the name of the MAIN configuration file on\n");
printf(" the command line and not the name of another configuration file. The\n");
printf(" main configuration file is typically '/usr/local/icinga/etc/icinga.cfg'\n");
printf(" or if using packages, most likely '/etc/icinga/icinga.cfg'\n");
}
printf("\n***> One or more problems was encountered while processing the config files...\n");
......@@ -536,7 +537,8 @@ int main(int argc, char **argv, char **env) {
printf(" version of %s, you should be aware that some variables/definitions\n", PROGRAM_NAME);
printf(" may have been removed or modified in this version. Make sure to read\n");
printf(" the HTML documentation regarding the config files, as well as the\n");
printf(" 'Whats New' section to find out what has changed.\n\n");
printf(" 'Whats New' section and the Changelog CHANGES section as well to find\n");
printf(" out what has changed.\n\n");
}
/* the config files were okay, so run the pre-flight check */
......
......@@ -68,6 +68,40 @@ int dummy; /* reduce compiler warnings */
static pthread_mutex_t debug_fp_lock;
/*
* add state translation helpers
* to prevent extatic macro grabbing
*/
static const char *service_state_name(int state) {
switch (state) {
case STATE_OK:
return "OK";
case STATE_WARNING:
return "WARNING";
case STATE_CRITICAL:
return "CRITICAL";
}
return "UNKNOWN";
}
static const char *host_state_name(int state) {
switch (state) {
case HOST_UP:
return "UP";
case HOST_DOWN:
return "DOWN";
case HOST_UNREACHABLE:
return "UNREACHABLE";
}
return "(unknown)";
}
static const char *state_type_name(int state_type) {
return state_type == HARD_STATE ? "HARD" : "SOFT";
}
/*
* since we don't want child processes to hang indefinitely
* in case they inherit a locked lock, we use soft-locking
......@@ -284,10 +318,8 @@ int write_to_syslog(char *buffer, unsigned long data_type) {
/* write a service problem/recovery to the icinga log file */
int log_service_event(service *svc) {
char *temp_buffer = NULL;
char *processed_buffer = NULL;
unsigned long log_options = 0L;
host *temp_host = NULL;
icinga_macros mac;
/* don't log soft errors if the user doesn't want to */
if (svc->state_type == SOFT_STATE && !log_service_retries)
......@@ -307,27 +339,28 @@ int log_service_event(service *svc) {
if ((temp_host = svc->host_ptr) == NULL)
return ERROR;
/* grab service macros */
memset(&mac, 0, sizeof(mac));
grab_host_macros_r(&mac, temp_host);
grab_service_macros_r(&mac, svc);
/* XXX: replace the macro madness with some simple helpers instead */
/* either log only the output, or if enabled, add long_output */
if (log_long_plugin_output == TRUE && svc->long_plugin_output != NULL) {
dummy = asprintf(&temp_buffer, "SERVICE ALERT: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\\n%s\n", svc->host_name, svc->description, (svc->plugin_output == NULL) ? "" : svc->plugin_output, svc->long_plugin_output);
dummy = asprintf(&temp_buffer, "SERVICE ALERT: %s;%s;%s;%s;%d;%s\\n%s\n",
svc->host_name, svc->description,
service_state_name(svc->current_state),
state_type_name(svc->state_type),
svc->current_attempt,
(svc->plugin_output == NULL) ? "" : svc->plugin_output,
svc->long_plugin_output
);
} else {
dummy = asprintf(&temp_buffer, "SERVICE ALERT: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\n", svc->host_name, svc->description, (svc->plugin_output == NULL) ? "" : svc->plugin_output);
dummy = asprintf(&temp_buffer, "SERVICE ALERT: %s;%s;%s;%s;%d;%s\n",
svc->host_name, svc->description,
service_state_name(svc->current_state),
state_type_name(svc->state_type),
svc->current_attempt,
(svc->plugin_output == NULL) ? "" : svc->plugin_output
);
}
process_macros_r(&mac, temp_buffer, &processed_buffer, 0);
clear_host_macros_r(&mac);
clear_service_macros_r(&mac);
write_to_all_logs(processed_buffer, log_options);
write_to_all_logs(temp_buffer, log_options);
my_free(temp_buffer);
my_free(processed_buffer);
return OK;
}
......@@ -336,13 +369,7 @@ int log_service_event(service *svc) {
/* write a host problem/recovery to the log file */
int log_host_event(host *hst) {
char *temp_buffer = NULL;
char *processed_buffer = NULL;
unsigned long log_options = 0L;
icinga_macros mac;
/* grab the host macros */
memset(&mac, 0, sizeof(mac));
grab_host_macros_r(&mac, hst);
/* get the log options */
if (hst->current_state == HOST_DOWN)
......@@ -352,21 +379,28 @@ int log_host_event(host *hst) {
else
log_options = NSLOG_HOST_UP;
/* XXX: replace the macro madness with some simple helpers instead */
/* either log only the output, or if enabled, add long_output */
if (log_long_plugin_output == TRUE && hst->long_plugin_output != NULL) {
dummy = asprintf(&temp_buffer, "HOST ALERT: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\\n%s\n", hst->name, (hst->plugin_output == NULL) ? "" : hst->plugin_output, hst->long_plugin_output);
dummy = asprintf(&temp_buffer, "HOST ALERT: %s;%s;%s;%d;%s\\n%s\n",
hst->name,
host_state_name(hst->current_state),
state_type_name(hst->state_type),
hst->current_attempt,
(hst->plugin_output == NULL) ? "" : hst->plugin_output,
hst->long_plugin_output
);
} else {
dummy = asprintf(&temp_buffer, "HOST ALERT: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\n", hst->name, (hst->plugin_output == NULL) ? "" : hst->plugin_output);
dummy = asprintf(&temp_buffer, "HOST ALERT: %s;%s;%s;%d;%s\n",
hst->name,
host_state_name(hst->current_state),
state_type_name(hst->state_type),
hst->current_attempt,
(hst->plugin_output == NULL) ? "" : hst->plugin_output
);
}
process_macros_r(&mac, temp_buffer, &processed_buffer, 0);
write_to_all_logs(processed_buffer, log_options);
clear_host_macros_r(&mac);
write_to_all_logs(temp_buffer, log_options);
my_free(temp_buffer);
my_free(processed_buffer);
return OK;
}
......@@ -375,30 +409,26 @@ int log_host_event(host *hst) {
/* logs host states */
int log_host_states(int type, time_t *timestamp) {
char *temp_buffer = NULL;
char *processed_buffer = NULL;
host *temp_host = NULL;
icinga_macros mac;
/* bail if we shouldn't be logging initial states */
if (type == INITIAL_STATES && log_initial_states == FALSE)
return OK;
memset(&mac, 0, sizeof(mac));
for (temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
/* grab the host macros */
grab_host_macros_r(&mac, temp_host);
dummy = asprintf(&temp_buffer, "%s HOST STATE: %s;%s;%s;%d;%s\n",
(type == INITIAL_STATES) ? "INITIAL" : "CURRENT",
temp_host->name,
host_state_name(temp_host->current_state),
state_type_name(temp_host->state_type),
temp_host->current_attempt,
(temp_host->plugin_output == NULL) ? "" : temp_host->plugin_output
);
dummy = asprintf(&temp_buffer, "%s HOST STATE: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\n", (type == INITIAL_STATES) ? "INITIAL" : "CURRENT", temp_host->name, (temp_host->plugin_output == NULL) ? "" : temp_host->plugin_output);
process_macros_r(&mac, temp_buffer, &processed_buffer, 0);
write_to_all_logs_with_timestamp(processed_buffer, NSLOG_INFO_MESSAGE, timestamp);
clear_host_macros_r(&mac);
write_to_all_logs_with_timestamp(temp_buffer, NSLOG_INFO_MESSAGE, timestamp);
my_free(temp_buffer);
my_free(processed_buffer);
}
return OK;
......@@ -408,38 +438,32 @@ int log_host_states(int type, time_t *timestamp) {
/* logs service states */
int log_service_states(int type, time_t *timestamp) {
char *temp_buffer = NULL;
char *processed_buffer = NULL;
service *temp_service = NULL;
host *temp_host = NULL;
icinga_macros mac;