#!/bin/sh -e
### BEGIN INIT INFO
# Provides:          ku-libvirt
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop libvirtd daemon
### END INIT INFO
#
# maintained by Allblue SA, Kubic Labs (IT Department) - Switzerland
# for copyright infos see /usr/share/doc/kusa/COPYRIGHT
#
# an old fashioned (NOT upstart) version of libvirt startup job,
# *reliable*, *traceable*, and that uses the good /etc/default way
# to set options (instead to manually edit *system scripts* .. the
# upstart developers must be stoned, system files SHOULD NEVER be
# changed by hands during normal admin tasks
#
set -e

PROGNAME="libvirtd"
DESC="[ku] Starting LIBVIRT Daemon"
DAEMON="/usr/sbin/libvirtd"
DEF_FILE="/etc/default/ku-libvirt"
PIDFILE="/var/run/$PROGNAME.pid"
PID=
MAKE_PIDFILE=false
START_OPTS="--start --quiet --background"
FIXED_OPTS=
DEBUGLOG="/var/log/libvirt/debug.log"

# defaults
#
START="no"
OPTS="--daemon"
SHUTDOWN_VMS_ON_STOP="false"
NEEDS_ISCSI=false

test -x $DAEMON || exit 0

. /lib/lsb/init-functions
. /etc/default/rcS

remove_stale_pidfile()
{
	local file=$1
	[ -f $file ] || return 0
	PID=`cat $file`
	kill -0 $PID 2>/dev/null || {
		debug_msg "removing stale lockfile $file (PID=$PID)"
		rm $file	# stale
		return 0
	}
	return 0
}


debug_msg()
{
	local now=`date '+%Y%m%d-%H%M%S'`
	local size=

	# cap logfile if needed
	[ -f "$DEBUGLOG" ] && {
		[ `stat --format='%s' $DEBUGLOG` -gt 102400 ] && {
			rm -f "$DEBUGLOG.old"
			mv "$DEBUGLOG" "$DEBUGLOG.old"
		}
	}
	echo "$now" "$@" >>$DEBUGLOG
	logger -p daemon.debug -t libvirt -- "$@"
}

run_virsh()
{
	# We parse the output for things like domain state;
	# make sure the output is in the language we expect.
	LANG=C virsh "$@"
}


run_pre_start()
{
	[ -d /var/run/libvirt ] || mkdir -p /var/run/libvirt
}

shutdown_vms()
{
	local uri=
	local domain=
	local delay=

	debug_msg "entering pre-stop"

	for uri in $libvirt_uris; do
		for domain in `run_virsh -c "$uri" list | awk '$3 == "running" {print $2}'`; do
			debug_msg "attempting clean shutdown of $domain"
			run_virsh -c "$uri" shutdown "$domain" >/dev/null
		done
	done

	delay=$libvirtd_shutdown_timeout
	while [ $delay -gt 0 ]; do
		for uri in $libvirt_uris; do
			if ! run_virsh -c "$uri" list | awk '$3 == "running" {exit 1}'; then
				# VMs at this URI are still running. Wait, then
				# start at the beginning looking for running VMs.
				sleep 1
				delay=`expr $delay - 1`
				continue 2
			fi
		done
		break
	done

	for uri in $libvirt_uris; do
		for domain in `run_virsh -c "$uri" list | awk '$3 == "running" {print $2}'`; do
			debug_msg "destroying $domain"
			run_virsh -c "$uri" destroy "$domain" >/dev/null
		done
	done
	debug_msg "exiting pre-stop"
}


check_iscsi_status()
{
	local devs=
	local delay="5 minutes"
	local failmsg="iscsi not ready, delaying startup by $delay"
	local retrymsg="iscsi not ready, try to login again to iscsi nodes"


	devs="`ls /dev/disk/by-path/*-iscsi-* 2>/dev/null`" || :
	debug_msg "check_iscsi_status, devices: " $devs
	[ "$devs" != "" ] && {
		sleep 2
		return 0
	}

	log_warning_msg "$retrymsg"
	iscsiadm -m node --login
	sleep 10
	devs="`ls /dev/disk/by-path/*-iscsi-* 2>/dev/null`" || :
	debug_msg "check_iscsi_status, devices: " $devs
	[ "$devs" != "" ] && {
		sleep 2
		return 0
	}

	log_failure_msg "$failmsg"
	debug_msg "$failmsg"
	exec 2>>$DEBUGLOG
	echo "/bin/sh $0 start" | at "now + $delay"
	return 1
}


# (MAIN)

# defaults
#
START=
OPTS=
NICE=
SHUTDOWN_VMS_ON_STOP=
NEED_ISCSI=
libvirtd_shutdown_timeout=30
libvirt_uris='qemu:///system lxc:///'

[ -f $DEF_FILE ] && . $DEF_FILE


# parms check

case "x$START" in
  xtrue|xyes)	START=true ;;
  xfalse|xno)	START=false ;;
  xinetd)	exit 0 ;;
  *)	log_failure_msg "'START' in $DEF_FILE must be 'true' or 'false'"
	log_failure_msg "not starting $PROGNAME daemon"
	exit 1
	;;
esac

case "x$NICE" in
  x[0-9])	NICE="--nicelevel $NICE";;
  x[1-9][0-9])	NICE="--nicelevel $NICE";;
  x)		;;
  *)	log_warning_msg "'NICE' in $DEF_FILE must be a value 0...19 (inclusive)"
	log_warning_msg "ignoring NICE now"
	;;
esac

case "x$SHUTDOWN_VMS_ON_STOP" in
  xtrue|xfalse)	;;
  *)	log_warning_msg "'SHUTDOWN_VMS_ON_STOP' in $DEF_FILE must be 'true' or 'false'"
	log_warning_msg "setting it to 'false'"
	SHUTDOWN_VMS_ON_STOP=false
	;;
esac

case "x$NEEDS_ISCSI" in
  xtrue|xfalse)	;;
  *)	log_warning_msg "'NEEDS_ISCSI' in $DEF_FILE must be 'true' or 'false'"
	log_warning_msg "setting it to 'false'"
	NEEDS_ISCSI=false
	;;
esac



export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"

do_start()
{
	$START || return 0

	$NEEDS_ISCSI && {
		check_iscsi_status || return 1
	}

	run_pre_start
	is_running && {
		debug_msg "service already running"
		return 0
	}

	local make_pidfile=

	$MAKE_PIDFILE && {
		make_pidfile="--pidfile $PIDFILE --make-pidfile"
	}

        log_daemon_msg "Starting $DESC:" "$PROGNAME"
        if start-stop-daemon $START_OPTS $make_pidfile $NICE --exec $DAEMON \
                -- $FIXED_OPTS $OPTS
	then
                log_end_msg 0
	else
                log_end_msg 1
                rm -f $PIDFILE
	fi
}


do_stop()
{
	local delay=
	local pid=`cat $PIDFILE`

	if is_running
	then
        	log_daemon_msg "Stopping $DESC:" "$PROGNAME"
		start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
        	log_end_msg $?
		delay=10
		while [ $delay -gt 0 ]; do
			ps -C $PROGNAME >/dev/null 2>/dev/null || break
			sleep 1
			delay=`expr $delay - 1`
		done
		# just in case ..
		ps -C $PROGNAME >/dev/null 2>/dev/null && kill -9 $pid
	else
		log_warning_msg "Daemon $PROGNAME is not running"
	fi
	rm -f $PIDFILE
}

is_running()
{
	if [ -f $PIDFILE ]
	then
		remove_stale_pidfile $PIDFILE
		kill -0 `cat $PIDFILE` >/dev/null 2>&1
	else
		ps -C $PROGNAME >/dev/null 2>/dev/null
		return $?
	fi
}


case "$1" in
  start)
  	do_start
  	;;
  stop)
  	$SHUTDOWN_VMS_ON_STOP && shutdown_vms
  	do_stop
	;;
  restart)
  	do_stop
	do_start
	;;
  reload|force-reload)
        #log_warning_msg "reloading $PROGNAME daemon not needed, the daemon re-reads the configs every run"
	# libvirt must be restarted to see any changes made outside his gui/interface
	do_stop
	do_start
	;;
  status)
	if is_running
	then
		echo "$PROGNAME is running (PID=$PID)"
	else
		echo "$PROGNAME is not running"
	fi
	;;
  *)
	echo "usage: /etc/init.d/$PROGNAME {start|stop|reload|force-reload|restart|status}"
	exit 1
esac

exit 0
