Home

Search this site:
 

Horshack’s
very
own site

 

This is Bavaria, Germany!
You will find links to Perl,
bootdisks for system administration,
a lot of Linux,
Windows administration
and some personal belongings.
Writing an own Service with Nagios

Writing an own Service with Nagios

The programm itself

A service which shall be called by Nagios must be an executable which returns a status code:

status-codemeaning
0OK
1WARNING
2CRITICAL
3UNKNOWN
The output of the programm is not important for Nagios, but it's good practice to output some information like this:
WEBAGE OK - URL http://.../picture.jpg is 43 min old
I had the problem to check the freshness of a webpicture loaded onto the webserver, so I wrote the programm /usr/lib/nagios/plugins_local/check_webage
#!/usr/bin/perl
# File: /usr/lib/nagios/plugins_local/check_webage
use strict;
use warnings;
use LWP::Simple;
use Log::Log4perl;
use Getopt::Long;
use LWP::UserAgent;
use HTTP::Date;

my $prg_version = "0.10";

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();
$logger->info("This is $0 V$prg_version");

# These parameter must be given
my $warning  = "";
my $critical = "";
my $url      = "";

# These parameter could be given
my $version = "";
my $help    = "";
my $verbose = "";

GetOptions(
    'warning=s', \$warning, 'critical=s', \$critical,
    'url=s',     \$url,     'version',    \$version,
    'help',      \$help,    'verbose',    \$verbose,
);

my %nagios_returnvalue = (
    'OK'       => 0,
    'WARNING'  => 1,
    'CRITICAL' => 2,
    'UNKNOWN'  => 3,
);

&help if $help || $version;
&help unless $warning;
&help unless $critical;
&help unless $url;
$logger->level($Log::Log4perl::DEBUG) if $verbose;

$logger->debug( sprintf( "%s = %s", "url",                        $url ) );
$logger->debug( sprintf( "%s = %s", "Borderminutes for warning",  $warning ) );
$logger->debug( sprintf( "%s = %s", "Borderminutes for critical", $critical ) );

my $modified_minutes = &get_age_of_url_in_minutes($url);

my $max_age_min;
my $status = "OK";

# Reached warning-age?
$max_age_min = $warning;
$max_age_min =~ s/m$//;
if ( $modified_minutes > $max_age_min ) {
    $status = "WARNING";
}

# Worse, reached critical-time?
$max_age_min = $critical;
$max_age_min =~ s/m$//;
if ( $modified_minutes > $max_age_min ) {
    $status = "CRITICAL";
}

# Even worse, a crazy number?
if ( $modified_minutes < 0 ) {
    $status = "UNKNOWN";
}

# create Output for Nagios
my $msg = sprintf "url_age %s - age is %d min for %s", $status,
  $modified_minutes, $url;
$logger->info("Statusmessage is: $msg");
print "$msg\n";

# this is the important thing for nagios!
exit $nagios_returnvalue{$status};

sub get_age_of_url_in_minutes {
    my $url = shift;

    # I got a lot of trouble here. There seem to be problems
    # with GMT, localtime. So I simply check the time _now_
    # at the webserver (header "date") and the last_modified
    # from the header (header "last_modified"). These are
    # both in the same timezone
    # Fetch head-infos, not the whole file, with LWP::Simple
    my $ua       = LWP::UserAgent->new;
    my $request  = HTTP::Request->new( 'HEAD', $url );
    my $response = $ua->request($request);
    $logger->debug( "Date from Webserver now: " . $response->header('date') );
    $logger->debug(
        "Modificationdate of doc: " . $response->header('last_modified') );
    $logger->debug( "Date from Webserver now (epoch): "
          . str2time( $response->header('date') ) );
    $logger->debug( "Modificationdate of doc (epoch): "
          . str2time( $response->header('last_modified') ) );

    # convert ascii-date "Tue, 27 Dec 2005 15:30:10 GMT" to epoch
    my $modified_minutes =
      str2time( $response->header('date') ) -
      str2time( $response->header('last_modified') );
    $modified_minutes = int( $modified_minutes / 60 );

    $logger->info("File was modified $modified_minutes minutes ago");
    return $modified_minutes;
}

sub help {
    print <<"EOUSAGE";
Hier ist $0 V$prg_version

Aufruf:

$0 --warning 60m --critical 130m --url http://www.zirndorf.de/bild/1.jpg [--verbose] [--version]

Output for nagios. How old is a file on a webserver?
EOUSAGE
    $logger->info("exit nach help");
    exit;
}

You could call the program like this to get help:
echolon:~# /usr/lib/nagios/plugins_local/check_webage --help

This is /usr/lib/nagios/plugins_local/check_webage V0.03

Usage:

/usr/lib/nagios/plugins_local/check_webage --warning 60m --critical 130m --url http://www.zirndorf.de/bild/1.jpg [--verbose] [--version]

Output for nagios. How old is a file on a webserver?
and like this in action:
echolon:~# /usr/lib/nagios/plugins_local/check_webage --warning 60m --critical 130m --url http://wwwpublish.zdf/pics_bilder_von_zirndorf/cyclop4/current_left_160x120.jpg
WEBAGE OK - age is 43 min for http://wwwpublish.zdf/pics_bilder_von_zirndorf/cyclop4/current_left_160x120.jpg

Implementing command into Nagios

Ok, the command works. Now I have to implement it into Nagios. Because all my "local" command not installed by the package-manager shall be in /usr/lib/nagios/plugins_local I define a $USER2$ variable for this path:
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.
Impressum