koichirok d030cdc8e5 2012-02-15 Koichiro Kikuchi <koichiro@rworks.jp>
* lib/PandoraFMS/PluginServer.pm: Now PluginServer treats exit
	 status code 124 as "Unknown" when plugin type of the module
	 is nagios and module type is boolean. timeout exits with 124
	 if command times out.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@5603 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
2012-02-15 06:24:14 +00:00

232 lines
8.3 KiB
Perl

package PandoraFMS::PluginServer;
##########################################################################
# Pandora FMS Plugin Server.
# Pandora FMS. the Flexible Monitoring System. http://www.pandorafms.org
##########################################################################
# Copyright (c) 2005-2009 Artica Soluciones Tecnologicas S.L
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; 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.
##########################################################################
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Semaphore;
use POSIX qw(strftime);
use HTML::Entities;
# Default lib dir for RPM and DEB packages
use lib '/usr/lib/perl5';
use PandoraFMS::Tools;
use PandoraFMS::DB;
use PandoraFMS::Core;
use PandoraFMS::ProducerConsumerServer;
# Inherits from PandoraFMS::ProducerConsumerServer
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);
########################################################################################
# Plugin Server class constructor.
########################################################################################
sub new ($$;$) {
my ($class, $config, $dbh) = @_;
return undef unless $config->{'pluginserver'} == 1;
# Check for plugin_exec
if (! -x $config->{'plugin_exec'}) {
logger ($config, ' [E] ' . $config->{'plugin_exec'} . ' not found. Plugin Server not started.', 1);
print_message ($config, ' [E] ' . $config->{'plugin_exec'} . ' not found. Plugin Server not started.', 1);
return undef;
}
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, 4, \&PandoraFMS::PluginServer::data_producer, \&PandoraFMS::PluginServer::data_consumer, $dbh);
bless $self, $class;
return $self;
}
###############################################################################
# Run.
###############################################################################
sub run ($) {
my $self = shift;
my $pa_config = $self->getConfig ();
print_message ($pa_config, " [*] Starting Pandora FMS Plugin Server.", 1);
$self->setNumThreads ($pa_config->{'plugin_threads'});
$self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
}
###############################################################################
# Data producer.
###############################################################################
sub data_producer ($) {
my $self = shift;
my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
my @tasks;
my @rows;
if ($pa_config->{'pandora_master'} != 1) {
@rows = get_db_rows ($dbh, 'SELECT tagente_modulo.id_agente_modulo, tagente_modulo.flag, UNIX_TIMESTAMP() - tagente_estado.current_interval - tagente_estado.last_execution_try AS time_left, last_execution_try
FROM tagente, tagente_modulo, tagente_estado
WHERE server_name = ?
AND tagente_modulo.id_agente = tagente.id_agente
AND tagente.disabled = 0
AND tagente_modulo.id_plugin != 0
AND tagente_modulo.disabled = 0
AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND (tagente_modulo.flag = 1 OR (tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP())
ORDER BY tagente_modulo.flag DESC, time_left DESC, last_execution_try ASC', $pa_config->{'servername'});
} else {
@rows = get_db_rows ($dbh, 'SELECT DISTINCT(tagente_modulo.id_agente_modulo), tagente_modulo.flag, UNIX_TIMESTAMP() - tagente_estado.current_interval - tagente_estado.last_execution_try AS time_left, last_execution_try
FROM tagente, tagente_modulo, tagente_estado
WHERE ((server_name = ?) OR (server_name = ANY(SELECT name FROM tserver WHERE status = 0)))
AND tagente_modulo.id_agente = tagente.id_agente
AND tagente.disabled = 0
AND tagente_modulo.disabled = 0
AND tagente_modulo.id_plugin != 0
AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND (tagente_modulo.flag = 1 OR (tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP())
ORDER BY tagente_modulo.flag DESC, time_left DESC, last_execution_try ASC', $pa_config->{'servername'});
}
foreach my $row (@rows) {
# Reset forced execution flag
if ($row->{'flag'} == 1) {
db_do ($dbh, 'UPDATE tagente_modulo SET flag = 0 WHERE id_agente_modulo = ?', $row->{'id_agente_modulo'});
}
push (@tasks, $row->{'id_agente_modulo'});
}
return @tasks;
}
###############################################################################
# Data consumer.
###############################################################################
sub data_consumer ($$) {
my ($self, $module_id) = @_;
my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
# Retrieve module data
my $module = get_db_single_row ($dbh, 'SELECT * FROM tagente_modulo WHERE id_agente_modulo = ?', $module_id);
return unless defined $module;
# Retrieve plugin data
my $plugin = get_db_single_row ($dbh, 'SELECT * FROM tplugin WHERE id = ?', $module->{'id_plugin'});
return unless defined $plugin;
# Use the smallest timeout
my $timeout = ($plugin->{'max_timeout'} < $pa_config->{'plugin_timeout'}) ?
$plugin->{'max_timeout'} : $pa_config->{'plugin_timeout'};
# Build command to execute
my $command = $plugin->{'execute'};
if ($plugin->{'net_dst_opt'} ne ''){
$command .= ' ' . $plugin->{'net_dst_opt'} . ' ' . $module->{'ip_target'};
}
if ($plugin->{'net_port_opt'} ne '') {
$command .= ' ' . $plugin->{'net_port_opt'} . ' ' . $module->{'tcp_port'};
}
if ($plugin->{'user_opt'} ne '') {
$command .= ' ' . $plugin->{'user_opt'} . ' ' . $module->{'plugin_user'};
}
if ($plugin->{'pass_opt'} ne '') {
$command .= ' ' . $plugin->{'pass_opt'} . ' ' . $module->{'plugin_pass'};
}
# Extra parameter
if ($module->{'plugin_parameter'} ne '') {
$command .= ' ' . $module->{'plugin_parameter'};
}
$command = decode_entities($command);
logger ($pa_config, "Executing AM # $module_id plugin command '$command'", 9);
# Execute command
$command = $pa_config->{'plugin_exec'} . ' ' . $timeout . ' ' . $command;
my $module_data;
eval {
$module_data = `$command`;
};
my $ReturnCode = ($? >> 8) & 0xff;
if ($plugin->{'plugin_type'} == 1) {
# Get the errorlevel if is a Nagios plugin type (parsing the errorlevel)
# Nagios errorlevels:
#('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
# Numerical modules (Data) or Alphanumeric modules (String)
# get reported data as is, ignoring return code.
# Boolean data, transform module data depending on returning error code.
if ($module->{'id_tipo_modulo'} == 2){
if ($ReturnCode == 0){
$module_data = 1;
}
elsif ($ReturnCode == 1){
$module_data = -1;
}
elsif ($ReturnCode == 2){
$module_data = 0;
}
elsif ($ReturnCode == 3 || $ReturnCode == 124){
# 124 should be a exit code of the timeout command (command times out)
$module_data = ''; # not defined = Uknown
}
elsif ($ReturnCode == 4){
$module_data = 1;
}
}
}
if (! defined $module_data || $module_data eq '') {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
my $utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
my %data = ("data" => $module_data);
pandora_process_module ($pa_config, \%data, '', $module, '', $timestamp, $utimestamp, $self->getServerID (), $dbh);
my $agent_os_version = get_db_value ($dbh, 'SELECT os_version FROM tagente WHERE id_agente = ?', $module->{'id_agente'});
if ($agent_os_version eq ''){
$agent_os_version = $pa_config->{'servername'}.'_Plugin';
}
pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, $agent_os_version, $pa_config->{'version'}, -1, $dbh);
}
1;
__END__