2013-08-01 Ramon Novoa <rnovoa@artica.es>

* lib/PandoraFMS/DataServer.pm,
	  lib/PandoraFMS/SNMPServer.pm,
	  lib/PandoraFMS/Server.pm,
	  lib/PandoraFMS/PluginServer.pm,
	  lib/PandoraFMS/ProducerConsumerServer.pm,
	  lib/PandoraFMS/PredictionServer.pm,
	  lib/PandoraFMS/ReconServer.pm,
	  lib/PandoraFMS/NetworkServer.pm,
	  lib/PandoraFMS/WMIServer.pm: Added clean-up code to avoid resource
	  leaks when there is a crash and the server has to auto-restart.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@8611 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
This commit is contained in:
ramonn 2013-08-01 09:54:21 +00:00
parent 4557e364b9
commit 094defb906
10 changed files with 127 additions and 44 deletions

View File

@ -1,3 +1,16 @@
2013-08-01 Ramon Novoa <rnovoa@artica.es>
* lib/PandoraFMS/DataServer.pm,
lib/PandoraFMS/SNMPServer.pm,
lib/PandoraFMS/Server.pm,
lib/PandoraFMS/PluginServer.pm,
lib/PandoraFMS/ProducerConsumerServer.pm,
lib/PandoraFMS/PredictionServer.pm,
lib/PandoraFMS/ReconServer.pm,
lib/PandoraFMS/NetworkServer.pm,
lib/PandoraFMS/WMIServer.pm: Added clean-up code to avoid resource
leaks when there is a crash and the server has to auto-restart.
2013-07-25 Ramon Novoa <rnovoa@artica.es>
* lib/PandoraFMS/NetworkServer.pm: Fixed some parentheses that prevented

View File

@ -46,10 +46,10 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
my @TaskQueue :shared;
my %PendingTasks :shared;
my %Agents :shared;
my $Sem :shared = Thread::Semaphore->new;
my $TaskSem :shared = Thread::Semaphore->new (0);
my $AgentSem :shared = Thread::Semaphore->new (1);
my $ModuleSem :shared = Thread::Semaphore->new (1);
my $Sem :shared;
my $TaskSem :shared;
my $AgentSem :shared;
my $ModuleSem :shared;
########################################################################################
# Data Server class constructor.
@ -59,6 +59,15 @@ sub new ($$;$) {
return undef unless $config->{'dataserver'} == 1;
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
%Agents = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
$AgentSem = Thread::Semaphore->new (1);
$ModuleSem = Thread::Semaphore->new (1);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 0, \&PandoraFMS::DataServer::data_producer, \&PandoraFMS::DataServer::data_consumer, $dbh);

View File

@ -42,9 +42,8 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared = new Thread::Semaphore;
my $TaskSem :shared = new Thread::Semaphore (0);
my $SNMPSem :shared = new Thread::Semaphore (1);
my $Sem :shared;
my $TaskSem :shared;
########################################################################################
# Network Server class constructor.
@ -60,6 +59,12 @@ sub new ($$$) {
return undef;
}
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 1, \&PandoraFMS::NetworkServer::data_producer, \&PandoraFMS::NetworkServer::data_consumer, $dbh);

View File

@ -42,8 +42,8 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared = Thread::Semaphore->new;
my $TaskSem :shared = Thread::Semaphore->new (0);
my $Sem :shared;
my $TaskSem :shared;
########################################################################################
# Plugin Server class constructor.
@ -59,7 +59,13 @@ sub new ($$;$) {
print_message ($config, ' [E] ' . $config->{'plugin_exec'} . ' not found. Plugin Server not started.', 1);
return undef;
}
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 4, \&PandoraFMS::PluginServer::data_producer, \&PandoraFMS::PluginServer::data_consumer, $dbh);

View File

@ -45,8 +45,8 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared = Thread::Semaphore->new;
my $TaskSem :shared = Thread::Semaphore->new (0);
my $Sem :shared;
my $TaskSem :shared;
########################################################################
# Prediction Server class constructor.
@ -55,10 +55,16 @@ sub new ($$;$) {
my ($class, $config, $dbh) = @_;
return undef unless $config->{'predictionserver'} == 1;
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 5, \&PandoraFMS::PredictionServer::data_producer, \&PandoraFMS::PredictionServer::data_consumer, $dbh);
bless $self, $class;
return $self;

View File

@ -31,9 +31,12 @@ use PandoraFMS::DB;
use PandoraFMS::Core;
use PandoraFMS::Server;
# inherits from PandoraFMS::Server
# Inherits from PandoraFMS::Server
our @ISA = qw(PandoraFMS::Server);
# Tells the producer and consumers to keep running
my $RUN :shared;
########################################################################################
# ProducerConsumerServer class constructor.
########################################################################################
@ -48,6 +51,9 @@ sub new ($$$$$;$) {
$self->{'_producer'} = $producer;
$self->{'_consumer'} = $consumer;
# Run!
$RUN = 1;
bless $self, $class;
return $self;
}
@ -101,14 +107,15 @@ sub run ($$$$$) {
sub data_producer ($$$$$) {
my ($self, $task_queue, $pending_tasks, $sem, $task_sem) = @_;
my $pa_config = $self->getConfig ();
my $dbh;
eval {
# Connect to the DB
my $dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'}, $pa_config->{'dbport'},
$dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'}, $pa_config->{'dbport'},
$pa_config->{'dbuser'}, $pa_config->{'dbpass'});
$self->setDBH ($dbh);
while (1) {
while ($RUN == 1) {
# Get pending tasks
my @tasks = &{$self->{'_producer'}}($self);
@ -140,6 +147,9 @@ sub data_producer ($$$$$) {
if ($@) {
$self->setErrStr ($@);
}
$task_sem->up($self->getNumThreads ());
db_disconnect ($dbh);
}
###############################################################################
@ -149,13 +159,14 @@ sub data_consumer ($$$$$) {
my ($self, $task_queue, $pending_tasks, $sem, $task_sem) = @_;
my $pa_config = $self->getConfig ();
my $dbh;
eval {
# Connect to the DB
my $dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'}, $pa_config->{'dbport'},
$dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'}, $pa_config->{'dbport'},
$pa_config->{'dbuser'}, $pa_config->{'dbpass'});
$self->setDBH ($dbh);
while (1) {
while ($RUN == 1) {
# Wait for data
$task_sem->down;
@ -164,6 +175,9 @@ sub data_consumer ($$$$$) {
my $task = shift (@{$task_queue});
$sem->up;
# The consumer was waiting for data when the producer exited
last if ($RUN == 0);
# Execute task
&{$self->{'_consumer'}}($self, $task);
@ -179,6 +193,17 @@ sub data_consumer ($$$$$) {
if ($@) {
$self->setErrStr ($@);
}
db_disconnect ($dbh);
}
###############################################################################
# Clean-up when the server is destroyed.
###############################################################################
sub DESTROY {
my $self = shift;
$RUN = 0;
}
1;

View File

@ -45,8 +45,8 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared = Thread::Semaphore->new;
my $TaskSem :shared = Thread::Semaphore->new (0);
my $Sem :shared;
my $TaskSem :shared;
########################################################################################
# Recon Server class constructor.
@ -61,6 +61,12 @@ sub new ($$$$$$) {
print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by Pandora FMS Recon Server not found.", 1);
return undef;
}
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 3, \&PandoraFMS::ReconServer::data_producer, \&PandoraFMS::ReconServer::data_consumer, $dbh);

View File

@ -38,6 +38,9 @@ use PandoraFMS::Server;
# Inherits from PandoraFMS::Server
our @ISA = qw(PandoraFMS::Server);
# Tells the server to keep running
my $RUN :shared;
########################################################################################
# SNMP Server class constructor.
########################################################################################
@ -50,13 +53,16 @@ sub new ($$;$) {
if (start_snmptrapd ($config) != 0) {
return undef;
}
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 2, $dbh);
# Save the path of snmptrapd
$self->{'snmp_trapd'} = $config->{'snmp_trapd'};
# Run!
$RUN = 1;
bless $self, $class;
return $self;
}
@ -79,9 +85,10 @@ sub pandora_snmptrapd {
my $self = shift;
my $pa_config = $self->getConfig ();
my $dbh;
eval {
# Connect to the DB
my $dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'},
$dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'},
$pa_config->{'dbport'}, $pa_config->{'dbuser'}, $pa_config->{'dbpass'});
$self->setDBH ($dbh);
@ -111,7 +118,7 @@ sub pandora_snmptrapd {
readline SNMPLOGFILE for (1..$last_line);
# Main loop
while (1) {
while ($RUN == 1) {
while (my $line = <SNMPLOGFILE>) {
$last_line++;
$last_size = (stat ($log_file))[7];
@ -189,6 +196,8 @@ sub pandora_snmptrapd {
if ($@) {
$self->setErrStr ($@);
}
db_disconnect ($dbh);
}
########################################################################################
@ -287,5 +296,14 @@ sub start_snmptrapd ($) {
return 0;
}
###############################################################################
# Clean-up when the server is destroyed.
###############################################################################
sub DESTROY {
my $self = shift;
$RUN = 0;
}
1;
__END__

View File

@ -29,7 +29,7 @@ use lib '/usr/lib/perl5';
use PandoraFMS::DB;
use PandoraFMS::Core;
# defined in PandoraFMS::Core.pm
# Defined in PandoraFMS::Core.pm
our @ServerSuffixes;
########################################################################################
@ -51,13 +51,7 @@ sub new ($$$;$) {
# Share variables that may be set from different threads
share ($self->{'_queue_size'});
share ($self->{'_errstr'});
# Thread kill signal handler
#$SIG{'KILL'} = sub {
# threads->exit() if threads->can('exit');
# exit();
#};
bless $self, $class;
return $self;
}
@ -290,17 +284,12 @@ sub stop ($) {
0, $self->{'_server_type'}, 0, 0);
};
# Kill server threads
# Detach server threads
foreach my $tid (@{$self->{'_threads'}}) {
my $thr = threads->object($tid);
next unless defined ($thr);
# A kill method might not be available
#if ($thr->can('kill')) {
# $thr->kill('KILL')->detach();
#} else {
$thr->detach();
#}
$thr->detach();
}
}

View File

@ -41,8 +41,8 @@ our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared = Thread::Semaphore->new;
my $TaskSem :shared = Thread::Semaphore->new (0);
my $Sem :shared;
my $TaskSem :shared;
########################################################################################
# NetworkServer class constructor.
@ -58,7 +58,13 @@ sub new ($$;$) {
print_message ($config, ' [E] ' . $config->{'wmi_client'} . " not found. Pandora FMS WMI Server needs a DCOM/WMI client.", 1);
return undef;
}
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 6, \&PandoraFMS::WMIServer::data_producer, \&PandoraFMS::WMIServer::data_consumer, $dbh);
@ -138,7 +144,7 @@ sub data_consumer ($$) {
# Build command to execute
my $wmi_command = '';
if ($module->{'plugin_user'}) {
if (defined ($module->{'plugin_pass'}) && $module->{'plugin_pass'} ne "") {
$wmi_command = $pa_config->{'wmi_client'} . ' -U "' . $module->{'plugin_user'} . '"%"' . $module->{'plugin_pass'} . '"';
}
else {