#!/bin/bash
#
# scsi_reserve persistent reservation service for lvm
#
# chkconfig: - 25 75
# description: start/stop persistent reservation service for lvm

if [ -n "$OCF_DEBUG_LIBRARY" ]; then
    . $OCF_DEBUG_LIBRARY
else
    . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs
fi

if [ $# -ne 1 ]; then
	scsi_reserve_usage
	exit $OCF_ERR_ARGS
fi


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

	<longdesc lang="en">
	The detailed description of OCF Resource Agent
	</longdesc>

	<shortdesc lang="en">
		The brief description of OCF Resource Agent
	</shortdesc>

	<parameters>

		<parameter name="sharedisk" unique="0" required="1">
		<longdesc lang="en">
		The detailed description of this parameter
		</longdesc>
		<shortdesc lang="en">
         Can be shared disk or clustered volume group
		</shortdesc>
		<content type="string" default="/dev/sdb" />
		</parameter>

	</parameters>

	<actions>
		<action name="start"   timeout="240" />
		<action name="stop"    timeout="100" />
		<action name="status"   timeout="90" />
		<action name="monitor" depth="0"  timeout="20" interval="20" start-delay="1m" role="Slave" />
		<action name="monitor" depth="0"  timeout="20" interval="10" start-delay="1m" role="Master" />
		<action name="meta-data"  timeout="5" />
		<action name="validate-all"  timeout="30" />
	</actions>
</resource-agent>
END
	return $OCF_SUCCESS
}

scsi_reserve_usage() {
	cat <<END
		usage: $0 {start|stop|monitor|validate-all|meta-data}
END
}

case $__OCF_ACTION in
	meta-data)  scsi_reserve_meta_data
		exit $OCF_SUCCESS
		;;
	usage|help) scsi_reserve_usage
		exit $OCF_SUCCESS
		;;
	*)
		;;
esac		
	

scsi_reserve_validate ()
{

    # check for sg_persist command provided by sg3_utils package
    #FIXME: should also check if the devices support scsi-3 as well
    if ! sg_persist -V &> /dev/null ; then
      ocf_log err	"unable to exec sg_persist"
      return $OCF_ERR_INSTALLED
    fi

	if [ -z "${OCF_RESKEY_sharedisk}" ]; then
		exit $OCF_SUCCESS
	fi	
    # if sharedisk is not empty, we default to all pvs belong to all clusterd vgs
	# if it's defined, but not a block device. then it's wrong
	if [ ! -b "${OCF_RESKEY_sharedisk}" ]; then
		exit $OCF_ERR_ARGS
	fi

}

scsi_reserve_validate

get_scsi_devices ()
{
  echo $OCF_RESKEY_sharedisk | grep -q "^/dev"
  rc=$?
  if [ $rc -eq 0 ]; then
    echo $OCF_RESKEY_sharedisk
    return 0
  fi
  if [ -z "${OCF_RESKEY_sharedisk}" ]; then
    echo $( vgs --config 'global { locking_type = 0 }' \
                    --noheadings -o vg_attr,pv_name 2> /dev/null \
              | awk ' $1 ~ /.*c$/ { print $2 } ' )
    return 0
  fi
  echo $( vgs --config 'global { locking_type = 0 }' \
                    --noheadings -o vg_attr,pv_name ${OCF_RESKEY_sharedisk} 2> /dev/null \
              | awk ' $1 ~ /.*c$/ { print $2 } ' )
}

# get physical volumes (devices) that are part of cluster volumes
#
scsi_devices=$(get_scsi_devices)

if [ -z "$scsi_devices" ] ; then
    ocf_log info "did not find devices in cluster volumes"
    exit 1
fi

# generate unique key
#FIXME: actually, we simple use the first 8 characters from host's uuid
#do we have better alternative ?
key=$( crmadmin -N | grep `uname -n` | awk '{print $4}' | sed "s/(//" | awk -F'-' '{print $1}' )

if [ -z "$key" ] ; then
    ocf_log info "unable to generate key"
    exit 1
fi

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

scsi_reserve_start ()
{

	error=0
	count=0

	ocf_log info "Starting scsi_reserve:"

	for dev in $scsi_devices
	do
	  # check if our key is already resgistered with this device
	  if sg_persist -n -d $dev -i -k | grep -qiE "^[[:space:]]*0x$key" ; then
	      ocf_log info "already registered with $dev (key=0x$key)"
	      continue
	  fi

	  # create the scsi registration
	  if ! sg_persist -n -d $dev -o -I -S $key &> /dev/null ; then
	      ocf_log err "unable to register device $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  else
		  ocf_log info "registered with device $dev (key=0x$key)"
	  fi

	  # check to see if reservation already exists
	  if sg_persist -n -d $dev -i -r | grep -qiE "^[[:space:]]*Key=0x" ; then
	      ocf_log info "reservation already exists on $dev"
	      continue
	  fi

	  # create the scsi reservation
	  if ! sg_persist -n -d $dev -o -R -K $key -T 5 &> /dev/null ; then
		  ocf_log err "unable to create reservation on $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  fi
	done

	if [ $error -ne 0 ]; then
		return $OCF_SUCCESS
	fi
	return $OCF_ERR_GENERIC
}

scsi_reserve_stop ()
{
	error=0
	count=0

	ocf_log info "Stopping scsi_reserve:"

	for dev in $scsi_devices
	do
	  # get list of keys registered with this device
	  #
	  key_list=$( sg_persist -n -d $dev -i -k | grep -iE "^[[:space:]]*0x" )

	  # check that our key is registered with this device
	  #
	  if ! sg_persist -d $dev -i -k | grep -qiE "^[[:space:]]*0x$key" ; then
	      ocf_log info "not registered with $dev (key=0x$key)"
	      continue
	  fi

	  # check if our key is the reservation holder
	  #FIXME: reservation holder cannot be stopped
	  #clone notify might be a good idea here
	  if sg_persist -n -d $dev -i -r 2>/dev/null | grep -qiE "$key" ; then
	      if echo "$key_list" | grep -qivE "$key" ; then
		      ocf_log err "unable to remove registration on $dev (key=0x$key)"
		  : $[ count = $count + 1 ]
		  error=1
		  continue
	      fi
	  fi

	  # remove registration for this device
	  #
	  if ! sg_persist -n -d $dev -o -G -K $key -S 0 &> /dev/null ; then
	      ocf_log err "failed to remove registration on $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  else
		  ocf_log info "removed registration on $dev (key=0x$key)"
	  fi

	done

	# report success or failure
	#
	if [ $error -eq 0 ] ; then
	    return $OCF_SUCCESS
	else
	    ocf_log info "$count errors occured during unregistration"
		return $OCF_ERR_GENERIC
	fi

}

scsi_reserve_monitor ()
{
	error=0

	for dev in $scsi_devices
	do
	  if sg_persist -n -d $dev -i -k | grep -qiE "$key" ; then
	      devices[${#devices[@]}]=$dev
	  fi
	done

	if [ -z "$devices" ] ; then
	    ocf_log debug "No registered devices found."
	else
	    ocf_log debug "Found ${#devices[@]} registered device(s):"

	    for i in "${devices[@]}"
	    do
	      ocf_log debug $i
	    done
	fi

	#FIXME: really nothing to do ?
	return $OCF_SUCCESS
}

case $__OCF_ACTION in
	start)      scsi_reserve_start
		;;
	stop)       scsi_reserve_stop
		;;
	monitor)    scsi_reserve_monitor
		;;
	validate-all)   scsi_reserve_validate
		;;
	*)      scsi_reserve_usage
	exit $OCF_ERR_UNIMPLEMENTED
	;;
esac
