#!/bin/bash
#
# clvmd - Clustered LVM Daemon init script
#
# chkconfig: - 24 76
# description: Cluster daemon for userland logical volume management tools.
#
# For Red-Hat-based distributions such as Fedora, RHEL, CentOS.
#
### BEGIN INIT INFO
# Provides:		clvmd
# Required-Start:	$local_fs
# Required-Stop:	$local_fs
# Short-Description:	This service is Clusterd LVM Daemon.
# Description:		Cluster daemon for userland logical volume management tools.
### END INIT INFO

. /etc/rc.d/init.d/functions

DAEMON=clvmd

exec_prefix=@exec_prefix@
sbindir=@sbindir@

lvm_vgchange=${sbindir}/vgchange
lvm_vgdisplay=${sbindir}/vgdisplay
lvm_vgscan=${sbindir}/vgscan
lvm_lvs=${sbindir}/lvs

CLVMDOPTS="-T30"

[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
[ -f /etc/sysconfig/$DAEMON ] && . /etc/sysconfig/$DAEMON

[ -n "$CLVMD_CLUSTER_IFACE" ] && CLVMDOPTS="$CLVMDOPTS -I $CLVMD_CLUSTER_IFACE" 

# allow up to $CLVMD_STOP_TIMEOUT seconds to clvmd to complete exit operations
# default to 10 seconds

[ -z $CLMVD_STOP_TIMEOUT ] && CLVMD_STOP_TIMEOUT=10

LOCK_FILE="/var/lock/subsys/$DAEMON"

# NOTE: replace this with vgs, once display filter per attr is implemented.
clustered_vgs() {
	${lvm_vgdisplay} 2>/dev/null | \
		awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'
}

clustered_lvs() {
	for i in $(clustered_vgs); do
		${lvm_lvs} -o lv_name --noheadings $i
	done
}

rh_status() {
	status $DAEMON
}

rh_status_q() {
	rh_status >/dev/null 2>&1
}

start()
{
	if ! rh_status_q; then
		echo -n "Starting $DAEMON: "
		daemon $DAEMON $CLVMDOPTS || return $?
		echo
	fi

	# Refresh local cache.
	#
	# It's possible that new PVs were added to this, or other VGs
	# while this node was down. So we run vgscan here to avoid
	# any potential "Missing UUID" messages with subsequent
	# LVM commands.

	# The following step would be better and more informative to the user:
	# 'action "Refreshing VG(s) local cache:" ${lvm_vgscan}'
	# but it could show warnings such as:
	# 'clvmd not running on node x-y-z  Unable to obtain global lock.'
	# and the action would be shown as FAILED when in reality it didn't.
	# Ideally vgscan should have a startup mode that would not print
	# unnecessary warnings.

	${lvm_vgscan} > /dev/null 2>&1

	action "Activating VG(s):" ${lvm_vgchange} -ayl $LVM_VGS || return $?

	touch $LOCK_FILE

	return 0
}

wait_for_finish()
{
	count=0
	while [ "$count" -le "$CLVMD_STOP_TIMEOUT" ] && \
		 rh_status_q ]; do
		sleep 1
		count=$((count+1))
	done

	! rh_status_q
}

stop()
{
	rh_status_q || return 0

	action "Deactivating clusterd VG(s):" ${lvm_vgchange} -anl ${LVM_VGS:-$(clustered_vgs)} || return $?

	action "Signaling $DAEMON to exit" kill -TERM $(pidofproc $DAEMON) || return $?

	# wait half second before we start the waiting loop or we will show
	# the loop more time than really necessary
	usleep 500000

	# clvmd could take some time to stop
	rh_status_q && action "Waiting for $DAEMON to exit:" wait_for_finish

	if rh_status_q; then
		echo -n "$DAEMON failed to exit"
		failure
		echo
		return 1
	else
		echo -n "$DAEMON terminated"
		success
		echo
	fi

	rm -f $LOCK_FILE

	return 0
}

reload() {
	rh_status_q || exit 7
	action "Reloading $DAEMON configuration: " $DAEMON -R || return $?
}

restart() {
	# if stop fails, restart will return the error and not attempt
	# another start. Even if start is protected by rh_status_q,
	# that would avoid spawning another daemon, it would try to
	# reactivate the VGs.
	stop && start
}

# See how we were called.
case "$1" in
  start)
	start
	rtrn=$?
	;;

  stop)
	stop
	rtrn=$?
	;;

  restart|force-reload)
	restart
	rtrn=$?
	;;

  condrestart|try-restart)
	rh_status_q || exit 0
	restart
	rtrn=$? 
	;;

  reload)
	reload
	rtrn=$?
	;;

  status)
	rh_status
	rtrn=$?
	if [ $rtrn = 0 ]; then
		cvgs="$(clustered_vgs)"
		echo Active clustered Volume Groups: ${cvgs:-"(none)"}
		clvs="$(clustered_lvs)"
		echo Active clustered Logical Volumes: ${clvs:-"(none)"}
	fi
	;;

  *)
	echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
	rtrn=2
	;;
esac

exit $rtrn
