#!/bin/sh
#
# 
# ServeRAID
#
# Description:	Enables/Disables shared ServeRAID merge groups
#
# Author:	Alan Robertson, Renzo Alejandro Granados
#
# Support:	linux-ha@lists.linux-ha.org
#
# License:	GNU General Public License (GPL)
#
# Copyright:	(C) 2002-2005 International Business Machines
#		(C) 2002 Renzo Alejandro Granados
#
# usage: ./ServeRAID (start|stop|status|monitor|validate-all|meta-data)
#
#	  OCF parameters are as below:
#		OCF_RESKEY_serveraid
#                  (Adapter number of the ServeRAID adapter)
#		OCF_RESKEY_mergegroup
#                  (MergeGroup # of the logical drive under consideration)
#
# The ServeRAID clustering model is a bit odd, and its terminology needs
# a little explanation
#
#	Logical Volume - a particular SCSI id {target id and LUN} on
#		a particular controller.
#
#	Merge Group - when active on one side or the other of the ServeRAID
#		configuration it corresponds with a logical drive.
#		Merge group numbers are permanently assigned to a particular
#		chunk of storage.  Shared merge groups are in the
#		range of 1 to 8, and are largely arbitrary.
#		Unshared merge groups start at 200.
#		We can only deal with shared merge groups.  When a merge
#		group is activated on one of the controllers, it becomes
#		a logical volume on that system.  NOTE:  The order in
#		which the Merge Groups are activated determines which
#		SCSI Ids they become.  This makes for extra headaches
#		for this script to deal with.  It also means that if
#		you have more than one shared ServeRAID merge group on
#		a particular controller, that the SCSI IDs will not
#		be constant.  This requires mounting by uuid or label.
#
#	One of the ServerRAID controllers has to be configured with
#	SCSI initiator ID 6, and the other with SCSI id 7.
#
#	At this time, the ServeRAID clustering solution only works with
#	RAID 1 setups.  It does NOT support RAID 5.  This is a firmware
#	bug in the ServeRAID where it doesn't fail over correctly
#	if the RAID5 array is in a critical state...
#
#	Note that this script requires ServeRAID software version 6.10 or
#	later.  This software is now available from IBM.
#
# An example usage in /etc/ha.d/haresources: 
#       node1  10.0.0.170 ServeRAID::1::1
#

#	Older ServeRAID utility returns 1 when it succeeds (weird)
#	BUT - the newly released version is more normal...

#######################################################################
# Initialization:

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs

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

srsuccess=0
SCSI="scsi "

usage() {
  cat <<-!
	usage: $0 (start|stop|status|monitor|validate-all|meta-data)

	You have to set the following environment virables before running $0 :
		OCF_RESKEY_serveraid
			(Adapter number of the ServeRAID adapter)
		OCF_RESKEY_mergegroup
			(MergeGroup # of the logical drive under consideration)

	ServeRAID adapters are numbered starting from 1.

	The shared merge group number is a number between 1 and 8 inclusive.
	It indicates to the controller which logical disk to fail over.

                node1  10.0.0.170 ServeRAID::1::1

f "$SAPDBCONNECT" ]
      then
        MYCP=".:$FRAME:$ANTLR:$JDDI:$IAIK_JCE_EXPORT:$IAIK_JCE:$EXCEPTION:$LOGGING:$OPENSQLSTA:$TC_SEC_SECSTOREFS:$DB_JARS:$SAPDBCONNECT" 
        EXECMD="com.sap.inst.jdbc.connect.JdbcCon -sec $SID:$SID"
      else
      # WebAS Java 7.10
        LAUNCHER=${BOOTSTRAP}/sap.com~tc~bl~offline_launcher~impl.jar

        if [ -f "$DB_JARS" -a -f "$SAPDBCONNECT" -a -f "$LAUNCHER" ]
        then
          MYCP="$LAUNCHER"
          EXECMD="com.sap.engine.offline.OfflineToolStart com.sap.inst.jdbc.connect.JdbcCon ${SAPDBCONNECT}:${SECSTORE}:${DB_JARS}:${BOOTSTRAP} -sec $SID:$SID"
        fi
      fi

      if [ -n "$EXECMD" ]
      then
        output=`eval ${JAVA_HOME}/bin/java -cp $MYCP $EXECMD`
        if [ $? -le 0 ]
        then
          rc=$OCF_SUCCESS
        else
          rc=$OCF_NOT_RUNNING
        fi
      else
        output="Cannot find all jar files needed for database monitoring."
        rc=$OCF_ERR_GENERIC
      fi
    fi
  fi

  if [ $rc -ne $OCF_SUCCESS ]
  then
    ocf_log err "The SAP database $SID ist not running: $output"
  fi
  return $rc
}


#
# sapdatabase_status: Are there any database processes on this host ?
#
sapdatabase_status() {
  case $DBTYPE in
    ADA) SEARCH="$SID/db/pgm/kernel"
         SUSER=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'`
         SNUM=2
         ;;
    ORA) SEARCH="ora_[a-z][a-z][a-z][a-z]_"
         SUSER="ora`echo $SID | tr [:upper:] [:lower:]`"
         SNUM=4
         ;;
    DB6) SEARCH="db2[a-z][a-z][a-z][a-z][a-z]"
         SUSER="db2`echo $SID | tr [:upper:] [:lower:]`"
         SNUM=5
         ;;
  esac

  # Note: ps cuts off it's output at column $COLUMNS, so "ps -ef" can not be used here
  # as the output might be to long.
  cnt=`ps efo args --user $SUSER 2> /dev/null | grep -c "$SEARCH"`
  if [ $cnt -ge $SNUM ]
  then
    rc=$OCF_SUCCESS
  else
    # ocf_log info "Database Instance $SID is not running on `hostname`"
    rc=$OCF_NOT_RUNNING
  fi
  return $rc
}


#
# sapdatabase_recover:
#
sapdatabase_recover() {

  case $DBTYPE in
    ORA) recoutput=`oracle_recover`
         ;;
    ADA) recoutput=`maxdb_recover`
         ;;
    DB6) recoutput=`db6udb_recover`
         ;;
  esac

  sapdatabase_monitor 1
  retcode=$?

  if [ $retcode -eq $OCF_SUCCESS ]
  then
    ocf_log info "Recover of SAP database $SID was successful: $recoutput"
  else
    ocf_log err "Recover of SAP database $SID failed: $recoutput"
  fi

  return $retcode
}


#
# sapdatabase_validate: Check the symantic of the input parameters 
#
sapdatabase_validate() {
  rc=$OCF_SUCCESS
  if [ `echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$'` -ne 1 ]
  then
    ocf_log err "Parsing parameter SID: '$SID' is not a valid system ID!"
    rc=$OCF_ERR_ARGS
  fi

  case "$DBTYPE" in
   ORA|ADA|DB6) ;;
   *) ocf_log err "Parsing parameter DBTYPE: '$DBTYPE' is not a supported database type!"
      rc=$OCF_ERR_ARGS ;;
  esac

  return $rc
}


#
#	'main' starts here...
#

if
  ( [ $# -ne 1 ] )
then
  usage
  exit $OCF_ERR_ARGS
fi

# Set a tempfile and make sure to clean it up again
TEMPFILE="/tmp/SAPDatabase.$$.tmp"
trap trap_handler INT TERM

# These operations don't require OCF instance parameters to be set
case "$1" in
  meta-data)	meta_data
		exit $OCF_SUCCESS;;

  usage) 	usage
		exit $OCF_SUCCESS;;

  methods)	sapdatabase_methods
		exit $?;;

  *);;
esac

US=`id -u -n`
US=`echo $US`
if
  [ $US != root  ]
then
  ocf_log err "$0 must be run as root"
  exit $OCF_ERR_PERM
fi

# mandatory parameter check
if  [ -z "$OCF_RESKEY_SID" ]; then
  ocf_log err "Please set OCF_RESKEY_SID to the SAP system id!"
  exit $OCF_ERR_ARGS
fi
SID=`echo "$OCF_RESKEY_SID"`

if [ -z "$OCF_RESKEY_DBTYPE" ]; then
  ocf_log err "Please set OCF_RESKEY_DBTYPE to the database vendor specific tag (ORA,ADA,DB6)!"
  exit $OCF_ERR_ARGS
fi
DBTYPE=`echo "$OCF_RESKEY_DBTYPE" | tr "[a-z]" "[A-Z]"`

# optional OCF parameters, we try to guess which directories are correct
EXESTARTDB="startdb"
EXESTOPDB="stopdb"
EXEDBCONNECT="R3trans"
if [ -z "$OCF_RESKEY_DBJ2EE_ONLY" ]; then
  DBJ2EE_ONLY=0
else
  case "$OCF_RESKEY_DBJ2EE_ONLY" in
   1|true|TRUE|yes|YES) DBJ2EE_ONLY=1
                        EXESTARTDB="startj2eedb"
                        EXESTOPDB="stopj2eedb"
                        EXEDBCONNECT="jdbcconnect.jar"
                        ;;
   0|false|FALSE|no|NO) DBJ2EE_ONLY=0;;
   *) ocf_log err "Parsing parameter DBJ2EE_ONLY: '$DBJ2EE_ONLY' is not a boolean value!"
      exit $OCF_ERR_ARGS ;;
  esac
fi

if [ -z "$OCF_RESKEY_NETSERVICENAME" ]; then
  case "$DBTYPE" in
    ORA|ora) NETSERVICENAME="LISTENER";;
    *)       NETSERVICENAME="";;
  esac
else
  NETSERVICENAME="$OCF_RESKEY_NETSERVICENAME"
fi

if [ -z "$OCF_RESKEY_STRICT_MONITORING" ]; then
  OCF_RESKEY_STRICT_MONITORING=0
else
  case "$OCF_RESKEY_STRICT_MONITORING" in
   1|true|TRUE|yes|YES) OCF_RESKEY_STRICT_MONITORING=1;;
   0|false|FALSE|no|NO) OCF_RESKEY_STRICT_MONITORING=0;;
   *)  ocf_log err "Parsing parameter STRICT_MONITORING: '$OCF_RESKEY_STRICT_MONITORING' is not a boolean value!"
       exit $OCF_ERR_ARGS ;;
  esac
fi

PATHLIST="
$OCF_RESKEY_DIR_EXECUTABLE
/usr/sap/$SID/*/exe
/usr/sap/$SID/SYS/exe/run
/sapmnt/$SID/exe
"
DIR_EXECUTABLE=""
for EXEPATH in $PATHLIST
do
  if [ -x $EXEPATH/$EXESTARTDB -a -x $EXEPATH/$EXESTOPDB -a -x $EXEPATH/$EXEDBCONNECT ]
  then
    DIR_EXECUTABLE=$EXEPATH
    SAPSTARTDB=$EXEPATH/$EXESTARTDB
    SAPSTOPDB=$EXEPATH/$EXESTOPDB
    SAPDBCONNECT=$EXEPATH/$EXEDBCONNECT
    break
  fi
done
if [ -z "$DIR_EXECUTABLE" ]
then
  ocf_log warn "Cannot find $EXESTARTDB,$EXESTOPDB and $EXEDBCONNECT executable, please set DIR_EXECUTABLE parameter!"
  exit $OCF_NOT_RUNNING
fi

if [ $DBJ2EE_ONLY -eq 1 ]
then
  if [ -n "$OCF_RESKEY_DIR_BOOTSTRAP" ]
  then
    BOOTSTRAP="$OCF_RESKEY_DIR_BOOTSTRAP"
  else
    BOOTSTRAP=`echo /usr/sap/$SID/*/j2ee/cluster/bootstrap | head -1`
  fi

  if [ -n "$OCF_RESKEY_DIR_SECSTORE" ]
  then
    SECSTORE="$OCF_RESKEY_DIR_SECSTORE"
  else
    SECSTORE=/usr/sap/$SID/SYS/global/security/lib/tools
  fi

  if [ -n "$OCF_RESKEY_JAVA_HOME" ]
  then
    JAVA_HOME="$OCF_RESKEY_JAVA_HOME"
    PATH=$JAVA_HOME/bin:$PATH
  else
    if [ -n "$JAVA_HOME" ]
    then
      PATH=$JAVA_HOME/bin:$PATH
    else
      ocf_log err "Cannot find JAVA_HOME directory, please set JAVA_HOME parameter!"
      exit $OCF_NOT_RUNNING
    fi
  fi

  if [ -n "$OCF_RESKEY_DB_JARS" ]
  then
    DB_JARS=$OCF_RESKEY_DB_JARS
  else
    if [ -f "$BOOTSTRAP"/bootstrap.properties ]; then
      DB_JARS=`cat $BOOTSTRAP/bootstrap.properties | grep -i rdbms.driverLocation | sed -e 's/\\\:/:/g' | awk -F= '{print $2}'`
    fi
  fi
fi

if [ -z "$OCF_RESKEY_AUTOMATIC_RECOVER" ]
then
  OCF_RESKEY_AUTOMATIC_RECOVER=0
else
  case "$OCF_RESKEY_AUTOMATIC_RECOVER" in
   1|true|TRUE|yes|YES) OCF_RESKEY_AUTOMATIC_RECOVER=1;;
   0|false|FALSE|no|NO) OCF_RESKEY_AUTOMATIC_RECOVER=0;;
  esac
fi

# as root user we need the library path to the SAP kernel to be able to call executables
if [ "$DIR_EXECUTABLE" ]; then
  if [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then
      LD_LIBRARY_PATH="$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
      export LD_LIBRARY_PATH
  fi
fi
sidadm="`echo $SID | tr [:upper:] [:lower:]`adm"

# What kind of method was invoked?
case "$1" in

  start)	sapda