#!/usr/local/bin/perl
#
# Check an m4000/m5000 xscf service processor
#
# $Header: /home/doke/work/nagios/RCS/check_xscf,v 1.8 2016/02/02 23:35:36 doke Exp $



use strict;
use warnings;
use Getopt::Long;
use Expect;

use vars qw( $user $pwfile $timeout $host $verbose $help @crits @warns
    @unknowns @ignores @oks $rc $sep );

$user = 'admin';
#$pwfile = '/home/its-a-trap.nss/usra/acnt/t3_root.pw';
$pwfile = '/opt/local/nagios/etc/t3_root.pw';
$timeout = 10;


$host = '';
$verbose = 0;
$help = 0;


sub usage {
    my( $rc ) = @_;
    print "Usage: $0 [-vh] -H <host> -p <pwfile>
    -H s  hostname
    -u s  username on xscf [$user]
    -p s  password file [$pwfile]
    -v    verbose
    -h    help
";
    exit $rc;
    }

Getopt::Long::Configure ("bundling");
GetOptions(
    'H=s' => \$host,
    'u=s' => \$user,
    'p=s' => \$pwfile,
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );

&usage( 0 ) if ( ! $host );

&check();

$rc = 0;
$sep = '';
if ( $#crits >= 0 ) {
    $rc = 2;
    print "CRITICAL ", join( ", ", @crits );
    $sep = '; ';
    }
if ( $#warns >= 0 ) {
    $rc = 1 if ( $rc == 0 );
    print $sep, "Warning ", join( ", ", @warns );
    $sep = '; ';
    }
if ( $#unknowns >= 0 ) {
    $rc = -1 if ( $rc == 0 );
    print $sep, "Unknown ", join( ", ", @unknowns );
    $sep = '; ';
    }
if ( $rc == 0 || $verbose ) {
    print "Ok ", join( ", ", @oks );
    $sep = '; ';
    }
if ( $#ignores >= 0 ) {
    print $sep, "Ignoring ", join( ", ", @ignores );
    $sep = '; ';
    }
print "\n";
exit $rc;


##################


sub check {
    my( $pw, $cmd, $exp, $saw_pw_prompt, $line, $got_prompt, $got_version,
	$failed );

    if ( ! open( fH, $pwfile ) ) {
	push @unknowns, "can't open pwfile, $!";
	return;
	}
    $pw = <fH>;
    close fH;
    chomp $pw;

    $cmd = "/usr/local/bin/timeout -t 60 -- "
	. " /usr/local/bin/ssh -4akx -enone"
        . " -o StrictHostKeyChecking=no"
        . " -o BatchMode=no"
        . " -o ConnectTimeout=30"
        . " -o ServerAliveInterval=15"
	. " $user\@$host";
    $verbose && print "cmd $cmd\n";

    if ( ! $verbose )  {
	# supposedly you can do $exp->log_stdout(0), but it doesn't work.
	$Expect::Log_Stdout = 0;
	}

    $exp = new Expect;
    $exp->raw_pty(1);
    unless ( $exp->spawn( $cmd ) ) {
        push @unknowns, "can't spawn ssh";
        }
    if ( $verbose > 1 ) {
        $exp->exp_internal(1);
        $exp->debug(1);
        }

    $failed = 0;
    $saw_pw_prompt = 0;
    $exp->expect( $timeout,
        [ qr/assword:/i, sub {
	    $saw_pw_prompt = 1;
	    } ],
	[ qr/permission.denied|could not resolve hostname [\w\d\.-]+/i, sub {
	    push @unknowns, $exp->match();
	    } ],
	);
    if ( $failed ) {
	$exp->hard_close();
	return;
	}
    if ( ! $saw_pw_prompt ) {
	push @crits, "didn't see password prompt";
	$exp->hard_close();
	ping_host( $host );
	return;
	}

    $exp->clear_accum();
    $exp->send( $pw . "\r" );

    $failed = 0;
    $got_prompt = 0;
    $exp->expect( $timeout,
        [ qr/Password:/i, sub {
	    push @crits, "password rejected";
	    $failed = 1;
	    } ],
        [ qr/permission denied:/i, sub {
	    push @crits, "permission denied";
	    $failed = 1;
	    } ],
        [ qr/XSCF>/i, sub {
	    $got_prompt = 1;
	    } ],
	);
    if ( $failed ) {
	$exp->hard_close();
	return;
	}
    if ( ! $got_prompt ) {
	push @crits, "didn't get xscf cli prompt";
	$exp->hard_close();
	return;
	}

    $exp->clear_accum();
    $exp->send( "version -c xscf\r" );

    # XSCF> version -c xscf
    # XSCF#0 (Active )
    # 01.09.0003(Reserve) 01.09.0003(Current)
    # or
    # 01.09.0003(Current) 01.09.0003(Reserve)

    $got_version = 0;
    $got_prompt = 0;
    $exp->expect( $timeout,
        [ qr/^XSCF#\d+/i, sub {
	    exp_continue;
	    } ],
        [ qr/([\d\.]+)\(Current\)/i, sub {
	    push @oks, "xscf version " . ($exp->matchlist)[0];
	    $got_version = 1;
	    exp_continue;
	    } ],
        [ qr/XSCF>/i, sub {
	    $got_prompt = 1;
	    } ],
	);
    if ( ! $got_version ) {
	push @crits, "didn't get xscf version";
	$exp->hard_close();
	return;
	}
    if ( ! $got_prompt ) {
	push @crits, "didn't get xscf cli prompt after version -c xscf";
	$exp->hard_close();
	return;
	}

    $exp->clear_accum();
    $exp->send( "showstatus\r" );

    # this may not produce any output
    # or
    # No failures found in System Initialization.

    $got_prompt = 0;
    $exp->expect( $timeout,
        [ qr/^[^\n]*\n/i, sub {
	    $line = $exp->match();
	    $line =~ s/\r//g;
	    if ( $line =~ m/^\s*\*\s*(\S.*)/ ) {
		push @crits, $1;
		}
	    elsif ( $line =~ m/(No failures found in System Initialization)/i ){
		push @oks, $1;
		}
	    exp_continue;
	    } ],
        [ qr/XSCF>/i, sub {
	    $got_prompt = 1;
	    } ],
	);
    if ( ! $got_prompt ) {
	push @crits, "didn't get xscf cli prompt after showstatus";
	$exp->hard_close();
	return;
	}

    $exp->send( "exit\r" );

    $exp->hard_close();
    }



sub ping_host {
    my( $host ) = @_;
    my( $cmd, $pingout, $rc );

    $rc = 1;
    $cmd = "ping $host 1 2>&1 |";
    $verbose && print "+ $cmd\n";
    $pingout = '';
    if ( open( pH, $cmd ) ) {
	while ( <pH> ) {
	    $verbose && print ">$_";
	    chomp;
	    $pingout .= $_ . ', ';
	    }
	close pH;
	$rc = $? >> 8;
	$pingout =~ s/, $//;
	}
    if ( $rc ) {
	$pingout =~ s/, $//;
	push @crits, "ping failed: $pingout";
	}
    else {
	push @unknowns, "ping worked, snmp may not be configured\n";
	}
    return $rc;
    }



