This is Bavaria, Germany!
package Nagios::Clientstatus;
use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
use Log::Log4perl;
use Exporter;
our $VERSION = "0.02";
=head1 Function
Create a program to check the function of some service or device
for Nagios. This module helps you to check the mandatory and
optional arguments. It helps you to send the right output so that
Nagios can check wether the service works ok or not.
=cut
=head1 Synopsis
use Nagios::Clientstatus;
# Arguments to the program are:
# --critical=40 --warning=35 --hostname=server1.zdf --sensor_nr=4
my $version = "0.01";
my $ncli = Nagios::Clientstatus->new(
help_subref => \&help,
version => $version,
mandatory_args => [ "hostname", "sensor_nr", "critical", "warning" ],
);
# ask only one time, because it's expensive
my $temperature = &get_temperature_of_sensor(
hostname => $ncli->get_given_arg('hostname'),
sensor_nr => $ncli->get_given_arg('sensor_nr'),
);
# Message for the user to read
my $msg;
my $status;
# strange case
if ( ( !defined $temperature )
|| ( defined $temperature && $temperature eq "" ) )
{
$status = "unknown";
$msg = "Could not get temperature from sensor";
}
else {
# We got a temperature
# worst case first
if ( $temperature > $ncli->get_given_arg('critical') ) {
$status = "critical";
}
elsif ( $temperature > $ncli->get_given_arg('warning') ) {
$status = "warning";
}
else {
$status = "ok";
}
$msg = sprintf "Temperature is %s degrees Celsius", $temperature;
}
printf "%s - %s", uc($status), $msg;
exit $ncli->exitvalue($status);
sub help {
print "Usage:\n";
print "$0 --critical=40 --warning=35"
. " --hostname=server1.zdf --sensor_nr=4";
# When supplying help you should exit
# 3 is "unknown" to Nagios
exit 3;
}
=cut
=head1 Functions
=cut
=head2 new
Create the object. Immediately check commandline arguments which
are mandatory for every Nagios command.
Call me like this:
my $ncli = Nagios::Clientstatus->new(
help_subref => \&help,
version => $version,
# mandatory_args is optional, maybe you don't need any
mandatory_args => [ "url" ],
);
=cut
sub new {
my ( $class, %args ) = @_;
my $new_object = bless {
help_subref => \&help_example,
version => $args{version},
mandatory_args => [],
given_args => {},
}, $class;
# help_subref
unless ( ( exists $args{help_subref} )
&& ( ref $args{help_subref} eq "CODE" ) )
{
print STDERR
"Missing ref to help-subroutine. This sub could output this:\n";
$new_object->help_example;
my $msg =
sprintf "Mandatory argument help_subref must point"
. " to a help-subroutine, but it is a '%s'",
ref( $args{help_subref} );
die $msg;
}
$new_object->{help_subref} = $args{help_subref};
# are there mandatory arguments?
if ( ( exists $args{mandatory_args} )
&& ( ref $args{mandatory_args} eq "ARRAY" ) )
{
$new_object->_set_mandatory_args( @{ $args{mandatory_args} } );
}
# don't set mandatory args, sometimes it's critical when
# the service does not run -> very simple
# $new_object->_set_mandatory_args( "critical", "warning" );
$new_object->_check_commandline_args;
return $new_object;
}
sub logger {
return Log::Log4perl->get_logger('Nagios.Clientstatus');
}
=head2_set_mandatory_args
Remind arguments which user must supply when calling the program.
Can be called several times.
=cut
sub _set_mandatory_args {
my ( $self, @args ) = @_;
push @{ $self->{mandatory_args} }, @args;
}
=head2 _get_mandatory_args
Which args MUST be given to the programm? Each argument must have a value, too.
=cut
sub _get_mandatory_args {
my $self = shift;
@{ $self->{mandatory_args} };
}
=head2 _set_given_args
Which arguments where given to the program?
=cut
sub _set_given_args {
my ( $self, $name, $value ) = @_;
$self->{given_args}->{name} = $value;
}
=head2 get_given_arg
Object-creator can ask for the value of an argument
given to the program.
=cut
sub get_given_arg {
my ( $self, $name ) = @_;
return exists $self->{given_args}->{$name}
? $self->{given_args}->{$name}
: undef;
}
=head2 _check_commandline_args
There are arguments which must exist when calling a Nagios-checker.
warning|critcal are mandatory, other mandatory were given by new.
=cut
sub _check_commandline_args {
my $self = shift;
my $logger = $self->logger;
my %getopt_long_arg;
my %got_this_option;
# Build up the argument hash for Getopt::Long
my @optional_args = ( "version", "help", "verbose", );
my @mandatory_args = $self->_get_mandatory_args;
# Build the hash for Getopt::Long
foreach (@optional_args) {
# Getopt::Long wants a ref to a scalar where value is stored in
$getopt_long_arg{$_} = $got_this_option{$_};
}
foreach (@mandatory_args) {
# Tell Getopt::Long that there must be an argument
# Getopt::Long wants a ref to a scalar where value is stored in
$getopt_long_arg{"$_=s"} = $got_this_option{$_};
}
# Unusual syntax for daily life in GetOptions
# Look in manpage of Getopt::Long for this:
# Storing option values in a hash
# All given options are stored in hash given as first argument
GetOptions(
\%got_this_option,
# all possible options are here:
%getopt_long_arg,
);
# Now all arguments given to the program are in %got_this_option
# Do mandatory args exist?
my @mand_forgotten;
foreach ( $self->_get_mandatory_args ) {
unless ( exists $got_this_option{$_} ) {
push @mand_forgotten, $_;
}
}
if ( scalar @mand_forgotten > 0 ) {
$logger->debug('%getopt_long_arg was: ');
$logger->debug( Dumper( \%getopt_long_arg ) );
$logger->debug('%got_this_option was: ');
$logger->debug( Dumper( \%got_this_option ) );
printf STDERR "Mandatory arguments not given: %s\n",
join( ", ", @mand_forgotten );
$self->{help_subref}->();
exit;
}
# all arguments where checked, now put them into given_args
$self->{given_args} = \%got_this_option;
}
=head2 exitvalue
Return the value the Nagios-command must return to Nagios.
This is the only value which is important for the Nagios state.
Use it like this:
exit $ncli->exitvalue( $status );
Returnvalue can be a string of these:
OK|WARNING|CRITICAL|UNKNOWN
=cut
sub exitvalue {
my ( $self, $status ) = @_;
$status = uc $status;
my %nagios_returnvalue = (
'OK' => 0,
'WARNING' => 1,
'CRITICAL' => 2,
'UNKNOWN' => 3,
);
unless ( exists $nagios_returnvalue{$status} ) {
die "Wrong status to return, status can only be: " . join ",",
sort keys %nagios_returnvalue;
}
return $nagios_returnvalue{$status};
}
=head2 help_example
Give the user a hint how to use this programm.
=cut
sub help_example {
shift;
print <<"EOUSAGE";
This is $0
Usage:
$0 --warning 60 \\
--critical 130 \\
--your_argument_here_1 xx \\
--your_argument_here_2 xx \\
[--verbose] [--version]
Tell the user what this programm does
EOUSAGE
}
1;
#!/usr/bin/perl
# usually this file is /usr/lib/nagios/plugins_local/$0
use strict;
use warnings;
use Log::Log4perl;
# Nagios calls files from a directory "somewhere"
# so my local perlmodules can not be found
# without defining this additional library:
use lib '/usr/lib/nagios/plugins_local';
use Nagios::Clientstatus;
my $version = "0.01";
# Initialize Logging
my $log_conf = q/
log4perl.category = ERROR, Screen
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
/;
Log::Log4perl::init( \$log_conf );
my $logger = Log::Log4perl::get_logger();
# Arguments to the program are:
# --critical=40 --warning=35 --hostname=server1.zdf --sensor_nr=4
my $ncli = Nagios::Clientstatus->new(
help_subref => \&help,
version => $version,
mandatory_args => [ "critical", "warning", "hostname", "sensor_nr" ],
);
my $temperature = &get_temperature_of_sensor(
hostname => $ncli->get_given_arg('hostname'),
sensor_nr => $ncli->get_given_arg('sensor_nr'),
);
# Message for the user to read
my $msg;
my $status;
# strange case
if ( ( !defined $temperature )
|| ( defined $temperature && $temperature eq "" ) )
{
$status = "unknown";
$msg = "Could not get temperature from sensor";
}
else {
# We got a temperature
# worst case first
if ( $temperature > $ncli->get_given_arg('critical') ) {
$status = "critical";
}
elsif ( $temperature > $ncli->get_given_arg('warning') ) {
$status = "warning";
}
else {
$status = "ok";
}
$msg = sprintf "Temperature is %s degrees Celsius", $temperature;
}
printf "%s - %s", uc($status), $msg;
exit $ncli->exitvalue($status);
sub help {
print "Usage:\n";
print "$0 --critical=40 --warning=35"
. " --hostname=server1.zdf --sensor_nr=4";
# When supplying help you should exit
exit $ncli->exitvalue("unknown");
}
sub get_temperature_of_sensor {
# This is the place where you place the code
# to automatically determine the state of your
# service
print "Input temperature: ";
my $t = ;
chomp $t;
return $t;
}
CRITICAL - Temperature is 43 degrees CelsiusTake the given files here and start it
root@echolon:/some/where# su - nagios nagios@echolon:~$ /usr/lib/nagios/plugins_local/check_temperature_testscript.pl --critical=40 --warning=35 --hostname=server1.zdf --sensor_nr=4 Input temperature: 38 WARNING - Temperature is 38 degrees Celsius
echolon:/etc/nagios# vim resource.cfg ... # Sets $USER1$ to be the path to the plugins $USER1$=/usr/lib/nagios/plugins # my own check-commands live here: $USER2$=/usr/lib/nagios/plugins_local ...There is a special file in Debian/Sarge where I can define my own commands. it' /etc/nagios/checkcommands.cfg:
# checkcommands.cfg - Nagios configuration file for local user changes
#
# Nagios packages wont touch this file anymore. If you want to define
# your own commands for nagios use this file and add the commands here.
# Dont add any command with a name that already exists or nagios wont
# run.
define command{
command_name check_webage
command_line $USER2$/check_webage --url $ARG1$ --warning $ARG2$ --critical $ARG3$
}
In the file services.cfg I did the following.
# Servicetemplate webage
define service {
use generic-service
name webage-service
service_description WEBAGE
is_volatile 0
check_period 24x7
max_check_attempts 3
normal_check_interval 5
retry_check_interval 1
notification_interval 240
notification_period 24x7
notification_options c,r
; not here, define this in service for server itself
; like this:
; check_command check_webage!http://wwwpublish.zdf/pics_bilder_von_zirndorf/cyclop4/current_left_160x120.jpg!70m!130m
; do not register, this is a template only
register 0
}
...
# Server wwwpublish.zdf, Webcam Pindertower
# the check_command will be splitted by "!",
# first part is the command like defined in checkcommands.cfg,
# next parts are $ARG1$, $ARG2$ etc.
define service{
use webage-service
service_description WEBAGE-WWWPUBLISH.ZDF-PINDER
host_name wwwpublish.zdf
check_command check_webage!http://wwwpublish.zdf/pics_bilder_von_zirndorf/cyclop3/current_left_160x120.jpg!70m!130m
}
Back to my Nagios homepage.