#!/usr/bin/perl -w
# -----------------------------------------------
# nagios: +epn

=head1 NAME

check_sap.pl - Nagios Plugin for checking SAP installations based on sapinfo from RFCSDK

=head1 SYNOPSIS

 check_sap.pl --ashost=<conn> --sap-sysnr=<sysnr> [options]
 check_sap.pl --mshost=<conn> --sap-id=<SID> [--group=<group>] [options]
 check_sap.pl [-h|-V]

Calls sapinfo (from RFCSDK, see Section RFCSDK AND SAPINFO) to connect 
to a SAP application or message server and returns some state info.

=head1 OPTIONS

=over 4

=item --ashost=<connect-string>

testing a SAP application server. See CONNECT STRINGS below for more
information on connect strings.

=item --mshost=<connect-string>

testing a SAP message server. See CONNECT STRINGS below for more
information on connect strings.

=item --sap-id=<SID>

SAP-ID (SID) of your System. To use in combination with --mshost

=item --sap-sysnr=<sysnr>

SAP system number. The first system number of each SAP-ID is '00'
(default). Use it in combination with --ashost.

=item --group=<logongroup>

Logon group (case sensitive) to estimate a SAP system for login. 
Only works with --mshost (default: PUBLIC).

=item --sapinfo=<sapinfo executable>

specify an alternate program. Default is /usr/local/sap/rfcsdk/bin/sapinfo.

=item -v|--verbose

increases verbosity, specify twice to see the original output from sapinfo.

=item -V|--version

print version an exit

=item -h|--help

print help message and exit

=head1 RFCSDK AND SAPINFO

This plugin uses the program sapinfo from the SAP RFCSDK. You can obtain
the RFCSDK from http://service.sap.com/swdc (protected area, you need an
account, please ask your SAP system administrators). SAP has released at
least two notes for getting and installing the RFCSDK: note 413708 and
27517. To extract the archive (SAPCAR format) you geht, you need the
program SAPCAR.EXE from the same location. Call it without parameters to
get an small help. Hint:  SAPCAR.EXE works very similar to tar.

=head1 CONNECT STRINGS

A connect string may be a host name, an ip address, or something like
/H/saprouter/S/port/H/sapserver, where /H/ means a host (name or ip), and
/S/ means the port of a message server (default is 3299). You can also
write something like /H/saprouter/H/sapserver.

=cut

# -----------------------------------------------

use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../perl/lib";

use Getopt::Long qw(:config no_ignore_case bundling);
use Pod::Usage;
use Nagios::Plugin 0.14 qw(%ERRORS);

# -----------------------------------------------
# global vars
# -----------------------------------------------

use vars qw ($plugin $sapinfocmd);

my $TIMEOUT = 10.0;
   $plugin = Nagios::Plugin->new( shortname => "CHECKSAP" );
my $command = '';
my $OUTPUT; my @OUTPUT;
my $result;
 
my $nagios_plugin_version = $Nagios::Plugin::VERSION;

# -----------------------------------------------
# Command line Parameters
# -----------------------------------------------

# -- Vars

my $ashost	= '';	# application server
my $mshost	= '';	# message server
my $sapsid	= '';	# SAP System ID (SID)
my $sapsysnr	= '00'; # SAP System Number
my $logongroup  = 'PUBLIC'; # Logon Group
   $sapinfocmd  = '/usr/local/sap/rfcsdk/bin/sapinfo'; # sapinfo executable

my $verbose    	= 0;	#
my $help	= 0;	# 
my $printversion = 0;	#

# -- -- -- -- -- -- -- -- 
my $version	= '$Revision: 1.8 $ / $Date: 2008-01-19 16:59:42 $ / wob';
# -- -- -- -- -- -- -- --

# -- GetOpt

GetOptions(
   "ashost=s"		=> \$ashost,
   "mshost=s"		=> \$mshost,
   "sap-id=s"		=> \$sapsid,
   "sap-sysnr=s"	=> \$sapsysnr,
   "group=s"		=> \$logongroup,
   "sapinfocmd=s"	=> \$sapinfocmd,
   "h|help"		=> \$help,
   "V|version"		=> \$printversion,
   "v|verbose+"		=> \$verbose,

   ) or pod2usage({ -exitval => $ERRORS{'UNKNOWN'},
   		    -verbose => 1,
   	            -msg     => "\n *** unknown argument found ***" });

# -- help message
pod2usage(-verbose => 2,
	  -exitval => $ERRORS{'UNKNOWN'} ,
	  -output  => \*STDOUT, 
	 ) if ( $help );

# -- version

pod2usage(-msg      => "\n$0 -- version: $version\n",
          -verbose  => 99,
	  -sections => "NAME|LICENSE",
	  -output   => \*STDOUT,
	  -exitval  => $ERRORS{'UNKNOWN'} ,
	 ) if ( $printversion );

# -- no host specified
if (("$ashost" ne "" && "$mshost" ne "") ||
     ("$ashost" eq "" && "$mshost" eq "")) {
   # -- no host or two hosts
   pod2usage(-msg     => "\n*** please specify ashost *or* mshost ***\n",
             -verbose => 1,
	     -exitval => $ERRORS{'UNKNOWN'});
}

# -- mshost
if ("$mshost" ne "" && "$sapsid" eq "") {
   # -- mshost needs sapsid
   pod2usage(-msg     => "\n*** mshost needs sap-id, but sap-id not specified ***\n",
             -verbose => 1,
	     -exitval => $ERRORS{'UNKNOWN'});
}

# -- sapinfocmd
if (! -x $sapinfocmd) {
   # -- not executable or does not exist
   pod2usage(-msg     => "\n*** program $sapinfocmd not found, please check your installation ***\n",
             -verbose => 0,
	     -exitval => $ERRORS{'UNKNOWN'});
}

# -- checking for old, buggy version
if ( $verbose ) {
   if ($nagios_plugin_version < 0.14) {
      print "WARNING: Your Nagios::Plugin Version $nagios_plugin_version is buggy,";
      print " please upgrade\n";
   } else {
      print "DEBUG Nagios::Plugin Version: $nagios_plugin_version\n";
   }
}

# -----------------------------------------------
# starting
# -----------------------------------------------

if ( "$ashost" ne "" ) {
   $command = "$sapinfocmd ashost=$ashost sysnr=$sapsysnr";
} elsif ( "$mshost" ne "" ) {
   $command = "$sapinfocmd mshost=$mshost r3name=$sapsid group=$logongroup";
} else {
   # -- should not occur
   $plugin->nagios_exit($ERRORS{UNKNOWN}, "program failure, please contact the author" );
}

print "DEBUG Command=$command\n" if ($verbose);

open( CHECK, "$command |" ) 
   or $plugin->nagios_exit($ERRORS{UNKNOWN}, "Could not execute $sapinfocmd" );


@OUTPUT = <CHECK>;
close ( CHECK );
$result = $? >> 8;

$OUTPUT = join " ", @OUTPUT;
print "$OUTPUT\n" if ($verbose > 1);
print "DEBUG Returncode=$result\n" if ($verbose);
print "DEBUG Errorcodes: $ERRORS{OK}, $ERRORS{WARNING}, $ERRORS{CRITICAL}, $ERRORS{UNKNOWN}\n" if ($verbose > 1);

# -- check if returned SAP System ID = $sapsid
if ( "$sapsid" ne "" ) {
   $OUTPUT =~ m/.*System ID\s+(\w+)/;
   my $found_sid = $1;
   if ( defined($found_sid) && ("$sapsid" eq "$found_sid") ) {
      print "DEBUG SID found : /$found_sid/\n" if ($verbose);
   } 
   else {
      $plugin->nagios_exit( $ERRORS{CRITICAL}, "returned SID $found_sid does not match given SID $sapsid"
       );
   }

}


SWITCH: {
   if ( $result == 0 ) { 
      $OUTPUT =~ m/.*Destination\s+(\w+)/;
      my $destination = $1;
      $plugin->nagios_exit($ERRORS{OK}, "system $destination available" );
      last SWITCH;

   }
   if ( $result == 1 ) { 
      my $version = &get_sapinfo_version();
      print "DEBUG sapinfo version: /$version/\n" if ($verbose);
      
      if ( $version =~ m/46C/ ) {
         # -- old version, return codes 0|1
	 $OUTPUT =~ m/.*Message\s+([^\n]+)\s*\n/;
	 my $message = $1;
	 $OUTPUT =~ m/.*ERROR\s+([^\n]+)\s*\n/;
	 my $error = $1;
	 $OUTPUT =~ m/.*Connect_PM\s+([^\n]+)\s*\n/;
	 my $connect_pm = $1;
	 $plugin->nagios_exit($ERRORS{CRITICAL}, "$message: $error ($connect_pm)" );
      } else {
         # -- may be plugin program failure
         $plugin->nagios_exit($ERRORS{UNKNOWN}, "plugin program failure, please contact the author" );
      }
      last SWITCH;
   }
   if ( $result == 2 ) { 
      $OUTPUT =~ m/.*Message\s+([^\n]+)\s*\n/;
      my $message = $1;
      $OUTPUT =~ m/.*ERROR\s+([^\n]+)\s*\n/;
      my $error = $1;
      $OUTPUT =~ m/.*Connect_PM\s+([^\n]+)\s*\n/;
      my $connect_pm = $1;
      $plugin->nagios_exit($ERRORS{CRITICAL}, "$message: $error ($connect_pm)" );
      last SWITCH;
   }
   if ( $result == 3 ) { 
      $plugin->nagios_exit($ERRORS{CRITICAL},"system not reachable, timed out" );
      last SWITCH;
   }
   if ( $result == 4 ) { 
      $plugin->nagios_exit($ERRORS{UNKNOWN},
             "login problem with sapinfo, check codepage and login account" );
      last SWITCH;
   }
}

# ---
sub get_sapinfo_version {
# ---
   my $version = '';

   open( SAPINFOVER, "$sapinfocmd -v |" ) 
      or $plugin->nagios_exit($ERRORS{UNKNOWN}, "Could not execute $sapinfocmd" );

   while (<SAPINFOVER>){
      if ( /This RFC library .* Release \*\*\*\s+([^\s]+)/ ) {
         $version = $1;
	 last;
      }
   }
   close(SAPINFOVER);
   return $version;
}

# ===============================================

=head1 AUTHOR

wob (at) swobspace (dot) net

=head1 KNOWN ISSUES

may be

=head1 BUGS

may be

=head1 LICENSE

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 (and no
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

=head1 HISTORY
 
$Log: check_sap.pl,v $
Revision 1.8  2008-01-19 16:59:42  wob
Path to Nagios::Plugin with Find::Bin as Ton Voon recommended

Revision 1.7  2008-01-07 20:26:10  wob
check, if SAP ID returned matches given SAP ID in --mshost mode

Revision 1.6  2008-01-07 19:07:34  wob
Version 2007-xx with ePN support

Revision 1.5  2006/11/05 16:51:49  wob
- Upgrade to Nagios::Plugin 0.14
  > changing from ->die to ->nagios_exit
  > removing workaround for previous versions of Nagios::Plugin

Revision 1.4  2006/10/14 08:38:18  wob
- verbose: print statement corrected

Revision 1.3  2006/10/14 08:08:53  wob
- Nagios::Plugin < 0.13 is buggy if exit status = OK, workaround
  implemented; --verbose shows current version of Nagios::Plugin

Revision 1.2  2006/09/27 09:41:47  wob
- if return code of sapinfo is 1, check, if sapinfo is old (from R/3 4.6C)
- manpage: hints to obtain sapinfo added

Revision 1.1  2006/09/25 16:15:40  wob
replacement of check_sap.sh; new parameter interface with getopt::long

=cut
