#!/usr/bin/perl
# nagios: -epn
#
# $Id: check_wview 251 2012-04-30 20:13:27Z mwall $
# check_wview - nagios plugin to monitor wview weather station
#   by Matthew Wall
#
# Copyright (c) 2011 Matthew Wall, all rights reserved
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
#
# This plugin checks either the database or html index file to see whether
# wview is doing what it is supposed to do.  Warning or critical is indicated
# if the last update is greater than the warning or critical threshold,
# respectively.
#
# Report weather data as performance data, but only if DBI is installed.
#
# Note that the default update interval for wview is 60 seconds and the default
# Nagios check interval is 300 seconds (5 minutes).
#
# Examples
#
# check for database updates and emit performance data, warn if over 10 minutes
#   check_wview -w 10 -c 20
#
# ensure that wviewhtmlgend is generating a new index file
#   check_wview --file /var/wview/img/index.htm
#
# check for database updates but do not emit performance data
#   check_wview --file /var/wview/archive/wview-archive.sdb --no-weather-data
#
# Revision History
#   0.3
#    * do not run in epn - epn has issues with dbi
#    * run cleanly with perl -w
#   0.2 19nov11
#    * check the database for changes rather than the html file
#    * query the database for performance data, but only if DBI is installed
#   0.1 16nov11
#    * initial release
#
# Prerequisites
#   DBI::sqlite is required for performance data
#   wview weather data collection system
#
# to install DBI:sqlite on debian:
#   apt-get install libdb-sqlite3-perl

use strict;
use POSIX qw(strftime);

my $STATE_OK = 0;
my $STATE_WARN = 1;
my $STATE_CRIT = 2;
my $STATE_UNKNOWN = 3;
my $state = $STATE_UNKNOWN;
my @STATESTR = ( 'OK', 'WARN', 'CRITICAL', 'UNKNOWN' );

my $PROG = 'check_wview';

my $htfile = '/var/wview/img/index.html';
my $dbfile = '/var/wview/archive/wview-archive.sdb';

# location of the file we want to check.  to ensure that wview is putting data
# into the database, check the sqlite file.  to ensure that wview is generating
# html pages, check the html index page.
my $chkfn = $dbfile;

# should we emit weather observations as performance data?
my $emitwdata = 1;

# minutes without update until we warn
my $mwarn = 30;

# minutes without update until we go critical
my $mcrit = 120;

# these are the elements that should not be recorded as performance data
my %excludes = ('dateTime', 1, 'usUnits', 1, 'interval', 1);

while($ARGV[0]) {
    my $arg = shift;
    if ($arg eq '--file') {
        $chkfn = shift;
    } elsif ($arg eq '-w') {
        $mwarn = shift;
    } elsif ($arg eq '-c') {
        $mcrit = shift;
    } elsif ($arg eq '--no-weather-data') {
        $emitwdata = 0;
    } elsif ($arg ne q()) {
        if ($arg ne '--help') {
            print "unknown argument '$arg'\n";
        }
        print "usage: $PROG [options]\n";
        print "options include:\n";
        print "  --help\n";
        print "  --file filename          $chkfn\n";
        print "  --no-weather-data\n";
        print "  -w minutes               $mwarn\n";
        print "  -c minutes               $mcrit\n";
        exit $state;
    }
}

if ($mwarn > $mcrit) {
    print "$STATESTR[$state] - warn threshold must be less than critical threshold\n";
    exit $state;
}

my $msg = q();
my $perfdata = q();
my $now = time;
my @s = stat($chkfn);
if (@s) {
    my $deltaS = $now - $s[9];
    my $deltaM = $deltaS / 60;
    my $mstr = q();
    if ($deltaS > 60) {
        $mstr = sprintf("%.0f minutes", $deltaM);
    } else {
        $mstr = sprintf("%.2f seconds", $deltaS);
    }
    my $dstr = strftime "%H:%M:%S %d %b %Y", localtime $s[9];
    $msg = "last update was $mstr ago at $dstr";
    $perfdata .= " lastupdate=$deltaM;$mwarn;$mcrit";

    if ($deltaM > $mcrit) {
        $state = $STATE_CRIT;
    } elsif ($deltaM > $mwarn) {
        $state = $STATE_WARN;
    } else {
        $state = $STATE_OK;
        if ($emitwdata) {
            my $rval = eval { require DBI; };
            if (defined $rval && $rval == 1) {
                my $dbh = DBI->connect("dbi:SQLite:$dbfile", "", "",
                                       {RaiseError => 1, AutoCommit => 0});
                if ($dbh) {
                    # query for the last record, using latest dateTime value
                    my $sth = $dbh->prepare("select * from archive where dateTime = (select max(dateTime) from archive)");
                    $sth->execute;
                    my $row = $sth->fetchrow_hashref();
                    if ($row) {
                        foreach my $field (keys %$row) {
                            # only report data if not excluded and not null
                            if (! $excludes{$field} && $row->{$field} ne q()) {
                                $perfdata .= " $field=$row->{$field}";
                            }
                        }
                    } else {
                        $state = $STATE_WARN;
                        $msg .= ' - database query returned no records';
                    }
                    $sth->finish;
                    $dbh->disconnect;
                } else {
                    $state = $STATE_WARN;
                    $msg .= ' - database connection failed';
                }
            } else {
                $state = $STATE_WARN;
                $msg .= ' - perfdata requested but DBI is not installed';
            }
        }
    }
} else {
    $msg = "cannot determine state of $chkfn";
}

print "$STATESTR[$state] - $msg";
print "|$perfdata" if $perfdata ne q();
print "\n";

exit $state;
