#!/usr/bin/perl
#
# Check Lenovo XClarity APIs for errors as "xcl".
# This server script is based on the conn6 server-side check which
# itself is based on a shell script from Debian hobbit-plugins
# 20101207 package, but rewritten in Perl.
#
# Just add "xcl" to the services of a host, enable the plguin via
# /etc/xymon/xymonlaunch.d/xcl.cfg and this script will check the
# XClarity API of the given host for errors.
#
# Copyright (c) 2011 Roland Rosenfeld <roland@spinnaker.de>
# Copyright (c) 2020, 2021  Axel Beckert <abe@debian.org>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

use strict;
use warnings;
use 5.014;

use Mojo::UserAgent;
use Mojo::JSON qw(decode_json);
# Hobbit needs to be loaded after Mojolicious as both fiddle around
# with %SIG.
use Hobbit;
use YAML::Tiny;

# Config
my $proto = 'https://';
my $path  = '/api/providers/imm_active_events';
my @fields = qw(severity misgid cmdid eventid source fru eventflag date message);
my @CONFIG = qw(/etc/xymon/xcl.yaml /etc/xymon/xcl.local.yaml);

# Init
my @ignore_patterns = ();

foreach my $filename (@CONFIG) {
    if ( -f $filename ) {
        my $xcl_cfg = YAML::Tiny->read($filename)->[0];
        foreach my $key (keys %$xcl_cfg) {
            my $value = $xcl_cfg->{$key};
            if ($key eq 'ignore' and ref($value) eq 'ARRAY') {
		@ignore_patterns = @$value
            } elsif ($key ne 'ignore') {
                say "$0: Unsupported YAML key: $key";
            } elsif (ref($value) ne 'ARRAY') {
                say "$0: Unsupported YAML value type of $key: ".ref($value);
	    }
        }
    }
}
my $ignore_pattern = join('|', @ignore_patterns);

#use Data::Dumper;
#say Dumper \@ignore_patterns, $ignore_pattern;

my $ua = Mojo::UserAgent->new(
    connect_timeout => '10',
    insecure => 1,
    max_redirects => 2,
    );

open(HOSTGREP, '-|', "$ENV{XYMONHOME}/bin/xymongrep xcl")
  || die "cannot run $ENV{XYMONHOME}/bin/xymongrep";
while (<HOSTGREP>) {
    if (/^(\d+\.\d+\.\d+\.\d+)\s+(\S+)\s+#\s+(.*)$/) {
        my ($ipv4, $host, $services) = ($1, $2, $3);
	# DEBUG
        #say "Checking $host";
        my $bb = new Hobbit({
            test => 'xcl',
            hostname => $host,
            dont_moan => 1,
            });

        # parse services:
        my $dialup = 0;
        foreach my $service (split /\s+/, $services) {
            if ($service eq 'dialup') {
                $dialup = 1;
            }
        }
	$bb->print(qq{Querying <a href="$proto$host$path">$proto$host$path</a> (expect JSON).\n\n});
        my $transaction = $ua->get("$proto$host$path");
	unless (my $error = $transaction->error) {
	    my $result = $transaction->result;
	    # DEBUG
	    #say("$host: ".$result->code." ".$result->message);

	    if ($result->is_success) {
		$bb->add_color('green');
		my $json = decode_json($result->body);
		my @items = @{$json->{items}};
		
		foreach my $item (@items) {
		    my $color = 'clear';
		    my $ignore = 0;

		    if ($item->{severity} =~ /^[IN]/i) {
			$color = 'green';
		    } elsif ($item->{severity} =~ /^W/i) {
			$color = 'yellow';
		    } elsif ($item->{severity} =~ /^[EC]/i) {
			$color = 'red';
		    }

		    my $ignored_field = '';
		    foreach my $field (@fields) {
			if (defined($item->{$field}) and
			    $item->{$field} =~ /$ignore_pattern/) {
			    $ignore++;
			    $color = 'clear';
			    $ignored_field = $field;
			}
		    }

		    foreach my $field (@fields) {
			next unless defined $item->{$field};
			$bb->print(sprintf('%9s: ', ucfirst($field)));
			$bb->color_line($color,
					($field eq $ignored_field ?
					 '[IGNORED VALUE] ' : '').
					$item->{$field}."\n");
		    }
		    
		    # DEBUG
		    #say("$host: ".$item->{message});
		}
	    } else { # = unless $result->is_success
		$bb->color_line($dialup ? 'clear' : 'red', $result->message);
	    }
	} else { # = if $transaction->error
	    $bb->color_line($dialup ? 'clear' : 'red',
			    $error->{code} ?
			    $error->{code}.": ".$error->{message} :
			    "Connection error: ".$error->{message});
	    # DEBUG
	    #say("$host: ".$error->{message});
	}
        $bb->send();
    }
}
