#!/bin/sh
#
# 
# db2
#
# Description:	Manages a DB2 Universal Database as a High-Availability
#		resource
#
#
# Author:	Alan Robertson
# Support:	linux-ha@lists.linux-ha.org
# License:	GNU General Public License (GPL)
# Copyright:	(C) 2002 - 2005 International Business Machines, Inc.
#
#		This code inspired by the FailSafe db2 resource script
#		written by Joachim Gleissner <jg@suse.de>
#
# An example usage in /etc/ha.d/haresources: 
#       node1  10.0.0.170 db2::db2inst1
#
# See usage() function below for more details...
#
# OCF instance parameters:
#	OCF_RESKEY_instance
#	OCF_RESKEY_admin

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

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

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

SH=/bin/sh

usage() {
  methods=`db2_methods`
  methods=`echo $methods | tr ' ' '|'`
  cat <<-!
	usage: $0 ($methods)

	$0 manages a DB2 Universal Database instance as an HA resource.

	The 'start' operation starts the database.
	The 'stop' operation stops the database.
	The 'status' operation reports whether the database is running
	The 'monitor' operation reports whether the database seems to be working
	The 'validate-all' operation reports whether the parameters are valid
	The 'methods' operation reports on the methods $0 supports

	!
}

meta_data() {
	cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="db2">
<version>1.0</version>

<longdesc lang="en">
Resource script for db2. It manages a DB2 Universal Database instance as an HA resource.
</longdesc>
<shortdesc lang="en">Manages an IBM DB2 Universal Database instance</shortdesc>

<parameters>
<parameter name="instance" unique="0" required="1">
<longdesc lang="en">
The instance of database.
</longdesc>
<shortdesc lang="en">instance</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="admin" unique="0" required="0">
<longdesc lang="en">
The admin user of the instance.
</longdesc>
<shortdesc lang="en">admin</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>

<actions>
<action name="start" timeout="120" />
<action name="stop" timeout="120" />
<action name="status" timeout="60" />
<action name="monitor" depth="0" timeout="60" interval="10" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
<action name="methods" timeout="5" />
</actions>
</resource-agent>
END
}


#
# methods: What methods/operations do we support?
#
db2_methods() {
  cat <<-!
	start
	stop
	status
	monitor
	validate-all
	methods
	meta-data
	usage
	!
}


#	Gather up information about our db2 instance

db2info() {
	instance=$1
	db2home=`sh -c "echo ~$db2admin"`
	db2sql=$db2home/sqllib
	db2profile=$db2sql/db2profile
	db2adm=$db2sql/adm
	db2ctrl=$db2sql/ctrl
	db2bin=$db2sql/bin
	db2db2=$db2bin/db2
	db2node=0 # single node instances are supported

	#	Let's make sure a few important things are there...
	if
	  [ -d "$db2sql" -a  -d "$db2bin" -a -f "$db2profile" -a \
		-x "$db2profile" -a -x "$db2db2" ]
	then
	  db2instance=`runasdb2 'echo $DB2INSTANCE'`
	  test ! -z "$db2instance"
        else
	  false
	fi
}

#
#	Run the given command in the db2 admin environment...
#
runasdb2() {
	if
	  [ $US = $db2admin ]
	then
	  $SH -c ". $db2profile; $*"
	else
	  su $db2admin -c ". $db2profile; $*"
	fi
}

#
#	Run a command as the DB2 admin, and log the output
#
logasdb2() {
	output=`runasdb2 $*`
	rc=$?
	if
	  [ $rc -eq 0 ]
	then
	  ocf_log info "$output"
	else
	  ocf_log err "$output"
	fi
	return $rc
}


#
# db2_start: Start the given db2 instance
#
db2_start() {
  if
    output=`runasdb2 $db2adm/db2start`
  then
    : Hurray! DB2 started OK
    ocf_log info "DB2 UDB instance $1 started: $output"
  else
    case $output in
      SQL1026N*|*"is already active"*)
    		ocf_log info "DB2 UDB instance $1 already running: $output";;

      *)	ocf_log err "$output"; return $OCF_ERR_GENERIC;;
    esac
  fi
  db2_status "$1" || {
    ocf_log err "DB2 UDB instance $1 not active!"
    return $OCF_ERR_GENERIC
  }
  # db2jstrt has been deprecated since v8.x and doesn't exist
  # anymore in v9.x
  if [ -x $db2bin/db2jstrt ]; then
	runasdb2 $db2bin/db2jstrt || {
	  ocf_log err "db2jstrt failed"
	  return $OCF_ERR_GENERIC
    }
  fi
  for DB in `db2_dblist`
  do
	if output=`runasdb2 $db2db2 activate database $DB`; then
      ocf_log info "DB2 UDB database $DB activated"
    else
      case $output in
        SQL1490W*|*"already been activated"*)
           ocf_log info "DB2 UDB database $DB already activated: $output";;

        *) ocf_log err "DB2 UDB database $DB didn't activate: $output"; return $OCF_ERR_GENERIC;;
      esac
    fi
  done
}

#
# db2_stop: Stop the given db2 database instance
#
db2_stop() {
  # We ignore the instance, the info we need is already in $vars
  rc=$OCF_SUCCESS
  db2_status || {
    ocf_log info "DB2 UDB instance $1 already stopped"
    return $rc
  }
  if
    output=`runasdb2 $db2adm/db2stop force`
  then
    : DB2 stopped OK
    ocf_log info "DB2 UDB instance $1 stopped: $output"
  else
    case $output in

      SQL1032N*|*"No start database manager command"*)
		ocf_log info "$output";;

      *)	ocf_log err "DB2 UDB instance $1 stop failed: $output"
		rc=$OCF_ERR_GENERIC;;
    esac
  fi
  logasdb2 $db2db2 terminate
  if [ -x $db2bin/db2_kill ]; then
    logasdb2 $db2bin/db2_kill
  elif [ -x $db2bin/db2nkill ]; then
    logasdb2 $db2bin/db2nkill $db2node
  fi
  pids=`our_db2_ps | grep db2jd | cut -d' ' -f1`
  for j in $pids
  do
    runasdb2 kill -9 $j
  done
  return $rc
}


#
# db2_status: is the given db2 instance running?
#
db2_status() {
  # We ignore the instance, the info we need is already in $vars
  pscount=`runasdb2 $db2bin/db2nps $db2node | cut -c9- |  grep ' db2[^ ]' | wc -l`
  test $pscount -ge 4
}

our_db2_ps() {
  ps -u $db2admin | grep db2
}


db2_dblist() {
  runasdb2 $db2db2 list database directory	\
  |	grep -i 'Database name.*=' | sed 's%.*= *%%'
}


#
# db2_monitor: Can the given db2 instance do anything useful?
#
db2_monitor() {
  # We ignore the instance, the info we need is already in $vars
  for DB in `db2_dblist`
  do

  CMD="	if $db2db2 connect to $DB;
	then 
	  $db2db2 select \* from sysibm.sysversions ; rc=\$?;
	  $db2db2 disconnect $DB;
	else
          rc=\$?;
	fi;
	exit \$rc"

    : Running this command: $CMD
    if
      output=`runasdb2 $CMD`
    then
      : Command succeeded!
    else
      ocf_log err "DB2 UDB instance $1 DB $DB is not working"
      ocf_log err "DB2 UDB message: $output"
      return $OCF_ERR_GENERIC
    fi
  done
  ocf_log debug "All DBs in DB2 UDB instance $1 appear to be working"
  return $OCF_SUCCESS
}

#
#	'main' starts here...
#

if
  ( [ $# -ne 1 ] )
then
  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)	db2_methods
		exit $?;;

  *);;
esac

if 
  [ -z "$OCF_RESKEY_instance" ]
then
  ocf_log err "Please set OCF_RESKEY_instance to the database instance !"
  exit $OCF_ERR_ARGS
fi

instance=$OCF_RESKEY_instance
db2admin=${OCF_RESKEY_admin:-$instance}

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

#
#	Grab common db2 information...
#
if
  db2info $instance 
then
  : DB2 info is OK!
else
  if ocf_is_probe; then
    exit $OCF_NOT_RUNNING
  else
    ocf_log err "DB2 instance [$instance] not available"
    exit $OCF_ERR_INSTALLED
  fi
fi


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

  start)	db2_start $instance
		exit $?;;

  stop)		db2_stop $instance
		exit $?;;

  status)	if
		  db2_status $instance
		then
		  echo DB2 UDB instance $instance is running
		  exit $OCF_SUCCESS
		else
		  echo DB2 UDB instance $instance is stopped
		  exit 3  # status: stopped exit code is 3
		fi
		;;

  monitor)	
		if
		  db2_status $instance
		then
		  db2_monitor $instance
		else
		  exit $OCF_NOT_RUNNING
		fi
		exit $?;;

  validate-all)	# OCF_RESKEY_instance has already checked within db2info(),
		# just exit successfully here.
		exit $OCF_SUCCESS;;

  *)		db2_methods
		exit $OCF_ERR_UNIMPLEMENTED;;
esac
