diff --git a/heartbeat/SAPDatabase b/heartbeat/SAPDatabase index bd7dc5e3b..0bcec9e0e 100644 --- a/heartbeat/SAPDatabase +++ b/heartbeat/SAPDatabase @@ -1,1004 +1,998 @@ #!/bin/sh # # SAPDatabase # # Description: Manages any type of SAP supported database instance # as a High-Availability OCF compliant resource. # # Author: Alexander Krauth, October 2006 # Support: linux@sap.com # License: GNU General Public License (GPL) # Copyright: (c) 2006, 2007 Alexander Krauth # # An example usage: # See usage() function below for more details... # # OCF instance parameters: # OCF_RESKEY_SID # OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) # OCF_RESKEY_DBTYPE # OCF_RESKEY_NETSERVICENAME (optional, non standard name of Oracle Listener) # OCF_RESKEY_DBJ2EE_ONLY (optional, default is false) # OCF_RESKEY_JAVA_HOME (optional, only needed if DBJ2EE_ONLY is true and JAVA_HOME enviroment variable is not set) # OCF_RESKEY_STRICT_MONITORING (optional, activate application level monitoring - with Oracle a failover will occur in case of an archiver stuck) # OCF_RESKEY_AUTOMATIC_RECOVER (optional, automatic startup recovery, default is false) # OCF_RESKEY_DIR_BOOTSTRAP (optional, if non standard J2EE server directory) # OCF_RESKEY_DIR_SECSTORE (optional, if non standard J2EE secure store directory) # OCF_RESKEY_DB_JARS (optional, if maintained in bootstrap.properties, mandatory for WebAS Java 7.10) # OCF_RESKEY_PRE_START_USEREXIT (optional, lists a script which can be executed before the resource is started) # OCF_RESKEY_POST_START_USEREXIT (optional, lists a script which can be executed after the resource is started) # OCF_RESKEY_PRE_STOP_USEREXIT (optional, lists a script which can be executed before the resource is stopped) # OCF_RESKEY_POST_STOP_USEREXIT (optional, lists a script which can be executed after the resource is stopped) # # ToDo: # Remove all the database dependend stuff from the agent and use # saphostcontrol daemon as soon as SAP will release it. # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### SH=/bin/sh usage() { methods=`sapdatabase_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages a SAP database of any type as an HA resource. Currently Oracle, MaxDB and DB/2 UDB are supported. ABAP databases as well as JAVA only databases are supported. The 'start' operation starts the instance. The 'stop' operation stops the instance. The 'status' operation reports whether the instance is running The 'monitor' operation reports whether the instance seems to be working The 'recover' operation tries to recover the instance after a crash (instance will be stopped first!) The 'validate-all' operation reports whether the parameters are valid The 'methods' operation reports on the methods $0 supports ! } meta_data() { cat < -1.91 +1.92 Resource script for SAP databases. It manages a SAP database of any type as an HA resource. SAP database resource agent The unique SAP system identifier. e.g. P01 SAP system ID The full qualified path where to find sapstartsrv and sapcontrol. path of sapstartsrv and sapcontrol The name of the database vendor you use. Set either: ORA,DB6,ADA database vendor The Oracle TNS listener name. listener name If you do not have a ABAP stack installed in the SAP database, set this to TRUE only JAVA stack installed This is only needed if the DBJ2EE_ONLY parameter is set to true. Enter the path to the Java SDK which is used by the SAP WebAS Java Path to Java SDK This controls how the resource agent monitors the database. If set to true, it will use SAP tools to test the connect to the database. Do not use with Oracle, because it will result in unwanted failovers in case of an archiver stuck Activates application level monitoring The SAPDatabase resource agent tries to recover a failed start attempt automaticaly one time. This is done by running a forced abort of the RDBMS and/or executing recovery commands. Enable or disable automatic startup recovery The full qualified path where to find the J2EE instance bootstrap directory. e.g. /usr/sap/P01/J00/j2ee/cluster/bootstrap path to j2ee bootstrap directory The full qualified path where to find the J2EE security store directory. e.g. /usr/sap/P01/SYS/global/security/lib/tools path to j2ee secure store directory The full qualified filename of the jdbc driver for the database connection test. It will be automaticaly read from the bootstrap.properties file in Java engine 6.40 and 7.00. For Java engine 7.10 the parameter is mandatory. file name of the jdbc driver The full qualified path where to find a script or program which should be executed before this resource gets started. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got started. path to a post-start script The full qualified path where to find a script or program which should be executed before this resource gets stopped. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got stopped. path to a post-start script END } trap_handler() { rm -f $TEMPFILE exit $OCF_ERR_GENERIC } # # listener_start: Start the given listener # listener_start() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" rc=$OCF_SUCCESS output=`echo "lsnrctl start $NETSERVICENAME" | su - $orasid 2>&1` if [ $? -eq 0 ] then ocf_log info "Oracle Listener $NETSERVICENAME started: $output" rc=$OCF_SUCCESS else ocf_log err "Oracle Listener $NETSERVICENAME start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # listener_stop: Stop the given listener # listener_stop() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" rc=$OCF_SUCCESS if listener_status then : listener is running, trying to stop it later... else return $OCF_SUCCESS fi output=`echo "lsnrctl stop $NETSERVICENAME" | su - $orasid 2>&1` if [ $? -eq 0 ] then ocf_log info "Oracle Listener $NETSERVICENAME stopped: $output" else ocf_log err "Oracle Listener $NETSERVICENAME stop failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # listener_status: is the given listener running? # listener_status() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" # 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 $orasid | grep $NETSERVICENAME | grep -c tnslsnr` if [ $cnt -eq 1 ] then rc=$OCF_SUCCESS else ocf_log info "listener process not running for $NETSERVICENAME for $SID" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_start: Start the given x_server # x_server_start() { rc=$OCF_SUCCESS output=`echo "x_server start" | su - $sidadm 2>&1` if [ $? -eq 0 ] then ocf_log info "MaxDB x_server start: $output" rc=$OCF_SUCCESS else ocf_log err "MaxDB x_server start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_stop: Stop the x_server # x_server_stop() { rc=$OCF_SUCCESS output=`echo "x_server stop" | su - $sidadm 2>&1` if [ $? -eq 0 ] then ocf_log info "MaxDB x_server stop: $output" else ocf_log err "MaxDB x_server stop failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_status: is the x_server running? # x_server_status() { sdbuser=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'` # 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 $sdbuser | grep -c vserver` - if [ $cnt -eq 1 ] + if [ $cnt -ge 1 ] then rc=$OCF_SUCCESS else ocf_log info "x_server process not running" rc=$OCF_ERR_GENERIC fi return $rc } # # oracle_stop: Stop the Oracle database without any condition # oracle_stop() { echo '#!/bin/sh LOG=$HOME/stopdb.log date > $LOG if [ -x "${ORACLE_HOME}/bin/sqlplus" ] then SRVMGRDBA_EXE="${ORACLE_HOME}/bin/sqlplus" else echo "Can not find executable sqlplus" >> $LOG exit 1 fi $SRVMGRDBA_EXE /NOLOG >> $LOG << ! connect / as sysdba shutdown immediate exit ! rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # maxdb_stop: Stop the MaxDB database without any condition # maxdb_stop() { # x_Server must be running to stop database x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi if [ $DBJ2EE_ONLY -eq 1 ]; then userkey=c_J2EE else userkey=c fi echo "#!/bin/sh LOG=\$HOME/stopdb.log date > \$LOG echo \"Stop database with xuserkey >$userkey<\" >> \$LOG dbmcli -U ${userkey} db_offline >> \$LOG 2>&1 exit \$?" > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # db6udb_stop: Stop the DB2/UDB database without any condition # db6udb_stop() { echo '#!/bin/sh LOG=$HOME/stopdb.log date > $LOG echo "Shut down the database" >> $LOG $INSTHOME/sqllib/bin/db2 deactivate database $DB2DBDFT |tee -a $LOG 2>&1 $INSTHOME/sqllib/adm/db2stop force |tee -a $LOG 2>&1 exit $?' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # oracle_recover: try to clean up oracle after a crash # oracle_recover() { echo '#!/bin/sh LOG=$HOME/recover.log date > $LOG echo "Logfile written by heartbeat SAPDatabase resource agent" >> $LOG if [ -x "${ORACLE_HOME}/bin/sqlplus" ] then SRVMGRDBA_EXE="${ORACLE_HOME}/bin/sqlplus" else echo "Can not find executable sqlplus" >> $LOG exit 1 fi $SRVMGRDBA_EXE /NOLOG >> $LOG << ! connect / as sysdba shutdown abort startup mount WHENEVER SQLERROR EXIT SQL.SQLCODE WHENEVER OSERROR EXIT FAILURE alter database recover automatic database; alter database open; exit ! rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # maxdb_recover: try to clean up MaxDB after a crash # maxdb_recover() { # x_Server must be running to stop database x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi if [ $DBJ2EE_ONLY -eq 1 ]; then userkey=c_J2EE else userkey=c fi echo "#!/bin/sh LOG=\$HOME/recover.log date > \$LOG echo \"Logfile written by heartbeat SAPDatabase resource agent\" >> \$LOG echo \"Cleanup database with xuserkey >$userkey<\" >> \$LOG echo \"db_stop\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_stop >> \$LOG 2>&1 echo \"db_clear\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_clear >> \$LOG 2>&1 echo \"db_online\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_online >> \$LOG 2>&1 rc=\$? cat \$LOG exit \$rc" > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # db6udb_recover: try to recover DB/2 after a crash # db6udb_recover() { db2sid="db2`echo $SID | tr [:upper:] [:lower:]`" echo '#!/bin/sh LOG=$HOME/recover.log date > $LOG echo "Logfile written by heartbeat SAPDatabase resource agent" >> $LOG $INSTHOME/sqllib/bin/db2_kill >> $LOG 2>&1 $INSTHOME/sqllib/adm/db2start >> $LOG 2>&1 $INSTHOME/sqllib/bin/db2 activate database $DB2DBDFT >> $LOG 2>&1 rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $db2sid $TEMPFILE su - $db2sid -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # methods: What methods/operations do we support? # sapdatabase_methods() { cat <<-! start stop status monitor recover validate-all methods meta-data usage ! } # # sapuserexit : Many SAP customers need some additional processes/tools to run their SAP systems. # This specialties do not allow a totally generic SAP cluster resource agent. # Someone should write a resource agent for each additional process you need, if it # is required to monitor that process within the cluster manager. To enable # you to extent this resource agent without developing a new one, this user exit # was introduced. # sapuserexit() { NAME="$1" VALUE="$2" if [ -n "$VALUE" ] then if [ -x "$VALUE" ] then ocf_log info "Calling userexit ${NAME} with customer script file ${VALUE}" eval "$VALUE" >& /dev/null ocf_log info "Exiting userexit ${NAME} with customer script file ${VALUE}, returncode: $?" else ocf_log warn "Attribute ${NAME} is set to ${VALUE}, but this file is not executable" fi fi return 0 } # # sapdatabase_start : Start the SAP database # sapdatabase_start() { sapuserexit PRE_START_USEREXIT "$OCF_RESKEY_PRE_START_USEREXIT" case $DBTYPE in ADA) x_server_start ;; ORA) listener_start ;; esac output=`su - $sidadm -c $SAPSTARTDB` rc=$? if [ $DBJ2EE_ONLY -eq 1 ] then sapdatabase_monitor 1 rc=$? fi if [ $rc -ne 0 -a $OCF_RESKEY_AUTOMATIC_RECOVER -eq 1 ] then ocf_log warn "SAP database $SID start failed: $output" ocf_log warn "Try to recover database $SID" output='' sapdatabase_recover rc=$? fi if [ $rc -eq 0 ] then ocf_log info "SAP database $SID started: $output" rc=$OCF_SUCCESS sapuserexit POST_START_USEREXIT "$OCF_RESKEY_POST_START_USEREXIT" else ocf_log err "SAP database $SID start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # sapdatabase_stop: Stop the SAP database # sapdatabase_stop() { sapuserexit PRE_STOP_USEREXIT "$OCF_RESKEY_PRE_STOP_USEREXIT" # use of the stopdb kernel script is not possible, because there are to may checks in that # script. We want to stop the database regardless of anything. #output=`su - $sidadm -c $SAPSTOPDB` case $DBTYPE in ORA) output=`oracle_stop` ;; ADA) output=`maxdb_stop` ;; DB6) output=`db6udb_stop` ;; esac if [ $? -eq 0 ] then ocf_log info "SAP database $SID stopped: $output" rc=$OCF_SUCCESS else ocf_log err "SAP database $SID stop failed: $output" rc=$OCF_ERR_GENERIC fi case $DBTYPE in ORA) listener_stop ;; ADA) x_server_stop ;; esac sapuserexit POST_STOP_USEREXIT "$OCF_RESKEY_POST_STOP_USEREXIT" return $rc } # # sapdatabase_monitor: Can the given database instance do anything useful? # sapdatabase_monitor() { strict=$1 rc=$OCF_SUCCESS case $DBTYPE in ADA) x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi ;; ORA) listener_status if [ $? -ne $OCF_SUCCESS ]; then listener_start; fi ;; esac if [ $strict -eq 0 ] then sapdatabase_status rc=$? else if [ $DBJ2EE_ONLY -eq 0 ] then output=`echo "$SAPDBCONNECT -d -w /dev/null" | su $sidadm 2>&1` if [ $? -le 4 ] then rc=$OCF_SUCCESS else rc=$OCF_NOT_RUNNING fi else MYCP="" EXECMD="" # WebAS Java 6.40+7.00 IAIK_JCE="$SECSTORE"/iaik_jce.jar IAIK_JCE_EXPORT="$SECSTORE"/iaik_jce_export.jar EXCEPTION="$BOOTSTRAP"/exception.jar LOGGING="$BOOTSTRAP"/logging.jar OPENSQLSTA="$BOOTSTRAP"/opensqlsta.jar TC_SEC_SECSTOREFS="$BOOTSTRAP"/tc_sec_secstorefs.jar JDDI="$BOOTSTRAP"/../server0/bin/ext/jdbdictionary/jddi.jar ANTLR="$BOOTSTRAP"/../server0/bin/ext/antlr/antlr.jar FRAME="$BOOTSTRAP"/../server0/bin/system/frame.jar # only start jdbcconnect when all jars available if [ -f "$EXCEPTION" -a -f "$LOGGING" -a -f "$OPENSQLSTA" -a -f "$TC_SEC_SECSTOREFS" -a -f "$JDDI" -a -f "$ANTLR" -a -f "$FRAME" -a -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 - SAPSTARTDB=`which $EXEPATH/$EXESTARTDB 2> /dev/null` - if [ $? -eq 0 ] + if [ -x $EXEPATH/$EXESTARTDB -a -x $EXEPATH/$EXESTOPDB -a -x $EXEPATH/$EXEDBCONNECT ] then - MYPATH=`echo "$SAPSTARTDB" | head -1` - MYPATH=`dirname "$MYPATH"` - if [ -x $MYPATH/$EXESTARTDB -a -x $MYPATH/$EXESTOPDB -a -x $MYPATH/$EXEDBCONNECT ] - then - DIR_EXECUTABLE=$MYPATH - SAPSTARTDB=$MYPATH/$EXESTARTDB - SAPSTOPDB=$MYPATH/$EXESTOPDB - SAPDBCONNECT=$MYPATH/$EXEDBCONNECT - break - fi + 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 [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then LD_LIBRARY_PATH=$DIR_EXECUTABLE:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH fi sidadm="`echo $SID | tr [:upper:] [:lower:]`adm" # What kind of method was invoked? case "$1" in start) sapdatabase_start exit $?;; stop) sapdatabase_stop exit $?;; monitor) sapdatabase_monitor $OCF_RESKEY_STRICT_MONITORING exit $?;; status) sapdatabase_status exit $?;; recover) sapdatabase_recover exit $?;; validate-all) sapdatabase_validate exit $?;; *) sapdatabase_methods exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/SAPInstance b/heartbeat/SAPInstance index 2807ee91d..db790e707 100644 --- a/heartbeat/SAPInstance +++ b/heartbeat/SAPInstance @@ -1,584 +1,771 @@ #!/bin/sh # # SAPInstance # # Description: Manages a single SAP Instance as a High-Availability # resource. One SAP Instance is defined by one # SAP Instance-Profile. start/stop handels all services # of the START-Profile, status and monitor care only # about essential services. # # Author: Alexander Krauth, June 2006 # Support: linux@sap.com # License: GNU General Public License (GPL) -# Copyright: (c) 2006, 2007 Alexander Krauth +# Copyright: (c) 2006-2008 Alexander Krauth # # An example usage: # See usage() function below for more details... # # OCF instance parameters: # OCF_RESKEY_InstanceName # OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) # OCF_RESKEY_DIR_PROFILE (optional, well known directories will be searched by default) # OCF_RESKEY_START_PROFILE (optional, well known directories will be searched by default) # OCF_RESKEY_START_WAITTIME (optional, to solve timing problems during J2EE-Addin start) # OCF_RESKEY_AUTOMATIC_RECOVER (optional, automatic startup recovery using cleanipc, default is false) +# OCF_RESKEY_MONITOR_SERVICES (optional, default is to monitor critical services only) +# OCF_RESKEY_ERS_InstanceName (optional, InstanceName of the ERS instance in a Master/Slave configuration) +# OCF_RESKEY_ERS_START_PROFILE (optional, START_PROFILE of the ERS instance in a Master/Slave configuration) # OCF_RESKEY_PRE_START_USEREXIT (optional, lists a script which can be executed before the resource is started) # OCF_RESKEY_POST_START_USEREXIT (optional, lists a script which can be executed after the resource is started) # OCF_RESKEY_PRE_STOP_USEREXIT (optional, lists a script which can be executed before the resource is stopped) # OCF_RESKEY_POST_STOP_USEREXIT (optional, lists a script which can be executed after the resource is stopped) # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### SH=/bin/sh -usage() { +sapinstance_usage() { methods=`sapinstance_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages a SAP Instance as an HA resource. - The 'start' operation starts the instance. - The 'stop' operation stops the instance. + The 'start' operation starts the instance or the ERS instance in a Master/Slave configuration + The 'stop' operation stops the instance The 'status' operation reports whether the instance is running The 'monitor' operation reports whether the instance seems to be working + The 'promote' operation starts the primary instance in a Master/Slave configuration + The 'demote' operation stops the primary instance and starts the ERS instance + The 'notify' operation always returns SUCCESS The 'validate-all' operation reports whether the parameters are valid The 'methods' operation reports on the methods $0 supports ! } -meta_data() { +sapinstance_meta_data() { cat < -1.91 +2.01 Resource script for SAP. It manages a SAP Instance as an HA resource. SAP instance resource agent The full qualified SAP instance name. e.g. P01_DVEBMGS00_sapp01ci instance name: SID_INSTANCE_VIR-HOSTNAME The full qualified path where to find sapstartsrv and sapcontrol. path of sapstartsrv and sapcontrol The full qualified path where to find the SAP START profile. path of start profile The name of the SAP START profile. start profile name After that time in seconds a monitor operation is executed by the resource agent. Does the monitor return SUCCESS, the start is handled as SUCCESS. This is useful to resolve timing problems with e.g. the J2EE-Addin instance. Check the successful start after that time (do not wait for J2EE-Addin) The SAPInstance resource agent tries to recover a failed start attempt automaticaly one time. This is done by killing runing instance processes and executing cleanipc. Enable or disable automatic startup recovery + + + + + + + + + + + + + + + The full qualified path where to find a script or program which should be executed before this resource gets started. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got started. path to a post-start script The full qualified path where to find a script or program which should be executed before this resource gets stopped. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got stopped. path to a post-start script - + + END } # # methods: What methods/operations do we support? # sapinstance_methods() { cat <<-! start - recover stop status monitor + promote + demote + notify validate-all methods meta-data usage ! } + +# +# is_clone : find out if we are configured to run in a Master/Slave configuration +# +is_clone() { + if [ -n "$OCF_RESKEY_CRM_meta_clone_max" ] \ + && [ "$OCF_RESKEY_CRM_meta_clone_max" -gt 0 ] + then + if [ "$OCF_RESKEY_CRM_meta_clone_max" -ne 2 ] || \ + [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] || \ + [ "$OCF_RESKEY_CRM_meta_master_node_max" -ne 1 ] || \ + [ "$OCF_RESKEY_CRM_meta_master_max" -ne 1 ] + then + ocf_log err "Clone options misconfigured. (expect: clone_max=2,clone_node_max=1,master_node_max=1,master_max=1)" + exit $OCF_ERR_CONFIGURED + fi + + if [ -z "$OCF_RESKEY_ERS_InstanceName" ] + then + ocf_log err "In a Master/Slave configuration the ERS_InstanceName parameter is mandatory." + exit $OCF_ERR_ARGS + fi + else + return 0 + fi + return 1 +} + + +# +# sapinstance_init : Define global variables with default values, if optional parameters are not set +# +# +sapinstance_init() { + + myInstanceName="$1" + + SID=`echo "$myInstanceName" | cut -d_ -f1` + InstanceName=`echo "$myInstanceName" | cut -d_ -f2` + InstanceNr=`echo "$InstanceName" | sed 's/.*\([0-9][0-9]\)$/\1/'` + SAPVIRHOST=`echo "$myInstanceName" | cut -d_ -f3` + + # optional OCF parameters, we try to guess which directories are correct + if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] + then + if [ -x /usr/sap/$SID/$InstanceName/exe/sapstartsrv -a -x /usr/sap/$SID/$InstanceName/exe/sapcontrol ] + then + DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" + SAPSTARTSRV="/usr/sap/$SID/$InstanceName/exe/sapstartsrv" + SAPCONTROL="/usr/sap/$SID/$InstanceName/exe/sapcontrol" + elif [ -x /usr/sap/$SID/SYS/exe/run/sapstartsrv -a -x /usr/sap/$SID/SYS/exe/run/sapcontrol ] + then + DIR_EXECUTABLE="/usr/sap/$SID/SYS/exe/run" + SAPSTARTSRV="/usr/sap/$SID/SYS/exe/run/sapstartsrv" + SAPCONTROL="/usr/sap/$SID/SYS/exe/run/sapcontrol" + else + ocf_log warn "Cannot find sapstartsrv and sapcontrol executable, please set DIR_EXECUTABLE parameter!" + exit $OCF_NOT_RUNNING + fi + else + DIR_EXECUTABLE="$OCF_RESKEY_DIR_EXECUTABLE" + SAPSTARTSRV="$OCF_RESKEY_DIR_EXECUTABLE/sapstartsrv" + SAPCONTROL="$OCF_RESKEY_DIR_EXECUTABLE/sapcontrol" + fi + + if [ -z "$OCF_RESKEY_DIR_PROFILE" ] + then + if [ -d /usr/sap/$SID/SYS/profile/ ] + then + DIR_PROFILE="/usr/sap/$SID/SYS/profile" + else + ocf_log warn "Expected /usr/sap/$SID/SYS/profile/ to be a directory, please set DIR_PROFILE parameter!" + exit $OCF_NOT_RUNNING + fi + else + DIR_PROFILE="$OCF_RESKEY_DIR_PROFILE" + fi + + if [ "$myInstanceName" != "$OCF_RESKEY_InstanceName" ] + then + currentSTART_PROFILE=$OCF_RESKEY_ERS_START_PROFILE + else + currentSTART_PROFILE=$OCF_RESKEY_START_PROFILE + fi + + if [ -z "$currentSTART_PROFILE" ] + then + SAPSTARTPROFILE="$DIR_PROFILE/START_${InstanceName}_${SAPVIRHOST}" + if [ ! -r $SAPSTARTPROFILE ] + then + ocf_log warn "Expected $SAPSTARTPROFILE to be the instance START profile, please set START_PROFILE parameter!" + exit $OCF_NOT_RUNNING + fi + else + SAPSTARTPROFILE="$currentSTART_PROFILE" + fi + + if [ -z "$OCF_RESKEY_START_WAITTIME" ] + then + export OCF_RESKEY_START_WAITTIME=3600 + 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) export OCF_RESKEY_AUTOMATIC_RECOVER=1;; + 0|false|FALSE|no|NO) export OCF_RESKEY_AUTOMATIC_RECOVER=0;; + esac + fi + + if [ -z "$OCF_RESKEY_MONITOR_SERVICES" ] + then + export OCF_RESKEY_MONITOR_SERVICES="disp+work|msg_server|enserver|enrepserver|jcontrol|jstart" + fi + + # as root user we need the library path to the SAP kernel to be able to call sapcontrol + if [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then + LD_LIBRARY_PATH=$DIR_EXECUTABLE:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH + fi + + sidadm="`echo $SID | tr [:upper:] [:lower:]`adm" + + return $OCF_SUCCESS +} + + # # check_sapstartsrv : Before using sapcontrol we make sure that the sapstartsrv is running for the correct instance. # We cannot use sapinit and the /usr/sap/sapservices file in case of an enquerep instance, # because then we have two instances with the same instance number. # check_sapstartsrv() { restart=0 runninginst="" chkrc=$OCF_SUCCESS output=`$SAPCONTROL -nr $InstanceNr -function ParameterValue INSTANCE_NAME -format script` if [ $? -eq 0 ] then runninginst=`echo "$output" | grep '^0 : ' | cut -d' ' -f3` if [ "$runninginst" != "$InstanceName" ] then ocf_log warn "sapstartsrv is running for instance $runninginst, that service will be killed" restart=1 fi else ocf_log warn "sapstartsrv is not running for instance $SID-$InstanceName, it will be started now" restart=1 fi if [ -z "$runninginst" ]; then runninginst=$InstanceName; fi if [ $restart -eq 1 ] then pkill -9 -f "sapstartsrv.*$runninginst" $SAPSTARTSRV pf=$SAPSTARTPROFILE -D -u $sidadm # now make sure the daemon has been started and is able to respond srvrc=1 while [ $srvrc -eq 1 -a `pgrep -f "sapstartsrv.*$runninginst" | wc -l` -gt 0 ] do sleep 1 $SAPCONTROL -nr $InstanceNr -function GetProcessList > /dev/null 2>&1 srvrc=$? done if [ $srvrc -ne 1 ] then ocf_log info "sapstartsrv for instance $SID-$InstanceName was restarted !" chkrc=$OCF_SUCCESS else ocf_log error "sapstartsrv for instance $SID-$InstanceName could not be started!" chkrc=$OCF_NOT_RUNNING fi fi return $chkrc } # # sapuserexit : Many SAP customers need some additional processes/tools to run their SAP systems. # This specialties do not allow a totally generic SAP cluster resource agent. # Someone should write a resource agent for each additional process you need, if it # is required to monitor that process within the cluster manager. To enable # you to extent this resource agent without developing a new one, this user exit # was introduced. # sapuserexit() { NAME="$1" VALUE="$2" if [ -n "$VALUE" ] then if [ -x "$VALUE" ] then ocf_log info "Calling userexit ${NAME} with customer script file ${VALUE}" eval "$VALUE" >& /dev/null ocf_log info "Exiting userexit ${NAME} with customer script file ${VALUE}, returncode: $?" else ocf_log warn "Attribute ${NAME} is set to ${VALUE}, but this file is not executable" fi fi return 0 } # # cleanup_instance : remove resources (processes and shared memory) from a crashed instance) # cleanup_instance() { pkill -9 -f -U $sidadm $InstanceName $DIR_EXECUTABLE/cleanipc $InstanceNr remove return 0 } # # sapinstance_start : Start the SAP instance # sapinstance_start() { sapuserexit PRE_START_USEREXIT "$OCF_RESKEY_PRE_START_USEREXIT" rc=$OCF_NOT_RUNNING loopcount=0 while [ $loopcount -lt 2 ] do loopcount=$(($loopcount + 1)) check_sapstartsrv output=`$SAPCONTROL -nr $InstanceNr -function Start` rc=$? ocf_log info "Starting SAP Instance $SID-$InstanceName: $output" if [ $rc -ne 0 ] then ocf_log err "SAP Instance $SID-$InstanceName start failed." return $OCF_ERR_GENERIC fi startrc=1 while [ $startrc -gt 0 ] do waittime_start=`date +%s` output=`$SAPCONTROL -nr $InstanceNr -function WaitforStarted $OCF_RESKEY_START_WAITTIME 10` startrc=$? waittime_stop=`date +%s` if [ $startrc -ne 0 ] then if [ $(($waittime_stop - $waittime_start)) -ge $OCF_RESKEY_START_WAITTIME ] then sapinstance_monitor NOLOG if [ $? -eq $OCF_SUCCESS ] then output="START_WAITTIME ($OCF_RESKEY_START_WAITTIME) has elapsed, but instance monitor returned SUCCESS. Instance considered running." startrc=0; loopcount=2 fi else if [ $loopcount -eq 1 -a $OCF_RESKEY_AUTOMATIC_RECOVER -eq 1 ] then ocf_log warn "SAP Instance $SID-$InstanceName start failed: $output" ocf_log warn "Try to recover $SID-$InstanceName" cleanup_instance else loopcount=2 fi startrc=-1 fi else loopcount=2 fi done done if [ $startrc -eq 0 ] then ocf_log info "SAP Instance $SID-$InstanceName started: $output" rc=$OCF_SUCCESS sapuserexit POST_START_USEREXIT "$OCF_RESKEY_POST_START_USEREXIT" else ocf_log err "SAP Instance $SID-$InstanceName start failed: $output" rc=$OCF_NOT_RUNNING fi return $rc } # # sapinstance_recover: Try startup of failed instance by cleaning up resources # sapinstance_recover() { cleanup_instance sapinstance_start return $? } # # sapinstance_stop: Stop the SAP instance # sapinstance_stop() { sapuserexit PRE_STOP_USEREXIT "$OCF_RESKEY_PRE_STOP_USEREXIT" check_sapstartsrv output=`$SAPCONTROL -nr $InstanceNr -function Stop` if [ $? -eq 0 ] then output=`$SAPCONTROL -nr $InstanceNr -function WaitforStopped 3600 1` if [ $? -eq 0 ] then ocf_log info "SAP Instance $SID-$InstanceName stopped: $output" rc=$OCF_SUCCESS else ocf_log err "SAP Instance $SID-$InstanceName stop failed: $output" rc=$OCF_ERR_GENERIC fi else ocf_log err "SAP Instance $SID-$InstanceName stop failed: $output" rc=$OCF_ERR_GENERIC fi sapuserexit POST_STOP_USEREXIT "$OCF_RESKEY_POST_STOP_USEREXIT" return $rc } # # sapinstance_monitor: Can the given SAP instance do anything useful? # sapinstance_monitor() { MONLOG=$1 check_sapstartsrv rc=$? if [ $rc -eq $OCF_SUCCESS ] then count=0 LOCALHOST=`hostname` output=`$SAPCONTROL -nr $InstanceNr -host $LOCALHOST -function GetProcessList -format script` # we have to parse the output, because the returncode doesn't tell anything about the instance status for SERVNO in `echo "$output" | grep '^[0-9] ' | cut -d' ' -f1 | sort -u` do COLOR=`echo "$output" | grep "^$SERVNO dispstatus: " | cut -d' ' -f3` SERVICE=`echo "$output" | grep "^$SERVNO name: " | cut -d' ' -f3` STATE=0 case $COLOR in GREEN|YELLOW) STATE=$OCF_SUCCESS;; *) STATE=$OCF_NOT_RUNNING;; esac - case $SERVICE in - disp+work|msg_server|enserver|enrepserver|jcontrol|jstart) - if [ $STATE -eq $OCF_NOT_RUNNING ] - then - if [ "$MONLOG" != "NOLOG" ] - then - ocf_log err "SAP instance service $SERVICE is not running with status $COLOR !" - fi - rc=$STATE - fi - count=1;; - *);; - esac + SEARCH=`echo "$OCF_RESKEY_MONITOR_SERVICES" | sed 's/\+/\\\+/g' | sed 's/\./\\\./g'` + if [ `echo "$SERVICE" | egrep -c "$SEARCH"` -eq 1 ] + then + if [ $STATE -eq $OCF_NOT_RUNNING ] + then + if [ "$MONLOG" != "NOLOG" ] + then + ocf_log err "SAP instance service $SERVICE is not running with status $COLOR !" + fi + rc=$STATE + fi + count=1 + fi done if [ $count -eq 0 -a $rc -eq $OCF_SUCCESS ] then if [ "$MONLOG" != "NOLOG" ] then ocf_log err "The SAP instance does not run any services which this RA could monitor!" fi rc=$OCF_ERR_ARGS fi fi - + return $rc } # # sapinstance_validate: Check the symantic of the input parameters # sapinstance_validate() { rc=$OCF_SUCCESS if [ `echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$SID' is not a valid system ID!" rc=$OCF_ERR_ARGS fi if [ `echo "$InstanceName" | grep -c '^[A-Z].*[0-9][0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$InstanceName' is not a valid instance name!" rc=$OCF_ERR_ARGS fi if [ `echo "$InstanceNr" | grep -c '^[0-9][0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$InstanceNr' is not a valid instance number!" rc=$OCF_ERR_ARGS fi if [ `echo "$SAPVIRHOST" | grep -c '^[A-Za-z][A-Za-z0-9_-]*$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$SAPVIRHOST' is not a valid hostname!" rc=$OCF_ERR_ARGS fi return $rc } +# +# sapinstance_start_clone +# +sapinstance_start_clone() { + sapinstance_init $OCF_RESKEY_ERS_InstanceName + ${HA_SBIN_DIR}/crm_master -v 100 -l reboot + sapinstance_start + return $? +} + + +# +# sapinstance_stop_clone +# +sapinstance_stop_clone() { + sapinstance_init $OCF_RESKEY_ERS_InstanceName + ${HA_SBIN_DIR}/crm_master -v 0 -l reboot + sapinstance_stop + return $? +} + + +# +# sapinstance_monitor_clone +# +sapinstance_monitor_clone() { + # resource agents running in Master mode must return other returncodes than default + if [ "$OCF_RESKEY_CRM_meta_op_target_rc" -eq $OCF_RUNNING_MASTER ] + then + sapinstance_init $OCF_RESKEY_InstanceName + sapinstance_monitor + case "$?" in + $OCF_SUCCESS) return $OCF_RUNNING_MASTER;; + $OCF_NOT_RUNNING) ${HA_SBIN_DIR}/crm_master -v 10 -l reboot + return $OCF_FAILED_MASTER;; + *) return $?;; + esac + else + sapinstance_init $OCF_RESKEY_ERS_InstanceName + sapinstance_monitor + return $? + fi +} + + +# +# sapinstance_promote_clone: In a Master/Slave configuration get Master by starting the SCS instance and stopping the ERS instance +# The order is important here to behave correct from the application levels view +# +sapinstance_promote_clone() { + sapinstance_init $OCF_RESKEY_InstanceName + ocf_log info "Promoting $SID-$InstanceName to running Master." + sapinstance_start + rc=$? + + if [ $rc -eq $OCF_SUCCESS ]; then + sapinstance_init $OCF_RESKEY_ERS_InstanceName + sapinstance_stop + rc=$? + fi + + return $rc +} + + +# +# sapinstance_demote_clone: In a Master/Slave configuration get Slave by stopping the SCS instance and starting the ERS instance +# +sapinstance_demote_clone() { + sapinstance_init $OCF_RESKEY_InstanceName + ocf_log info "Demoting $SID-$InstanceName to a slave." + sapinstance_stop + rc=$? + + if [ $rc -eq $OCF_SUCCESS ]; then + sapinstance_init $OCF_RESKEY_ERS_InstanceName + sapinstance_start + rc=$? + fi + + return $rc +} + + +# +# sapinstance_notify: After promotion of one master in the cluster, we make sure that all clones reset thier master +# value back to 100. This is because a failed monitor on a master might have degree one clone +# instance to score 10. +# +sapinstance_notify() { + local n_type="$OCF_RESKEY_CRM_meta_notify_type" + local n_op="$OCF_RESKEY_CRM_meta_notify_operation" + + if [ "${n_type}_${n_op}" = "post_promote" ]; then + ${HA_SBIN_DIR}/crm_master -v 100 -l reboot + fi +} + + # # 'main' starts here... # +## GLOBALS +SID="" +sidadm="" +InstanceName="" +InstanceNr="" +SAPVIRHOST="" +DIR_EXECUTABLE="" +SAPSTARTSRV="" +SAPCONTROL="" +DIR_PROFILE="" +SAPSTARTPROFILE="" +CLONE=0 + + if ( [ $# -ne 1 ] ) then - usage + sapinstance_usage exit $OCF_ERR_ARGS fi -# 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) sapinstance_methods - exit $?;; +ACTION=$1 +if [ "$ACTION" = "status" ]; then + ACTION=monitor +fi +# These operations don't require OCF instance parameters to be set +case "$ACTION" in + usage|methods) sapinstance_$ACTION + exit $OCF_SUCCESS;; + meta-data) sapinstance_meta_data + exit $OCF_SUCCESS;; + notify) sapinstance_notify + exit $OCF_SUCCESS;; *);; 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 # parameter check if [ -z "$OCF_RESKEY_InstanceName" ] then ocf_log err "Please set OCF_RESKEY_InstanceName to the name to the SAP instance profile!" exit $OCF_ERR_ARGS fi -SID=`echo "$OCF_RESKEY_InstanceName" | cut -d_ -f1` -InstanceName=`echo "$OCF_RESKEY_InstanceName" | cut -d_ -f2` -InstanceNr=`echo "$InstanceName" | sed 's/.*\([0-9][0-9]\)$/\1/'` -SAPVIRHOST=`echo "$OCF_RESKEY_InstanceName" | cut -d_ -f3` - -# optional OCF parameters, we try to guess which directories are correct -if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] -then - if [ -x /usr/sap/$SID/$InstanceName/exe/sapstartsrv -a -x /usr/sap/$SID/$InstanceName/exe/sapcontrol ] - then - DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" - SAPSTARTSRV="/usr/sap/$SID/$InstanceName/exe/sapstartsrv" - SAPCONTROL="/usr/sap/$SID/$InstanceName/exe/sapcontrol" - elif [ -x /usr/sap/$SID/SYS/exe/run/sapstartsrv -a -x /usr/sap/$SID/SYS/exe/run/sapcontrol ] - then - DIR_EXECUTABLE="/usr/sap/$SID/SYS/exe/run" - SAPSTARTSRV="/usr/sap/$SID/SYS/exe/run/sapstartsrv" - SAPCONTROL="/usr/sap/$SID/SYS/exe/run/sapcontrol" - else - ocf_log warn "Cannot find sapstartsrv and sapcontrol executable, please set DIR_EXECUTABLE parameter!" - exit $OCF_NOT_RUNNING - fi -else - DIR_EXECUTABLE="$OCF_RESKEY_DIR_EXECUTABLE" - SAPSTARTSRV="$OCF_RESKEY_DIR_EXECUTABLE/sapstartsrv" - SAPCONTROL="$OCF_RESKEY_DIR_EXECUTABLE/sapcontrol" -fi - -if [ -z "$OCF_RESKEY_DIR_PROFILE" ] -then - if [ -d /usr/sap/$SID/SYS/profile/ ] - then - DIR_PROFILE="/usr/sap/$SID/SYS/profile" - else - ocf_log warn "Expected /usr/sap/$SID/SYS/profile/ to be a directory, please set DIR_PROFILE parameter!" - exit $OCF_NOT_RUNNING - fi -else - DIR_PROFILE="$OCF_RESKEY_DIR_PROFILE" -fi - -if [ -z "$OCF_RESKEY_START_PROFILE" ] -then - SAPSTARTPROFILE="$DIR_PROFILE/START_${InstanceName}_${SAPVIRHOST}" - if [ ! -r $SAPSTARTPROFILE ] - then - ocf_log warn "Expected $SAPSTARTPROFILE to be the instance START profile, please set START_PROFILE parameter!" - exit $OCF_NOT_RUNNING - fi -else - SAPSTARTPROFILE="$OCF_RESKEY_START_PROFILE" -fi - -if [ -z "$OCF_RESKEY_START_WAITTIME" ] -then - OCF_RESKEY_START_WAITTIME=3600 -fi - - -if [ -z "$OCF_RESKEY_AUTOMATIC_RECOVER" ] +is_clone; CLONE=$? +if [ ${CLONE} -eq 1 ] then - OCF_RESKEY_AUTOMATIC_RECOVER=0 + CLACT=_clone 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 + sapinstance_init $OCF_RESKEY_InstanceName fi -# as root user we need the library path to the SAP kernel to be able to call sapcontrol -if [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then - LD_LIBRARY_PATH=$DIR_EXECUTABLE:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH -fi -sidadm="`echo $SID | tr [:upper:] [:lower:]`adm" - # What kind of method was invoked? -case "$1" in - - start) sapinstance_start - exit $?;; - - recover) sapinstance_recover - exit $?;; - - stop) sapinstance_stop - exit $?;; - - status|monitor) - sapinstance_monitor - exit $?;; - - validate-all) sapinstance_validate - exit $?;; - - *) sapinstance_methods - exit $OCF_ERR_UNIMPLEMENTED;; +case "$ACTION" in + start|stop|monitor|promote|demote) sapinstance_$ACTION$CLACT + exit $?;; + validate-all) sapinstance_validate + exit $?;; + *) sapinstance_methods + exit $OCF_ERR_UNIMPLEMENTED;; esac