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 5cfd5b4353
commit b2ece3be75
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> 2008-03-11 Manuel Arostegui <marostegui@artica.es>
* pandora_server, pandora_network, pandora_recon: * pandora_server, pandora_network, pandora_recon:

View File

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

View File

@ -57,27 +57,30 @@ pandora_loadconfig (\%pa_config, 4);
# Audit server starting # Audit server starting
pandora_audit (\%pa_config, "Pandora FMS Plugin server starting", "SYSTEM", "System"); pandora_audit (\%pa_config, "Pandora FMS Plugin server starting", "SYSTEM", "System");
print " [*] Starting up plugin threads\n"; # Daemonize and put in background
if ( $pa_config{"daemon"} eq "1" ){
die "Aqui me quedo"; if ($pa_config{"quiet"} eq "0"){
if ( $pa_config{"daemon"} eq "1" ) {
print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n"; print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n";
&daemonize; }
&pandora_daemonize ( \%pa_config);
} }
=for COMMENT BLOCK
# Launch now all plugin threads # Launch now all plugin threads
# $ax is local thread id for this server # $ax is local thread id for this server
for (my $ax=0; $ax < $pa_config{'plugin_threads'}; $ax++){ for (my $ax=0; $ax < $pa_config{'plugin_threads'}; $ax++){
threads->new( \&pandora_plugin_consumer, \%pa_config, $ax); threads->new( \&pandora_plugin_consumer, \%pa_config, $ax);
} }
=cut
# Launch now the producer thread # Launch now the producer thread
threads->new( \&pandora_plugin_producer, \%pa_config); threads->new( \&pandora_plugin_producer, \%pa_config);
print " [*] All threads loaded and running \n\n";
# Last thread is the main process (this process) # 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 $dbhost = $pa_config{'dbhost'};
my $dbname = $pa_config{'dbname'}; 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 # Server keepalive thread running in main thread on a infinite loop
while (1) { while (1) {
pandora_serverkeepaliver (\%pa_config, 1, $dbh); pandora_serverkeepaliver (\%pa_config, 4, $dbh);
threads->yield; threads->yield;
sleep ($pa_config{"server_threshold"}); sleep ($pa_config{"server_threshold"});
} }
@ -120,7 +123,9 @@ sub pandora_plugin_consumer ($$) {
my $pa_config = $_[0]; my $pa_config = $_[0];
my $thread_id = $_[1]; my $thread_id = $_[1];
if ($pa_config->{"quiet"} == 0){
print " [*] Starting up Plugin Consumer Thread # $thread_id \n"; print " [*] Starting up Plugin Consumer Thread # $thread_id \n";
}
my $data_id_agent_module; my $data_id_agent_module;
# Create Database handler # Create Database handler
@ -139,6 +144,7 @@ sub pandora_plugin_consumer ($$) {
{ {
lock $queue_lock; lock $queue_lock;
$data_id_agent_module = shift(@pending_task); $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}); delete($pending_task_hash{$data_id_agent_module});
$current_task_hash{$data_id_agent_module}=1; $current_task_hash{$data_id_agent_module}=1;
} }
@ -147,6 +153,7 @@ sub pandora_plugin_consumer ($$) {
eval { eval {
# Call network execution process # Call network execution process
# exec_network_module ( $pa_config, $data_id_agent_module, $dbh); # 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); exec_plugin_module ($pa_config, $data_id_agent_module, $dbh);
}; };
if ($@){ if ($@){
@ -158,6 +165,7 @@ sub pandora_plugin_consumer ($$) {
# not been processed, but has been freed from task queue # not been processed, but has been freed from task queue
{ {
lock $queue_lock; lock $queue_lock;
#print "[CLIENT] Removing from queue (current task) module $data_id_agent_module \n";
delete($current_task_hash{$data_id_agent_module}); delete($current_task_hash{$data_id_agent_module});
} }
$counter = 0; $counter = 0;
@ -191,13 +199,15 @@ sub pandora_plugin_producer ($) {
FROM FROM
tagente, tagente_modulo, tagente_estado tagente, tagente_modulo, tagente_estado
WHERE WHERE
id_server = $server_id id_plugin_server = $server_id
AND AND
tagente_modulo.id_agente = tagente.id_agente tagente_modulo.id_agente = tagente.id_agente
AND AND
tagente.disabled = 0 tagente.disabled = 0
AND AND
tagente_modulo.id_tipo_modulo > 4 tagente_modulo.id_plugin != 0
AND
tagente_modulo.disabled = 0
AND AND
tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND ( AND (
@ -214,23 +224,28 @@ sub pandora_plugin_producer ($) {
FROM FROM
tagente, tagente_modulo, tagente_estado, tserver tagente, tagente_modulo, tagente_estado, tserver
WHERE WHERE
( (tagente.id_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) 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 AND tagente.id_plugin_server = tserver.id_server AND tserver.status = 0)
) AND ) AND
tagente.disabled = 0 tagente.disabled = 0
AND AND
tagente_modulo.id_tipo_modulo > 4 tagente_modulo.disabled = 0
AND
tagente_modulo.id_plugin != 0
AND AND
tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND AND
((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 ) ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 )
ORDER BY last_execution_try ASC"; ORDER BY last_execution_try ASC";
} }
#print "[DEBUG] SQL is $query1 \n";
$exec_sql1 = $dbh->prepare($query1); $exec_sql1 = $dbh->prepare($query1);
$exec_sql1 ->execute; $exec_sql1 ->execute;
while (@sql_data1 = $exec_sql1->fetchrow_array()) { while (@sql_data1 = $exec_sql1->fetchrow_array()) {
$data_id_agente_modulo = $sql_data1[0]; $data_id_agente_modulo = $sql_data1[0];
$data_flag = $sql_data1[1]; $data_flag = $sql_data1[1];
print "[DEBUG] Procesando candidato $data_id_agente_modulo\n";
# Skip modules already queued # Skip modules already queued
if ((!defined($pending_task_hash{$data_id_agente_modulo})) && if ((!defined($pending_task_hash{$data_id_agente_modulo})) &&
(!defined($current_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 { } # Locking scope, do not remove redundant { }
{ {
#print "[DEBUG] Metiendo $data_id_agente_modulo en cola \n";
lock $queue_lock; lock $queue_lock;
push (@pending_task, $data_id_agente_modulo); push (@pending_task, $data_id_agente_modulo);
$pending_task_hash {$data_id_agente_modulo}=1; $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); #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(); $exec_sql1->finish();
sleep($pa_config->{"server_threshold"}); sleep($pa_config->{"server_threshold"});
} # Main loop } # Main loop
@ -263,17 +280,17 @@ sub exec_plugin_module {
# Set global variables for this sub # Set global variables for this sub
my $timeout = $pa_config->{'plugin_timeout'}; 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 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 $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_am";
my $exec_sql = $dbh->prepare($query_sql); my $exec_sql = $dbh->prepare($query_sql);
$exec_sql ->execute; $exec_sql ->execute;
$agent_plugin = $exec_sql->fetchrow_hashref; $agent_module = $exec_sql->fetchrow_hashref;
# Get a full hash for plugin record reference ($plugin) # 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 = $dbh->prepare($query_sql);
$exec_sql->execute(); $exec_sql->execute();
$plugin = $exec_sql->fetchrow_hashref; $plugin = $exec_sql->fetchrow_hashref;
@ -284,7 +301,7 @@ sub exec_plugin_module {
} }
# Initialize another global sub variables. # 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_result = 1; # Fail by default
my $module_data = 0; # 0 data for default my $module_data = 0; # 0 data for default
my $module_interval = 0; my $module_interval = 0;
@ -293,23 +310,23 @@ sub exec_plugin_module {
my $exec_output = ""; my $exec_output = "";
my $plugin_command = $plugin->{"execute"}; my $plugin_command = $plugin->{"execute"};
if ($plugin->{'net_dst_opt'} ne ""){ 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 "") { 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 "") { 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 "") { 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 # Proccess field / optional / dynamic field
if ($agent_plugin->{'plugin_parameter'} ne "") { if ($agent_module->{'plugin_parameter'} ne "") {
$plugin_command = $plugin_command . $agent_plugin->{'plugin_parameter'}; $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" # Final command line execution is stored at "plugin_command"
eval { eval {
alarm ($timeout); alarm ($timeout);
@ -317,12 +334,18 @@ sub exec_plugin_module {
alarm(0); # Cancel the pending alarm if plugin call returns alive alarm(0); # Cancel the pending alarm if plugin call returns alive
$module_result = 0; # If comes here, this is a successfull exec $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/) { 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); logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_module->{'id_agente_modulo'}." causes a system timeout in exec", 1);
# resuming eval block... logger ($pa_config, "Executing plugin command '$plugin_command'", 9);
} else { print "[DEBUG] Executing plugin TIMEOUT\n";
logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_plugin->{'id_agente_modulo'}." causes an unknown system error", 1); # 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); logger ($pa_config, "[ERROR] $@", 1);
print "[DEBUG] Executing plugin ERROR $@\n";
} }
sub timed_out { sub timed_out {
@ -335,46 +358,60 @@ sub exec_plugin_module {
# If module execution get a valid value # If module execution get a valid value
if ($module_result == 0) { if ($module_result == 0) {
print "[DEBUG] MODULERESULT = 0\n";
my %part; my %part;
$part{'name'}[0] = $agent_plugin->{'id_agent'}; $part{'name'}[0] = $agent_module->{'nombre'};
$part{'description'}[0] = ""; $part{'description'}[0] = "";
$part{'data'}[0] = $module_data; $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 # 1 - generic_data
# 2 - generic_proc # 2 - generic_proc
# 3 - generic_data_string # 3 - generic_data_string
# 4 - generic_data_inc # 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); 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); 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); 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); 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); 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 # Update agent last contact
# Insert Pandora version as agent version # Insert Pandora version as agent version
pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh); pandora_lastagentcontact ($pa_config, $timestamp, $agent_name, $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
} else {
# If module execution get a INVALID value
if ($agent_plugin->{'intervalo'} == 0){
$module_interval = dame_intervalo ($pa_config, $agent_plugin->{'id_agente'}, $dbh);
} }
# 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_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 # 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); 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_plugin->{'id_agente_modulo'}; 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); $dbh->do($query_act);
} }
skipdb_execmod:
$exec_sql->finish(); #close tagent_plugin hash reference $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 @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( pandora_help_screen our @EXPORT = qw(
pandora_help_screen
pandora_init pandora_init
pandora_loadconfig ); pandora_loadconfig
pandora_startlog
);
# There is no global vars, all variables (setup) passed as hash reference # There is no global vars, all variables (setup) passed as hash reference
# version: Defines actual version of Pandora Server for this module only # version: Defines actual version of Pandora Server for this module only
my $pandora_version = "2.0-dev"; my $pandora_version = "2.0-dev";
my $pandora_build="PS080226"; my $pandora_build="PS080311";
our $VERSION = $pandora_version." ".$pandora_build; our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash # Setup hash
@ -48,11 +51,13 @@ my %pa_config;
########################################################################## ##########################################################################
sub help_screen { 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 "Following options are optional : \n";
printf " -v : Verbose mode activated, give more information in logfile \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 : Debug mode activated, give extensive information in logfile \n";
printf " -D : Daemon mode (runs in backgroup)\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 " -h : This screen, show a little help screen \n";
printf " \n"; printf " \n";
exit; exit;
@ -67,8 +72,8 @@ sub pandora_init {
my $pa_config = $_[0]; my $pa_config = $_[0];
my $init_string = $_[1]; my $init_string = $_[1];
printf "\n$init_string $pandora_version Build $pandora_build Copyright (c) 2004-2008 ArticaST\n"; 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 "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"; printf "You can download latest versions and documentation at http://pandora.sourceforge.net \n\n";
# Load config file from command line # Load config file from command line
if ($#ARGV == -1 ){ if ($#ARGV == -1 ){
@ -78,6 +83,8 @@ sub pandora_init {
} }
$pa_config->{"verbosity"}=1; # Verbose 1 by default $pa_config->{"verbosity"}=1; # Verbose 1 by default
$pa_config->{"daemon"}=0; # Daemon 0 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 # If there are not valid parameters
my $parametro; my $parametro;
@ -90,9 +97,15 @@ sub pandora_init {
elsif ($parametro =~ m/-v\z/i) { elsif ($parametro =~ m/-v\z/i) {
$pa_config->{"verbosity"}=5; $pa_config->{"verbosity"}=5;
} }
elsif ($parametro =~ m/^-P\z/i) {
$pa_config->{'PID'}= clean_blank($ARGV[$ax+1]);
}
elsif ($parametro =~ m/-d\z/) { elsif ($parametro =~ m/-d\z/) {
$pa_config->{"verbosity"}=10; $pa_config->{"verbosity"}=10;
} }
elsif ($parametro =~ m/-q\z/) {
$pa_config->{"quiet"}=1;
}
elsif ($parametro =~ m/-D\z/) { elsif ($parametro =~ m/-D\z/) {
$pa_config->{"daemon"}=1; $pa_config->{"daemon"}=1;
} }
@ -161,15 +174,19 @@ sub pandora_loadconfig {
$pa_config->{"tcp_timeout"} = 20; # Introduced on 1.3.1 $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->{"snmp_proc_deadresponse"} = 0; # Introduced on 1.3.1 10 Feb08
$pa_config->{"plugin_threads"} = 3; # Introduced on 2.0 $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->{"plugin_timeout"} = 5; # Introduced on 2.0
$pa_config->{"wmi_threads"} = 3; # Introduced on 2.0 $pa_config->{"wmi_threads"} = 3; # Introduced on 2.0
$pa_config->{"wmi_timeout"} = 5; # Introduced on 2.0 $pa_config->{"wmi_timeout"} = 5; # Introduced on 2.0
# Check for UID0 # Check for UID0
if ($pa_config->{"quiet"} != 0){
if ($> == 0){ if ($> == 0){
printf " [W] Not all Pandora FMS components need to be executed as root\n"; 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"; printf " please consider starting it with a non-privileged user.\n";
} }
}
# Check for file # Check for file
if ( ! -e $archivo_cfg ) { if ( ! -e $archivo_cfg ) {
printf "\n [ERROR] Cannot open configuration file at $archivo_cfg. \n"; 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){ elsif ($parametro =~ m/^dataserver\s([0-9]*)/i){
$pa_config->{'dataserver'}= clean_blank($1); $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){ elsif ($parametro =~ m/^pluginserver\s([0-9]*)/i){
$pa_config->{'pluginserver'}= clean_blank($1); $pa_config->{'pluginserver'}= clean_blank($1);
} }
@ -316,6 +336,9 @@ sub pandora_loadconfig {
elsif ($parametro =~ m/^plugin_threads\s([0-9]*)/i) { elsif ($parametro =~ m/^plugin_threads\s([0-9]*)/i) {
$pa_config->{'plugin_threads'}= clean_blank($1); $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) { elsif ($parametro =~ m/^plugin_timeout\s([0-9]*)/i) {
$pa_config->{'plugin_timeout'}= clean_blank($1); $pa_config->{'plugin_timeout'}= clean_blank($1);
} }
@ -326,7 +349,10 @@ sub pandora_loadconfig {
} # end of loop for parameter # } # 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 basepath is ".$pa_config->{'basepath'}."\n";
print " [*] Server logfile at ".$pa_config->{"logfile"}."\n"; print " [*] Server logfile at ".$pa_config->{"logfile"}."\n";
print " [*] Server errorlogfile at ".$pa_config->{"errorlogfile"}."\n"; print " [*] Server errorlogfile at ".$pa_config->{"errorlogfile"}."\n";
@ -367,6 +393,9 @@ sub pandora_loadconfig {
print " [ERROR] You must enable 'wmiserver' in setup file to run Pandora FMS WMI server. \n\n"; print " [ERROR] You must enable 'wmiserver' in setup file to run Pandora FMS WMI server. \n\n";
exit; exit;
} }
# Show some config options in startup
if ($pa_config->{"quiet"} == 0){
if ($opmode == 0){ if ($opmode == 0){
print " [*] You are running Pandora FMS Data Server. \n"; print " [*] You are running Pandora FMS Data Server. \n";
$parametro ="Pandora FMS Data Server"; $parametro ="Pandora FMS Data Server";
@ -408,9 +437,10 @@ sub pandora_loadconfig {
if ($pa_config->{"pandora_master"} == 1) { if ($pa_config->{"pandora_master"} == 1) {
print " [*] This server is running in MASTER mode.\n"; print " [*] This server is running in MASTER mode.\n";
} }
}
logger ($pa_config, "Launching $parametro $pa_config->{'version'} $pa_config->{'build'}", 0); 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"}."'"; 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; my $dbh;
# Check valid Database variables and update server status # Check valid Database variables and update server status
eval { eval {
@ -423,15 +453,24 @@ sub pandora_loadconfig {
print $@; print $@;
exit; exit;
} }
if ($pa_config->{"quiet"} == 0){
print " [*] Pandora FMS Server [".$pa_config->{'servername'}.$pa_config->{"servermode"}."] is running and operative \n"; 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); $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 function declaration
# End of defined Code # End of defined Code

View File

@ -33,7 +33,8 @@ require Exporter;
our @ISA = ("Exporter"); our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( crea_agente_modulo our @EXPORT = qw(
crea_agente_modulo
dame_server_id dame_server_id
dame_agente_id dame_agente_id
dame_agente_modulo_id dame_agente_modulo_id
@ -64,7 +65,9 @@ our @EXPORT = qw( crea_agente_modulo
execute_alert execute_alert
give_network_component_profile_name give_network_component_profile_name
pandora_create_incident pandora_create_incident
give_db_value get_db_value
get_db_free_row
get_db_free_field
); );
# Spanish translation note: # Spanish translation note:
@ -374,18 +377,22 @@ sub pandora_writestate (%$$$$$$$) {
# now we use only local timestamp to stamp state of modules # now we use only local timestamp to stamp state of modules
my $pa_config = $_[0]; my $pa_config = $_[0];
my $nombre_agente = $_[1]; my $nombre_agente = $_[1];
my $tipo_modulo = $_[2]; my $tipo_modulo = $_[2]; # passed as string
my $nombre_modulo = $_[3]; my $nombre_modulo = $_[3];
my $datos = $_[4]; # Careful: Dont pass a hash, only a single value my $datos = $_[4]; # Careful: Dont pass a hash, only a single value
my $estado = $_[5]; my $estado = $_[5];
my $dbh = $_[6]; my $dbh = $_[6];
my $needs_update = $_[7]; 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 @data;
my $cambio = 0; my $cambio = 0;
my $id_grupo; 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 $server_name = $pa_config->{'servername'}.$pa_config->{"servermode"};
my $id_server = dame_server_id($pa_config, $server_name, $dbh); 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_agente = dame_agente_id ($pa_config, $nombre_agente, $dbh);
my $id_modulo = dame_modulo_id ($pa_config, $tipo_modulo, $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); 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)) { if (($id_agente == -1) || ($id_agente_modulo == -1)) {
goto fin_pandora_writestate; return 0;
} }
# Seek for agent_interval or module_interval # Seek for agent_interval or module_interval
@ -453,17 +461,16 @@ sub pandora_writestate (%$$$$$$$) {
pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh); pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh);
} }
if ($needs_update == 1) { 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'"; $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 } else { # dont update last_try field, that it's the field
# we use to check last update time in database # 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'"; $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); my $a_idages = $dbh->prepare($query_act);
$a_idages->execute; $a_idages->execute;
$a_idages->finish(); $a_idages->finish();
$s_idages->finish(); $s_idages->finish();
fin_pandora_writestate:
} }
########################################################################## ##########################################################################
@ -529,11 +536,11 @@ sub pandora_accessupdate (%$$) {
} }
# Update keepalive module (if present, if there is more than one, only updates first one!). # 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); 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){ if ($id_agent_module ne -1){
my $agent_name = give_db_free ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh); my $agent_name = get_db_free_field ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh);
my $module_typename = "keep_alive"; my $module_typename = "keep_alive";
my $module_name = give_db_free ("SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = $id_agent_module", $dbh); 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); pandora_writestate ($pa_config, $agent_name, $module_typename, $module_name, 1, 0, $dbh, 1);
} }
} }
@ -961,7 +968,9 @@ fin_DB_insert_datos:
########################################################################## ##########################################################################
sub pandora_serverkeepaliver (%$$) { sub pandora_serverkeepaliver (%$$) {
my $pa_config= $_[0]; my $pa_config= $_[0];
my $opmode = $_[1]; # 0 dataserver, 1 network server, 2 snmp console, 3 recon server 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 $dbh = $_[2];
my $version_data; my $version_data;
my $pandorasuffix; my $pandorasuffix;
@ -1024,7 +1033,7 @@ sub pandora_updateserver (%$$$) {
} elsif ($opmode == 4){ } elsif ($opmode == 4){
$pandorasuffix = "_Plugin"; $pandorasuffix = "_Plugin";
} elsif ($opmode == 5){ } elsif ($opmode == 5){
$pandorasuffix = "_IA"; $pandorasuffix = "_Prediction";
} elsif ($opmode == 6){ } elsif ($opmode == 6){
$pandorasuffix = "_WMI"; $pandorasuffix = "_WMI";
} else { } else {
@ -1382,7 +1391,7 @@ sub dame_modulo_id (%$$) {
if ($s_idag->rows == 0) { if ($s_idag->rows == 0) {
logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1); logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1);
logger($pa_config, "ERROR: SQL Query is $query_idag ",2); logger($pa_config, "ERROR: SQL Query is $query_idag ",2);
$id_modulo = -1; $id_modulo = 0;
} else { } else {
@data = $s_idag->fetchrow_array(); @data = $s_idag->fetchrow_array();
$id_modulo = $data[0]; $id_modulo = $data[0];
@ -1686,7 +1695,7 @@ sub crea_agente_modulo (%$$$$$$$) {
# Generic access to a field ($field) given a table # Generic access to a field ($field) given a table
# give_db_value (field_name_to_be_returned, table, field_search, condition_value, dbh) # 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 $field = $_[0];
my $table = $_[1]; my $table = $_[1];
my $field_search = $_[2]; 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 $condition = $_[0];
my $dbh = $_[1]; my $dbh = $_[1];
@ -1724,6 +1734,28 @@ sub give_db_free ($$) {
return -1; 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 function declaration
# End of defined Code # End of defined Code

View File

@ -27,7 +27,8 @@ require Exporter;
our @ISA = ("Exporter"); our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( daemonize our @EXPORT = qw(
pandora_daemonize
logger logger
limpia_cadena limpia_cadena
md5check md5check
@ -43,15 +44,23 @@ our @EXPORT = qw( daemonize
# Put program in background (for daemon mode) # Put program in background (for daemon mode)
########################################################################## ##########################################################################
sub daemonize { sub pandora_daemonize {
chdir '/tmp' or die "Can't chdir to /tmp: $!"; my $pa_config = $_[0];
open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "Can't write to /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: $!"; 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: $!"; defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid; exit if $pid;
setsid or die "Can't start a new session: $!"; setsid or die "Can't start a new session: $!";
umask 0; 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. random - To generate "random" data.
curve - To generate a math curve using trigonometrical functions, useful to see interpolation working with different intervals, etc curve - To generate a math curve using trigonometrical functions, useful to see interpolation working with different intervals, etc
boolean - Generate "random" boolean data. 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_module = -1; # -1 for all modules of that agent
my $target_agent = -1; my $target_agent = -1;
my $target_interval = 1200; my $target_interval = 300;
my $target_days = 12; my $target_days = 30;
################################################################################ ################################################################################
################################################################################ ################################################################################