2017-05-20 15:26:21 +02:00
|
|
|
|
#!@PERL@
|
|
|
|
|
# nagios: -epn
|
|
|
|
|
## @PKG_NAME@–@PKG_VERSION@
|
2017-05-20 15:29:39 +02:00
|
|
|
|
## Copyright (c) 2005-2015 Joerg Linge (http://www.pnp4nagios.org)
|
2017-05-20 15:26:21 +02:00
|
|
|
|
##
|
|
|
|
|
## This program is free software; you can redistribute it and/or
|
|
|
|
|
## modify it under the terms of the GNU General Public License
|
|
|
|
|
## as published by the Free Software Foundation; either version 2
|
|
|
|
|
## of the License, or (at your option) any later version.
|
|
|
|
|
##
|
|
|
|
|
## This program is distributed in the hope that it will be useful,
|
|
|
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
## GNU General Public License for more details.
|
|
|
|
|
##
|
|
|
|
|
## You should have received a copy of the GNU General Public License
|
|
|
|
|
## along with this program; if not, write to the Free Software
|
|
|
|
|
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
@PERL_LIB_PATH_CODE@
|
|
|
|
|
|
|
|
|
|
if( $< == 0 ){
|
|
|
|
|
print "dont try this as root \n";
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
|
use strict;
|
|
|
|
|
use POSIX;
|
|
|
|
|
use Getopt::Long;
|
|
|
|
|
use Time::HiRes qw(gettimeofday tv_interval);
|
|
|
|
|
use vars qw ( $TEMPLATE %NAGIOS $t0 $t1 $rt $delayed_write $rrdfile @ds_create $count $line $name $ds_update $dstype %CTPL);
|
|
|
|
|
|
|
|
|
|
my %conf = (
|
|
|
|
|
TIMEOUT => 15,
|
|
|
|
|
CFG_DIR => "@sysconfdir@/",
|
|
|
|
|
USE_RRDs => 1,
|
|
|
|
|
RRDPATH => "@PERFDATA_DIR@",
|
|
|
|
|
RRDTOOL => "@RRDTOOL@",
|
|
|
|
|
RRD_STORAGE_TYPE => "SINGLE",
|
|
|
|
|
RRD_HEARTBEAT => 8640,
|
|
|
|
|
RRA_STEP => 60,
|
|
|
|
|
RRA_CFG => "@sysconfdir@/rra.cfg",
|
|
|
|
|
STATS_DIR => "@localstatedir@/stats",
|
|
|
|
|
LOG_FILE => "@PERFDATA_LOG@",
|
|
|
|
|
LOG_FILE_MAX_SIZE => "10485760", #Truncate after 10MB
|
|
|
|
|
LOG_LEVEL => @DEBUG@,
|
|
|
|
|
XML_ENC => "UTF-8",
|
|
|
|
|
XML_UPDATE_DELAY => 0, # Write XML only if file is older then XML_UPDATE_DELAY seconds
|
|
|
|
|
RRD_DAEMON_OPTS => "",
|
|
|
|
|
GEARMAN_HOST => "localhost:4730", # How many gearman worker childs to start
|
|
|
|
|
PREFORK => 2, # How many gearman worker childs to start
|
|
|
|
|
REQUESTS_PER_CHILD => 20000, # Restart after a given count of requests
|
|
|
|
|
ENCRYPTION => 1, # Decrypt mod_gearman packets
|
|
|
|
|
KEY => 'should_be_changed',
|
|
|
|
|
KEY_FILE => '@sysconfdir@/secret.key',
|
|
|
|
|
UOM2TYPE => { 'c' => 'DERIVE', 'd' => 'DERIVE' },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
my %const = (
|
|
|
|
|
XML_STRUCTURE_VERSION => "@XML_STRUCTURE_VERSION@",
|
|
|
|
|
VERSION => "@PKG_VERSION@",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Dont change anything below these lines ...
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
# "rrdtool create" Syntax
|
|
|
|
|
#
|
|
|
|
|
my @default_rrd_create = ( "RRA:AVERAGE:0.5:1:2880", "RRA:AVERAGE:0.5:5:2880", "RRA:AVERAGE:0.5:30:4320", "RRA:AVERAGE:0.5:360:5840", "RRA:MAX:0.5:1:2880", "RRA:MAX:0.5:5:2880", "RRA:MAX:0.5:30:4320", "RRA:MAX:0.5:360:5840", "RRA:MIN:0.5:1:2880", "RRA:MIN:0.5:5:2880", "RRA:MIN:0.5:30:4320", "RRA:MIN:0.5:360:5840", );
|
|
|
|
|
|
|
|
|
|
Getopt::Long::Configure('bundling');
|
|
|
|
|
my ( $opt_d, $opt_V, $opt_h, $opt_i, $opt_n, $opt_b, $opt_s, $opt_gm, $opt_pidfile,$opt_daemon );
|
|
|
|
|
my $opt_t = my $opt_t_default = $conf{TIMEOUT}; # Default Timeout
|
|
|
|
|
my $opt_c = $conf{CFG_DIR} . "process_perfdata.cfg";
|
|
|
|
|
GetOptions(
|
|
|
|
|
"V" => \$opt_V,
|
|
|
|
|
"version" => \$opt_V,
|
|
|
|
|
"h" => \$opt_h,
|
|
|
|
|
"help" => \$opt_h,
|
|
|
|
|
"i" => \$opt_i,
|
|
|
|
|
"inetd" => \$opt_i,
|
|
|
|
|
"b=s" => \$opt_b,
|
|
|
|
|
"bulk=s" => \$opt_b,
|
|
|
|
|
"d=s" => \$opt_d,
|
|
|
|
|
"datatype=s" => \$opt_d,
|
|
|
|
|
"t=i" => \$opt_t,
|
|
|
|
|
"timeout=i" => \$opt_t,
|
|
|
|
|
"c=s" => \$opt_c,
|
|
|
|
|
"config=s" => \$opt_c,
|
|
|
|
|
"n" => \$opt_n,
|
|
|
|
|
"npcd" => \$opt_n,
|
|
|
|
|
"s" => \$opt_s,
|
|
|
|
|
"stdin" => \$opt_s,
|
|
|
|
|
"gearman:s" => \$opt_gm,
|
|
|
|
|
"daemon" => \$opt_daemon,
|
|
|
|
|
"pidfile=s" => \$opt_pidfile,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
parse_config($opt_c);
|
|
|
|
|
$conf{'GLOBAL_RRD_STORAGE_TYPE'} = uc($conf{'RRD_STORAGE_TYPE'}); # store the initial value for later use
|
|
|
|
|
|
|
|
|
|
my %stats = init_stats();
|
|
|
|
|
my $cypher;
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# RRDs Perl Module Detection
|
|
|
|
|
#
|
|
|
|
|
if ( $conf{USE_RRDs} == 1 ) {
|
|
|
|
|
unless ( eval "use RRDs;1" ) {
|
|
|
|
|
$conf{USE_RRDs} = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Include Gearman modules if needed
|
|
|
|
|
#
|
|
|
|
|
if ( defined($opt_gm) ) {
|
|
|
|
|
unless ( eval "use Gearman::Worker;1" ) {
|
|
|
|
|
print "Perl module Gearman::Worker not found\n";
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
unless ( eval "use MIME::Base64;1" ) {
|
|
|
|
|
print "Perl module MIME::Base64 not found\n";
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
unless ( eval "use Crypt::Rijndael;1" ) {
|
|
|
|
|
print "Perl module Crypt::Rijndael not found\n";
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_help() if ($opt_h);
|
|
|
|
|
print_version() if ($opt_V);
|
|
|
|
|
|
|
|
|
|
# Use the timeout specified on the command line and if none use what is in the configuration
|
|
|
|
|
# If timeout is not in command line or the config file use the default
|
|
|
|
|
$opt_t = $conf{TIMEOUT} if ( $opt_t == $opt_t_default && $opt_t != $conf{TIMEOUT} );
|
|
|
|
|
print_log( "Default Timeout: $opt_t_default secs.", 2 );
|
|
|
|
|
print_log( "Config Timeout: $conf{TIMEOUT} secs.", 2 );
|
|
|
|
|
print_log( "Actual Timeout: $opt_t secs.", 2 );
|
|
|
|
|
|
|
|
|
|
init_signals();
|
|
|
|
|
my %children = (); # keys are current child process IDs
|
|
|
|
|
my $children = 0; # current number of children
|
|
|
|
|
if( ! defined($opt_gm) ){
|
|
|
|
|
#
|
|
|
|
|
# synchronos / bulk / npcd mode
|
|
|
|
|
#
|
|
|
|
|
main();
|
|
|
|
|
}else{
|
|
|
|
|
#
|
|
|
|
|
# Gearman worker main loop
|
|
|
|
|
#
|
|
|
|
|
print_log( "process_perfdata.pl-$const{VERSION} Gearman Worker Daemon", 0 );
|
|
|
|
|
if($opt_gm =~ /:\d+/ ){
|
|
|
|
|
$conf{'GEARMAN_HOST'} = $opt_gm;
|
|
|
|
|
}
|
|
|
|
|
if($conf{ENCRYPTION} == 1){
|
|
|
|
|
print_log( "Encryptions is enabled", 0 );
|
|
|
|
|
read_keyfile($conf{'KEY_FILE'});
|
|
|
|
|
# fill key up to 32 bytes
|
|
|
|
|
$conf{'KEY'} = substr($conf{'KEY'},0,32) . chr(0) x ( 32 - length( $conf{'KEY'} ) );
|
|
|
|
|
$cypher = Crypt::Rijndael->new( $conf{'KEY'}, Crypt::Rijndael::MODE_ECB() );
|
|
|
|
|
}
|
|
|
|
|
daemonize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Subs
|
|
|
|
|
#
|
|
|
|
|
# Main function to switch to the right mode.
|
|
|
|
|
sub main {
|
|
|
|
|
my $job = shift;
|
|
|
|
|
my $t0 = [gettimeofday];
|
|
|
|
|
my $t1;
|
|
|
|
|
my $rt;
|
|
|
|
|
my $lines = 0;
|
|
|
|
|
# Gearman Worker
|
|
|
|
|
if (defined $opt_gm) {
|
|
|
|
|
print_log( "Gearman Worker Job start", 1 );
|
|
|
|
|
%NAGIOS = parse_env($job->arg);
|
|
|
|
|
$lines = process_perfdata();
|
|
|
|
|
$t1 = [gettimeofday];
|
|
|
|
|
$rt = tv_interval $t0, $t1;
|
|
|
|
|
$stats{runtime} += $rt;
|
|
|
|
|
$stats{rows}++;
|
|
|
|
|
if( ( int $stats{timet} / 60 ) < ( int time / 60 )){
|
|
|
|
|
store_internals();
|
|
|
|
|
init_stats();
|
|
|
|
|
}
|
|
|
|
|
print_log( "Gearman job end (runtime ${rt}s) ...", 1 );
|
|
|
|
|
return 1;
|
|
|
|
|
} elsif ( $opt_b && !$opt_n && !$opt_s ) {
|
|
|
|
|
# Bulk mode
|
|
|
|
|
alarm($opt_t);
|
|
|
|
|
print_log( "process_perfdata.pl-$const{VERSION} starting in BULK Mode called by Nagios", 1 );
|
|
|
|
|
$lines = process_perfdata_file();
|
|
|
|
|
} elsif ( $opt_b && $opt_n && !$opt_s ) {
|
|
|
|
|
# Bulk mode with npcd
|
|
|
|
|
alarm($opt_t);
|
|
|
|
|
print_log( "process_perfdata.pl-$const{VERSION} starting in BULK Mode called by NPCD", 1 );
|
|
|
|
|
$lines = process_perfdata_file();
|
|
|
|
|
} elsif ( $opt_s ) {
|
|
|
|
|
# STDIN mode
|
|
|
|
|
alarm($opt_t);
|
|
|
|
|
print_log( "starting in STDIN Mode", 1 );
|
|
|
|
|
$lines = process_perfdata_stdin();
|
|
|
|
|
} else {
|
|
|
|
|
# Synchronous mode
|
|
|
|
|
$opt_t = 5 if $opt_t > 5; # maximum timeout
|
|
|
|
|
alarm($opt_t);
|
|
|
|
|
print_log( "process_perfdata.pl-$const{VERSION} starting in SYNC Mode", 1 );
|
|
|
|
|
%NAGIOS = parse_env();
|
|
|
|
|
$lines = process_perfdata();
|
|
|
|
|
}
|
|
|
|
|
$rt = tv_interval $t0, $t1;
|
|
|
|
|
$stats{runtime} = $rt;
|
|
|
|
|
$stats{rows} = $lines;
|
|
|
|
|
store_internals();
|
|
|
|
|
print_log( "PNP exiting (runtime ${rt}s) ...", 1 );
|
|
|
|
|
exit 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Parse %ENV and return a global hash %NAGIOS
|
|
|
|
|
#
|
|
|
|
|
sub parse_env {
|
|
|
|
|
my $job_data = shift;
|
|
|
|
|
%NAGIOS = ();
|
|
|
|
|
$NAGIOS{DATATYPE} = "SERVICEPERFDATA";
|
|
|
|
|
|
|
|
|
|
if(defined $opt_gm){
|
|
|
|
|
# Gearman Worker
|
|
|
|
|
$job_data = decode_base64($job_data);
|
|
|
|
|
if($conf{ENCRYPTION} == 1){
|
|
|
|
|
$job_data = $cypher->decrypt( $job_data );
|
|
|
|
|
}
|
|
|
|
|
my @LINE = split(/\t/, $job_data);
|
|
|
|
|
foreach my $k (@LINE) {
|
|
|
|
|
$k =~ /([A-Z 0-9_]+)::(.*)$/;
|
|
|
|
|
$NAGIOS{$1} = $2 if ($2);
|
|
|
|
|
}
|
|
|
|
|
if ( !$NAGIOS{HOSTNAME} ) {
|
|
|
|
|
print_log( "Gearman job data missmatch. Please check your encryption key.", 0 );
|
|
|
|
|
return %NAGIOS;
|
|
|
|
|
}
|
|
|
|
|
} elsif ( defined($opt_b) || defined($opt_s) ){
|
|
|
|
|
# Bulk Mode/Stdin Mode
|
|
|
|
|
my @LINE = split(/\t/, $job_data);
|
|
|
|
|
foreach my $k (@LINE) {
|
|
|
|
|
$k =~ /([A-Z 0-9_]+)::(.*)$/;
|
|
|
|
|
$NAGIOS{$1} = $2 if ($2);
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
|
|
if ( ( !$ENV{NAGIOS_HOSTNAME} ) and ( !$ENV{ICINGA_HOSTNAME} ) ) {
|
|
|
|
|
print_log( "Cant find Nagios Environment. Exiting ....", 1 );
|
|
|
|
|
exit 2;
|
|
|
|
|
}
|
|
|
|
|
foreach my $key ( sort keys %ENV ) {
|
|
|
|
|
if ( $key =~ /^(NAGIOS|ICINGA)_(.*)/ ) {
|
|
|
|
|
$NAGIOS{$2} = $ENV{$key};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($opt_d) {
|
|
|
|
|
$NAGIOS{DATATYPE} = $opt_d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$NAGIOS{DISP_HOSTNAME} = $NAGIOS{HOSTNAME};
|
|
|
|
|
$NAGIOS{DISP_SERVICEDESC} = $NAGIOS{SERVICEDESC};
|
|
|
|
|
$NAGIOS{HOSTNAME} = cleanup( $NAGIOS{HOSTNAME} );
|
|
|
|
|
$NAGIOS{SERVICEDESC} = cleanup( $NAGIOS{SERVICEDESC} );
|
|
|
|
|
$NAGIOS{PERFDATA} = $NAGIOS{SERVICEPERFDATA};
|
|
|
|
|
$NAGIOS{CHECK_COMMAND} = $NAGIOS{SERVICECHECKCOMMAND};
|
|
|
|
|
|
|
|
|
|
if ( $NAGIOS{DATATYPE} eq "HOSTPERFDATA" ) {
|
|
|
|
|
$NAGIOS{SERVICEDESC} = "_HOST_";
|
|
|
|
|
$NAGIOS{DISP_SERVICEDESC} = "Host Perfdata";
|
|
|
|
|
$NAGIOS{PERFDATA} = $NAGIOS{HOSTPERFDATA};
|
|
|
|
|
$NAGIOS{CHECK_COMMAND} = $NAGIOS{HOSTCHECKCOMMAND};
|
|
|
|
|
}
|
|
|
|
|
print_log( "Datatype set to '$NAGIOS{DATATYPE}' ", 2 );
|
|
|
|
|
return %NAGIOS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Perfdata sanity check
|
|
|
|
|
#
|
|
|
|
|
sub process_perfdata {
|
|
|
|
|
if ( keys( %NAGIOS ) == 1 && defined($opt_gm) ) {
|
|
|
|
|
$stats{skipped}++;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if ( ! defined($NAGIOS{PERFDATA}) && ! defined($opt_gm) ) {
|
|
|
|
|
print_log( "No Performance Data for $NAGIOS{HOSTNAME} / $NAGIOS{SERVICEDESC} ", 1 );
|
|
|
|
|
if ( !$opt_b && !$opt_s ) {
|
|
|
|
|
print_log( "PNP exiting ...", 1 );
|
|
|
|
|
exit 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $NAGIOS{PERFDATA} =~ /^(.*)\s\[(.*)\]$/ ) {
|
|
|
|
|
$NAGIOS{PERFDATA} = $1;
|
|
|
|
|
$NAGIOS{CHECK_COMMAND} = $2;
|
|
|
|
|
print_log( "Found Perfdata from Distributed Server $NAGIOS{HOSTNAME} / $NAGIOS{SERVICEDESC} ($NAGIOS{PERFDATA})", 1 );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "Found Performance Data for $NAGIOS{HOSTNAME} / $NAGIOS{SERVICEDESC} ($NAGIOS{PERFDATA}) ", 1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$NAGIOS{PERFDATA} =~ s/,/./g;
|
|
|
|
|
$NAGIOS{PERFDATA} =~ s/\s+=/=/g;
|
|
|
|
|
$NAGIOS{PERFDATA} =~ s/=\s+/=/g;
|
|
|
|
|
$NAGIOS{PERFDATA} =~ s/\\n//g;
|
|
|
|
|
$NAGIOS{PERFDATA} .= " ";
|
|
|
|
|
parse_perfstring( $NAGIOS{PERFDATA} );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Process Perfdata in Bulk Mode
|
|
|
|
|
#
|
|
|
|
|
sub process_perfdata_file {
|
|
|
|
|
if ( $opt_b =~ /-PID-(\d+)/ ) {
|
|
|
|
|
print_log( "Oops: $opt_b already processed by $1 - please check timeout settings", 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_log( "searching for $opt_b", 2 );
|
|
|
|
|
if ( -e "$opt_b" ) {
|
|
|
|
|
my $pdfile = "$opt_b" . "-PID-" . $$;
|
|
|
|
|
print_log( "renaming $opt_b to $pdfile for bulk update", 2 );
|
|
|
|
|
unless ( rename "$opt_b", "$pdfile" ) {
|
|
|
|
|
print_log( "ERROR: rename $opt_b to $pdfile failed", 1 );
|
|
|
|
|
exit 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_log( "reading $pdfile for bulk update", 2 );
|
|
|
|
|
open( PDFILE, "< $pdfile" );
|
|
|
|
|
my $count = 0;
|
|
|
|
|
while (<PDFILE>) {
|
|
|
|
|
my $job_data = $_;
|
|
|
|
|
$count++;
|
|
|
|
|
print_log( "Processing Line $count", 2 );
|
|
|
|
|
my @LINE = split(/\t/);
|
|
|
|
|
%NAGIOS = (); # cleaning %NAGIOS Hash
|
|
|
|
|
#foreach my $k (@LINE) {
|
|
|
|
|
# $k =~ /([A-Z 0-9_]+)::(.*)$/;
|
|
|
|
|
# $ENV{ 'NAGIOS_' . $1 } = $2 if ($2);
|
|
|
|
|
#}
|
|
|
|
|
parse_env($job_data);
|
|
|
|
|
if ( $NAGIOS{SERVICEPERFDATA} || $NAGIOS{HOSTPERFDATA} ) {
|
|
|
|
|
process_perfdata();
|
|
|
|
|
} else {
|
|
|
|
|
print_log( "No Perfdata. Skipping line $count", 2 );
|
|
|
|
|
$stats{skipped}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_log( "$count lines processed", 1 );
|
|
|
|
|
|
|
|
|
|
if ( unlink("$pdfile") == 1 ) {
|
|
|
|
|
print_log( "$pdfile deleted", 1 );
|
|
|
|
|
}else {
|
|
|
|
|
print_log( "Could not delete $pdfile:$!", 1 );
|
|
|
|
|
}
|
|
|
|
|
return $count;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "ERROR: File $opt_b not found", 1 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Process Perfdata in STDIN Mode
|
|
|
|
|
#
|
|
|
|
|
sub process_perfdata_stdin {
|
|
|
|
|
print_log( "reading from STDIN for bulk update", 2 );
|
|
|
|
|
my $count = 0;
|
|
|
|
|
while (<STDIN>) {
|
|
|
|
|
my $job_data = $_;
|
|
|
|
|
$count++;
|
|
|
|
|
print_log( "Processing Line $count", 2 );
|
|
|
|
|
my @LINE = split(/\t/);
|
|
|
|
|
%NAGIOS = (); # cleaning %NAGIOS Hash
|
|
|
|
|
parse_env($job_data);
|
|
|
|
|
if ( $NAGIOS{SERVICEPERFDATA} || $NAGIOS{HOSTPERFDATA} ) {
|
|
|
|
|
process_perfdata();
|
|
|
|
|
} else {
|
|
|
|
|
print_log( "No Perfdata. Skipping line $count", 2 );
|
|
|
|
|
$stats{skipped}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_log( "$count lines processed", 1 );
|
|
|
|
|
return $count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Write Data to RRD Files
|
|
|
|
|
#
|
|
|
|
|
sub data2rrd {
|
|
|
|
|
|
|
|
|
|
my @data = @_;
|
|
|
|
|
my @rrd_state = ();
|
|
|
|
|
my $rrd_storage_type;
|
|
|
|
|
|
|
|
|
|
print_log( "data2rrd called", 2 );
|
|
|
|
|
$NAGIOS{XMLFILE} = $conf{RRDPATH} . "/" . $data[0]{hostname} . "/" . $data[0]{servicedesc} . ".xml";
|
|
|
|
|
$NAGIOS{SERVICEDESC} = $data[0]{servicedesc};
|
|
|
|
|
$NAGIOS{DISP_SERVICEDESC} = $data[0]{disp_servicedesc};
|
|
|
|
|
$NAGIOS{AUTH_SERVICEDESC} = $data[0]{auth_servicedesc} || "";
|
|
|
|
|
$NAGIOS{AUTH_HOSTNAME} = $data[0]{auth_hostname} || "";
|
|
|
|
|
$NAGIOS{MULTI_PARENT} = "";
|
|
|
|
|
$NAGIOS{MULTI_PARENT} = $data[0]{multi_parent} || "";
|
|
|
|
|
$TEMPLATE = $data[0]{template};
|
|
|
|
|
|
|
|
|
|
unless ( -d "$conf{RRDPATH}" ) {
|
|
|
|
|
unless ( mkdir "$conf{RRDPATH}" ) {
|
|
|
|
|
print_log( "mkdir $conf{RRDPATH}, permission denied ", 1 );
|
|
|
|
|
print_log( "PNP exiting ...", 1 );
|
|
|
|
|
exit 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unless ( -d "$conf{RRDPATH}/$NAGIOS{HOSTNAME}" ) {
|
|
|
|
|
unless ( mkdir "$conf{RRDPATH}/$NAGIOS{HOSTNAME}" ) {
|
|
|
|
|
print_log( "mkdir $conf{RRDPATH}/$NAGIOS{HOSTNAME}, permission denied ", 1 );
|
|
|
|
|
print_log( "PNP exiting ...", 1 );
|
|
|
|
|
exit 6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Create PHP Template File
|
|
|
|
|
#
|
|
|
|
|
open_template( $NAGIOS{XMLFILE} );
|
|
|
|
|
|
|
|
|
|
@ds_create = ();
|
|
|
|
|
$ds_update = '';
|
|
|
|
|
|
|
|
|
|
for my $i ( 0 .. $#data ) {
|
|
|
|
|
print_log( " -- Job $i ", 3 );
|
|
|
|
|
my $DS = $i + 1;
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# for each datasource
|
|
|
|
|
#
|
|
|
|
|
for my $job ( sort keys %{ $data[$i] } ) {
|
|
|
|
|
if ( defined $data[$i]{$job} ) {
|
|
|
|
|
print_log( " -- $job -> $data[$i]{$job}", 3 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( uc($conf{'GLOBAL_RRD_STORAGE_TYPE'}) eq "MULTIPLE" ) {
|
|
|
|
|
my $file = $conf{RRDPATH} . "/" . $data[$i]{hostname} . "/" . $data[$i]{servicedesc} . ".rrd";
|
|
|
|
|
if ( -e $file ){
|
|
|
|
|
print_log("RRD_STORAGE_TYPE=MULTIPLE ignored because $file exists!", 1 ) if $i == 0;
|
|
|
|
|
$data[$i]{rrd_storage_type} = "SINGLE";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $i == 0 ){
|
|
|
|
|
$ds_update = "$data[$i]{timet}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $data[$i]{rrd_storage_type} eq "MULTIPLE" ) {
|
|
|
|
|
print_log( "DEBUG: MULTIPLE Storage Type", 3 );
|
|
|
|
|
$DS = 1;
|
|
|
|
|
# PNP 0.4.x Template compatibility
|
|
|
|
|
$NAGIOS{RRDFILE} = "";
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
$rrd_storage_type = "MULTIPLE";
|
|
|
|
|
$rrdfile = $conf{RRDPATH} . "/" . $data[$i]{hostname} . "/" . $data[$i]{servicedesc} . "_" . $data[$i]{name} . ".rrd";
|
|
|
|
|
|
|
|
|
|
# DS is set to 1
|
|
|
|
|
@ds_create = "DS:$DS:$data[$i]{dstype}:$data[$i]{rrd_heartbeat}:$data[$i]{rrd_min}:$data[$i]{rrd_max}";
|
|
|
|
|
$ds_update = "$data[$i]{timet}:$data[$i]{value}";
|
|
|
|
|
@rrd_state = write_rrd();
|
|
|
|
|
@ds_create = ();
|
|
|
|
|
$ds_update = "";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "DEBUG: SINGLE Storage Type", 3 );
|
|
|
|
|
|
|
|
|
|
# PNP 0.4.x Template compatibility
|
|
|
|
|
$NAGIOS{RRDFILE} = $conf{RRDPATH} . "/" . $data[0]{hostname} . "/" . $data[0]{servicedesc} . ".rrd";
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
$rrd_storage_type = "SINGLE";
|
|
|
|
|
$rrdfile = $conf{RRDPATH} . "/" . $data[$i]{hostname} . "/" . $data[$i]{servicedesc} . ".rrd";
|
|
|
|
|
push( @ds_create, "DS:$DS:$data[$i]{dstype}:$data[$i]{rrd_heartbeat}:$data[$i]{rrd_min}:$data[$i]{rrd_max}" );
|
|
|
|
|
$ds_update = "$ds_update:$data[$i]{value}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_to_template( "TEMPLATE", $data[0]{template} );
|
|
|
|
|
write_to_template( "RRDFILE", $rrdfile );
|
|
|
|
|
write_to_template( "RRD_STORAGE_TYPE", $data[$i]{rrd_storage_type} );
|
|
|
|
|
write_to_template( "RRD_HEARTBEAT", $data[$i]{rrd_heartbeat} );
|
|
|
|
|
write_to_template( "IS_MULTI", $data[0]{multi} );
|
|
|
|
|
write_to_template( "DS", $DS );
|
|
|
|
|
write_to_template( "NAME", $data[$i]{name} );
|
|
|
|
|
write_to_template( "LABEL", $data[$i]{label} );
|
|
|
|
|
write_to_template( "UNIT", $data[$i]{uom} );
|
|
|
|
|
write_to_template( "ACT", $data[$i]{value} );
|
|
|
|
|
write_to_template( "WARN", $data[$i]{warning} );
|
|
|
|
|
write_to_template( "WARN_MIN", $data[$i]{warning_min} );
|
|
|
|
|
write_to_template( "WARN_MAX", $data[$i]{warning_max} );
|
|
|
|
|
write_to_template( "WARN_RANGE_TYPE", $data[$i]{warning_range_type} );
|
|
|
|
|
write_to_template( "CRIT", $data[$i]{critical} );
|
|
|
|
|
write_to_template( "CRIT_MIN", $data[$i]{critical_min} );
|
|
|
|
|
write_to_template( "CRIT_MAX", $data[$i]{critical_max} );
|
|
|
|
|
write_to_template( "CRIT_RANGE_TYPE", $data[$i]{critical_range_type} );
|
|
|
|
|
write_to_template( "MIN", $data[$i]{min} );
|
|
|
|
|
write_to_template( "MAX", $data[$i]{max} );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $rrd_storage_type eq "SINGLE" ) {
|
|
|
|
|
@rrd_state = write_rrd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_state_to_template(@rrd_state);
|
|
|
|
|
write_env_to_template();
|
|
|
|
|
close_template( $NAGIOS{XMLFILE} );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub write_rrd {
|
|
|
|
|
my @rrd_create = ();
|
|
|
|
|
my @rrd_state = ();
|
|
|
|
|
|
|
|
|
|
print_log( "DEBUG: TPL-> $TEMPLATE", 3 );
|
|
|
|
|
print_log( "DEBUG: CRE-> @ds_create", 3 );
|
|
|
|
|
print_log( "DEBUG: UPD-> $ds_update", 3 );
|
|
|
|
|
|
|
|
|
|
if ( !-e "$rrdfile" ) {
|
|
|
|
|
@rrd_create = parse_rra_config($TEMPLATE);
|
|
|
|
|
if ( $conf{USE_RRDs} == 1 ) {
|
|
|
|
|
print_log( "RRDs::create $rrdfile @rrd_create @ds_create --start=$NAGIOS{TIMET} --step=$conf{RRA_STEP}", 2 );
|
|
|
|
|
RRDs::create( "$rrdfile", @rrd_create, @ds_create, "--start=$NAGIOS{TIMET}", "--step=$conf{RRA_STEP}" );
|
|
|
|
|
|
|
|
|
|
my $err = RRDs::error();
|
|
|
|
|
if ($err) {
|
|
|
|
|
print_log( "RRDs::create $rrdfile @rrd_create @ds_create --start=$NAGIOS{TIMET} --step=$conf{RRA_STEP}", 0 );
|
|
|
|
|
print_log( "RRDs::create ERROR $err", 0 );
|
|
|
|
|
@rrd_state = ( 1, $err );
|
|
|
|
|
$stats{error}++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "$rrdfile created", 2 );
|
|
|
|
|
@rrd_state = ( 0, "just created" );
|
|
|
|
|
$stats{create}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "RRDs Perl Modules are not installed. Falling back to rrdtool system call.", 2 );
|
|
|
|
|
print_log( "$conf{RRDTOOL} create $rrdfile @rrd_create @ds_create --start=$NAGIOS{TIMET} --step=$conf{RRA_STEP}", 2 );
|
|
|
|
|
system("$conf{RRDTOOL} create $rrdfile @rrd_create @ds_create --start=$NAGIOS{TIMET} --step=$conf{RRA_STEP}");
|
|
|
|
|
if ( $? > 0 ) {
|
|
|
|
|
print_log( "$conf{RRDTOOL} create $rrdfile @rrd_create @ds_create --start=$NAGIOS{TIMET} --step=$conf{RRA_STEP}", 0 );
|
|
|
|
|
print_log( "rrdtool create returns $?", 0 );
|
|
|
|
|
@rrd_state = ( $?, "create failed" );
|
|
|
|
|
$stats{error}++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "rrdtool create returns $?", 1 );
|
|
|
|
|
@rrd_state = ( 0, "just created" );
|
|
|
|
|
$stats{create}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ( $conf{USE_RRDs} == 1 ) {
|
|
|
|
|
if ( $conf{RRD_DAEMON_OPTS} ) {
|
|
|
|
|
print_log( "RRDs::update --daemon=$conf{RRD_DAEMON_OPTS} $rrdfile $ds_update", 2 );
|
|
|
|
|
RRDs::update( "--daemon=$conf{RRD_DAEMON_OPTS}", "$rrdfile", "$ds_update" );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "RRDs::update $rrdfile $ds_update", 2 );
|
|
|
|
|
RRDs::update( "$rrdfile", "$ds_update" );
|
|
|
|
|
}
|
|
|
|
|
my $err = RRDs::error();
|
|
|
|
|
if ($err) {
|
|
|
|
|
print_log( "RRDs::update $rrdfile $ds_update", 0 );
|
|
|
|
|
print_log( "RRDs::update ERROR $err", 0 );
|
|
|
|
|
@rrd_state = ( 1, $err );
|
|
|
|
|
$stats{error}++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "$rrdfile updated", 2 );
|
|
|
|
|
@rrd_state = ( 0, "successful updated" );
|
|
|
|
|
$stats{update}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "RRDs Perl Modules are not installed. Falling back to rrdtool system call.", 2 );
|
|
|
|
|
if ( $conf{RRD_DAEMON_OPTS} ) {
|
|
|
|
|
print_log( "$conf{RRDTOOL} update --daemon=$conf{RRD_DAEMON_OPTS} $rrdfile $ds_update", 2 );
|
|
|
|
|
system("$conf{RRDTOOL} update --daemon=$conf{RRD_DAEMON_OPTS} $rrdfile $ds_update");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "$conf{RRDTOOL} update $rrdfile $ds_update", 2 );
|
|
|
|
|
system("$conf{RRDTOOL} update $rrdfile $ds_update");
|
|
|
|
|
}
|
|
|
|
|
if ( $? > 0 ) {
|
|
|
|
|
print_log( "$conf{RRDTOOL} update $rrdfile $ds_update", 0 );
|
|
|
|
|
print_log( "rrdtool update returns $?", 0 );
|
|
|
|
|
@rrd_state = ( $?, "update failed" );
|
|
|
|
|
$stats{error}++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "rrdtool update returns $?", 1 );
|
|
|
|
|
@rrd_state = ( $?, "successful updated" );
|
|
|
|
|
$stats{update}++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return @rrd_state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Write Template
|
|
|
|
|
#
|
|
|
|
|
sub open_template {
|
|
|
|
|
my $xmlfile = shift;
|
|
|
|
|
$delayed_write = 0;
|
|
|
|
|
if( -e $xmlfile ){
|
|
|
|
|
my $mtime = (stat($xmlfile))[9];
|
|
|
|
|
my $t = time();
|
|
|
|
|
my $age = ($t - $mtime);
|
|
|
|
|
if ( $age < $conf{'XML_UPDATE_DELAY'} ){
|
|
|
|
|
print_log( "DEBUG: XML File is $age seconds old. No update needed", 3 );
|
|
|
|
|
$delayed_write = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
print_log( "DEBUG: XML File is $age seconds old. UPDATE!", 3 );
|
|
|
|
|
}
|
|
|
|
|
open( XML, "> $xmlfile.$$" ) or die "Cant create temporary XML file ", $!;
|
|
|
|
|
print XML "<?xml version=\"1.0\" encoding=\"" . $conf{XML_ENC} . "\" standalone=\"yes\"?>\n";
|
|
|
|
|
print XML "<NAGIOS>\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Close Template FH
|
|
|
|
|
#
|
|
|
|
|
sub close_template {
|
|
|
|
|
return if $delayed_write == 1;
|
|
|
|
|
my $xmlfile = shift;
|
|
|
|
|
printf( XML " <XML>\n" );
|
|
|
|
|
printf( XML " <VERSION>%d</VERSION>\n", $const{'XML_STRUCTURE_VERSION'} );
|
|
|
|
|
printf( XML " </XML>\n" );
|
|
|
|
|
|
|
|
|
|
printf( XML "</NAGIOS>\n" );
|
|
|
|
|
close(XML);
|
|
|
|
|
rename( "$xmlfile.$$", "$xmlfile" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Add Lines
|
|
|
|
|
#
|
|
|
|
|
sub write_to_template {
|
|
|
|
|
return if $delayed_write == 1;
|
|
|
|
|
my $tag = shift;
|
|
|
|
|
my $data = shift;
|
|
|
|
|
if ( !defined $data ) {
|
|
|
|
|
$data = "";
|
|
|
|
|
}
|
|
|
|
|
if ( $tag =~ /^TEMPLATE$/ ) {
|
|
|
|
|
printf( XML " <DATASOURCE>\n" );
|
|
|
|
|
printf( XML " <%s>%s</%s>\n", $tag, "$data", $tag );
|
|
|
|
|
}
|
|
|
|
|
elsif ( $tag =~ /^MAX$/ ) {
|
|
|
|
|
printf( XML " <%s>%s</%s>\n", $tag, "$data", $tag );
|
|
|
|
|
printf( XML " </DATASOURCE>\n" );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
printf( XML " <%s>%s</%s>\n", $tag, "$data", $tag );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub write_state_to_template {
|
|
|
|
|
return if $delayed_write == 1;
|
|
|
|
|
my @rrd_state = @_;
|
|
|
|
|
printf( XML " <RRD>\n" );
|
|
|
|
|
printf( XML " <RC>%s</RC>\n", $rrd_state[0] );
|
|
|
|
|
printf( XML " <TXT>%s</TXT>\n", $rrd_state[1] );
|
|
|
|
|
printf( XML " </RRD>\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Store the complete Nagios ENV
|
|
|
|
|
#
|
|
|
|
|
sub write_env_to_template {
|
|
|
|
|
return if $delayed_write == 1;
|
|
|
|
|
foreach my $key ( sort keys %NAGIOS ) {
|
|
|
|
|
$NAGIOS{$key} = urlencode($NAGIOS{$key});
|
|
|
|
|
printf( XML " <NAGIOS_%s>%s</NAGIOS_%s>\n", $key, $NAGIOS{$key}, $key );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Recursive Template search
|
|
|
|
|
#
|
|
|
|
|
sub adjust_template {
|
|
|
|
|
my $command = shift;
|
|
|
|
|
my $uom = shift;
|
|
|
|
|
my $count = shift;
|
|
|
|
|
my @temp_template = split /\!/, $command;
|
|
|
|
|
my $initial_template = cleanup( $temp_template[0] );
|
|
|
|
|
my $template = cleanup( $temp_template[0] );
|
|
|
|
|
%CTPL = (
|
|
|
|
|
UOM => $uom,
|
|
|
|
|
COUNT => $count,
|
|
|
|
|
COMMAND => $command,
|
|
|
|
|
TEMPLATE => $template,
|
|
|
|
|
DSTYPE => $dstype,
|
|
|
|
|
RRD_STORAGE_TYPE => $conf{'RRD_STORAGE_TYPE'},
|
|
|
|
|
RRD_HEARTBEAT => $conf{'RRD_HEARTBEAT'},
|
|
|
|
|
USE_MIN_ON_CREATE => 0,
|
|
|
|
|
USE_MAX_ON_CREATE => 0,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
read_custom_template ( );
|
|
|
|
|
#
|
|
|
|
|
if ( $CTPL{'TEMPLATE'} ne $initial_template ){
|
|
|
|
|
read_custom_template ( );
|
|
|
|
|
}
|
|
|
|
|
return %CTPL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Analyse check_command to find PNP Template .
|
|
|
|
|
#
|
|
|
|
|
sub read_custom_template {
|
|
|
|
|
my $command = $CTPL{'COMMAND'};
|
|
|
|
|
my $uom = $CTPL{'UOM'};
|
|
|
|
|
my $count = $CTPL{'COUNT'};
|
|
|
|
|
my @dstype_list = ();
|
|
|
|
|
my $use_min_on_create = 0;
|
|
|
|
|
my $use_max_on_create = 0;
|
|
|
|
|
my $rrd_storage_type = $CTPL{'RRD_STORAGE_TYPE'};
|
|
|
|
|
my $rrd_heartbeat = $CTPL{'RRD_HEARTBEAT'};
|
|
|
|
|
|
|
|
|
|
if ( defined($conf{'UOM2TYPE'}{$uom}) ) {
|
|
|
|
|
$dstype = $conf{'UOM2TYPE'}{$uom};
|
|
|
|
|
print_log( "DEBUG: DSTYPE adjusted to $dstype by UOM", 3 );
|
|
|
|
|
}else {
|
|
|
|
|
$dstype = 'GAUGE';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_log( "DEBUG: RAW Command -> $command", 3 );
|
|
|
|
|
my @temp_template = split /\!/, $command;
|
|
|
|
|
my $template = cleanup( $temp_template[0] );
|
|
|
|
|
$template = trim($template);
|
|
|
|
|
my $template_cfg = "$conf{CFG_DIR}/check_commands/$template.cfg";
|
|
|
|
|
print_log( "DEBUG: read_custom_template() => $command", 3 );
|
|
|
|
|
if ( -e $template_cfg ) {
|
|
|
|
|
print_log( "DEBUG: adjust_template() => $template_cfg", 3 );
|
|
|
|
|
my $initial_dstype = $dstype;
|
|
|
|
|
open FH, "<", $template_cfg;
|
|
|
|
|
while (<FH>) {
|
|
|
|
|
next if /^#/;
|
|
|
|
|
next if /^$/;
|
|
|
|
|
s/#.*//;
|
|
|
|
|
s/ //g;
|
|
|
|
|
if (/^(.*)=(.*)$/) {
|
|
|
|
|
if ( $1 eq "DATATYPE" ) {
|
|
|
|
|
$dstype = uc($2);
|
|
|
|
|
$dstype =~ s/ //g;
|
|
|
|
|
@dstype_list = split /,/, $dstype;
|
|
|
|
|
if ( exists $dstype_list[$count] && $dstype_list[$count] =~ /^(COUNTER|GAUGE|ABSOLUTE|DERIVE)$/ ) {
|
|
|
|
|
$dstype = $dstype_list[$count];
|
|
|
|
|
print_log( "Adapting RRD Datatype to \"$dstype\" as defined in $template_cfg with key $count", 2 );
|
|
|
|
|
}
|
|
|
|
|
elsif ( $dstype =~ /^(COUNTER|GAUGE|ABSOLUTE|DERIVE)$/ ) {
|
|
|
|
|
print_log( "Adapting RRD Datatype to \"$dstype\" as defined in $template_cfg", 2 );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "RRD Datatype \"$dstype\" defined in $template_cfg is invalid", 2 );
|
|
|
|
|
$dstype = $initial_dstype;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if ( $1 eq "CUSTOM_TEMPLATE" ) {
|
|
|
|
|
print_log( "Adapting Template using ARG $2", 2 );
|
|
|
|
|
my $i = 1;
|
|
|
|
|
my @keys = split /,/, $2;
|
|
|
|
|
foreach my $keys (@keys) {
|
|
|
|
|
if ( $i == 1 && exists $temp_template[$keys] ) {
|
|
|
|
|
$template = trim( $temp_template[$keys] );
|
|
|
|
|
print_log( "Adapting Template to $template.php (added ARG$keys)", 2 );
|
|
|
|
|
}elsif( exists $temp_template[$keys] ){
|
|
|
|
|
$template .= "_" . trim( $temp_template[$keys] );
|
|
|
|
|
print_log( "Adapting Template to $template.php (added ARG$keys)", 2 );
|
|
|
|
|
}
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
print_log( "Adapting Template to $template.php as defined in $template_cfg", 2 );
|
|
|
|
|
}
|
|
|
|
|
if ( $1 eq "USE_MIN_ON_CREATE" && $2 eq "1" ) {
|
|
|
|
|
$use_min_on_create = 1;
|
|
|
|
|
}
|
|
|
|
|
if ( $1 eq "USE_MAX_ON_CREATE" && $2 eq "1" ) {
|
|
|
|
|
$use_max_on_create = 1;
|
|
|
|
|
}
|
|
|
|
|
if ( $1 eq "RRD_STORAGE_TYPE" && uc($2) eq "MULTIPLE" ) {
|
|
|
|
|
$rrd_storage_type = uc($2);
|
|
|
|
|
}
|
|
|
|
|
if ( $1 eq "RRD_HEARTBEAT" ) {
|
|
|
|
|
$rrd_heartbeat = $2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close FH;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "No Custom Template found for $template ($template_cfg) ", 3 );
|
|
|
|
|
print_log( "RRD Datatype is $dstype", 3 );
|
|
|
|
|
}
|
|
|
|
|
print_log( "Template is $template.php", 3 );
|
|
|
|
|
$CTPL{'COMMAND'} = $template;
|
|
|
|
|
$CTPL{'TEMPLATE'} = $template;
|
|
|
|
|
$CTPL{'DSTYPE'} = $dstype;
|
|
|
|
|
$CTPL{'RRD_STORAGE_TYPE'} = $rrd_storage_type;
|
|
|
|
|
$CTPL{'RRD_HEARTBEAT'} = $rrd_heartbeat;
|
|
|
|
|
$CTPL{'USE_MIN_ON_CREATE'} = $use_min_on_create;
|
|
|
|
|
$CTPL{'USE_MAX_ON_CREATE'} = $use_max_on_create;
|
|
|
|
|
return %CTPL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Parse process_perfdata.cfg
|
|
|
|
|
#
|
|
|
|
|
sub parse_config {
|
|
|
|
|
my $config_file = shift;
|
|
|
|
|
my $line = 0;
|
|
|
|
|
|
|
|
|
|
if ( -e $config_file ) {
|
|
|
|
|
open CFG, '<', "$config_file";
|
|
|
|
|
while (<CFG>) {
|
|
|
|
|
$line++;
|
|
|
|
|
chomp;
|
|
|
|
|
s/ //g;
|
|
|
|
|
next if /^#/;
|
|
|
|
|
next if /^$/;
|
|
|
|
|
s/#.*//;
|
|
|
|
|
|
|
|
|
|
if (/^(.*)=(.*)$/) {
|
|
|
|
|
if ( defined $conf{$1} ) {
|
|
|
|
|
$conf{$1} = $2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close CFG;
|
|
|
|
|
print_log( "Using Config File $config_file parameters", 2 );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "Config File $config_file not found, using defaults", 2 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Parse rra.cfg
|
|
|
|
|
#
|
|
|
|
|
sub parse_rra_config {
|
|
|
|
|
my $template = shift;
|
|
|
|
|
my $rra_template = "";
|
|
|
|
|
my @rrd_create = @default_rrd_create;
|
|
|
|
|
if ( -r $conf{'CFG_DIR'} . "/" . $template . ".rra.cfg" ) {
|
|
|
|
|
$rra_template = $conf{'CFG_DIR'} . "/" . $template . ".rra.cfg";
|
|
|
|
|
print_log( "Reading $rra_template", 2 );
|
|
|
|
|
}
|
|
|
|
|
elsif ( -r $conf{'RRA_CFG'} ) {
|
|
|
|
|
$rra_template = $conf{'RRA_CFG'};
|
|
|
|
|
print_log( "Reading $conf{'RRA_CFG'}", 2 );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "No usable rra.cfg found. Using default values.", 2 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $rra_template ne "" ) {
|
|
|
|
|
@rrd_create = ();
|
|
|
|
|
open RRA, "<", $rra_template;
|
|
|
|
|
while (<RRA>) {
|
|
|
|
|
next if /^#/;
|
|
|
|
|
next if /^$/;
|
|
|
|
|
s/#.*//;
|
|
|
|
|
if(/^RRA_STEP=(\d+)/i){
|
|
|
|
|
$conf{'RRA_STEP'} = $1;
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
chomp;
|
|
|
|
|
push @rrd_create, "$_";
|
|
|
|
|
}
|
|
|
|
|
close RRA;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
@rrd_create = @default_rrd_create;
|
|
|
|
|
}
|
|
|
|
|
return @rrd_create;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Function adapted from Nagios::Plugin::Performance
|
|
|
|
|
# Thanks to Gavin Carr and Ton Voon
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
sub _parse {
|
|
|
|
|
# Nagios::Plugin::Performance
|
|
|
|
|
my $string = shift;
|
|
|
|
|
my $tmp_string = $string;
|
|
|
|
|
$string =~ s/^([^=]+)=(U|[\d\.\-]+)([\w\/%]*);?([\d\.\-:~@]+)?;?([\d\.\-:~@]+)?;?([\d\.\-]+)?;?([\d\.\-]+)?;?\s*//;
|
|
|
|
|
|
|
|
|
|
if ( $tmp_string eq $string ) {
|
|
|
|
|
print_log( "No pattern match in function _parse($string)", 2 );
|
|
|
|
|
return undef;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return undef unless ( ( defined $1 && $1 ne "" ) && ( defined $2 && $2 ne "" ) );
|
|
|
|
|
|
|
|
|
|
# create hash from all performance data values
|
|
|
|
|
|
|
|
|
|
my %p = (
|
|
|
|
|
"label" => $1,
|
|
|
|
|
"name" => $1,
|
|
|
|
|
"value" => $2,
|
|
|
|
|
"uom" => $3,
|
|
|
|
|
"warning" => $4,
|
|
|
|
|
"critical" => $5,
|
|
|
|
|
"min" => $6,
|
|
|
|
|
"max" => $7
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$p{label} =~ s/[&"']//g; # cleanup
|
|
|
|
|
$p{name} =~ s/["']//g; # cleanup
|
|
|
|
|
$p{name} =~ s/[\/\\]/_/g; # cleanup
|
|
|
|
|
$p{name} = cleanup($p{name});
|
|
|
|
|
|
|
|
|
|
if ( $p{uom} eq "%" ) {
|
|
|
|
|
$p{uom} = "%%";
|
|
|
|
|
print_log( "DEBUG: UOM adjust = $p{uom}", 3 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Check for warning and critical ranges
|
|
|
|
|
#
|
|
|
|
|
if ( $p{warning} && $p{warning} =~ /^([\d\.\-~@]+)?:([\d\.\-~@]+)?$/ ) {
|
|
|
|
|
print_log( "DEBUG: Processing warning ranges ( $p{warning} )", 3 );
|
|
|
|
|
$p{warning_min} = $1;
|
|
|
|
|
$p{warning_max} = $2;
|
|
|
|
|
delete( $p{warning} );
|
|
|
|
|
if ( $p{warning_min} =~ /^@/ ) {
|
|
|
|
|
$p{warning_min} =~ s/@//;
|
|
|
|
|
$p{warning_range_type} = "inside";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$p{warning_range_type} = "outside";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $p{critical} && $p{critical} =~ /^([\d\.\-~@]+)?:([\d\.\-~@]+)?$/ ) {
|
|
|
|
|
print_log( "DEBUG: Processing critical ranges ( $p{critical} )", 3 );
|
|
|
|
|
$p{critical_min} = $1;
|
|
|
|
|
$p{critical_max} = $2;
|
|
|
|
|
delete( $p{critical} );
|
|
|
|
|
if ( $p{critical_min} =~ /^@/ ) {
|
|
|
|
|
$p{critical_min} =~ s/@//;
|
|
|
|
|
$p{critical_range_type} = "inside";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$p{critical_range_type} = "outside";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# Strip Range indicators
|
|
|
|
|
$p{warning} =~ s/[~@]// if($p{warning});
|
|
|
|
|
$p{critical} =~ s/[~@]// if($p{critical});
|
|
|
|
|
|
|
|
|
|
return ( $string, %p );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# clean Strings
|
|
|
|
|
#
|
|
|
|
|
sub cleanup {
|
|
|
|
|
my $string = shift;
|
|
|
|
|
if ($string) {
|
|
|
|
|
$string =~ s/[& :\/\\]/_/g;
|
|
|
|
|
}
|
|
|
|
|
return $string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Urlencode
|
|
|
|
|
#
|
|
|
|
|
sub urlencode {
|
|
|
|
|
my $string = shift;
|
|
|
|
|
if ($string) {
|
|
|
|
|
$string =~ s/([<>&])/sprintf("%%%02x",ord($1))/eg; # URLencode;
|
|
|
|
|
}
|
|
|
|
|
return $string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Trim leading whitespaces
|
|
|
|
|
#
|
|
|
|
|
sub trim {
|
|
|
|
|
my $string = shift;
|
|
|
|
|
$string =~ s/^\s*//g;
|
|
|
|
|
return $string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Parse the Performance String and call data2rrd()
|
|
|
|
|
#
|
|
|
|
|
sub parse_perfstring {
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Default RRD Datatype
|
|
|
|
|
# Value will be overwritten by adjust_template()
|
|
|
|
|
#
|
|
|
|
|
my %CTPL = ();
|
|
|
|
|
$dstype = "GAUGE";
|
|
|
|
|
my $perfstring = shift;
|
|
|
|
|
my $is_multi = "0";
|
|
|
|
|
my @perfs;
|
|
|
|
|
my @multi;
|
|
|
|
|
my %p;
|
|
|
|
|
my $use_min_on_create = 0;
|
|
|
|
|
my $use_max_on_create = 0;
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# check_multi
|
|
|
|
|
#
|
|
|
|
|
if ( $perfstring =~ /^[']?([a-zA-Z0-9\.\-_\s\/\#]+)::([a-zA-Z0-9\.\-_\s]+)::([^=]+)[']?=/ ) {
|
|
|
|
|
$is_multi = 1;
|
|
|
|
|
print_log( "check_multi Perfdata start", 3 );
|
|
|
|
|
my $count = 0;
|
|
|
|
|
my $check_multi_blockcount = 0;
|
|
|
|
|
my $multi_parent = cleanup( $NAGIOS{SERVICEDESC} );
|
|
|
|
|
my $auth_servicedesc = $NAGIOS{DISP_SERVICEDESC};
|
2017-10-20 17:10:51 +02:00
|
|
|
|
my $seen_multi_label = "";
|
2017-05-20 15:26:21 +02:00
|
|
|
|
while ($perfstring) {
|
|
|
|
|
( $perfstring, %p ) = _parse($perfstring);
|
|
|
|
|
if ( !$p{label} ) {
|
|
|
|
|
print_log( "Invalid Perfdata detected ", 1 );
|
|
|
|
|
$stats{invalid}++;
|
|
|
|
|
@perfs = ();
|
|
|
|
|
last;
|
|
|
|
|
}
|
2017-10-20 17:10:51 +02:00
|
|
|
|
|
|
|
|
|
if ( $p{label} =~ /$seen_multi_label/ ) {
|
|
|
|
|
# multi label format for each perfdata item (e.g Icinga2)
|
|
|
|
|
# we're in a sub tree of a multi block, adjust label for further processing
|
|
|
|
|
my $tmp_prefix = $seen_multi_label."::";
|
|
|
|
|
$p{label} =~ s/$tmp_prefix//;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-20 15:26:21 +02:00
|
|
|
|
if ( $p{label} =~ /^[']?([a-zA-Z0-9\.\-_\s\/\#]+)::([a-zA-Z0-9\.\-_\s]+)::([^=]+)[']?$/ ) {
|
|
|
|
|
@multi = ( $1, $2, $3 );
|
2017-10-20 17:10:51 +02:00
|
|
|
|
|
|
|
|
|
$seen_multi_label = $multi[0]."::".$multi[1];
|
|
|
|
|
|
2017-05-20 15:26:21 +02:00
|
|
|
|
if ( $count == 0 ) {
|
|
|
|
|
print_log( "DEBUG: First check_multi block", 3 );
|
|
|
|
|
|
|
|
|
|
# Keep servicedesc while processing the first block.
|
|
|
|
|
$p{servicedesc} = cleanup( $NAGIOS{SERVICEDESC} );
|
|
|
|
|
$p{disp_servicedesc} = $NAGIOS{DISP_SERVICEDESC};
|
|
|
|
|
$p{auth_servicedesc} = $auth_servicedesc;
|
|
|
|
|
$p{multi} = 1;
|
|
|
|
|
$p{multi_parent} = $multi_parent;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "DEBUG: A new check_multi block ($count) starts", 3 );
|
|
|
|
|
$p{servicedesc} = cleanup( $multi[0] ); # Use the multi servicedesc.
|
|
|
|
|
$p{multi} = 2;
|
|
|
|
|
$p{multi_parent} = $multi_parent;
|
|
|
|
|
$p{servicedesc} = cleanup( $multi[0] ); # Use the multi servicedesc.
|
|
|
|
|
$p{disp_servicedesc} = cleanup( $multi[0] ); # Use the multi servicedesc.
|
|
|
|
|
$p{auth_servicedesc} = $auth_servicedesc;
|
|
|
|
|
data2rrd(@perfs) if ( $#perfs >= 0 ); # Process when a new block starts.
|
|
|
|
|
@perfs = (); # Clear the perfs array.
|
|
|
|
|
# reset check_multi block count
|
|
|
|
|
$check_multi_blockcount = 0;
|
|
|
|
|
}
|
|
|
|
|
%CTPL = adjust_template( $multi[1], $p{uom}, $check_multi_blockcount++ );
|
|
|
|
|
|
|
|
|
|
if ( $CTPL{'USE_MAX_ON_CREATE'} == 1 && defined $p{max} ) {
|
|
|
|
|
$p{rrd_max} = $p{max};
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_max} = "U";
|
|
|
|
|
}
|
|
|
|
|
if ( $CTPL{'USE_MIN_ON_CREATE'} == 1 && defined $p{min} ) {
|
|
|
|
|
$p{rrd_min} = $p{min};
|
|
|
|
|
} elsif( $CTPL{'DSTYPE'} eq 'DERIVE' ){
|
|
|
|
|
$p{rrd_min} = 0; # Add minimum value 0 if DSTYPE = DERIVE
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_min} = "U";
|
|
|
|
|
}
|
|
|
|
|
$p{template} = $CTPL{'TEMPLATE'};
|
|
|
|
|
$p{dstype} = $CTPL{'DSTYPE'};
|
|
|
|
|
$p{rrd_storage_type} = $CTPL{'RRD_STORAGE_TYPE'};
|
|
|
|
|
$p{rrd_heartbeat} = $CTPL{'RRD_HEARTBEAT'};
|
|
|
|
|
$p{label} = cleanup( $multi[2] ); # store the original label from check_multi header
|
|
|
|
|
$p{name} = cleanup( $multi[2] ); # store the original label from check_multi header
|
|
|
|
|
$p{hostname} = cleanup( $NAGIOS{HOSTNAME} );
|
|
|
|
|
$p{disp_hostname} = $NAGIOS{DISP_HOSTNAME};
|
|
|
|
|
$p{auth_hostname} = $NAGIOS{HOSTNAME};
|
|
|
|
|
$p{timet} = $NAGIOS{TIMET};
|
|
|
|
|
push @perfs, {%p};
|
|
|
|
|
$count++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "DEBUG: Next check_multi data for block $count multiblock $check_multi_blockcount", 3 );
|
|
|
|
|
|
|
|
|
|
# additional check_multi data
|
|
|
|
|
%CTPL = adjust_template( $multi[1], $p{uom}, $check_multi_blockcount++ );
|
|
|
|
|
|
|
|
|
|
if ( $CTPL{'USE_MAX_ON_CREATE'} == 1 && defined $p{max} ) {
|
|
|
|
|
$p{rrd_max} = $p{max};
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_max} = "U";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $CTPL{'USE_MIN_ON_CREATE'} == 1 && defined $p{min} ) {
|
|
|
|
|
$p{rrd_min} = $p{min};
|
|
|
|
|
} elsif( $CTPL{'DSTYPE'} eq 'DERIVE' ){
|
|
|
|
|
$p{rrd_min} = 0; # Add minimum value 0 if DSTYPE = DERIVE
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_min} = "U";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$p{template} = $CTPL{'TEMPLATE'};
|
|
|
|
|
$p{dstype} = $CTPL{'DSTYPE'};
|
|
|
|
|
$p{rrd_storage_type} = $CTPL{'RRD_STORAGE_TYPE'};
|
|
|
|
|
$p{rrd_heartbeat} = $CTPL{'RRD_HEARTBEAT'};
|
|
|
|
|
$p{hostname} = cleanup( $NAGIOS{HOSTNAME} );
|
|
|
|
|
$p{disp_hostname} = $NAGIOS{DISP_HOSTNAME};
|
|
|
|
|
$p{auth_hostname} = $NAGIOS{HOSTNAME};
|
|
|
|
|
$p{timet} = $NAGIOS{TIMET};
|
|
|
|
|
if ( $count == 1 ) {
|
|
|
|
|
$p{servicedesc} = cleanup( $NAGIOS{SERVICEDESC} ); # Use the servicedesc.
|
|
|
|
|
$p{disp_servicedesc} = $NAGIOS{DISP_SERVICEDESC}; # Use the servicedesc.
|
|
|
|
|
} else {
|
|
|
|
|
$p{servicedesc} = cleanup( $multi[0] ); # Use the multi servicedesc.
|
|
|
|
|
$p{disp_servicedesc} = $multi[0]; # Use the multi servicedesc.
|
|
|
|
|
}
|
|
|
|
|
$p{multi} = $is_multi;
|
|
|
|
|
$p{multi_parent} = $multi_parent;
|
|
|
|
|
$p{auth_servicedesc} = $auth_servicedesc; # Use the servicedesc.
|
|
|
|
|
push @perfs, {%p};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
data2rrd(@perfs) if ( $#perfs >= 0 );
|
|
|
|
|
@perfs = ();
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Normal Performance Data
|
|
|
|
|
#
|
|
|
|
|
print_log( "DEBUG: Normal perfdata", 3 );
|
|
|
|
|
my $count = 0;
|
|
|
|
|
while ($perfstring) {
|
|
|
|
|
( $perfstring, %p ) = _parse($perfstring);
|
|
|
|
|
if ( !$p{label} ) {
|
|
|
|
|
print_log( "Invalid Perfdata detected ", 1 );
|
|
|
|
|
@perfs = ();
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
%CTPL = adjust_template( $NAGIOS{CHECK_COMMAND}, $p{uom}, $count );
|
|
|
|
|
|
|
|
|
|
if ( $CTPL{'USE_MAX_ON_CREATE'} == 1 && defined $p{max} ) {
|
|
|
|
|
$p{rrd_max} = $p{max};
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_max} = "U";
|
|
|
|
|
}
|
|
|
|
|
if ( $CTPL{'USE_MIN_ON_CREATE'} == 1 && defined $p{min} ) {
|
|
|
|
|
$p{rrd_min} = $p{min};
|
|
|
|
|
} elsif ( $CTPL{'DSTYPE'} eq 'DERIVE' ){
|
|
|
|
|
$p{rrd_min} = 0; # Add minimum value 0 if DSTYPE = DERIVE
|
|
|
|
|
} else {
|
|
|
|
|
$p{rrd_min} = "U";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$p{template} = $CTPL{'TEMPLATE'};
|
|
|
|
|
$p{dstype} = $CTPL{'DSTYPE'};
|
|
|
|
|
$p{rrd_storage_type} = $CTPL{'RRD_STORAGE_TYPE'};
|
|
|
|
|
$p{rrd_heartbeat} = $CTPL{'RRD_HEARTBEAT'};
|
|
|
|
|
$p{multi} = $is_multi;
|
|
|
|
|
$p{hostname} = cleanup( $NAGIOS{HOSTNAME} );
|
|
|
|
|
$p{disp_hostname} = $NAGIOS{DISP_HOSTNAME};
|
|
|
|
|
$p{auth_hostname} = $NAGIOS{DISP_HOSTNAME};
|
|
|
|
|
$p{servicedesc} = cleanup( $NAGIOS{SERVICEDESC} );
|
|
|
|
|
$p{disp_servicedesc} = $NAGIOS{DISP_SERVICEDESC};
|
|
|
|
|
$p{auth_servicedesc} = $NAGIOS{DISP_SERVICEDESC};
|
|
|
|
|
$p{timet} = $NAGIOS{TIMET};
|
|
|
|
|
|
|
|
|
|
push @perfs, {%p};
|
|
|
|
|
$count++;
|
|
|
|
|
}
|
|
|
|
|
data2rrd(@perfs) if ( $#perfs >= 0 );
|
|
|
|
|
@perfs = ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Write to Logfile
|
|
|
|
|
#
|
|
|
|
|
sub print_log {
|
|
|
|
|
my $out = shift;
|
|
|
|
|
my $severity = shift;
|
|
|
|
|
if ( $severity <= $conf{LOG_LEVEL} ) {
|
|
|
|
|
open( LOG, ">>" . $conf{LOG_FILE} ) || die "Can't open logfile ($conf{LOG_FILE}) ", $!;
|
|
|
|
|
if ( -s LOG > $conf{LOG_FILE_MAX_SIZE} ) {
|
|
|
|
|
truncate( LOG, 0 );
|
|
|
|
|
printf( LOG "File truncated" );
|
|
|
|
|
}
|
|
|
|
|
my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
|
|
|
|
|
printf( LOG "%02d-%02d-%02d %02d:%02d:%02d [%d] [%d] %s\n", $year + 1900, $mon + 1, $mday, $hour, $min, $sec, $$, $severity, $out );
|
|
|
|
|
close(LOG);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Signals and Handlers
|
|
|
|
|
#
|
|
|
|
|
sub init_signals {
|
|
|
|
|
$SIG{'INT'} = \&handle_signal;
|
|
|
|
|
$SIG{'QUIT'} = \&handle_signal;
|
|
|
|
|
$SIG{'ALRM'} = \&handle_signal;
|
|
|
|
|
$SIG{'ILL'} = \&handle_signal;
|
|
|
|
|
$SIG{'ABRT'} = \&handle_signal;
|
|
|
|
|
$SIG{'FPE'} = \&handle_signal;
|
|
|
|
|
$SIG{'SEGV'} = \&handle_signal;
|
|
|
|
|
$SIG{'TERM'} = \&handle_signal;
|
|
|
|
|
$SIG{'BUS'} = \&handle_signal;
|
|
|
|
|
$SIG{'SYS'} = \&handle_signal;
|
|
|
|
|
$SIG{'XCPU'} = \&handle_signal;
|
|
|
|
|
$SIG{'XFSZ'} = \&handle_signal;
|
|
|
|
|
$SIG{'IOT'} = \&handle_signal;
|
|
|
|
|
$SIG{'PIPE'} = \&handle_signal;
|
|
|
|
|
$SIG{'HUP'} = \&handle_signal;
|
|
|
|
|
$SIG{'CHLD'} = \&handle_signal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Handle Signals
|
|
|
|
|
#
|
|
|
|
|
sub handle_signal {
|
|
|
|
|
my ($signal) = (@_);
|
|
|
|
|
#
|
|
|
|
|
# Gearman child process
|
|
|
|
|
#
|
|
|
|
|
if ( defined ( $opt_gm ) ){
|
|
|
|
|
if($signal eq "CHLD" && defined($opt_gm) ){
|
|
|
|
|
my $pid = waitpid(-1, &WNOHANG);
|
|
|
|
|
if($pid == -1){
|
|
|
|
|
print_log( "### no hanging child ###", 1 );
|
|
|
|
|
} elsif ( WIFEXITED($?)) {
|
|
|
|
|
print_log( "### child $pid exited ###", 1 );
|
|
|
|
|
$children--;
|
|
|
|
|
} else {
|
|
|
|
|
print_log( "### wrong signal ###", 1 );
|
|
|
|
|
$children--;
|
|
|
|
|
}
|
|
|
|
|
$SIG{'CHLD'} = \&handle_signal;
|
|
|
|
|
}
|
|
|
|
|
if($signal eq "INT" || $signal eq "TERM"){
|
|
|
|
|
local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children
|
|
|
|
|
kill $signal => keys %children;
|
|
|
|
|
print_log( "*** process_perfdata.pl terminated on signal $signal", 0 );
|
|
|
|
|
pidlock("remove");
|
|
|
|
|
exit; # clean up with dignity
|
|
|
|
|
}
|
|
|
|
|
print_log( "*** process_perfdata.pl received signal $signal (ignored)", 0 );
|
|
|
|
|
}else{
|
|
|
|
|
if ( $signal eq "ALRM" ) {
|
|
|
|
|
print_log( "*** TIMEOUT: Timeout after $opt_t secs. ***", 0 );
|
|
|
|
|
if ( $opt_b && !$opt_n && !$opt_s ) {
|
|
|
|
|
print_log( "*** TIMEOUT: Deleting current file to avoid loops", 0 );
|
|
|
|
|
print_log( "*** TIMEOUT: Please check your process_perfdata.cfg", 0 );
|
|
|
|
|
}
|
|
|
|
|
elsif ( $opt_b && $opt_n && !$opt_s ) {
|
|
|
|
|
print_log( "*** TIMEOUT: Deleting current file to avoid NPCD loops", 0 );
|
|
|
|
|
print_log( "*** TIMEOUT: Please check your process_perfdata.cfg", 0 );
|
|
|
|
|
}
|
|
|
|
|
if ($opt_b && !$opt_s ) {
|
|
|
|
|
my $pdfile = "$opt_b" . "-PID-" . $$;
|
|
|
|
|
if ( unlink("$pdfile") == 1 ) {
|
|
|
|
|
print_log( "*** TIMEOUT: $pdfile deleted", 0 );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print_log( "*** TIMEOUT: Could not delete $pdfile:$!", 0 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
my $temp_file = "$conf{RRDPATH}/$NAGIOS{HOSTNAME}/$NAGIOS{SERVICEDESC}.xml.$$";
|
|
|
|
|
if ( -f $temp_file ) {
|
|
|
|
|
unlink($temp_file);
|
|
|
|
|
}
|
|
|
|
|
$t1 = [gettimeofday];
|
|
|
|
|
$rt = tv_interval $t0, $t1;
|
|
|
|
|
$stats{runtime} = $rt;
|
|
|
|
|
print_log( "*** Timeout while processing Host: \"$NAGIOS{HOSTNAME}\" Service: \"$NAGIOS{SERVICEDESC}\"", 0 );
|
|
|
|
|
print_log( "*** process_perfdata.pl terminated on signal $signal", 0 );
|
|
|
|
|
exit 7;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sub init_stats {
|
|
|
|
|
%stats = (
|
|
|
|
|
timet => time,
|
|
|
|
|
error => 0,
|
|
|
|
|
invalid => 0,
|
|
|
|
|
skipped => 0,
|
|
|
|
|
runtime => 0,
|
|
|
|
|
rows => 0,
|
|
|
|
|
create => 0,
|
|
|
|
|
update => 0,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Store some internal runtime infos
|
|
|
|
|
#
|
|
|
|
|
sub store_internals {
|
|
|
|
|
if( ! -w $conf{'STATS_DIR'}){
|
|
|
|
|
print_log("*** ERROR: ".$conf{'STATS_DIR'}." is not writable or does not exist",0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
my $statsfile = $conf{'STATS_DIR'}."/".(int $stats{timet} / 60);
|
|
|
|
|
open( STAT, ">> $statsfile" ) or die "Cant create statistic file ", $!;
|
|
|
|
|
printf(STAT "%d %f %d %d %d %d %d %d\n", $stats{timet},$stats{runtime},$stats{rows},$stats{update},$stats{create},$stats{error},$stats{invalid},$stats{skipped});
|
|
|
|
|
close(STAT);
|
|
|
|
|
check_internals();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Search for statistic files
|
|
|
|
|
#
|
|
|
|
|
sub check_internals {
|
|
|
|
|
my $file;
|
|
|
|
|
my @files;
|
|
|
|
|
opendir(STATS, $conf{'STATS_DIR'});
|
|
|
|
|
while ( defined ( my $file = readdir STATS) ){
|
|
|
|
|
next if $file =~ /^\.\.?$/; # skip . and ..
|
|
|
|
|
next if $file =~ /-PID-/; # skip temporary files
|
|
|
|
|
next if $file == (int $stats{timet} / 60); # skip our current file
|
|
|
|
|
push @files, $file;
|
|
|
|
|
}
|
|
|
|
|
read_internals(@files);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Read and aggregate files found by check_internals()
|
|
|
|
|
#
|
|
|
|
|
sub read_internals {
|
|
|
|
|
my @files = @_;
|
|
|
|
|
my @chunks;
|
|
|
|
|
foreach my $file (sort { $a <=> $b} @files){
|
|
|
|
|
unless ( rename($conf{'STATS_DIR'}."/".$file, $conf{'STATS_DIR'}."/".$file."-PID-".$$) ){
|
|
|
|
|
print_log( "ERROR: renaming stats file " . $conf{'STATS_DIR'}."/".$file . " to " . $conf{'STATS_DIR'}."/".$file."-PID-".$$ . " failed", 1 );
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
open( STAT, "< ".$conf{'STATS_DIR'}."/".$file."-PID-".$$ );
|
|
|
|
|
%stats = (
|
|
|
|
|
timet => 0,
|
|
|
|
|
error => 0,
|
|
|
|
|
invalid => 0,
|
|
|
|
|
skipped => 0,
|
|
|
|
|
runtime => 0,
|
|
|
|
|
rows => 0,
|
|
|
|
|
create => 0,
|
|
|
|
|
update => 0,
|
|
|
|
|
);
|
|
|
|
|
while(<STAT>){
|
|
|
|
|
@chunks = split();
|
|
|
|
|
$stats{timet} = $chunks[0];
|
|
|
|
|
$stats{runtime} += $chunks[1];
|
|
|
|
|
$stats{rows} += $chunks[2];
|
|
|
|
|
$stats{update} += $chunks[3];
|
|
|
|
|
$stats{create} += $chunks[4];
|
|
|
|
|
$stats{error} += $chunks[5];
|
|
|
|
|
$stats{invalid} += $chunks[6];
|
|
|
|
|
$stats{skipped} += $chunks[7];
|
|
|
|
|
}
|
|
|
|
|
close(STAT);
|
|
|
|
|
unlink($conf{'STATS_DIR'}."/".$file."-PID-".$$);
|
|
|
|
|
process_internals();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
sub process_internals {
|
|
|
|
|
my $last_rrd_dtorage_type = $conf{'RRD_STORAGE_TYPE'};
|
|
|
|
|
$conf{'RRD_STORAGE_TYPE'} = "MULTIPLE";
|
|
|
|
|
%NAGIOS = (
|
|
|
|
|
HOSTNAME => '.pnp-internal',
|
|
|
|
|
DISP_HOSTNAME => 'pnp-internal',
|
|
|
|
|
SERVICEDESC => 'runtime',
|
|
|
|
|
DISP_SERVICEDESC => 'runtime',
|
|
|
|
|
TIMET => $stats{timet},
|
|
|
|
|
DATATYPE => 'SERVICEPERFDATA',
|
|
|
|
|
CHECK_COMMAND => 'pnp-runtime',
|
|
|
|
|
PERFDATA => "runtime=".$stats{runtime}."s rows=".$stats{rows}." errors=".$stats{error}." invalid=".$stats{invalid}." skipped=".$stats{skipped} ." update=".$stats{update}. " create=".$stats{create}
|
|
|
|
|
);
|
|
|
|
|
parse_perfstring( $NAGIOS{PERFDATA} );
|
|
|
|
|
$conf{'RRD_STORAGE_TYPE'} = $last_rrd_dtorage_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Gearman Worker Daemon
|
|
|
|
|
#
|
|
|
|
|
sub daemonize {
|
|
|
|
|
if( defined($opt_daemon) ){
|
|
|
|
|
print_log("daemonize init",1);
|
|
|
|
|
chdir '/' or die "Can't chdir to /: $!";
|
|
|
|
|
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: $!";
|
|
|
|
|
exit if $pid;
|
|
|
|
|
pidlock("create");
|
|
|
|
|
setsid or die "Can't start a new session: $!";
|
|
|
|
|
} else {
|
|
|
|
|
pidlock("create");
|
|
|
|
|
}
|
|
|
|
|
# Fork off our children.
|
|
|
|
|
for (1 .. $conf{'PREFORK'}) {
|
|
|
|
|
new_child();
|
|
|
|
|
print_log( "starting child process $children", 1 );
|
|
|
|
|
}
|
|
|
|
|
while (1) {
|
|
|
|
|
sleep; # wait for a signal (i.e., child's death)
|
|
|
|
|
for (my $i = $children; $i < $conf{'PREFORK'}; $i++) {
|
|
|
|
|
print_log("starting new child (running = $i)",1);
|
|
|
|
|
new_child(); # top up the child pool
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# start a new worker process
|
|
|
|
|
#
|
|
|
|
|
sub new_child {
|
|
|
|
|
my $pid;
|
|
|
|
|
my $sigset;
|
|
|
|
|
my $req = 0;
|
|
|
|
|
# block signal for fork
|
|
|
|
|
$sigset = POSIX::SigSet->new(SIGINT);
|
|
|
|
|
sigprocmask(SIG_BLOCK, $sigset)
|
|
|
|
|
or die "Can't block SIGINT for fork: $!\n";
|
|
|
|
|
|
|
|
|
|
die "fork: $!" unless defined ($pid = fork);
|
|
|
|
|
|
|
|
|
|
if ($pid) {
|
|
|
|
|
# Parent records the child's birth and returns.
|
|
|
|
|
sigprocmask(SIG_UNBLOCK, $sigset)
|
|
|
|
|
or die "Can't unblock SIGINT for fork: $!\n";
|
|
|
|
|
$children{$pid} = 1;
|
|
|
|
|
$children++;
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
# Child can *not* return from this subroutine.
|
|
|
|
|
$SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before
|
|
|
|
|
|
|
|
|
|
# unblock signals
|
|
|
|
|
sigprocmask(SIG_UNBLOCK, $sigset)
|
|
|
|
|
or die "Can't unblock SIGINT for fork: $!\n";
|
|
|
|
|
|
|
|
|
|
my $worker = Gearman::Worker->new();
|
|
|
|
|
my @job_servers = split(/,/, $conf{'GEARMAN_HOST'}); # allow multiple gearman job servers
|
|
|
|
|
$worker->job_servers(@job_servers);
|
|
|
|
|
$worker->register_function("perfdata", 2, sub { return main(@_); });
|
|
|
|
|
my %opt = (
|
|
|
|
|
on_complete => sub { $req++; },
|
|
|
|
|
stop_if => sub { if ( $req > $conf{'REQUESTS_PER_CHILD'} ) { return 1;}; }
|
|
|
|
|
);
|
|
|
|
|
print_log("connecting to gearmand '".$conf{'GEARMAN_HOST'}."'",0);
|
|
|
|
|
$worker->work( %opt );
|
|
|
|
|
print_log("max requests per child reached (".$conf{'REQUESTS_PER_CHILD'}.")",1);
|
|
|
|
|
# this exit is VERY important, otherwise the child will become
|
|
|
|
|
# a producer of more and more children, forking yourself into
|
|
|
|
|
# process death.
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#
|
|
|
|
|
# Create a pid file
|
|
|
|
|
#
|
|
|
|
|
sub pidlock {
|
|
|
|
|
return unless defined $opt_pidfile;
|
|
|
|
|
my $action = shift;
|
|
|
|
|
my $PIDFILE = $opt_pidfile;
|
|
|
|
|
if($action eq "create"){
|
|
|
|
|
if ( -e $PIDFILE ) {
|
|
|
|
|
if ( open( OLDPID, "<$PIDFILE" ) ) {
|
|
|
|
|
$_ = <OLDPID>;
|
|
|
|
|
chop($_);
|
|
|
|
|
my $oldpid = $_;
|
|
|
|
|
close(OLDPID);
|
|
|
|
|
if ( -e "/proc/$oldpid/cmdline" ) {
|
|
|
|
|
print_log("Another instance is already running with PID: $oldpid",0);
|
|
|
|
|
exit 0;
|
|
|
|
|
} else {
|
|
|
|
|
print_log("Pidfile $PIDFILE seems to be stale!",0);
|
|
|
|
|
print_log("Removing old pidfile",0);
|
|
|
|
|
unlink $PIDFILE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( !open( PID, ">$PIDFILE" ) ) {
|
|
|
|
|
print_log("Can not create $PIDFILE ( $! )",0);
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
print( PID "$$\n" );
|
|
|
|
|
close(PID);
|
|
|
|
|
print_log("Pidfile ($PIDFILE) created",0);
|
|
|
|
|
}elsif( $action eq "remove" ){
|
|
|
|
|
if ( -e $PIDFILE ) {
|
|
|
|
|
print_log("Removing pidfile ($PIDFILE)",0);
|
|
|
|
|
unlink $PIDFILE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Read crypt key
|
|
|
|
|
#
|
|
|
|
|
sub read_keyfile {
|
|
|
|
|
my $file = shift;
|
|
|
|
|
my $key = '';
|
|
|
|
|
if( -r $file){
|
|
|
|
|
open(FH, "<", $file);
|
|
|
|
|
while(<FH>){
|
|
|
|
|
chomp(); # avoid \n on last field
|
|
|
|
|
$conf{'KEY'} = $_;
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
close(FH);
|
|
|
|
|
print_log("Using encryption key specified in '$file'",0);
|
|
|
|
|
return 1;
|
|
|
|
|
}else{
|
|
|
|
|
print_log("Using encryption key specified in ".$conf{'CFG_DIR'}."/process_perfdata.cfg",0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
sub print_help {
|
|
|
|
|
print <<EOD;
|
|
|
|
|
|
2017-05-20 15:29:39 +02:00
|
|
|
|
Copyright (c) 2005-2015 Joerg Linge <pitchfork\@pnp4nagios.org>
|
2017-05-20 15:26:21 +02:00
|
|
|
|
Use process_perfdata.pl to store Nagios Plugin Performance Data into RRD Databases
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
-h, --help
|
|
|
|
|
Print detailed help screen
|
|
|
|
|
-V, --version
|
|
|
|
|
Print version information
|
|
|
|
|
-t, --timeout=INTEGER
|
|
|
|
|
Seconds before process_perfdata.pl times out (default: $opt_t_default)
|
|
|
|
|
-i, --inetd
|
|
|
|
|
Use this Option if process_perfdata.pl is executed by inetd/xinetd.
|
|
|
|
|
-d, --datatype
|
|
|
|
|
Defaults to \"SERVICEPERFDATA\". Use \"HOSTPERFDATA\" to process Perfdata from regular Host Checks
|
|
|
|
|
Only used in default or inetd mode
|
|
|
|
|
-b, --bulk
|
|
|
|
|
Provide a file for bulk update
|
|
|
|
|
-s, --stdin
|
|
|
|
|
Read input from stdin
|
|
|
|
|
-n, --npcd
|
|
|
|
|
Hint the program, that it was invoked by NPCD
|
|
|
|
|
-c, --config
|
|
|
|
|
Optional process_perfdata config file
|
|
|
|
|
Default: @sysconfdir@/process_perfdata.cfg
|
|
|
|
|
|
|
|
|
|
Gearman Worker Options:
|
|
|
|
|
--gearman
|
|
|
|
|
Start in Gearman worker mode
|
|
|
|
|
--daemon
|
|
|
|
|
Run as daemon
|
|
|
|
|
--pidfile=/var/run/process_perfdata.pid
|
|
|
|
|
The pidfile used while running in as Gearman worker daemon
|
|
|
|
|
|
|
|
|
|
EOD
|
|
|
|
|
exit 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
sub print_version {
|
|
|
|
|
print "Version: process_perfdata.pl $const{VERSION}\n";
|
|
|
|
|
print "Copyright (c) 2005-2010 Joerg Linge <pitchfork\@pnp4nagios.org>\n";
|
|
|
|
|
exit 0;
|
|
|
|
|
}
|
|
|
|
|
|