/* * bronx_nagios.c -- Functions for interfacing with nagios. * * Copyright (C) 2008 Groundwork Open Source * Written by Daniel Emmanuel Feinsmith * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301, USA. * * Change Log: * DEF Created on September 17, 2007, 1:00 PM */ #include "bronx.h" #include "bronx_log.h" /* * Globals. */ apr_pool_t *_auto_add_pool; apr_thread_mutex_t *_auto_add_mutex; apr_queue_t *_auto_add_queue; int _auto_add_initialized=0; /* * Nagios Externals. */ extern circular_buffer external_command_buffer; extern int external_command_buffer_slots; extern circular_buffer service_result_buffer; extern int check_result_buffer_slots; extern service *service_list; extern host *host_list; /* * Functionality. */ void insert_into_service_result_buffer(service_message *svc_msg) { service_message *new_message; //bronx_logprintf(BRONX_LOGGING_DEBUG, "{insert_into_service_result_buffer} check_buffer_slots=%d, buffer items=%d",check_result_buffer_slots, service_result_buffer.items); new_message=(service_message *)malloc(sizeof(service_message)); memcpy(new_message,svc_msg,sizeof(service_message)); /* obtain a lock for writing to the buffer */ pthread_mutex_lock(&service_result_buffer.buffer_lock); /* handle overflow conditions */ if(service_result_buffer.items==check_result_buffer_slots) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{insert_into_service_result_buffer} Warning: Service Result Buffer Overflow, Items In Buffer=%d", service_result_buffer.items); /* record overflow */ service_result_buffer.overflow++; /* update tail pointer */ service_result_buffer.tail=(service_result_buffer.tail + 1) % check_result_buffer_slots; } /* save the data to the buffer */ ((service_message **)service_result_buffer.buffer)[service_result_buffer.head]=new_message; /* increment the head counter and items */ service_result_buffer.head=(service_result_buffer.head + 1) % check_result_buffer_slots; if(service_result_buffer.itemsservice_result_buffer.high) service_result_buffer.high=service_result_buffer.items; /* release lock on buffer */ pthread_mutex_unlock(&service_result_buffer.buffer_lock); } service * find_service_only(char *svc_description) { service *temp_service; bronx_logprintf(BRONX_LOGGING_DEBUG, "{find_service_only} Top Of Loop"); for (temp_service=service_list; temp_service; temp_service=temp_service->next) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{find_service_only} Looping, service='%s'", temp_service->description); if (!strcmp(temp_service->description, svc_description)) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{find_service_only} Exiting good"); return(temp_service); } } bronx_logprintf(BRONX_LOGGING_DEBUG, "{find_service_only} Exiting bad"); return(NULL); } apr_status_t auto_add(char *host_name, char *svc_description) { host *hst; service *svc; service *mirror_svc; apr_status_t result=ERROR; // // Do we need to add the host? // bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} auto_add, host=%s, svc=%s, checking for mirror service", host_name, svc_description); mirror_svc = find_service_only(svc_description); if (mirror_svc != NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Found a mirror service, searching for host"); if ((hst = find_host(host_name)) == NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Could not find host, adding it"); hst = auto_add_nagios_host(mirror_svc, host_name); } if (hst != NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Trying to add nagios service"); if ((svc = auto_add_nagios_service(mirror_svc, hst, svc_description)) != NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Added service, outputting to file!!!"); if (_configuration->listener_auto_add_log == NULL) bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} FILE pointer is NULL!!!"); else { fprintf(_configuration->listener_auto_add_log, "%s,%s\n", hst->name, svc->description); fflush(_configuration->listener_auto_add_log); bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Wrote successfully!!!"); } result = APR_SUCCESS; } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Failed to add service!!!!"); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Host is messed up"); } else bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add} Error: Could not find mirror service '%s'", svc_description); return(result); } void auto_add_nagios_service_to_cache(service *svc) { FILE *fp; bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_service_to_cache} Opening object cache file='%s'", _configuration->listener_auto_add_objects_cache); if ((fp = fopen(_configuration->listener_auto_add_objects_cache, "a")) != NULL) { fprintf(fp, "define service {\n\thost_name\t%s\n\tservice_description\t%s\n\tcheck_period\t24x7\n\tcheck_command\tcheck_alive\n\tcontact_groups\tnagiosadmin\n\tnotification_period\t24x7\n\tnormal_check_interval\t10\n\tretry_check_interval\t1\n\tmax_check_attempts\t1\n\tis_volatile\t0\n\tparallelize_check\t1\n\tactive_checks_enabled\t0\n\tpassive_checks_enabled\t1\n\tobsess_over_service\t1\n\tevent_handler_enabled\t1\n\tlow_flap_threshold\t0.000000\n\thigh_flap_threshold\t0.000000\n\tflap_detection_enabled\t1\n\tfreshness_threshold\t0\n\tcheck_freshness\t0\n\tnotification_options\tu,w,c,r\n\tnotifications_enabled\t1\n\tnotification_interval\t60\n\tstalking_options\tn\n\tprocess_perf_data\t1\n\tfailure_prediction_enabled\t1\n\tretain_status_information\t1\n\tretain_nonstatus_information\t1\n\t}\n\n", svc->host_name, svc->description); fclose(fp); } else bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_service_to_cache} failed to open object cache file='%s'", _configuration->listener_auto_add_objects_cache); } void auto_add_nagios_host_to_cache(host *hst) { FILE *fp; bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host_to_cache} Opening object cache file='%s'", _configuration->listener_auto_add_objects_cache); if ((fp = fopen(_configuration->listener_auto_add_objects_cache, "a")) != NULL) { bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host_to_cache} Adding! Hostname = %s", hst->name); fprintf(fp, "define host {\n\thost_name\t%s\n\talias\t%s\n\taddress\t172.28.111.3\n\tcheck_period\t24x7\n\tcheck_command\tcheck-host-alive\n\tcontact_groups\tnagiosadmin\n\tnotification_period\t24x7\n\tcheck_interval\t0\n\tmax_check_attempts\t3\n\tactive_checks_enabled\t1\n\tpassive_checks_enabled\t1\n\tobsess_over_host\t0\n\tevent_handler_enabled\t1\n\tlow_flap_threshold\t0.000000\n\thigh_flap_threshold\t0.000000\n\tflap_detection_enabled\t1\n\tfreshness_threshold\t0\n\tcheck_freshness\t0\n\tnotification_options\td,u,r\n\tnotifications_enabled\t1\n\tnotification_interval\t60\n\tstalking_options\tn\n\tprocess_perf_data\t1\n\tfailure_prediction_enabled\t1\n\tretain_status_information\t1\n\tretain_nonstatus_information\t1\n\t}\n\n", hst->name, hst->name); fclose(fp); } else bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host_to_cache} failed to open object cache file='%s'", _configuration->listener_auto_add_objects_cache); } host * auto_add_nagios_host(service *mirror_svc, char *host_name) { host *mirror_hst, *hst = NULL; bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host} mirror_svc='%s', host_name=%s", mirror_svc->description, host_name); mirror_hst = find_host(mirror_svc->host_name); if (mirror_hst != NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add} Found mirror host! Adding"); hst = add_host( host_name, // name host_name, // alias host_name, // ip address mirror_hst->check_period, mirror_hst->check_interval, mirror_hst->max_attempts, mirror_hst->notify_on_down, // Indicates notify_up, which means ... ?!?! mirror_hst->notify_on_down, mirror_hst->notify_on_unreachable, mirror_hst->notify_on_flapping, mirror_hst->notification_interval, mirror_hst->notification_period, mirror_hst->notifications_enabled, mirror_hst->host_check_command, mirror_hst->checks_enabled, mirror_hst->accept_passive_host_checks, mirror_hst->event_handler, mirror_hst->event_handler_enabled, mirror_hst->flap_detection_enabled, mirror_hst->low_flap_threshold, mirror_hst->high_flap_threshold, mirror_hst->stalk_on_up, mirror_hst->stalk_on_down, mirror_hst->stalk_on_unreachable, mirror_hst->process_performance_data, mirror_hst->failure_prediction_enabled, mirror_hst->failure_prediction_options, mirror_hst->check_freshness, mirror_hst->freshness_threshold, mirror_hst->retain_status_information, mirror_hst->retain_nonstatus_information, mirror_hst->obsess_over_host ); if (hst == NULL) bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host} Error: add_host('%s') failed", host_name); else { auto_add_nagios_host_to_cache(hst); /* hostgroup *hg; bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host} Finding Hostgroup"); if ((hg=find_hostgroup("network")) != NULL) add_host_to_hostgroup(hg, host_name); else bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host} Error: Unable to find hostgroup!"); */ } } else bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_host} Couldn't find mirror host '%s'", mirror_svc->host_name); return(hst); } service * auto_add_nagios_service(service *mirror_svc, host *hst, char *svc_description) { service *svc; svc = add_service( hst->name, svc_description, //description mirror_svc->check_period, mirror_svc->max_attempts, mirror_svc->parallelize, mirror_svc->accept_passive_service_checks, mirror_svc->check_interval, mirror_svc->retry_interval, mirror_svc->notification_interval, mirror_svc->notification_period, mirror_svc->notify_on_recovery, mirror_svc->notify_on_unknown, mirror_svc->notify_on_warning, mirror_svc->notify_on_critical, mirror_svc->notify_on_flapping, mirror_svc->notifications_enabled, mirror_svc->is_volatile, mirror_svc->event_handler, mirror_svc->event_handler_enabled, mirror_svc->service_check_command, mirror_svc->checks_enabled, mirror_svc->flap_detection_enabled, mirror_svc->low_flap_threshold, mirror_svc->high_flap_threshold, mirror_svc->stalk_on_ok, mirror_svc->stalk_on_warning, mirror_svc->stalk_on_unknown, mirror_svc->stalk_on_critical, mirror_svc->process_performance_data, mirror_svc->failure_prediction_enabled, mirror_svc->failure_prediction_options, mirror_svc->check_freshness, mirror_svc->freshness_threshold, mirror_svc->retain_status_information, mirror_svc->retain_nonstatus_information, mirror_svc->obsess_over_service ); if (svc == NULL) bronx_logprintf(BRONX_LOGGING_NORMAL, "{auto_add_nagios_service} Error: add_service('%s') failed", svc_description); else auto_add_nagios_service_to_cache(svc); return(svc); } apr_status_t auto_add_init() { apr_status_t rv; _auto_add_pool = NULL; _auto_add_mutex = NULL; _auto_add_queue = NULL; if ((rv = apr_pool_create(&_auto_add_pool, NULL)) == APR_SUCCESS) { if ((rv=apr_thread_mutex_create(&_auto_add_mutex, APR_THREAD_MUTEX_DEFAULT, _auto_add_pool)) == APR_SUCCESS) { if ((rv=apr_queue_create(&_auto_add_queue, _configuration->listener_auto_add_queue_size, _auto_add_pool)) == APR_SUCCESS) _auto_add_initialized = 1; else { apr_thread_mutex_destroy(_auto_add_mutex); apr_pool_destroy(_auto_add_pool); _auto_add_mutex = NULL; _auto_add_pool = NULL; } } else { apr_pool_destroy(_auto_add_pool); _auto_add_pool = NULL; } } return(rv); } void auto_add_uninit() { if (_auto_add_pool) { if (_auto_add_mutex) apr_thread_mutex_destroy(_auto_add_mutex); apr_pool_destroy(_auto_add_pool); } } apr_status_t assert_auto_add_initialized() { apr_status_t rv; if (_auto_add_initialized) rv = APR_SUCCESS; else rv = auto_add_init(); return(rv); } apr_status_t auto_add_queue_push(char *host_name, char *svc_description, int return_code, char *plugin_output, time_t check_time) { apr_pool_t *pool; bronx_metric *metric; apr_status_t rv; if ((rv = assert_auto_add_initialized()) != APR_SUCCESS) return(rv); apr_thread_mutex_lock(_auto_add_mutex); if ((rv = apr_pool_create(&pool, _auto_add_pool)) == APR_SUCCESS) { metric = apr_palloc(pool, sizeof(bronx_metric)); metric->pool = pool; strncpy(metric->host_name, host_name, sizeof(metric->host_name)); strncpy(metric->svc_description, svc_description, sizeof(metric->svc_description)); strncpy(metric->plugin_output, plugin_output, sizeof(metric->plugin_output)); metric->return_code = return_code; metric->check_time = check_time; if ((rv = apr_queue_trypush(_auto_add_queue, metric)) != APR_SUCCESS) apr_pool_destroy(pool); } apr_thread_mutex_unlock(_auto_add_mutex); return(rv); } void auto_add_harvest_queue() { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} harvesting queue"); if (assert_auto_add_initialized() == APR_SUCCESS) { bronx_metric *metric; bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} initialized, going through queue"); apr_thread_mutex_lock(_auto_add_mutex); while (apr_queue_size(_auto_add_queue) != 0) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} looping, trying to pop"); if (apr_queue_trypop(_auto_add_queue, (void*)(&metric)) == APR_SUCCESS) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} got something, trying to add it!!!!"); if (auto_add(metric->host_name, metric->svc_description) == APR_SUCCESS) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} successfully added! Now posting the check result"); _submit_check_result_to_nagios(metric->host_name, metric->svc_description, metric->return_code, metric->plugin_output, metric->check_time); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} failed to add it to nagios"); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} failed to pop it from the queue"); } apr_thread_mutex_unlock(_auto_add_mutex); bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} done with loop"); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{auto_add_harvest_queue} auto_add system not initialized"); } apr_status_t submit_check_result_to_nagios(char *host_name, char *svc_description, int return_code, char *plugin_output, time_t check_time) { // // If we are auto add'ing any unknown entities, then // check to see if we can find the entities passed. If not, then // hand it off to be added to nagios before commencing. // if (_configuration->listener_auto_add) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{submit_check_result_to_nagios} auto add is on, host=%s, svc=%s", host_name, svc_description); if (find_service(host_name, svc_description) == NULL) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{submit_check_result_to_nagios} found service, adding to queue"); if (auto_add_queue_push(host_name, svc_description, return_code, plugin_output, check_time) == APR_SUCCESS) { bronx_logprintf(BRONX_LOGGING_DEBUG, "{submit_check_result_to_nagios} added to queue successfully, returning good."); return(APR_SUCCESS); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{submit_check_result_to_nagios} error adding to queue."); } else bronx_logprintf(BRONX_LOGGING_DEBUG, "{submit_check_result_to_nagios} couldn't find service."); } return(_submit_check_result_to_nagios(host_name, svc_description, return_code, plugin_output, check_time)); } apr_status_t _submit_check_result_to_nagios(char *host_name, char *svc_description, int return_code, char *plugin_output, time_t check_time) { service_message svc_msg; host *hst; bronx_logprintf(BRONX_LOGGING_DEBUG, "{_submit_check_result_to_nagios} Hello world, host_name=%s, svc=%s", host_name, svc_description); // // Create a svc_msg structure, and pass this // through to nagios. // memset((void *)&svc_msg,0,sizeof(service_message)); strncpy(svc_msg.host_name,host_name,sizeof(svc_msg.host_name)-1); svc_msg.host_name[sizeof(svc_msg.host_name)-1]='\x0'; strncpy(svc_msg.description,svc_description,sizeof(svc_msg.description)-1); svc_msg.description[sizeof(svc_msg.description)-1]='\x0'; normalize_plugin_output(plugin_output, "B2"); snprintf(svc_msg.output,sizeof(svc_msg.output)-1,"%s",plugin_output); svc_msg.output[sizeof(svc_msg.output)-1]='\x0'; svc_msg.return_code=return_code; svc_msg.parallelized=FALSE; svc_msg.exited_ok=TRUE; svc_msg.check_type=SERVICE_CHECK_PASSIVE; svc_msg.start_time.tv_sec=check_time; svc_msg.start_time.tv_usec=0; svc_msg.finish_time=svc_msg.start_time; bronx_logprintf(BRONX_LOGGING_DEBUG, "{_submit_check_result_to_nagios} inserting into service result buffer."); insert_into_service_result_buffer(&svc_msg); return(APR_SUCCESS); } int submit_command_to_nagios(char *cmd) { int result = OK; /* obtain a lock for writing to the buffer */ pthread_mutex_lock(&external_command_buffer.buffer_lock); if(external_command_buffer.itemsexternal_command_buffer.high) external_command_buffer.high=external_command_buffer.items; } else /* buffer was full */ result=ERROR; /* release lock on buffer */ pthread_mutex_unlock(&external_command_buffer.buffer_lock); return(result); }