From 36c0b322581486f9ba4c6501621429b648b0216c Mon Sep 17 00:00:00 2001 From: slerena Date: Tue, 31 Jul 2007 17:26:09 +0000 Subject: [PATCH] 2007-07-31 Sancho Lerena * pandora_snmpconsole: Fixed startup scripts. Many checks added to manage NetSNMP Trap daemon. Now uses /usr/sbin/snmptrapd by default. Solved many problems. This also solve bug #1763691. * conf/pandora_server.conf: Added snmp_logfile token (before inside CODE!, UGLY!). * bin/pandora_network.pl: I hope Fixed BUG #1763305 with Master Server. * bin/PandoraFMS/Config.pm: Support for config token snmp_logfile. * bin/PandoraFMS/DB.pm: Fixed (stupid) BUG #1763304 with alerts. * bin/pandora_snmpconsole.pl: Removed logfile filename from code (VERY ugly!). * pandora_server, pandora_network, pandora_recon: This also solve bug #1763691. Some additional checks included. * util/pandora_SNMP_test.pl: Removed, old stuff. git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@576 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f --- pandora_server/ChangeLog | 23 +++++ pandora_server/bin/PandoraFMS/Config.pm | 8 +- pandora_server/bin/PandoraFMS/DB.pm | 10 +-- pandora_server/bin/pandora_network.pl | 36 ++++++-- pandora_server/bin/pandora_snmpconsole.pl | 2 +- pandora_server/conf/pandora_server.conf | 12 ++- pandora_server/pandora_network | 41 ++++++--- pandora_server/pandora_recon | 30 ++++--- pandora_server/pandora_server | 44 ++++++---- pandora_server/pandora_snmpconsole | 101 ++++++++++++++++------ pandora_server/util/pandora_SNMP_test.pl | 92 -------------------- pandora_server/util/snmptrapd | Bin 20992 -> 22748 bytes 12 files changed, 222 insertions(+), 177 deletions(-) delete mode 100755 pandora_server/util/pandora_SNMP_test.pl diff --git a/pandora_server/ChangeLog b/pandora_server/ChangeLog index 3f5e874ba0..5d3d273c97 100644 --- a/pandora_server/ChangeLog +++ b/pandora_server/ChangeLog @@ -1,3 +1,26 @@ +2007-07-31 Sancho Lerena + + * pandora_snmpconsole: Fixed startup scripts. Many checks added to + manage NetSNMP Trap daemon. Now uses /usr/sbin/snmptrapd by + default. Solved many problems. This also solve bug #1763691. + + * conf/pandora_server.conf: Added snmp_logfile token (before + inside CODE!, UGLY!). + + * bin/pandora_network.pl: I hope Fixed BUG #1763305 with Master Server. + + * bin/PandoraFMS/Config.pm: Support for config token snmp_logfile. + + * bin/PandoraFMS/DB.pm: Fixed (stupid) BUG #1763304 with alerts. + + * bin/pandora_snmpconsole.pl: Removed logfile filename from code + (VERY ugly!). + + * pandora_server, pandora_network, pandora_recon: This also solve + bug #1763691. Some additional checks included. + + * util/pandora_SNMP_test.pl: Removed, old stuff. + 2007-07-20 Sancho Lerena * pandora_network.pl: Fixed a typo in pandora_ping_latency function. diff --git a/pandora_server/bin/PandoraFMS/Config.pm b/pandora_server/bin/PandoraFMS/Config.pm index d8ee9d530e..f1e84c1487 100755 --- a/pandora_server/bin/PandoraFMS/Config.pm +++ b/pandora_server/bin/PandoraFMS/Config.pm @@ -34,8 +34,8 @@ our @EXPORT = qw( pandora_help_screen # There is no global vars, all variables (setup) passed as hash reference # version: Defines actual version of Pandora Server for this module only -my $pandora_version = "1.3-beta2"; -my $pandora_build="PS070717"; +my $pandora_version = "1.3-dev"; +my $pandora_build="PS070731"; our $VERSION = $pandora_version; # Setup hash @@ -138,7 +138,8 @@ sub pandora_loadconfig { $pa_config->{"dataserver"}=0; $pa_config->{"reconserver"}=0; $pa_config->{"servermode"}=""; - $pa_config->{"network_threads"}=4; # Fixed default + $pa_config->{'pandora_snmp_logfile'}="/var/log/pandora/pandora_snmptrap.log"; + $pa_config->{"network_threads"}=5; # Fixed default $pa_config->{"keepalive"}=60; # 60 Seconds initially for server keepalive $pa_config->{"keepalive_orig"} = $pa_config->{"keepalive"}; # Check for UID0 @@ -204,6 +205,7 @@ sub pandora_loadconfig { $pa_config->{"errorlogfile"} = $tbuf; } } + elsif ($parametro =~ m/^pandora_snmp_logfile\s(.*)/i) { $pa_config->{'pandora_snmp_logfile'}= $1; } elsif ($parametro =~ m/^dbname\s(.*)/i) { $pa_config->{'dbname'}= $1; } elsif ($parametro =~ m/^dbuser\s(.*)/i) { $pa_config->{'dbuser'}= $1; } elsif ($parametro =~ m/^dbpass\s(.*)/i) { $pa_config->{'dbpass'}= $1; } diff --git a/pandora_server/bin/PandoraFMS/DB.pm b/pandora_server/bin/PandoraFMS/DB.pm index 7994cb9612..1682e788ff 100644 --- a/pandora_server/bin/PandoraFMS/DB.pm +++ b/pandora_server/bin/PandoraFMS/DB.pm @@ -64,6 +64,7 @@ our @EXPORT = qw( crea_agente_modulo execute_alert give_network_component_profile_name pandora_create_incident + give_db_value ); # Spanish translation note: @@ -375,10 +376,7 @@ sub pandora_writestate (%$$$$$$$) { # Check alert subroutine eval { - # Alerts checks for Agents, only for master servers - if ($pa_config->{"pandora_master"} == 1){ - pandora_calcula_alerta ($pa_config, $timestamp, $nombre_agente, $tipo_modulo, $nombre_modulo, $datos, $dbh); - } + pandora_calcula_alerta ($pa_config, $timestamp, $nombre_agente, $tipo_modulo, $nombre_modulo, $datos, $dbh); }; if ($@) { logger($pa_config, "ERROR: Error in SUB calcula_alerta(). ModuleName: $nombre_modulo ModuleType: $tipo_modulo AgentName: $nombre_agente", 4); @@ -780,7 +778,7 @@ sub pandora_writedata (%$$$$$$$$$$){ $min = "0"; } # Obtenemos los identificadores - my $id_agente = dame_agente_id($pa_config, $nombre_agente,$dbh); + my $id_agente = dame_agente_id ($pa_config, $nombre_agente,$dbh); # Check if exists module and agent_module reference in DB, if not, and learn mode activated, insert module in DB if ($id_agente eq "-1"){ goto fin_DB_insert_datos; @@ -809,7 +807,7 @@ sub pandora_writedata (%$$$$$$$$$$){ $min = $data[6]; $s_idag->finish(); } else { # Id AgenteModulo DOESNT exist, it could need to be created... - if (dame_learnagente($pa_config, $id_agente,$dbh) eq "1"){ + if (dame_learnagente($pa_config, $id_agente,$dbh) eq "1" ){ # Try to write a module and agent_module definition for that datablock logger( $pa_config, "Pandora_insertdata will create module (learnmode) for agent $nombre_agente",6); $id_agente_modulo = crea_agente_modulo ($pa_config, $nombre_agente, $tipo_modulo, $nombre_modulo, $max, $min, $descripcion, $dbh); diff --git a/pandora_server/bin/pandora_network.pl b/pandora_server/bin/pandora_network.pl index 7a4ddd37af..f3b84889bb 100755 --- a/pandora_server/bin/pandora_network.pl +++ b/pandora_server/bin/pandora_network.pl @@ -37,7 +37,7 @@ use PandoraFMS::DB; # FLUSH in each IO (only for debug, very slooow) # ENABLED in DEBUGMODE # DISABLE FOR PRODUCTION -$| = 0; +$| = 1; my %pa_config; my @pending_task : shared; @@ -173,7 +173,7 @@ sub pandora_network_producer ($) { my $exec_sql1; while (1) { - if ($pa_config->{"pandora_master"} != 666) { + if ($pa_config->{"pandora_master"} != 1) { # Query for normal server, not MASTER server $query1 = "SELECT tagente_modulo.id_agente_modulo, @@ -198,8 +198,23 @@ sub pandora_network_producer ($) { ORDER BY last_execution_try ASC "; } else { - # Query for master server - # PENDING TODO ! + # Query for MASTER SERVER ! + $query1 = "SELECT + DISTINCT(tagente_modulo.id_agente_modulo), tagente_modulo.flag + FROM + tagente, tagente_modulo, tagente_estado, tserver + WHERE + ( (tagente.id_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR + (tagente.id_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_server = tserver.id_server AND tserver.status = 0) + ) AND + tagente.disabled = 0 + AND + tagente_modulo.id_tipo_modulo > 4 + AND + tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo + AND + ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 ) + ORDER BY last_execution_try ASC"; } $exec_sql1 = $dbh->prepare($query1); $exec_sql1 ->execute; @@ -221,6 +236,7 @@ sub pandora_network_producer ($) { } } } + #logger ($pa_config, "Items in Network Pending Queue: ".scalar(@pending_task), 5); $exec_sql1->finish(); sleep($pa_config->{"server_threshold"}); } # Main loop @@ -325,7 +341,7 @@ sub pandora_query_tcp (%$$$$$$$) { if (($tcp_rcv ne "") || ($id_tipo_modulo == 10) || ($id_tipo_modulo ==8) || ($id_tipo_modulo == 11)) { # Receive data, non-blocking !!!! (VERY IMPORTANT!) $temp2 = ""; - for ($tam=0; $tam<($pa_config->{'networktimeout'}/2); $tam++){ + for ($tam=0; $tam<($pa_config->{'networktimeout'}); $tam++){ $handle->recv($temp,16000,0x40); $temp2 = $temp2.$temp; if ($temp ne ""){ @@ -452,7 +468,9 @@ sub exec_network_module { my $id_module_group; my $flag; my @sql_data; - + if ((!defined($id_agente_modulo)) || ($id_agente_modulo eq "")){ + return; + } my $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_agente_modulo"; my $exec_sql = $dbh->prepare($query_sql); $exec_sql ->execute; @@ -579,9 +597,13 @@ sub exec_network_module { pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh); } else { # $module_result != 0) + + if ($module_interval == 0){ + $module_interval = dame_intervalo ($pa_config, $id_agente, $dbh); + } # Modules who cannot connect or something go bad, update last_execution_try field logger ($pa_config, "Cannot obtain exec Network Module $nombre from agent $agent_name", 4); - my $query_act = "UPDATE tagente_estado SET last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo "; + my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo "; my $a_idages = $dbh->prepare($query_act); $a_idages->execute; $a_idages->finish(); diff --git a/pandora_server/bin/pandora_snmpconsole.pl b/pandora_server/bin/pandora_snmpconsole.pl index 4e0a7f287b..ce11a2a0c0 100755 --- a/pandora_server/bin/pandora_snmpconsole.pl +++ b/pandora_server/bin/pandora_snmpconsole.pl @@ -62,7 +62,7 @@ pandora_snmptrapd (\%pa_config); sub pandora_snmptrapd { my $pa_config = $_[0]; - my $snmp_logfile = $pa_config->{'pandora_path'}."/log/snmptrapd.log"; + my $snmp_logfile = $pa_config->{'pandora_snmp_logfile'}; my $logfile_size; # Size of logfile, use for calculating index file my @array; my $datos; diff --git a/pandora_server/conf/pandora_server.conf b/pandora_server/conf/pandora_server.conf index d2f2246ee8..2febbee4d5 100755 --- a/pandora_server/conf/pandora_server.conf +++ b/pandora_server/conf/pandora_server.conf @@ -6,7 +6,7 @@ # if not given, it takes localhost. It's preferable to setup one # because machine name could change by some reason. -servername endor +#servername endor # incomingdir: Defines directory where incoming data packets are stored # You could set directory relative to base path or absolute, starting with / @@ -18,6 +18,10 @@ incomingdir /var/spool/pandora/data_in log_file /var/log/pandora_server.log +# Log file for Pandora FMS SNMP console. Its generated by NetSNMP Trap daemon + +snmp_logfile /var/log/pandora/pandora_snmptrap.log + # Error logfile: aux logfile for pandora_server errors (in Daemon mode) # You could set file relative to base path or absolute, starting with / @@ -25,11 +29,11 @@ errorlog_file /var/log/pandora_server.error # dbname: Database name (pandora by default -dbname pandora13 +dbname pandora # dbuser: Database user name (pandora by default) -dbuser pandora +dbuser zhriopul # daemon: Runs in daemon mode (background) if 1, if 0 runs in foreground # this could be setup on command line with -D option @@ -55,7 +59,7 @@ alert_threshold 45 # Master Server, 1 if master server (normal mode), 0 for slave mode (slave in multi-server setup) -master 0 +master 1 # Check datafiles using a MD5 hash, 1 to check (default), 0 to ignore .checksum diff --git a/pandora_server/pandora_network b/pandora_server/pandora_network index f3338a6f32..a943a877eb 100755 --- a/pandora_server/pandora_network +++ b/pandora_server/pandora_network @@ -1,16 +1,23 @@ #!/bin/bash -# Pandora Network Server, startup script +# Pandora FMS Network Server, startup script # Sancho Lerena, -# Linux Version (generico) -# v1.3 (Jul/2007) +# Linux Version (generic) +# v1.3 Build 070731 # Configurable path and filenames PANDORA_HOME="/usr/share/pandora_server" -PANDORA_NETWORK_PID="/var/run/pandora/pandora_network.pid" +PANDORA_PID_PATH="/var/run/pandora" +PANDORA_PID=$PANDORA_PID_PATH/pandora_network.pid # Main script +if [ ! -d "$PANDORA_PID_PATH" ] +then + echo "Pandora FMS cannot write it's PID file in $PANDORA_PID_PATH. Please create that directory" + exit +fi + if [ ! -f $PANDORA_HOME/bin/pandora_network.pl ] then echo "Pandora FMS Network Server not found, please check setup and read manual" @@ -20,34 +27,40 @@ fi case "$1" in start) OLD_PATH="`pwd`" - if [ -f $PANDORA_NETWORK_PID ] + if [ -f $PANDORA_PID ] then - echo "Pandora FMS Network Server is currently running on this machine. Aborting now..." - exit + CHECK_PID=`cat $PANDORA_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "pandora_network" | wc -l` + if [ $CHECK_PID_RESULT == 1 ] + then + echo "Pandora FMS Network Server is currently running on this machine with PID ($CHECK_PID). Aborting now..." + exit + fi fi cd $PANDORA_HOME/bin ./pandora_network.pl $PANDORA_HOME -D + MYPID=`ps aux | grep 'pandora_network.pl' | grep -v grep | tail -1 | awk '{print $2}'` if [ ! -z "$MYPID" ] then - echo $MYPID > $PANDORA_NETWORK_PID + echo $MYPID > $PANDORA_PID echo "Pandora Network Server is now running with PID $MYPID" else echo "Cannot start Pandora FMS Network Server. Aborted." fi - cd "$OLD_PATH" + cd "$OLD_PATH" ;; stop) - if [ -f $PANDORA_NETWORK_PID ] + if [ -f $PANDORA_PID ] then echo "Stopping Pandora FMS Network Server" - PID_2=`cat $PANDORA_NETWORK_PID` - if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_network'`" ] + PID_2=`cat $PANDORA_PID` + if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_network' `" ] then - kill `cat $PANDORA_NETWORK_PID` 2> /dev/null > /dev/null + kill `cat $PANDORA_PID` 2> /dev/null > /dev/null fi - rm -f $PANDORA_NETWORK_PID + rm -f $PANDORA_PID else echo "Pandora FMS Network Server is not running, cannot stop it." fi diff --git a/pandora_server/pandora_recon b/pandora_server/pandora_recon index 3bd327a829..62a1d4b315 100755 --- a/pandora_server/pandora_recon +++ b/pandora_server/pandora_recon @@ -1,15 +1,23 @@ -#!/bin/sh +#!/bin/bash + # Pandora FMS Recon Server, startup script # Sancho Lerena, # Linux Version (generic) -# v1.3 (Jul/2007) +# v1.3 Build 070731 # Configurable path and filenames PANDORA_HOME="/usr/share/pandora_server" -PANDORA_PID="/var/run/pandora/pandora_recon.pid" +PANDORA_PID_PATH="/var/run/pandora" +PANDORA_PID=$PANDORA_PID_PATH/pandora_recon.pid # Main script +if [ ! -d "$PANDORA_PID_PATH" ] +then + echo "Pandora FMS cannot write it's PID file in $PANDORA_PID_PATH. Please create that directory" + exit +fi + if [ ! -f $PANDORA_HOME/bin/pandora_recon.pl ] then echo "Pandora FMS Recon Server not found, please check setup and read manual" @@ -21,32 +29,34 @@ case "$1" in OLD_PATH="`pwd`" if [ -f $PANDORA_PID ] then - PID_2=`cat $PANDORA_PID` - if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_recon.pl'`" ] + CHECK_PID=`cat $PANDORA_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "pandora_recon" | wc -l` + if [ $CHECK_PID_RESULT == 1 ] then - echo "Pandora FMS Recon Server is currently running on this machine. Aborting now..." + echo "Pandora FMS Recon Server is currently running on this machine with PID ($CHECK_PID). Aborting now..." exit fi fi cd $PANDORA_HOME/bin ./pandora_recon.pl $PANDORA_HOME -D + MYPID=`ps aux | grep 'pandora_recon.pl' | grep -v grep | tail -1 | awk '{print $2}'` if [ ! -z "$MYPID" ] then echo $MYPID > $PANDORA_PID - echo "Pandora FMS Recon Server is now running with PID $MYPID" + echo "Pandora Recon Server is now running with PID $MYPID" else - echo "Cannot start Pandora FMS Recon Server. Aborted" + echo "Cannot start Pandora FMS Recon Server. Aborted." fi - cd "$OLD_PATH" + cd "$OLD_PATH" ;; stop) if [ -f $PANDORA_PID ] then echo "Stopping Pandora FMS Recon Server" PID_2=`cat $PANDORA_PID` - if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_recon.pl'`" ] + if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_recon' `" ] then kill `cat $PANDORA_PID` 2> /dev/null > /dev/null fi diff --git a/pandora_server/pandora_server b/pandora_server/pandora_server index ae065efbcb..0b069ee0fe 100755 --- a/pandora_server/pandora_server +++ b/pandora_server/pandora_server @@ -1,15 +1,23 @@ #!/bin/bash -# Pandora Data Server startup script + +# Pandora Data Server, startup script # Sancho Lerena, -# Linux Version (generic) -# v1.3 (Jul/2007) +# Linux Version (generico) +# v1.3 Build 070731 # Configurable path and filenames PANDORA_HOME="/usr/share/pandora_server" -PANDORA_SERVER_PID="/var/run/pandora/pandora_server.pid" +PANDORA_PID_PATH="/var/run/pandora" +PANDORA_PID=$PANDORA_PID_PATH/pandora_dataserver.pid # Main script +if [ ! -d "$PANDORA_PID_PATH" ] +then + echo "Pandora FMS cannot write it's PID file in $PANDORA_PID_PATH. Please create that directory" + exit +fi + if [ ! -f $PANDORA_HOME/bin/pandora_server.pl ] then echo "Pandora FMS Data Server not found, please check setup and read manual" @@ -19,34 +27,40 @@ fi case "$1" in start) OLD_PATH="`pwd`" - if [ -f $PANDORA_SERVER_PID ] + if [ -f $PANDORA_PID ] then - echo "Pandora FMS Data Server is currently running on this machine. Aborting now..." - exit + CHECK_PID=`cat $PANDORA_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "pandora_server.pl" | wc -l` + if [ $CHECK_PID_RESULT == 1 ] + then + echo "Pandora FMS Data Server is currently running on this machine with PID ($CHECK_PID). Aborting now..." + exit + fi fi cd $PANDORA_HOME/bin ./pandora_server.pl $PANDORA_HOME -D + MYPID=`ps aux | grep 'pandora_server.pl' | grep -v grep | tail -1 | awk '{print $2}'` if [ ! -z "$MYPID" ] then - echo $MYPID > $PANDORA_SERVER_PID - echo "Pandora FMS Data Server is now running with PID $MYPID" + echo $MYPID > $PANDORA_PID + echo "Pandora Data Server is now running with PID $MYPID" else - echo "Cannot start Pandora FMS Data Server. Aborted" + echo "Cannot start Pandora FMS Data Server. Aborted." fi cd "$OLD_PATH" ;; stop) - if [ -f $PANDORA_SERVER_PID ] + if [ -f $PANDORA_PID ] then echo "Stopping Pandora FMS Data Server" - PID_2=`cat $PANDORA_SERVER_PID` - if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_server'`" ] + PID_2=`cat $PANDORA_PID` + if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_server' `" ] then - kill `cat $PANDORA_SERVER_PID` 2> /dev/null > /dev/null + kill `cat $PANDORA_PID` 2> /dev/null > /dev/null fi - rm -f $PANDORA_SERVER_PID + rm -f $PANDORA_PID else echo "Pandora FMS Data Server is not running, cannot stop it." fi diff --git a/pandora_server/pandora_snmpconsole b/pandora_server/pandora_snmpconsole index c4655e5781..41ed15c8ca 100755 --- a/pandora_server/pandora_snmpconsole +++ b/pandora_server/pandora_snmpconsole @@ -1,24 +1,36 @@ #!/bin/bash + # Startup script for Pandora SNMP Console # Sancho Lerena, -# Linux Version(generic) -# v1.3 (May/2007) +# Linux Version (generic) +# v1.3 BUILD 070731 # Compatible with NetSNMP 5.1 or higher # Configurable path and filenames + PANDORA_HOME="/usr/share/pandora_server" -DAEMON_PATH="$PANDORA_HOME/util" -DAEMON_LOG="$PANDORA_HOME/log/snmptrapd.log" -DAEMON_PID="$PANDORA_HOME/var/snmptrapd.pid" -PANDORA_SNMP_PID="$PANDORA_HOME/var/pandora_snmp.pid" +PANDORA_PID_PATH="/var/run/pandora" +PANDORA_PID=$PANDORA_PID_PATH/pandora_snmp.pid -# Dont touch this call unless you know are doing. -DAEMON="$DAEMON_PATH/snmptrapd -t -On -n -a -Lf $DAEMON_LOG -p $DAEMON_PID -F %4y-%02.2m-%l[**]%02.2h:%02.2j:%02.2k[**]%B[**]%N[**]%w[**]%W[**]%q[**]%v\n" +DAEMON_LOG="/var/log/pandora/pandora_snmptrap.log" +DAEMON_PID="$PANDORA_PID_PATH/pandora_snmptrapd.pid" +DAEMON_PATH=/usr/sbin/snmptrapd -if [ ! -f $DAEMON_PATH/snmptrapd ] +# Dont touch this call unless you know are doing. For different versions of NetSNMP Trap daemon, it's possible you need to change some options +# Please refer NetSNMP documentation in that case. +DAEMON_OPTIONS="-t -On -n -a -Lf $DAEMON_LOG -p $DAEMON_PID -F %4y-%02.2m-%l[**]%02.2h:%02.2j:%02.2k[**]%B[**]%N[**]%w[**]%W[**]%q[**]%v\n" +DAEMON="$DAEMON_PATH $DAEMON_OPTIONS" + +if [ ! -d "$PANDORA_PID_PATH" ] then - echo "NetSNMP snmptrapd not found at $DAEMON_PATH/snmptrapd, please check setup and read manual" + echo "Pandora FMS cannot write it's PID file in $PANDORA_PID_PATH. Please create that directory" + exit +fi + +if [ ! -f "$DAEMON_PATH" ] +then + echo "NetSNMP snmptrapd not found at $DAEMON_PATH, please check setup and read manual" exit fi @@ -26,13 +38,46 @@ case "$1" in start) if [ -f $DAEMON_PID ] then - echo "NetSNMP Trap daemon is currently running on this machine. Aborting now..." + CHECK_PID=`cat $DAEMON_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "snmp" | wc -l` + if [ $CHECK_PID_RESULT == 1 ] + then + echo "NetSNMP Trap daemon is currently running on this machine with PID ($CHECK_PID). Aborting now..." + exit + fi + fi + + SNMP_WARNING=`ps aux | grep "snmptrapd" | grep -v grep | wc -l` + if [ $SNMP_WARNING == 1 ] + then + echo "WARNING: Seems to be already running a SNMP trap daemon on this system not associated with Pandora FMS" + echo "Check manually if their output logfile is been used for Pandora FMS and it's format is correct" + fi + + # Launch SNMP TRAP Daemon + $DAEMON + + sleep 1 + if [ ! -f $DAEMON_LOG ] + then + echo "Problem with NetSNMP Trap daemon (Logfile $DAEMON_LOG not found!). Aborting" + exit + fi + + if [ -f $DAEMON_PID ] + then + CHECK_PID=`cat $DAEMON_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "snmp" | wc -l` + if [ $CHECK_PID_RESULT != 1 ] + then + echo "Problem starting NetSNMP Trap daemon on this machine (PID File not correct). Aborting now..." + exit + fi + else + echo "Problem starting NetSNMP Trap daemon on this machine (Cannot get PID File). Aborting now..." exit fi - rm -f $DAEMON_LOG 2> /dev/null - $DAEMON 2> /dev/null - sleep 1 RESULT="`cat $DAEMON_LOG | grep 'errno 13' 2> /dev/null`" if [ -z "$RESULT" ] then @@ -41,19 +86,25 @@ case "$1" in echo "NetSNMP cannot open port (udp/162). Please execute as root user" rm -f $DAEMON_PID 2> /dev/null fi - - if [ -f $PANDORA_SNMP_PID ] - then - echo "Pandora FMS SNMP Server is currently running on this machine. Aborting now..." - exit - fi + if [ -f $PANDORA_PID ] + then + CHECK_PID=`cat $PANDORA_PID` + CHECK_PID_RESULT=`ps aux | grep -v grep | grep "$CHECK_PID" | grep "pandora_snmpconsole.pl" | wc -l` + if [ $CHECK_PID_RESULT == 1 ] + then + echo "Pandora FMS SNMP Server is currently running on this machine with PID ($CHECK_PID). Aborting now..." + exit + fi + fi + cd $PANDORA_HOME/bin ./pandora_snmpconsole.pl $PANDORA_HOME -D + MYPID=`ps aux | grep 'pandora_snmpconsole.pl' | grep -v grep | tail -1 | awk '{print $2}'` if [ ! -z "$MYPID" ] then - echo $MYPID > $PANDORA_SNMP_PID + echo $MYPID > $PANDORA_PID echo "Pandora FMS SNMP Server is now running with PID $MYPID" else echo "Cannot start Pandora FMS SNMP Server. Aborted" @@ -75,15 +126,15 @@ case "$1" in echo "NetSNMP Trap daemon is not running, cannot stop it." fi - if [ -f $PANDORA_SNMP_PID ] + if [ -f $PANDORA_PID ] then echo "Stopping Pandora SNMP Console" - PID_2=`cat $PANDORA_SNMP_PID` + PID_2=`cat $PANDORA_PID` if [ ! -z "`ps -F -p $PID_2 | grep -v grep | grep 'pandora_snmpconsole'`" ] then - kill `cat $PANDORA_SNMP_PID` 2> /dev/null > /dev/null + kill `cat $PANDORA_PID` 2> /dev/null > /dev/null fi - rm -f $PANDORA_SNMP_PID + rm -f $PANDORA_PID else echo "Pandora FMS SNMP Console is not running, cannot stop it." fi diff --git a/pandora_server/util/pandora_SNMP_test.pl b/pandora_server/util/pandora_SNMP_test.pl deleted file mode 100755 index 8f3b839cc7..0000000000 --- a/pandora_server/util/pandora_SNMP_test.pl +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/perl -################################################################################## -# SNMP Test tool -################################################################################## -# Copyright (c) 2004-2006 Sancho Lerena, slerena@gmail.com -# Copyright (c) 2005-2006 Artica Soluciones Tecnológicas S.L -# -#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. -################################################################################## - -#use Net::SNMP; # For query2 testing -use SNMP '5.0.2.pre1' || die("Cannot load module\n"); - -########################################################################################## -# SUB pandora_query_snmp (pa_config, oid, community, target, error, dbh) -# Makes a call to SNMP modules to get a value, -########################################################################################## -sub pandora_query_snmp2 { - my $snmp_oid = shift; - my $snmp_community = shift; - my $snmp_target = shift; - - - print "DEBUG OID $snmp_oid comm $snmp_community target $snmp_target \n"; - my $output =""; - - my ($session1, $error) = Net::SNMP->session( - -hostname => $snmp_target, - -community => $snmp_community, - -port => 161 ); - - if (!defined($session1)) { - printf("SNMP ERROR SESSION"); - } - - my $result = $session1->get_request( - -varbindlist => $snmp_oid - ); - - if (!defined($result)) { - printf("SNMP ERROR GET"); - $session1->close; - } else { - $output = $result->{$snmp_oid}; - $session1->close; - } - - return $output; -} - -sub pandora_query_snmp { - my $snmp_oid = shift; - my $snmp_community = shift; - my $snmp_target = shift; - - $ENV{'MIBS'}="ALL"; #Load all available MIBs - $SNMP_TARGET = $snmp_target; - $SNMP_COMMUNITY = $snmp_community; - - $SESSION = new SNMP::Session (DestHost => $SNMP_TARGET, - Community => $SNMP_COMMUNITY, - Version => 1); - - # Populate a VarList with OID values. - $APC_VLIST = new SNMP::VarList([$snmp_oid]); - - # Pass the VarList to getnext building an array of the output - @APC_INFO = $SESSION->getnext($APC_VLIST); - - print $APC_INFO[0]; - print "\n"; -} - -if ($#ARGV == -1 ){ - print "Syntax: snmptest community hostname oid\n"; - exit; - } -my $snmp_community = $ARGV[0]; -my $snmp_target = $ARGV[1]; -my $snmp_oid = $ARGV[2]; - -pandora_query_snmp($snmp_oid, $snmp_community, $snmp_target); diff --git a/pandora_server/util/snmptrapd b/pandora_server/util/snmptrapd index 184b69d531e01092932e4fd7beb9602e049602f4..18b0eae000028ff7cbba28157f8459a9656ce006 100755 GIT binary patch literal 22748 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

0e#kyuj9T2bR6a8gID00cRHvUbO-1g zAU+5G1auhm+5aY;g@=h#%V=jvJ5}a?3V&Sv|7(HvH^qPRz~4OZu^t%2#Y~&?o(Fd} zy@ng!@4|5(c_R)W$XgZv7LH|!w<*3uaej}<6DIz4(7E9J%@ZVv>G(Z9{*yz=SMd!Y zczePn51_W`=hKlD|{+(coZsFVfMbFm1z$VYqv<^=%j6|5q1(|IlvGMc;Jgj{((yW`Y)hR)E%l zHiGU4Z3jIKIskedbQts@sPF+-{zafMpc>Fj&?3+Z&^pjY(EXt8pr=6xK(B)igFXZm zK8W(5F`ydIOwc0G3eY;xM$rAB?VzVY2SBfb4ud`f6@CllL1REQpqZdWpcSBXppBsW zLEAx3gARaR2OS1|2r7ICFj&?3+ZknP`3;zf>raLVzO1jZmvb>!&|@0}MhzPxmYrmGZX}BBBzfE56DbC(o$RJ*}eB?}_@tYI4kr(v^DR13Gf;u(h_X;ZIPis`lUsb7$hUJeFRQmk*Jr4dD zMrAV|w_~WlVk?@V2ueI{fo9YeMsfV9l-jJ4_*H{5IpJf{I3Kay^qu@IQvl8}_QgD2 zOvCgg<>YUUB0~eVFV1_sE&*}wqdv}qoU?+(l>jjj* zm&vzaDaZNuIONzCTOTp*tTm}S3ZYCbpiUA$L&z^9d4gu})rhf^4}BFS+tJG-UIbZ_6c>oE+1fHySN}QHGZ-*M)oP zqg+1Z@;^rIK8GB?Tq}W`tpiz^`v-7u&oA<~bEyv%*e+xl_S-*!?0QFG{T+1^z8y!J zeNm3I9c0UKo$i60mkH{!<#qtuayuO-8TIk9 Qby*0qko%DhR6gN<0l~TsO8@`> literal 20992 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