/*
ex: set tabstop=4 shiftwidth=4 autoindent:
+-------------------------------------------------------------------------+
| Copyright (C) 2002-2007 The Cacti Group |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 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 Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301, USA |
| |
+-------------------------------------------------------------------------+
| spine: a backend data gatherer for cacti |
+-------------------------------------------------------------------------+
| This poller would not have been possible without: |
| - Larry Adams (current development and enhancements) |
| - Rivo Nurges (rrd support, mysql poller cache, misc functions) |
| - RTG (core poller code, pthreads, snmp, autoconf examples) |
| - Brady Alleman/Doug Warner (threading ideas, implimentation details) |
+-------------------------------------------------------------------------+
| - Cacti - http://www.cacti.net/ |
+-------------------------------------------------------------------------+
*/
#include "common.h"
#include "spine.h"
/*! \fn void *child(void *arg)
* \brief function is called via the fork command and initiates a poll of a host
* \param arg a pointer to an integer point to the host_id to be polled
*
* This function will call the primary Spine polling function to poll a host
* and then reduce the number of active threads by one so that the next host
* can be polled.
*
*/
void *child(void *arg) {
int host_id = *(int *) arg;
SPINE_LOG_DEBUG(("DEBUG: In Poller, About to Start Polling of Host\n"));
poll_host(host_id);
thread_mutex_lock(LOCK_THREAD);
active_threads--;
SPINE_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i\n" ,active_threads));
thread_mutex_unlock(LOCK_THREAD);
/* end the thread */
pthread_exit(0);
exit(0);
}
/*! \fn void poll_host(int host_id)
* \brief core Spine function that polls a host
* \param host_id integer value for the host_id from the hosts table in Cacti
*
* This function is core to Spine. It will take a host_id and then poll it.
*
* Prior to the poll, the system will ping the host to verifiy that it is up.
* In addition, the system will check to see if any reindexing of data query's
* is required.
*
* If reindexing is required, the Cacti poller.php function will spawn that
* reindexing process.
*
* In the case of hosts that require reindexing because of a sysUptime
* rollback, Spine will store an unknown (NaN) value for all objects to prevent
* spikes in the graphs.
*
* With regard to snmp calls, if the host has multiple snmp agents running
* Spine will re-initialize the snmp session and poll under those new ports
* as the host poller_items table dictates.
*
*/
void poll_host(int host_id) {
char query1[BUFSIZE];
char query2[BUFSIZE];
char *query3;
char query4[BUFSIZE];
char query5[BUFSIZE];
char query6[BUFSIZE];
char query7[BUFSIZE];
char query8[BUFSIZE];
char query9[BUFSIZE];
char query10[BUFSIZE];
char errstr[BUFSIZE];
char sysUptime[40];
char result_string[BUFSIZE];
int result_length;
int num_rows;
int assert_fail = 0;
int spike_kill = 0;
int rows_processed = 0;
int i;
int j;
int num_oids = 0;
int snmp_poller_items = 0;
int out_buffer;
int php_process;
char *poll_result = NULL;
char *host_time = NULL;
char update_sql[BUFSIZE];
char temp_result[BUFSIZE];
int num_snmp_agents = 0;
int last_snmp_version = 0;
int last_snmp_port = 0;
char last_snmp_community[50];
char last_snmp_username[50];
char last_snmp_password[50];
char last_snmp_auth_protocol[5];
char last_snmp_priv_passphrase[200];
char last_snmp_priv_protocol[6];
char last_snmp_context[65];
/* reindex shortcuts to speed polling */
int previous_assert_failure = FALSE;
int last_data_query_id = 0;
int perform_assert = TRUE;
int new_buffer = TRUE;
reindex_t *reindex;
host_t *host;
ping_t *ping;
target_t *poller_items;
snmp_oids_t *snmp_oids;
MYSQL mysql;
MYSQL_RES *result;
MYSQL_ROW row;
db_connect(set.dbdb, &mysql);
/* allocate host and ping structures with appropriate values */
if (!(host = (host_t *) malloc(sizeof(host_t)))) {
die("ERROR: Fatal malloc error: poller.c host struct!");
}
if (!(ping = (ping_t *) malloc(sizeof(ping_t)))) {
die("ERROR: Fatal malloc error: poller.c ping struct!");
}
if (!(reindex = (reindex_t *) malloc(sizeof(reindex_t)))) {
die("ERROR: Fatal malloc error: poller.c reindex poll!");
}
sysUptime[0] = '\0';
/* single polling interval query for items */
snprintf(query1, BUFSIZE,
"SELECT action, hostname, snmp_community, "
"snmp_version, snmp_username, snmp_password, "
"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
"rrd_num, snmp_port, snmp_timeout, "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context "
" FROM poller_item"
" WHERE host_id=%i"
" ORDER BY snmp_port", host_id);
/* host structure for uptime checks */
snprintf(query2, BUFSIZE,
"SELECT id, hostname, snmp_community, snmp_version, "
"snmp_username, snmp_password, snmp_auth_protocol, "
"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_port, snmp_timeout, max_oids, "
"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
"status, status_event_count, status_fail_date, "
"status_rec_date, status_last_error, "
"min_time, max_time, cur_time, avg_time, "
"total_polls, failed_polls, availability "
" FROM host"
" WHERE id=%i", host_id);
/* data query structure for reindex detection */
snprintf(query4, BUFSIZE,
"SELECT data_query_id, action, op, assert_value, arg1"
" FROM poller_reindex"
" WHERE host_id=%i", host_id);
/* multiple polling interval query for items */
snprintf(query5, BUFSIZE,
"SELECT action, hostname, snmp_community, "
"snmp_version, snmp_username, snmp_password, "
"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
"rrd_num, snmp_port, snmp_timeout, "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context "
" FROM poller_item"
" WHERE host_id=%i and rrd_next_step <=0"
" ORDER by snmp_port", host_id);
/* query to setup the next polling interval in cacti */
snprintf(query6, BUFSIZE,
"UPDATE poller_item"
" SET rrd_next_step=rrd_next_step-%i"
" WHERE host_id=%i", set.poller_interval, host_id);
/* query to setup the next polling interval in cacti */
snprintf(query7, BUFSIZE,
"UPDATE poller_item"
" SET rrd_next_step=rrd_step-%i"
" WHERE rrd_next_step < 0 and host_id=%i",
set.poller_interval, host_id);
/* query to add output records to the poller output table */
snprintf(query8, BUFSIZE,
"INSERT INTO poller_output"
" (local_dat