#!/usr/bin/perl -w

# Version:      0.5
# Date:         Sept 30, 2020
# Author:       ivan.stetka@live.com
# Summary:      This is a Nagios plugin to check html time for RGB, Bodet or Bodet Analog clock

use strict;
use Getopt::Long qw(:config no_ignore_case bundling);
use LWP::UserAgent;
use HTTP::Request::Common;
use Time::Piece;
use POSIX qw(strftime);

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

my %TIMEZONES = (
    "UTC"     => "date -u ",
    "UTC1"    => "date -u -d '+1 hour' ",
    "UTC2"    => "date -u -d '+2 hour' ",
    "CZ"      => "date ",
);

my $uri = undef;
my $timeZone = 'CZ';
my $timeout = 15;
my $crit = 10;
my $warn = 2;
my $labelEquipment = undef;
my $type = undef;
my $unit = 's';
my $version = 0;
my $archive = 0;
my $help = 0;
my $htmlTime;
my $systemTime;
my $zoneText = "";
my $diffSign = undef;
my $diffText = undef;
my $diffInUnit = undef; 

GetOptions(
    'u|uri:s'         => \$uri,
    'w|warning:n'     => \$warn,
    'c|critical:n'    => \$crit,
    'z|timeZone:s'    => \$timeZone,
    't|timeout:n'     => \$timeout,
    'l|labelE:s'      => \$labelEquipment,
    'T|type:s'        => \$type,
    'U|unit:s'        => \$unit,
    'V|version'       => \$version,
    'a|archive'       => \$archive,
    'h|help'          => \$help
);

if ($help) {
    help();
    exit($STATES{OK});
}

if ($version) {
    version();
    exit($STATES{OK});
}

# input control
if (!defined ($TIMEZONES{$timeZone} )) {
    print "Bad format of time zone '$timeZone'.\n";
    usage();
    exit($STATES{UNKNOWN});
}

if (!defined $uri) {
    print "Missing required parameter (uri).\n";
    usage();
    exit($STATES{UNKNOWN});
}

if ($type ne 'RGB' && $type ne 'Bodet' && $type ne 'BodetA') {
    print "Incorrect format of the type '$type' of clock.";
    exit($STATES{UNKNOWN});
}

# opening of the HTTP connection
my $ua = LWP::UserAgent->new();

# timeout control
$SIG{ALRM} = sub {
    print "Warn: Exceeded timeout parameter.\n";
    exit($STATES{UNKNOWN});
};
alarm $timeout;

# timeout URI
my $request = GET ( $uri );

# basic authentication to URI for RGB clock
if ($type eq 'RGB') {
$request->authorization_basic('admin', 'pass');
}

my $resp = $ua->request($request);

my $htmlResponse = undef;

if ($resp->is_success) {
    $htmlResponse .= $resp->content();
} else {
    die "Error getting $uri: ", $resp->status_line
    unless $resp->is_success;
    exit($STATES{UNKNOWN});
}

#composing Bodet time and date from html
if ($type eq 'Bodet') {
my @htmlArrayResponse = split "\n", $htmlResponse;
$htmlResponse = ($htmlArrayResponse[5]) . "&" . ($htmlArrayResponse[4]);
$htmlResponse =~ s/\//./g;
}

if ($type eq 'BodetA') {
my @htmlArrayResponse = split "\n", $htmlResponse;
$htmlResponse = ($htmlArrayResponse[4]) . "&" . ($htmlArrayResponse[3]);
$htmlResponse =~ s/\//./g;
}

# parsing time from html 
if ($htmlResponse =~ /^(\d{2}):(\d{2}):(\d{2})&(\d{2}).(\d{2}).(\d{4})$/) {
    $htmlTime = Time::Piece->strptime($htmlResponse, "%H:%M:%S&%d.%m.%Y");
} else {
    print "Wrong html date format or bad page. \nResponse:\n$htmlResponse\n";
    exit($STATES{UNKNOWN});
}

# retrieving time from the console (Nagios-Linux)
open CH, "$TIMEZONES{$timeZone} '+%F %T' |";
my $consoleTime = <CH>;
close CH;
$consoleTime =~ s/\n//;

# parsing time from the console
if ($consoleTime =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/) {
    $systemTime = Time::Piece->strptime($consoleTime, "%Y-%m-%d %H:%M:%S");
} else {
    print "Wrong System date format\n";
    exit($STATES{UNKNOWN});
}

# calculation of time differences
my $diffInS = $htmlTime - $systemTime;
my $diffInM = (int($diffInS / 60));
my $diffInAbsM = abs($diffInM);
my $diffInAbsH = (int($diffInAbsM / 60));
my $restInAbsM = $diffInAbsM - ($diffInAbsH * 60);
my $restInAbsS = abs($diffInS) - ($diffInAbsM * 60); 

# checking whether the time difference is exactly 1 or 2 hours
if ($diffInAbsM == 60 || $diffInAbsM == 120) {
    $zoneText = ", maybe wrong time zone " . $timeZone;
}

# evaluation of the time difference type
if ($diffInS < 0 ) {
    $diffSign = " delayed";
} elsif ($diffInS > 0 ) {
    $diffSign = " overflowed";
} else {
    $diffSign = " the same";
}

# preparation diff output text
if ($diffInS == 0) {
    $diffText = " as System time.";
} else {  
    $diffText = ". Difference is "
    . sprintf("%02d:%02d:%02d", $diffInAbsH, $restInAbsM, $restInAbsS);
} 

# check the unit of threshold and the performance data
if ($unit eq 'm') {
    $diffInUnit = $diffInM;
} elsif ($unit eq 's') {
    $diffInUnit = $diffInS;
} else {
    print "Wrong threshold unit\n";
    usage();
    print "Check -h (help) for more information.\n";
    exit($STATES{UNKNOWN});
} 

# text output, long text and perf data
my $outputText = $labelEquipment 
    . " time is" . $diffSign . $zoneText . $diffText 
    . "\n$labelEquipment time: $htmlTime"
    . "\nSystem time: $systemTime" 
    . "\nTime zone: $timeZone"
    . "|Difference=$diffInUnit" . $unit . ";" . $warn . ";" . $crit . "\n";

# evaluating states according to thresholds
if (abs($diffInUnit) >= $crit) {
    print "CRITICAL: " . $outputText;
    exit($STATES{CRITICAL});
} elsif (abs($diffInUnit) >= $warn) {
    print "WARNING: " . $outputText;
    exit($STATES{WARNING});
} else {
    print "OK: " . $outputText;
    exit($STATES{OK});
}

die;

# # # SUBROUTINES # # #

# Usage 
sub usage {
    print "Usage: $0 -u <uri> -w <warning> -c <critical> [-z <timeZone>]" 
    . "[-t <timeout>] [-l <labelE>] [-U <unit>]"
    . "\nFor more information, use the -h (help).\n";
}

# Help
sub help {
    print <<HELP;

This is a nagios plugin to check html time for RGB or Bodet clock.

Example RGB Clock ZA20:
perl $0 -u http://10.4.30.10/T0 -w 20 -c 60 -z CZ -t 15 -l "RGB clock ZA20" -U s


-u, --uri           # uri with time data - required value
                    # RGB example"   'http://192.168.0.1/T0'
                    # Bodet example: 'http://192.168.0.2/home.cgi?'
                    # Bodet Analog example: 'http://192.168.0.3//overviewdata.cgi'
-w, --warning       # warning threshold in unit -U [default 1]
-c, --critical      # critical threshold in unit -U [default 5]
-z, --timeZone      # time zone [default CZ]
                    UTC  - Coordinated Universal Time 
                    UTC1 - UTC +1h, CZ winter time, Central European Time
                    UTC2 - UTC +2h, CZ summer time, Central European Summer Time
                    CZ   - respect CZ summer/winter time CET/CEST
-t, --timeout       # Timeout in seconds [default 15]
-l, --labelE        # Equipment label [Equipment]
-T  --type          # Type of clock (RGB, Bodet or BodetA)
-U, --unit          # Threshold and Performance data unit [default s]
                    s - seconds
                    m - minutes
-V, --version       # Print plugin version history
-h, --help          # Print this help
HELP
}

# Version history 
sub version {
    print "\n$0\n";
    print <<VERSION;

Plugin to check time from html page RGB or Bodet clock.

version 0.5 (30.09.2020)
 - add check Bodet Analog clock (type: BodetA)
version 0.4 (22.06.2020)
 - add check Bodet clock
version 0.3 (17.04.2018)
 - code cleanup
version 0.2 (09.03.2018)
 - code cleanup
version 0.1 (05.02.2018)
 - new plugin to check check time for RGB Clock from html page based on plugin check_snmp_lastwritetime.pl
VERSION
}