2008-03-13 Sancho Lerena <slerena@gmail.com>

* lib/PandoraFMS/Config.pm: New pandora_startlog function. Added support to manage PID
    in daemon mode. Added support for quiet mode. Added prediction_threads option. 

    * lib/PandoraFMS/Tools.pm: daemonize function now manages PID and store in a file when
    it forks. 

    * lib/PandoraFMS/DB.pm: Removed some gotos.  Modified generic-access DB functions and 
    added one to manage entire row in a hash: get_db_free_row ().

    * bin/pandora_plugin: A lot of fixes. This code actually works fine :-)

    * bin/pandora_prediction: First version of usable code. Works but not seriously tested.

    * bin/pandora_network: Adjusted to work with new features (quiet mode) and new db 
    schema. Some code cleanup.

    * util/pandora_dbstress.pl: Updated default values.

    * util/pandora_dbstress.README: Improved README documentation for dbstress tool.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@747 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
This commit is contained in:
slerena 2008-03-13 18:33:44 +00:00
parent 2a00c93230
commit daaa63e192
9 changed files with 858 additions and 253 deletions

View File

@ -1,3 +1,25 @@
2008-03-13 Sancho Lerena <slerena@gmail.com>
* lib/PandoraFMS/Config.pm: New pandora_startlog function. Added support to manage PID
in daemon mode. Added support for quiet mode. Added prediction_threads option.
* lib/PandoraFMS/Tools.pm: daemonize function now manages PID and store in a file when
it forks.
* lib/PandoraFMS/DB.pm: Removed some gotos. Modified generic-access DB functions and
added one to manage entire row in a hash: get_db_free_row ().
* bin/pandora_plugin: A lot of fixes. This code actually works fine :-)
* bin/pandora_prediction: First version of usable code. Works but not seriously tested.
* bin/pandora_network: Adjusted to work with new features (quiet mode) and new db
schema. Some code cleanup.
* util/pandora_dbstress.pl: Updated default values.
* util/pandora_dbstress.README: Improved README documentation for dbstress tool.
2008-03-11 Manuel Arostegui <marostegui@artica.es>
* pandora_server, pandora_network, pandora_recon:

View File

@ -62,13 +62,20 @@ pandora_loadconfig (\%pa_config,1);
# Audit server starting
pandora_audit (\%pa_config, "Pandora FMS Network Daemon starting", "SYSTEM", "System");
print " [*] Starting up network threads\n";
if ( $pa_config{"daemon"} eq "1" ) {
print " [*] Backgrounding Pandora FMS Network Server process.\n\n";
&daemonize;
# Thread startup
if ($pa_config{"quiet"} == 0){
print " [*] Starting up network threads\n";
}
# Daemonize and put in background
if ( $pa_config{"daemon"} eq "1" ){
if ($pa_config{"quiet"} eq "0"){
print " [*] Backgrounding Pandora FMS Network Server process.\n\n";
}
&pandora_daemonize ( \%pa_config);
}
# Launch now all network threads
# $ax is local thread id for this server
for (my $ax=0; $ax < $pa_config{'network_threads'}; $ax++){
@ -78,9 +85,15 @@ for (my $ax=0; $ax < $pa_config{'network_threads'}; $ax++){
# Launch now the network producer thread
threads->new( \&pandora_network_producer, \%pa_config);
print " [*] All threads loaded and running \n\n";
# Last thread is the main process (this process)
if ($pa_config{"quiet"} == 0){
print " [*] All threads loaded and running \n\n";
}
# Start Pandora FMS loggin
pandora_startlog (\%pa_config);
# Last thread is the main process (this process)
my $dbhost = $pa_config{'dbhost'};
my $dbname = $pa_config{'dbname'};
my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
@ -122,7 +135,9 @@ sub pandora_network_consumer ($$) {
my $pa_config = $_[0];
my $thread_id = $_[1];
print " [*] Starting up Network Consumer Thread # $thread_id \n";
if ($pa_config->{"quiet"} == 0){
print " [*] Starting up Network Consumer Thread # $thread_id \n";
}
my $data_id_agent_module;
# Create Database handler
@ -170,7 +185,10 @@ sub pandora_network_consumer ($$) {
sub pandora_network_producer ($) {
my $pa_config = $_[0];
print " [*] Starting up Network Producer Thread ...\n";
if ($pa_config->{"quiet"} == 0){
print " [*] Starting up Network Producer Thread ...\n";
}
my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
@ -192,13 +210,17 @@ sub pandora_network_producer ($) {
FROM
tagente, tagente_modulo, tagente_estado
WHERE
id_server = $server_id
id_network_server = $server_id
AND
tagente_modulo.id_agente = tagente.id_agente
AND
tagente.disabled = 0
AND
tagente_modulo.id_tipo_modulo > 4
tagente_modulo.id_tipo_modulo > 4
AND
tagente_modulo.id_tipo_modulo < 19
AND
tagente_modulo.disabled = 0
AND
tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND (
@ -215,12 +237,16 @@ sub pandora_network_producer ($) {
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)
( (tagente.id_network_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
(tagente.id_network_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_network_server = tserver.id_server AND tserver.status = 0)
) AND
tagente.disabled = 0
AND
tagente_modulo.disabled = 0
AND
tagente_modulo.id_tipo_modulo > 4
AND
tagente_modulo.id_tipo_modulo < 19
AND
tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND
@ -600,10 +626,12 @@ sub exec_network_module {
}
}
# --------------------------------------------------------
# Write data section
my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
my $utimestamp = &UnixDate("today","%s");
# Is everything goes ok
if ($module_result == 0) {
my %part;
$part{'name'}[0]=$nombre;
@ -626,17 +654,19 @@ sub exec_network_module {
}
else {
logger ($pa_config, "Problem with unknown module type '$tipo_modulo'", 0);
goto skipdb_execmod;
$module_result = 1;
}
# Update agent last contact
# Insert Pandora version as agent version
pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
} else {
# $module_result != 0)
}
if ($module_result != 0) {
if ($module_interval == 0){
$module_interval = dame_intervalo ($pa_config, $id_agente, $dbh);
}
$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 current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo ";
@ -644,7 +674,4 @@ sub exec_network_module {
$a_idages->execute;
$a_idages->finish();
}
skipdb_execmod:
#$dbh->disconnect();
}

View File

@ -57,27 +57,30 @@ pandora_loadconfig (\%pa_config, 4);
# Audit server starting
pandora_audit (\%pa_config, "Pandora FMS Plugin server starting", "SYSTEM", "System");
print " [*] Starting up plugin threads\n";
die "Aqui me quedo";
if ( $pa_config{"daemon"} eq "1" ) {
print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n";
&daemonize;
# Daemonize and put in background
if ( $pa_config{"daemon"} eq "1" ){
if ($pa_config{"quiet"} eq "0"){
print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n";
}
&pandora_daemonize ( \%pa_config);
}
=for COMMENT BLOCK
# Launch now all plugin threads
# $ax is local thread id for this server
for (my $ax=0; $ax < $pa_config{'plugin_threads'}; $ax++){
threads->new( \&pandora_plugin_consumer, \%pa_config, $ax);
}
=cut
# Launch now the producer thread
threads->new( \&pandora_plugin_producer, \%pa_config);
print " [*] All threads loaded and running \n\n";
# Last thread is the main process (this process)
if ($pa_config{"quiet"} == 0){
print " [*] All threads loaded and running \n\n";
}
# Start Pandora FMS loggin
pandora_startlog (\%pa_config);
my $dbhost = $pa_config{'dbhost'};
my $dbname = $pa_config{'dbname'};
@ -88,7 +91,7 @@ my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
# Server keepalive thread running in main thread on a infinite loop
while (1) {
pandora_serverkeepaliver (\%pa_config, 1, $dbh);
pandora_serverkeepaliver (\%pa_config, 4, $dbh);
threads->yield;
sleep ($pa_config{"server_threshold"});
}
@ -120,7 +123,9 @@ sub pandora_plugin_consumer ($$) {
my $pa_config = $_[0];
my $thread_id = $_[1];
print " [*] Starting up Plugin Consumer Thread # $thread_id \n";
if ($pa_config->{"quiet"} == 0){
print " [*] Starting up Plugin Consumer Thread # $thread_id \n";
}
my $data_id_agent_module;
# Create Database handler
@ -139,6 +144,7 @@ sub pandora_plugin_consumer ($$) {
{
lock $queue_lock;
$data_id_agent_module = shift(@pending_task);
#print "[CLIENT] Pop out of queue module (pending queue) $data_id_agent_module \n";
delete($pending_task_hash{$data_id_agent_module});
$current_task_hash{$data_id_agent_module}=1;
}
@ -147,6 +153,7 @@ sub pandora_plugin_consumer ($$) {
eval {
# Call network execution process
# exec_network_module ( $pa_config, $data_id_agent_module, $dbh);
print "[CLIENT] Executing module $data_id_agent_module \n";
exec_plugin_module ($pa_config, $data_id_agent_module, $dbh);
};
if ($@){
@ -158,6 +165,7 @@ sub pandora_plugin_consumer ($$) {
# not been processed, but has been freed from task queue
{
lock $queue_lock;
#print "[CLIENT] Removing from queue (current task) module $data_id_agent_module \n";
delete($current_task_hash{$data_id_agent_module});
}
$counter = 0;
@ -191,13 +199,15 @@ sub pandora_plugin_producer ($) {
FROM
tagente, tagente_modulo, tagente_estado
WHERE
id_server = $server_id
id_plugin_server = $server_id
AND
tagente_modulo.id_agente = tagente.id_agente
AND
tagente.disabled = 0
AND
tagente_modulo.id_plugin != 0
AND
tagente_modulo.id_tipo_modulo > 4
tagente_modulo.disabled = 0
AND
tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND (
@ -214,23 +224,28 @@ sub pandora_plugin_producer ($) {
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)
( (tagente.id_plugin_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
(tagente.id_plugin_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_plugin_server = tserver.id_server AND tserver.status = 0)
) AND
tagente.disabled = 0
AND
tagente_modulo.disabled = 0
AND
tagente_modulo.id_tipo_modulo > 4
tagente_modulo.id_plugin != 0
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";
}
#print "[DEBUG] SQL is $query1 \n";
$exec_sql1 = $dbh->prepare($query1);
$exec_sql1 ->execute;
while (@sql_data1 = $exec_sql1->fetchrow_array()) {
$data_id_agente_modulo = $sql_data1[0];
$data_flag = $sql_data1[1];
print "[DEBUG] Procesando candidato $data_id_agente_modulo\n";
# Skip modules already queued
if ((!defined($pending_task_hash{$data_id_agente_modulo})) &&
(!defined($current_task_hash{$data_id_agente_modulo}))) {
@ -239,6 +254,7 @@ sub pandora_plugin_producer ($) {
}
# Locking scope, do not remove redundant { }
{
#print "[DEBUG] Metiendo $data_id_agente_modulo en cola \n";
lock $queue_lock;
push (@pending_task, $data_id_agente_modulo);
$pending_task_hash {$data_id_agente_modulo}=1;
@ -246,6 +262,7 @@ sub pandora_plugin_producer ($) {
}
}
#logger ($pa_config, "Items in Network Pending Queue: ".scalar(@pending_task), 5);
#print "[DEBUG] Items in Network Pending Queue: ".scalar(@pending_task);
$exec_sql1->finish();
sleep($pa_config->{"server_threshold"});
} # Main loop
@ -263,17 +280,17 @@ sub exec_plugin_module {
# Set global variables for this sub
my $timeout = $pa_config->{'plugin_timeout'};
my $agent_plugin; # hash container for tagent_plugin record
my $agent_module; # hash container for tagente_modulo record
my $plugin; # hash container for tplugin
# Get a full hash for agent_plugin record reference ($agent_plugin)
# Get a full hash for agent_plugin record reference ($agent_module)
my $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_am";
my $exec_sql = $dbh->prepare($query_sql);
$exec_sql ->execute;
$agent_plugin = $exec_sql->fetchrow_hashref;
$agent_module = $exec_sql->fetchrow_hashref;
# Get a full hash for plugin record reference ($plugin)
$query_sql = "SELECT * FROM tplugin WHERE id = ".$agent_plugin->{'id_plugin'};
$query_sql = "SELECT * FROM tplugin WHERE id = ".$agent_module->{'id_plugin'};
$exec_sql = $dbh->prepare($query_sql);
$exec_sql->execute();
$plugin = $exec_sql->fetchrow_hashref;
@ -284,7 +301,7 @@ sub exec_plugin_module {
}
# Initialize another global sub variables.
my $agent_name = dame_agente_nombre ($pa_config, $agent_plugin->{'id_agente'}, $dbh);
my $agent_name = dame_agente_nombre ($pa_config, $agent_module->{'id_agente'}, $dbh);
my $module_result = 1; # Fail by default
my $module_data = 0; # 0 data for default
my $module_interval = 0;
@ -293,23 +310,23 @@ sub exec_plugin_module {
my $exec_output = "";
my $plugin_command = $plugin->{"execute"};
if ($plugin->{'net_dst_opt'} ne ""){
$plugin_command = $plugin_command . " ". $plugin->{'net_dst_opt'} ." ". $agent_plugin->{'ip_target'};
$plugin_command = $plugin_command . " ". $plugin->{'net_dst_opt'} ." ". $agent_module->{'ip_target'};
}
if ($plugin->{'net_port_opt'} ne "") {
$plugin_command = $plugin_command . " ". $plugin->{'net_port_opt'} ." ". $agent_plugin->{'tcp_port'};
$plugin_command = $plugin_command . " ". $plugin->{'net_port_opt'} ." ". $agent_module->{'tcp_port'};
}
if ($plugin->{'user_opt'} ne "") {
$plugin_command = $plugin_command . " ". $plugin->{'user_opt'} ." ". $agent_plugin->{'plugin_user'};
$plugin_command = $plugin_command . " ". $plugin->{'user_opt'} ." ". $agent_module->{'plugin_user'};
}
if ($plugin->{'pass_opt'} ne "") {
$plugin_command = $plugin_command . " ". $plugin->{'pass_opt'} ." ". $agent_plugin->{'plugin_pass'};
$plugin_command = $plugin_command . " ". $plugin->{'pass_opt'} ." ". $agent_module->{'plugin_pass'};
}
# Proccess field / optional / dynamic field
if ($agent_plugin->{'plugin_parameter'} ne "") {
$plugin_command = $plugin_command . $agent_plugin->{'plugin_parameter'};
if ($agent_module->{'plugin_parameter'} ne "") {
$plugin_command = $plugin_command . " ". $agent_module->{'plugin_parameter'};
}
logger ($pa_config, "Executing AM # $id_am plugin command '$plugin_command'", 9);
# Final command line execution is stored at "plugin_command"
eval {
alarm ($timeout);
@ -317,12 +334,18 @@ sub exec_plugin_module {
alarm(0); # Cancel the pending alarm if plugin call returns alive
$module_result = 0; # If comes here, this is a successfull exec
};
# print "[DEBUG] Output for $plugin_command is --$module_data-- \n";
# Timeout
if ($@ =~ /PANDORA PLUGIN SERVER TIMED OUT/) {
logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_plugin->{'id_agente_modulo'}." causes a system timeout in exec", 1);
# resuming eval block...
} else {
logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_plugin->{'id_agente_modulo'}." causes an unknown system error", 1);
logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_module->{'id_agente_modulo'}." causes a system timeout in exec", 1);
logger ($pa_config, "Executing plugin command '$plugin_command'", 9);
print "[DEBUG] Executing plugin TIMEOUT\n";
# General error, not timed-out
} elsif ($module_result == 1) {
logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_module->{'id_agente_modulo'}." causes an unknown system error", 1);
logger ($pa_config, "[ERROR] $@", 1);
print "[DEBUG] Executing plugin ERROR $@\n";
}
sub timed_out {
@ -332,49 +355,63 @@ sub exec_plugin_module {
# Get current timestamp
my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
my $utimestamp = &UnixDate("today","%s");
# If module execution get a valid value
if ($module_result == 0) {
print "[DEBUG] MODULERESULT = 0\n";
my %part;
$part{'name'}[0] = $agent_plugin->{'id_agent'};
$part{'name'}[0] = $agent_module->{'nombre'};
$part{'description'}[0] = "";
$part{'data'}[0] = $module_data;
my $tipo_modulo = $agent_plugin->{'id_module_type'};
my $tipo_modulo = dame_nombretipomodulo_idagentemodulo ($pa_config, $agent_module->{'id_tipo_modulo'}, $dbh);
# 1 - generic_data
# 2 - generic_proc
# 3 - generic_data_string
# 4 - generic_data_inc
# 19, 20 - image
if (1 == $tipo_modulo) {
if (1 == $agent_module->{'id_tipo_modulo'}) {
module_generic_data ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
elsif (4 == $tipo_modulo) {
elsif (4 == $agent_module->{'id_tipo_modulo'}) {
module_generic_data_inc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
elsif (3 == $tipo_modulo) {
elsif (3 == $agent_module->{'id_tipo_modulo'}) {
module_generic_data_string ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
elsif (2 == $tipo_modulo) {
# Generic_proc
elsif (2 == $agent_module->{'id_tipo_modulo'}) {
print "[DEBUG FINAL]: ".$agent_module->{'nombre'}." ".$module_data." ".$tipo_modulo." ".$agent_name. " ".$timestamp;
module_generic_proc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
else {
elsif ( (19 == $agent_module->{'id_tipo_modulo'}) || (20 == $agent_module->{'id_tipo_modulo'}) ) {
module_generic_image ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
else { # Unknown module!, this IS a problem
logger ($pa_config, "Plugin Server Problem with unknown module type '$tipo_modulo'", 0);
goto skipdb_execmod;
print "[DEBUG] Executing plugin UNKONWN MODULE TYPE$@\n";
$module_result = 1;
}
# Update agent last contact
# Insert Pandora version as agent version
pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
} else {
}
# If something went wrong in module processing...
if ($module_result != 0){
print "[DEBUG] MODULERESULT != 0\n";
# If module execution get a INVALID value
if ($agent_plugin->{'intervalo'} == 0){
$module_interval = dame_intervalo ($pa_config, $agent_plugin->{'id_agente'}, $dbh);
if ($agent_module->{'intervalo'} == 0){
$module_interval = dame_intervalo ($pa_config, $agent_module->{'id_agente'}, $dbh);
}
# Modules who cannot connect or something go bad, update last_execution_try field
logger ($pa_config, "Cannot obtain exec plugin Module ".$agent_plugin->{'nombre'}." from agent $agent_name", 3);
my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = ".$agent_plugin->{'id_agente_modulo'};
logger ($pa_config, "Cannot obtain exec plugin Module ".$agent_module->{'nombre'}." from agent $agent_name", 2);
my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = ".$agent_module->{'id_agente_modulo'};
$dbh->do($query_act);
}
skipdb_execmod:
$exec_sql->finish(); #close tagent_plugin hash reference
}

View File

@ -0,0 +1,413 @@
#!/usr/bin/perl
##########################################################################
# Pandora FMS Prediction Server
##########################################################################
# Copyright (c) 2008 Sancho Lerena, slerena@gmail.com
# (c) 2008 Artica Soluciones Tecnologicas 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; version 2.
#
# 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.
##########################################################################
# Includes list
use strict;
use warnings;
use Date::Manip; # Needed to manipulate DateTime formats of input, output and compare
use Time::Local; # DateTime basic manipulation
use threads;
use threads::shared;
# Pandora Modules
use PandoraFMS::Config;
use PandoraFMS::Tools;
use PandoraFMS::DB;
# Queue management
my @pending_task : shared;
my %pending_task_hash : shared;
my %current_task_hash : shared;
my $queue_lock : shared;
# FLUSH in each IO (only for debug, very slooow)
# ENABLED in DEBUGMODE
# DISABLE FOR PRODUCTION
$| = 0;
my %pa_config;
$SIG{'TERM'} = 'pandora_shutdown';
$SIG{'INT'} = 'pandora_shutdown';
# Inicio del bucle principal de programa
pandora_init(\%pa_config, "Pandora FMS Prediction Server");
# Read config file for Global variables
pandora_loadconfig (\%pa_config, 5);
# Audit server starting
pandora_audit (\%pa_config, "Pandora FMS Prediction server starting", "SYSTEM", "System");
# Daemonize and put in background
if ( $pa_config{"daemon"} eq "1" ){
if ($pa_config{"quiet"} eq "0"){
print " [*] Backgrounding Pandora FMS Prediction Server process.\n\n";
}
&pandora_daemonize ( \%pa_config);
}
# Launch now all prediction threads
# $ax is local thread id for this server
for (my $ax=0; $ax < $pa_config{'prediction_threads'}; $ax++){
threads->new( \&pandora_prediction_consumer, \%pa_config, $ax);
}
# Launch now the producer thread
threads->new( \&pandora_prediction_producer, \%pa_config);
# Last thread is the main process (this process)
if ($pa_config{"quiet"} == 0){
print " [*] All threads loaded and running \n";
}
# Start Pandora FMS loggin
pandora_startlog (\%pa_config);
my $dbhost = $pa_config{'dbhost'};
my $dbname = $pa_config{'dbname'};
my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
$pa_config{'dbuser'},
$pa_config{'dbpass'},
{ RaiseError => 1, AutoCommit => 1 });
# Server keepalive thread running in main thread on a infinite loop
while (1) {
pandora_serverkeepaliver (\%pa_config, 5, $dbh);
threads->yield;
sleep ($pa_config{"server_threshold"});
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
#--------------------- Main Perl Code below this line-----------------------
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
########################################################################################
# pandora_shutdown ()
# Close system on a received signal
########################################################################################
sub pandora_shutdown {
logger (\%pa_config,"Pandora FMS Prediction Server Shutdown by signal ",0);
print " [*] Shutting down Pandora FMS Prediction Server (received signal)...\n";
exit;
}
sub pandora_prediction_consumer ($$) {
my $pa_config = $_[0];
my $thread_id = $_[1];
if ($pa_config->{"quiet"} == 0){
print " [*] Starting up Prediction Consumer Thread # $thread_id \n";
}
my $data_id_agent_module;
# Create Database handler
my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
my $counter =0;
while (1) {
if ($counter > 10) {
sleep (1);
$counter = 0;
}
# Take the first element on the shared queue
# Insert this element on the current task hash
if (scalar(@pending_task) > 0){
{
lock $queue_lock;
$data_id_agent_module = shift(@pending_task);
print "[CLIENT] Pop out of queue module (pending queue) $data_id_agent_module \n";
delete($pending_task_hash{$data_id_agent_module});
$current_task_hash{$data_id_agent_module}=1;
}
# Executing network task with unmanaged error trapping
eval {
# Call network execution process
# exec_network_module ( $pa_config, $data_id_agent_module, $dbh);
print "[PREDICT-CLIENT] Executing module # $data_id_agent_module \n";
exec_prediction_module ($pa_config, $data_id_agent_module, $dbh);
};
if ($@){
logger ($pa_config, "[ERROR] Prediction Task for module $data_id_agent_module causes a system exception", 0);
logger ($pa_config, "ERROR Code: $@", 1);
}
# Remove from queue. If catch an error, probably data is
# not been processed, but has been freed from task queue
{
lock $queue_lock;
print "[CLIENT] Removing from queue (current task) module $data_id_agent_module \n";
delete($current_task_hash{$data_id_agent_module});
}
$counter = 0;
} else {
$counter ++;
}
}
}
sub pandora_prediction_producer ($) {
my $pa_config = $_[0];
my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
my $server_id = $pa_config->{'server_id'};
# Initialize variables for posterior usage
my $query1;
my @sql_data1;
my $data_id_agente_modulo;
my $data_flag;
my $exec_sql1;
while (1) {
if ($pa_config->{"pandora_master"} != 1) {
# Query for normal server, not MASTER server
$query1 = "SELECT
tagente_modulo.id_agente_modulo,
tagente_modulo.flag
FROM
tagente, tagente_modulo, tagente_estado
WHERE
id_prediction_server = $server_id
AND
tagente_modulo.id_agente = tagente.id_agente
AND
tagente.disabled = 0
AND
tagente_modulo.prediction_module != 0
AND
tagente_modulo.disabled = 0
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 ";
} else {
# 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_prediction_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
(tagente.id_prediction_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_prediction_server = tserver.id_server AND tserver.status = 0)
) AND
tagente.disabled = 0
AND
tagente_modulo.disabled = 0
AND
tagente_modulo.prediction_module != 0
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";
}
# print "[DEBUG] SQL is $query1 \n";
$exec_sql1 = $dbh->prepare($query1);
$exec_sql1 ->execute;
while (@sql_data1 = $exec_sql1->fetchrow_array()) {
$data_id_agente_modulo = $sql_data1[0];
$data_flag = $sql_data1[1];
print "[DEBUG] Procesando candidato $data_id_agente_modulo\n";
# Skip modules already queued
if ((!defined($pending_task_hash{$data_id_agente_modulo})) &&
(!defined($current_task_hash{$data_id_agente_modulo}))) {
if ($data_flag == 1){
$dbh->do("UPDATE tagente_modulo SET flag = 0 WHERE id_agente_modulo = $data_id_agente_modulo")
}
# Locking scope, do not remove redundant { }
{
print "[DEBUG] Metiendo $data_id_agente_modulo en cola \n";
lock $queue_lock;
push (@pending_task, $data_id_agente_modulo);
$pending_task_hash {$data_id_agente_modulo}=1;
}
}
}
#logger ($pa_config, "Items in Network Pending Queue: ".scalar(@pending_task), 5);
print "[DEBUG] Items in Network Pending Queue: ".scalar(@pending_task);
$exec_sql1->finish();
sleep($pa_config->{"server_threshold"});
} # Main loop
}
##########################################################################
# SUB exec_prediction_module (paconfig, id_agente_modulo, dbh )
# Execute prediction module task
##########################################################################
sub exec_prediction_module {
my $pa_config = $_[0];
my $id_am = $_[1];
my $dbh = $_[2];
# This function internal variables
my $i; # Internal counter for loops
my $n = 0; # total of real data values
# Set global variables for this sub
my $agent_module; # hash reference for tagente_modulo record
my $target_module; # hash reference for targetted tagente_modulo
# Get a full hash for agent_module record reference ($agent_module)
my $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_am";
my $exec_sql = $dbh->prepare($query_sql);
$exec_sql ->execute;
$agent_module = $exec_sql->fetchrow_hashref;
# Get a full hash for target agent_module record reference ($target_module)
$query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = " . $agent_module->{'prediction_module'};
$exec_sql = $dbh->prepare($query_sql);
$exec_sql ->execute;
$target_module = $exec_sql->fetchrow_hashref;
# Prediction mode explanation
#
# 0 is for target type of generic_proc. It compares latest data with current data. Needs to get
# data on a "middle" interval, so if interval is 300, get data to compare with 150 before
# and 150 in the future. If current data is ABOVE or BELOW average +- typical_deviation
# this is a BAD value (0), if not is ok (1) and written in target module as is.
# more interval configured for this module, more "margin" has to compare data.
#
# 1 is for target type of generic_data. It get's data in the future, using the interval given in
# module. It gets average from current timestamp to INTERVAL in the future and gets average
# value. Typical deviation is not used here.
my $prediction_mode;
if ($agent_module->{'id_tipo_modulo'} == 2){
$prediction_mode = 0; # proc
} else {
$prediction_mode = 1; # data
}
# Initialize another global sub variables.
my $agent_name = dame_agente_nombre ($pa_config, $agent_module->{'id_agente'}, $dbh);
my $module_data = 0; # 0 data for default
# Get current timestamp
my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
my $utimestamp = &UnixDate("today","%s");
# Get different data from each week one month ago (4 values)
# $agent_module->{'module_interval'} uses a margin of interval to get average data from the past
my @week_data;
my @week_utimestamp;
for ($i=0; $i<4; $i++){
$week_utimestamp[$i] = $utimestamp - (84600*7*($i+1));
# Adjust for proc prediction
if ($prediction_mode == 0) {
$week_utimestamp[$i] = $week_utimestamp[$i] - ($agent_module->{'module_interval'} / 2);
}
}
# Let's calculate statistical average using past data
my $average = 0;
my $temp1 = 0;
for ($i=0; $i < 4; $i++){
print "DEBUG HASH REF ".$target_module->{'id_agente_modulo'};
print "\n";
$temp1 = $week_utimestamp[$i] + $agent_module->{'module_interval'};
# Get data for week $i in the past
$query_sql = 'SELECT AVG(datos) FROM tagente_datos WHERE id_agente_modulo = '. $target_module->{'id_agente_modulo'}. ' AND utimestamp > '.$week_utimestamp[$i].' AND utimestamp < '.$temp1;
print "DEBUG SQL - $query_sql \n";
$week_data[$i] = get_db_free_field ($query_sql, $dbh);
# It's possible that one of the week_data[i] values was not valid (NULL)
# so recheck it and relay on n=0 for "no data" values set to 0 in result
# Calculate total ammount of valida data for each data sample
if ( (is_numeric($week_data[$i])) && ($week_data[$i] > 0) ){
$n++;
# Average SUM
$average = $average + $week_data[$i];
}
}
# Real average value
print "Value of n is $n \n";
if ($n > 0){
$average = $average / $n;
} else {
$average = 0;
}
# Calculate typical deviation
my $typical_deviation = 0;
for ($i=0; $i< $n; $i++){
if ( (is_numeric($week_data[$i])) && ($week_data[$i] > 0) ) {
$typical_deviation = $typical_deviation + (($week_data[$i] - $average)**2);
}
}
$typical_deviation = sqrt ($typical_deviation / ($n-1));
# (PROC) Compare with current data
if ($prediction_mode == 0){
$query_sql = 'SELECT data FROM tagente_estado WHERE id_agente_modulo = '.$target_module->{'id_agente_modulo'};
my $current_value = get_db_free_field ($query_sql, $dbh);
if ( ($current_value >= ($average - $typical_deviation)) || ($current_value <= ($average + $typical_deviation)) ){
$module_data = 1; # OK !!
} else {
$module_data = 0; # Out of predictions
}
} else {
# Prediction based on data
$module_data = $average;
}
# Build data for insertion
my %part;
$part{'name'}[0] = $agent_module->{'nombre'};
$part{'description'}[0] = "";
$part{'data'}[0] = $module_data;
my $tipo_modulo = dame_nombretipomodulo_idagentemodulo ($pa_config, $agent_module->{'id_tipo_modulo'}, $dbh);
# 1 - generic_data
# 2 - generic_proc
if (1 == $agent_module->{'id_tipo_modulo'}) {
module_generic_data ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
elsif (2 == $agent_module->{'id_tipo_modulo'}) {
module_generic_data_inc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
}
else { # Unknown module!, this IS a problem
logger ($pa_config, "[FATAL] Prediction Server Problem with unknown module type '$tipo_modulo'", 0);
print "[DEBUG] Executing Prediction UNKONWN MODULE TYPE$@\n";
exit;
}
# Update agent last contact
# Insert Pandora version as agent version
pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
}

View File

@ -27,15 +27,18 @@ require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( pandora_help_screen
pandora_init
pandora_loadconfig );
our @EXPORT = qw(
pandora_help_screen
pandora_init
pandora_loadconfig
pandora_startlog
);
# 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 = "2.0-dev";
my $pandora_build="PS080226";
my $pandora_build="PS080311";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash
@ -48,12 +51,14 @@ my %pa_config;
##########################################################################
sub help_screen {
printf "\n\nSyntax: \n pandora_server < fullpathname to pandora server configuration file > [ options ] \n\n";
printf "\nSyntax: \n\n pandora_server < fullpathname to pandora server configuration file > [ options ] \n\n";
printf "Following options are optional : \n";
printf " -v : Verbose mode activated, give more information in logfile \n";
printf " -d : Debug mode activated, give extensive information in logfile \n";
printf " -D : Daemon mode (runs in backgroup)\n";
printf " -h : This screen, show a little help screen \n";
printf " -v : Verbose mode activated, give more information in logfile \n";
printf " -d : Debug mode activated, give extensive information in logfile \n";
printf " -D : Daemon mode (runs in backgroup)\n";
printf " -P <file> : Store PID to file.\n";
printf " -q : Quiet startup\n";
printf " -h : This screen, show a little help screen \n";
printf " \n";
exit;
}
@ -67,8 +72,8 @@ sub pandora_init {
my $pa_config = $_[0];
my $init_string = $_[1];
printf "\n$init_string $pandora_version Build $pandora_build Copyright (c) 2004-2008 ArticaST\n";
printf "This program is Free Software, licensed under the terms of GPL License v2.\n";
printf "You can download latest versions and documentation at http://pandora.sourceforge.net. \n\n";
printf "This program is OpenSource, licensed under the terms of GPL License version 2.\n";
printf "You can download latest versions and documentation at http://pandora.sourceforge.net \n\n";
# Load config file from command line
if ($#ARGV == -1 ){
@ -78,6 +83,8 @@ sub pandora_init {
}
$pa_config->{"verbosity"}=1; # Verbose 1 by default
$pa_config->{"daemon"}=0; # Daemon 0 by default
$pa_config->{'PID'}=""; # PID file not exist by default
$pa_config->{"quiet"}=0; # Daemon 0 by default
# If there are not valid parameters
my $parametro;
@ -90,9 +97,15 @@ sub pandora_init {
elsif ($parametro =~ m/-v\z/i) {
$pa_config->{"verbosity"}=5;
}
elsif ($parametro =~ m/^-P\z/i) {
$pa_config->{'PID'}= clean_blank($ARGV[$ax+1]);
}
elsif ($parametro =~ m/-d\z/) {
$pa_config->{"verbosity"}=10;
}
elsif ($parametro =~ m/-q\z/) {
$pa_config->{"quiet"}=1;
}
elsif ($parametro =~ m/-D\z/) {
$pa_config->{"daemon"}=1;
}
@ -161,15 +174,19 @@ sub pandora_loadconfig {
$pa_config->{"tcp_timeout"} = 20; # Introduced on 1.3.1
$pa_config->{"snmp_proc_deadresponse"} = 0; # Introduced on 1.3.1 10 Feb08
$pa_config->{"plugin_threads"} = 3; # Introduced on 2.0
$pa_config->{"prediction_threads"} = 3; # Introduced on 2.0
$pa_config->{"plugin_timeout"} = 5; # Introduced on 2.0
$pa_config->{"wmi_threads"} = 3; # Introduced on 2.0
$pa_config->{"wmi_timeout"} = 5; # Introduced on 2.0
# Check for UID0
if ($> == 0){
printf " [W] Not all Pandora FMS components need to be executed as root\n";
printf " please consider starting it with a non-privileged user.\n";
}
if ($pa_config->{"quiet"} != 0){
if ($> == 0){
printf " [W] Not all Pandora FMS components need to be executed as root\n";
printf " please consider starting it with a non-privileged user.\n";
}
}
# Check for file
if ( ! -e $archivo_cfg ) {
printf "\n [ERROR] Cannot open configuration file at $archivo_cfg. \n";
@ -250,6 +267,9 @@ sub pandora_loadconfig {
elsif ($parametro =~ m/^dataserver\s([0-9]*)/i){
$pa_config->{'dataserver'}= clean_blank($1);
}
elsif ($parametro =~ m/^networkserver\s([0-9]*)/i){
$pa_config->{'networkserver'}= clean_blank($1);
}
elsif ($parametro =~ m/^pluginserver\s([0-9]*)/i){
$pa_config->{'pluginserver'}= clean_blank($1);
}
@ -316,6 +336,9 @@ sub pandora_loadconfig {
elsif ($parametro =~ m/^plugin_threads\s([0-9]*)/i) {
$pa_config->{'plugin_threads'}= clean_blank($1);
}
elsif ($parametro =~ m/^prediction_threads\s([0-9]*)/i) {
$pa_config->{'prediction_threads'}= clean_blank($1);
}
elsif ($parametro =~ m/^plugin_timeout\s([0-9]*)/i) {
$pa_config->{'plugin_timeout'}= clean_blank($1);
}
@ -326,7 +349,10 @@ sub pandora_loadconfig {
} # end of loop for parameter #
if ( $pa_config->{"verbosity"} > 0){
if (($pa_config->{"verbosity"} > 0) && ($pa_config->{"quiet"} == 0)){
if ($pa_config->{"PID"} ne ""){
print " [*] PID File is written at ".$pa_config->{'PID'}."\n";
}
print " [*] Server basepath is ".$pa_config->{'basepath'}."\n";
print " [*] Server logfile at ".$pa_config->{"logfile"}."\n";
print " [*] Server errorlogfile at ".$pa_config->{"errorlogfile"}."\n";
@ -367,50 +393,54 @@ sub pandora_loadconfig {
print " [ERROR] You must enable 'wmiserver' in setup file to run Pandora FMS WMI server. \n\n";
exit;
}
if ($opmode == 0){
print " [*] You are running Pandora FMS Data Server. \n";
$parametro ="Pandora FMS Data Server";
$pa_config->{"servermode"}="_Data";
}
if ($opmode == 1){
print " [*] You are running Pandora FMS Network Server. \n";
$parametro ="Pandora FMS Network Server";
$pa_config->{"servermode"}="_Net";
}
if ($opmode == 2){
print " [*] You are running Pandora FMS SNMP Console. \n";
$parametro ="Pandora FMS SNMP Console";
$pa_config->{"servermode"}="_SNMP";
}
if ($opmode == 3){
print " [*] You are running Pandora FMS Recon Server. \n";
$parametro ="Pandora FMS Recon Server";
$pa_config->{"servermode"}="_Recon";
}
if ($opmode == 4){
print " [*] You are running Pandora FMS Plugin Server. \n";
$parametro ="Pandora FMS Plugin Server";
$pa_config->{"servermode"}="_Plugin";
# Show some config options in startup
if ($pa_config->{"quiet"} == 0){
if ($opmode == 0){
print " [*] You are running Pandora FMS Data Server. \n";
$parametro ="Pandora FMS Data Server";
$pa_config->{"servermode"}="_Data";
}
if ($opmode == 1){
print " [*] You are running Pandora FMS Network Server. \n";
$parametro ="Pandora FMS Network Server";
$pa_config->{"servermode"}="_Net";
}
if ($opmode == 2){
print " [*] You are running Pandora FMS SNMP Console. \n";
$parametro ="Pandora FMS SNMP Console";
$pa_config->{"servermode"}="_SNMP";
}
if ($opmode == 3){
print " [*] You are running Pandora FMS Recon Server. \n";
$parametro ="Pandora FMS Recon Server";
$pa_config->{"servermode"}="_Recon";
}
if ($opmode == 4){
print " [*] You are running Pandora FMS Plugin Server. \n";
$parametro ="Pandora FMS Plugin Server";
$pa_config->{"servermode"}="_Plugin";
}
if ($opmode == 5){
print " [*] You are running Pandora FMS Prediction Server. \n";
$parametro ="Pandora FMS Prediction Server";
$pa_config->{"servermode"}="_Prediction";
}
if ($opmode == 6){
print " [*] You are running Pandora FMS WMI Server. \n";
$parametro ="Pandora FMS WMI Server";
$pa_config->{"servermode"}="_WMI";
}
if ($pa_config->{"pandora_check"} == 1) {
print " [*] MD5 Security enabled.\n";
}
if ($pa_config->{"pandora_master"} == 1) {
print " [*] This server is running in MASTER mode.\n";
}
}
if ($opmode == 5){
print " [*] You are running Pandora FMS Prediction Server. \n";
$parametro ="Pandora FMS Prediction Server";
$pa_config->{"servermode"}="_Prediction";
}
if ($opmode == 6){
print " [*] You are running Pandora FMS WMI Server. \n";
$parametro ="Pandora FMS WMI Server";
$pa_config->{"servermode"}="_WMI";
}
if ($pa_config->{"pandora_check"} == 1) {
print " [*] MD5 Security enabled.\n";
}
if ($pa_config->{"pandora_master"} == 1) {
print " [*] This server is running in MASTER mode.\n";
}
logger ($pa_config, "Launching $parametro $pa_config->{'version'} $pa_config->{'build'}", 0);
my $config_options = "Logfile at ".$pa_config->{"logfile"}.", Basepath is ".$pa_config->{"basepath"}.", Checksum is ".$pa_config->{"pandora_check"}.", Master is ".$pa_config->{"pandora_master"}.", SNMP Console is ".$pa_config->{"snmpconsole"}.", Server Threshold at ".$pa_config->{"server_threshold"}." sec, verbosity at ".$pa_config->{"verbosity"}.", Alert Threshold at $pa_config->{'alert_threshold'}, ServerName is '".$pa_config->{'servername'}.$pa_config->{"servermode"}."'";
logger ($pa_config, "Config options: $config_options");
logger ($pa_config, "Config options: $config_options", 1);
my $dbh;
# Check valid Database variables and update server status
eval {
@ -423,15 +453,24 @@ sub pandora_loadconfig {
print $@;
exit;
}
print " [*] Pandora FMS Server [".$pa_config->{'servername'}.$pa_config->{"servermode"}."] is running and operative \n";
if ($pa_config->{"quiet"} == 0){
print " [*] Pandora FMS Server [".$pa_config->{'servername'}.$pa_config->{"servermode"}."] is running and operative \n";
}
$pa_config->{'server_id'} = dame_server_id ($pa_config, $pa_config->{'servername'}.$pa_config->{"servermode"}, $dbh);
# Dump all errors to errorlog
open STDERR, ">>$pa_config->{'errorlogfile'}" or die " [ERROR] Pandora FMS can't write to Errorlog. Aborting : \n $!";
my $time_now = &UnixDate("today","%Y/%m/%d %H:%M:%S");
print STDERR "$time_now - ".$pa_config->{'servername'}." Starting Pandora FMS server. Error logging activated \n";
}
sub pandora_startlog ($){
my $pa_config = $_[0];
# Dump all errors to errorlog
open STDERR, ">>$pa_config->{'errorlogfile'}" or die " [ERROR] Pandora FMS can't write to Errorlog. Aborting : \n $! \n";
my $time_now = &UnixDate("today","%Y/%m/%d %H:%M:%S");
print STDERR "$time_now - ".$pa_config->{'servername'}.$pa_config->{"servermode"}." Starting Pandora FMS Server. Error logging activated \n";
# This redirect ANY output to errorlog. Not a good idea for real usage !
# open STDOUT, ">>$pa_config->{'errorlogfile'}"
}
# End of function declaration
# End of defined Code

View File

@ -33,39 +33,42 @@ require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( crea_agente_modulo
dame_server_id
dame_agente_id
dame_agente_modulo_id
dame_agente_nombre
dame_comando_alerta
dame_desactivado
dame_grupo_agente
dame_id_tipo_modulo
dame_intervalo
dame_learnagente
dame_modulo_id
dame_nombreagente_agentemodulo
dame_nombretipomodulo_idagentemodulo
dame_ultimo_contacto
give_networkserver_status
pandora_updateserver
pandora_serverkeepaliver
pandora_audit
pandora_event
pandora_lastagentcontact
pandora_writedata
pandora_writestate
pandora_calcula_alerta
module_generic_proc
module_generic_data
module_generic_data_inc
module_generic_data_string
execute_alert
give_network_component_profile_name
pandora_create_incident
give_db_value
);
our @EXPORT = qw(
crea_agente_modulo
dame_server_id
dame_agente_id
dame_agente_modulo_id
dame_agente_nombre
dame_comando_alerta
dame_desactivado
dame_grupo_agente
dame_id_tipo_modulo
dame_intervalo
dame_learnagente
dame_modulo_id
dame_nombreagente_agentemodulo
dame_nombretipomodulo_idagentemodulo
dame_ultimo_contacto
give_networkserver_status
pandora_updateserver
pandora_serverkeepaliver
pandora_audit
pandora_event
pandora_lastagentcontact
pandora_writedata
pandora_writestate
pandora_calcula_alerta
module_generic_proc
module_generic_data
module_generic_data_inc
module_generic_data_string
execute_alert
give_network_component_profile_name
pandora_create_incident
get_db_value
get_db_free_row
get_db_free_field
);
# Spanish translation note:
# 'Crea' in spanish means 'create'
@ -374,18 +377,22 @@ sub pandora_writestate (%$$$$$$$) {
# now we use only local timestamp to stamp state of modules
my $pa_config = $_[0];
my $nombre_agente = $_[1];
my $tipo_modulo = $_[2];
my $tipo_modulo = $_[2]; # passed as string
my $nombre_modulo = $_[3];
my $datos = $_[4]; # Careful: Dont pass a hash, only a single value
my $estado = $_[5];
my $dbh = $_[6];
my $needs_update = $_[7];
my $timestamp = &UnixDate ("today", "%Y-%m-%d %H:%M:%S");
my $utimestamp; # integer version of timestamp
$utimestamp = &UnixDate($timestamp,"%s"); # convert from human to integer
my @data;
my $cambio = 0;
my $id_grupo;
# Get current timestamp / unix numeric time
my $timestamp = &UnixDate ("today", "%Y-%m-%d %H:%M:%S"); # string timestamp
my $utimestamp = &UnixDate($timestamp,"%s"); # convert from human to integer
# Get server id
my $server_name = $pa_config->{'servername'}.$pa_config->{"servermode"};
my $id_server = dame_server_id($pa_config, $server_name, $dbh);
@ -395,8 +402,9 @@ sub pandora_writestate (%$$$$$$$) {
my $id_agente = dame_agente_id ($pa_config, $nombre_agente, $dbh);
my $id_modulo = dame_modulo_id ($pa_config, $tipo_modulo, $dbh);
my $id_agente_modulo = dame_agente_modulo_id($pa_config, $id_agente, $id_modulo, $nombre_modulo, $dbh);
if (($id_agente == -1) || ($id_agente_modulo == -1)) {
goto fin_pandora_writestate;
return 0;
}
# Seek for agent_interval or module_interval
@ -432,38 +440,37 @@ sub pandora_writestate (%$$$$$$$) {
my $query_act; # OJO que dentro de una llave solo tiene existencia en esa llave !!
if ($s_idages->rows == 0) { # Doesnt exist entry in table, lets make the first entry
logger($pa_config, "Create entry in tagente_estado for module $nombre_modulo",4);
$query_act = "INSERT INTO tagente_estado (id_agente_modulo, datos, timestamp, estado, cambio, id_agente, last_try, utimestamp, current_interval, running_by, last_execution_try) VALUES ($id_agente_modulo,$datos,'$timestamp','$estado','1',$id_agente,'$timestamp',$utimestamp, $module_interval, $id_server, $utimestamp)"; # Cuando se hace un insert, siempre hay un cambio de estado
$query_act = "INSERT INTO tagente_estado (id_agente_modulo, datos, timestamp, estado, cambio, id_agente, last_try, utimestamp, current_interval, running_by, last_execution_try) VALUES ($id_agente_modulo,$datos,'$timestamp','$estado','1',$id_agente,'$timestamp',$utimestamp, $module_interval, $id_server, $utimestamp)"; # Cuando se hace un insert, siempre hay un cambio de estado
} else { # There are an entry in table already
@data = $s_idages->fetchrow_array();
# Se supone que $data[5](estado) ( nos daria el estado ANTERIOR
# For xxxx_PROC type (boolean / monitor), create an event if state has changed
if (( $data[5] != $estado) && ( ($tipo_modulo =~/keep_alive/) || ($tipo_modulo =~ /proc/)) ) {
# Cambio de estado detectado !
$cambio = 1;
# Este seria el momento oportuno de probar a saltar la alerta si estuviera definida
# Makes an event entry, only if previous state changes, if new state, doesnt give any alert
$id_grupo = dame_grupo_agente($pa_config, $id_agente,$dbh);
my $descripcion;
if ( $estado == 0) {
$descripcion = "Monitor ($nombre_modulo) goes up ";
}
if ( $estado == 1) {
$descripcion = "Monitor ($nombre_modulo) goes down";
}
pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh);
}
if ($needs_update == 1) {
$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, last_try = '$timestamp', current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = '$id_agente_modulo'";
} else { # dont update last_try field, that it's the field
# we use to check last update time in database
$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = '$id_agente_modulo'";
}
}
@data = $s_idages->fetchrow_array();
# Se supone que $data[5](estado) ( nos daria el estado ANTERIOR
# For xxxx_PROC type (boolean / monitor), create an event if state has changed
if (( $data[5] != $estado) && ( ($tipo_modulo =~/keep_alive/) || ($tipo_modulo =~ /proc/)) ) {
# Cambio de estado detectado !
$cambio = 1;
# Este seria el momento oportuno de probar a saltar la alerta si estuviera definida
# Makes an event entry, only if previous state changes, if new state, doesnt give any alert
$id_grupo = dame_grupo_agente($pa_config, $id_agente,$dbh);
my $descripcion;
if ( $estado == 0) {
$descripcion = "Monitor ($nombre_modulo) goes up ";
}
if ( $estado == 1) {
$descripcion = "Monitor ($nombre_modulo) goes down";
}
pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh);
}
if ($needs_update == 1) {
$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, last_try = '$timestamp', current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo";
} else { # dont update last_try field, that it's the field
# we use to check last update time in database
$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo";
}
}
my $a_idages = $dbh->prepare($query_act);
$a_idages->execute;
$a_idages->finish();
$s_idages->finish();
fin_pandora_writestate:
$s_idages->finish();
}
##########################################################################
@ -528,14 +535,14 @@ sub pandora_accessupdate (%$$) {
logger($pa_config,"Updating tagent_access for agent id $id_agent",9);
}
# Update keepalive module (if present, if there is more than one, only updates first one!).
my $id_agent_module = give_db_free ("SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = $id_agent AND id_tipo_modulo = 100", $dbh);
if ($id_agent_module ne -1){
my $agent_name = give_db_free ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh);
my $module_typename = "keep_alive";
my $module_name = give_db_free ("SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = $id_agent_module", $dbh);
pandora_writestate ($pa_config, $agent_name, $module_typename, $module_name, 1, 0, $dbh, 1);
}
# Update keepalive module (if present, if there is more than one, only updates first one!).
my $id_agent_module = get_db_free_field ("SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = $id_agent AND id_tipo_modulo = 100", $dbh);
if ($id_agent_module ne -1){
my $agent_name = get_db_free_field ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh);
my $module_typename = "keep_alive";
my $module_name = get_db_free_field ("SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = $id_agent_module", $dbh);
pandora_writestate ($pa_config, $agent_name, $module_typename, $module_name, 1, 0, $dbh, 1);
}
}
}
@ -960,8 +967,10 @@ fin_DB_insert_datos:
## Update server status
##########################################################################
sub pandora_serverkeepaliver (%$$) {
my $pa_config= $_[0];
my $opmode = $_[1]; # 0 dataserver, 1 network server, 2 snmp console, 3 recon server
my $pa_config= $_[0];
my $opmode = $_[1]; # 0 dataserver, 1 network server, 2 snmp console
# 3 recon srv, 4 plugin srv, 5 prediction srv
# 6 WMI server
my $dbh = $_[2];
my $version_data;
my $pandorasuffix;
@ -1024,7 +1033,7 @@ sub pandora_updateserver (%$$$) {
} elsif ($opmode == 4){
$pandorasuffix = "_Plugin";
} elsif ($opmode == 5){
$pandorasuffix = "_IA";
$pandorasuffix = "_Prediction";
} elsif ($opmode == 6){
$pandorasuffix = "_WMI";
} else {
@ -1091,7 +1100,7 @@ sub pandora_lastagentcontact (%$$$$$$) {
my $dbh = $_[6];
my $id_agente = dame_agente_id($pa_config, $nombre_agente,$dbh);
pandora_accessupdate ($pa_config, $id_agente, $dbh);
pandora_accessupdate ($pa_config, $id_agente, $dbh);
my $query = "";
if ($interval == -1){ # no update for interval field (some old agents doest support it)
$query = "update tagente set agent_version = '$agent_version', ultimo_contacto_remoto = '$timestamp', ultimo_contacto = '$time_now', os_version = '$os_data' where id_agente = $id_agente";
@ -1370,25 +1379,25 @@ sub give_group_disabled (%$$) {
## Return module ID, given "nombre_modulo" as module name
##########################################################################
sub dame_modulo_id (%$$) {
my $pa_config = $_[0];
my $nombre_modulo = $_[1];
my $dbh = $_[2];
my $pa_config = $_[0];
my $nombre_modulo = $_[1];
my $dbh = $_[2];
my $id_modulo; my @data;
# Calculate agent ID using select by its name
my $query_idag = "select * from ttipo_modulo where nombre = '$nombre_modulo'";
my $s_idag = $dbh->prepare($query_idag);
$s_idag ->execute;
if ($s_idag->rows == 0) {
logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1);
logger($pa_config, "ERROR: SQL Query is $query_idag ",2);
$id_modulo = -1;
} else {
@data = $s_idag->fetchrow_array();
$id_modulo = $data[0];
}
$s_idag->finish();
return $id_modulo;
my $id_modulo; my @data;
# Calculate agent ID using select by its name
my $query_idag = "select * from ttipo_modulo where nombre = '$nombre_modulo'";
my $s_idag = $dbh->prepare($query_idag);
$s_idag ->execute;
if ($s_idag->rows == 0) {
logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1);
logger($pa_config, "ERROR: SQL Query is $query_idag ",2);
$id_modulo = 0;
} else {
@data = $s_idag->fetchrow_array();
$id_modulo = $data[0];
}
$s_idag->finish();
return $id_modulo;
}
##########################################################################
@ -1686,7 +1695,7 @@ sub crea_agente_modulo (%$$$$$$$) {
# Generic access to a field ($field) given a table
# give_db_value (field_name_to_be_returned, table, field_search, condition_value, dbh)
# ---------------------------------------------------------------
sub give_db_value ($$$$$) {
sub get_db_value ($$$$$) {
my $field = $_[0];
my $table = $_[1];
my $field_search = $_[2];
@ -1706,9 +1715,10 @@ sub give_db_value ($$$$$) {
}
# ---------------------------------------------------------------
# Generic access to a field ($field) given a table
# Free SQL sentence. Return first field on exit
# ---------------------------------------------------------------
sub give_db_free ($$) {
sub get_db_free_field ($$) {
my $condition = $_[0];
my $dbh = $_[1];
@ -1724,6 +1734,28 @@ sub give_db_free ($$) {
return -1;
}
# ---------------------------------------------------------------
# Free SQL sentence. Return entire hash in row
# ---------------------------------------------------------------
sub get_db_free_row ($$) {
my $condition = $_[0];
my $dbh = $_[1];
my $rowref;
my $query = $condition;
my $s_idag = $dbh->prepare($query);
$s_idag ->execute;
if ($s_idag->rows != 0) {
$rowref = $s_idag->fetchrow_hashref;
$s_idag->finish();
return $rowref;
}
return -1;
}
# End of function declaration
# End of defined Code

View File

@ -27,15 +27,16 @@ require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( daemonize
logger
limpia_cadena
md5check
float_equal
sqlWrap
is_numeric
clean_blank
);
our @EXPORT = qw(
pandora_daemonize
logger
limpia_cadena
md5check
float_equal
sqlWrap
is_numeric
clean_blank
);
##########################################################################
@ -43,15 +44,23 @@ our @EXPORT = qw( daemonize
# Put program in background (for daemon mode)
##########################################################################
sub daemonize {
chdir '/tmp' or die "Can't chdir to /tmp: $!";
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
defined(my $pid = fork) or die "Can't fork: $!";
sub pandora_daemonize {
my $pa_config = $_[0];
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
chdir '/tmp' or die "Can't chdir to /tmp: $!";
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!";
setsid or die "Can't start a new session: $!";
umask 0;
# Store PID of this process in file presented by config token
if ($pa_config->{'PID'} ne ""){
open (FILE, "> ".$pa_config->{'PID'}) or die "[FATAL] Cannot open PIDfile at ".$pa_config->{'PID'};
print FILE "$$";
close (FILE);
}
}

View File

@ -1,8 +1,34 @@
This small utility is make to test your database speed in Pandora Scheme.
Pandora FMS DB Stress
=====================
You need to create an agent and assing modules for automated data injection with this tool. Name this modules acording this:
This is a small tool to test your database performance. It also could be used to "pregenerate" random or periodic data (using trigonometry functions) and populate ficticious modules.
You need to create an agent and assign modules for automated data injection with this tool. You need to name that modules according to this notation:
random - To generate "random" data.
curve - To generate a math curve using trigonometrical functions, useful to see interpolation working with different intervals, etc
boolean - Generate "random" boolean data.
So you could use any name that contains words "random, curve or boolean", for example:
random_1 or curve_other
You only could choose "data server" kind of module.
Finetuning DB stress tool
=========================
Tool is preconfigured to search in all agents for modules called random, curve or boolean, and to use a interval of 300 and during 30 days.
If want to modify this behaviour you should edit pandora_dbstress script and modify some variables at the top of file:
# Configure here target (AGENT_ID for Stress)
my $target_module = -1; # -1 for all modules of that agent
my $target_agent = -1;
my $target_interval = 300;
my $target_days = 30;
Set there target_module (for a fixed module) or set -1 to process all matching targets
Set there target_agent (for a specific agent).
Set target_interval in seconds for default module interval data periodicity.
Set target_days, number of days in the past from current timestamp.

View File

@ -21,8 +21,8 @@
my $target_module = -1; # -1 for all modules of that agent
my $target_agent = -1;
my $target_interval = 1200;
my $target_days = 12;
my $target_interval = 300;
my $target_days = 30;
################################################################################
################################################################################