#!/usr/bin/perl

# This script is intended to be used to check the local clock against
# multiple NTP servers.
###############################################################################
# sgichk_ntp.pl -- SGI custom Nagios plugin to check local clock against
#    multiple NTP servers
#
# History:
#   20090120	Created plugin. Brent Bice (bbice@sgi.com)
#   20100318	Updated to be able to use sntp (bbice@sgi.com)
###############################################################################

use strict;
use warnings;

# Core modules
use Getopt::Long;
use Pod::Usage;

# SGI specific modules
use lib "/usr/local/nagios/libexec";
use lib "/usr/local/nagios/nrpe/libexec";
use lib "/usr/local/nagios/common-files/libexec";
use SgiPlugs;

#####
# Secure thyself
####
# Remove ENV vars that shells will use
delete @ENV{qw(IFS CDPATH ENV BASH_ENV PATH)};

# General vars
my $progname = 'sgichk_unix_postfixq.pl';
my %rcs_info = ('SOURCE' => '$Source: /source/Development/SGI-Plugins/RCS/sgichk_ntp.pl,v $',
                'NAME' => '$Name:  $',
                'REVISION' => '$Revision: 1.5 $',
                'DATE' => '$Date: 2012/11/14 18:20:04 $');

#####
# Get the command line arguments
####
my $help = 0;
my $Hostlist = "ntpmaster0.sgi.com ntpmaster1.emea.sgi.com";
my $o_version = undef;
my $timeout = $SgiPlugs::TIMEOUT;
my $verbose = 0;
my $postfixqcmd;
my $warning;
my $critical;
my $sntp = 1;   # we're using the new sntp
my $ntpdate = "/usr/sbin/sntp";
   if (! stat $ntpdate) {
      $ntpdate = "/usr/sbin/ntpdate";
      $sntp = 0;
      if (! stat $ntpdate) {
         $ntpdate = "/usr/freeware/bin/ntpdate";
      }
   }

# Configure Getopt::Long to be case-sensitive and not use abbreviated option names.
Getopt::Long::Configure('no_ignore_case', 'no_auto_abbrev');

my $arg_count = scalar(@ARGV);

# Parse the command line
GetOptions('help|h' => \$help,
		'host|H=s' => \$Hostlist,
                'version|V' => \$o_version,
                'timeout|t=i' => \$timeout,
                'verbose|v' => \$verbose,
                'warning|w=i' => \$warning,
                'critical|c=i' => \$critical
           ) or &SgiPlugs::print_syntax_error("Use option --help for help");
# No more options on the command line
&SgiPlugs::print_syntax_error("Use option --help for help") if ($ARGV[0]);


# Print help if asked to
if ($help) {
    pod2usage(-exitstatus => $SgiPlugs::ERRORS{'UNKNOWN'}, -verbose => 2) ;
}

# Print version if asked to
if ($o_version) {
    &SgiPlugs::print_revision($rcs_info{'REVISION'}) ;
}

# Check for the thresholds
&SgiPlugs::exit_unknown( "Option -w is required. Please use option -h for help" ) unless (defined $warning);
&SgiPlugs::exit_unknown( "Option -c is required. Please use option -h for help" ) unless (defined $critical);
&SgiPlugs::exit_unknown( "Warning threshold should be non-negative" ) if ($warning < 0);
&SgiPlugs::exit_unknown( "Critical threshold should be non-negative" ) if ($critical < 0);
&SgiPlugs::exit_unknown("Warning threshold is greater than Critical threshold") if ($warning > $critical);

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
    &SgiPlugs::exit_unknown("Plugin timeout");
};
alarm($timeout);

my $host = "";
my $offset = 0;
my $stratum = 0;
my $avgoffset = 0;
my $numservers = 0;
my $sign = "+1.0";

if ($sntp == 1) {   # Are we using sntp or ntpdate?
   #my @bobo = split(/ +/,$Hostlist);
   foreach (split(/ +/,$Hostlist)) {
      $host = $_;
      open NTPDATE, "$ntpdate -c 1 -E 2 -d 3 $host 2>/dev/null |"  || die ("Couldn't run $ntpdate");
      while (<NTPDATE>) {
         if (/[0-9]+ ([^ ]) ([^ ]+) \+\//) {
            $sign = "$1" . "1.0";
            $offset = $2 * $sign * 1000;
            $avgoffset += $offset;
            $numservers++;
            print "Host: $host Offset:$offset\n" if ($verbose);
         }
      }
      close NTPDATE;
   }
} else {
   open NTPDATE, "$ntpdate -t 1 -q $Hostlist 2>/dev/null |"   || die ("Couldn't run $ntpdate");
   while (<NTPDATE>) {
      if (/server ([^,]+), stratum (\d+), offset ([^,]+), /) {
         $host = $1;
         $stratum = $2;
         $offset = abs($3) * 1000;   # convert to ms
         if ($stratum > 0) {   # it's an "up" server
            $avgoffset += $offset;
            $numservers++;
            print "Host: $host Stratum:$stratum Offset:$offset\n" if ($verbose);
         } else {
            print ("Ignoring stratum $stratum server $host\n") if ($verbose);
         }
      }
   }
   close NTPDATE;
}

# Did we at least find one server?
if ($numservers > 0) {
   $avgoffset = $avgoffset / $numservers;
} else {
   print "WARNING: couldn't reach any ntp servers specified\n";
   exit(1);
}

if ($avgoffset > $critical) {
   print "CRITICAL: average clock offset is $avgoffset ms\n";
   exit (2);
} elsif ($avgoffset > $warning) {
   print "WARNING: average clock offset is $avgoffset ms\n";
   exit (1);
} else {
   print "OK: clock average offset is $avgoffset ms\n";
   exit (0);
}

__END__

=head1 Name

sgichk_ntp.pl -- SGI Nagios plugin to check local clock against multiple
ntp servers

=head1 Description

This plugin checks the local system clock against multiple ntp servers.

=head1 Usage

sgichk_ntp.pl -h

sgichk_ntp.pl -V

sgichk_ntp.pl [-t <timeout interval>] [-v] -w <warning> -c <critical> [-H "ntp1 ntp2 ntp3 ...]"

=head1 Options

=over 2

=item -h, --help

Prints this help

=item -V, --version

Prints the version of the plugin

=item -t, --timeout=INTEGER

Timeout after specified interval (seconds). The default is 15.

=item -v, --verbose

Run verbose. Only for debugging. Do not use this for Nagios.

=item -w, --warning=INTEGER

Warning threshold in ms. This is a rquired option.

Warning threshold should not be greater than the critical threshold.

=item -c, --critical=INTEGER

Critical threshold in ms. This is a rquired option.

=back

=head1 Notes

*

=head1 Pre-requisites

This plugin requires the following modules:

=over 2

=item

=back

=head1 Authors

=over 2

=item Brent Bice (bbice@sgi.com)

=item

=back


=head1 Revision

$Id: sgichk_ntp.pl,v 1.5 2012/11/14 18:20:04 root Exp $

=cut


