#!/bin/bash

CONFIG_DIR="/etc/vstorage"
CLUSTERS_DIR="${CONFIG_DIR}/clusters"
LOG_COMPRESS="zst"
VSTORAGE_SHM_DIR=/dev/shm/vstorage
LOG_FILE=/dev/null

load_config() 
{
	# check control dir
	if [ ! -d "$DAEMON_DIR/$CONTROL_DIR" ]; then
		echo "Folder $DAEMON_DIR/$CONTROL_DIR not found"
		#exit 1
	fi

	# load cluster config, it can use environment variables
	[ -f "${CONFIG_DIR}/$CONFIG_FILE" ] && source "${CONFIG_DIR}/$CONFIG_FILE"
	[ -f "${CONFIG_DIR}/service.config" ] && source "${CONFIG_DIR}/service.config"
	[ -f "${CLUSTER_DIR}/$CONFIG_FILE" ] && source "${CLUSTER_DIR}/$CONFIG_FILE"
	[ -f "${DAEMON_DIR}/$CONTROL_DIR/$CONFIG_FILE" ] && source "${DAEMON_DIR}/$CONTROL_DIR/$CONFIG_FILE"

	return 0
}

check_host_id()
{
	repo_host_id=$(cat "$1" 2>>$LOG_FILE)
	if [ -z "$repo_host_id" ]; then
		echo "Can't read host_id from $1" 1>&2
		exit 1
	fi

	host_id=$(cat /etc/vstorage/host_id 2>>$LOG_FILE)
	if [ -z "$host_id" ]; then
		echo "Unable read host_id" 1>&2
		exit 1
	fi

	if [ "$host_id" != "$repo_host_id" ] ; then
		echo "Wrong host ID '$repo_host_id'" 1>&2
		exit 1
	fi

	return 0
}

is_log_valid()
{
	[ -L "$DAEMON_DIR/logs" ] || return 1
	[ -d "$DAEMON_DIR/logs" ] || return 1
	return 0
}

get_log_files()
{
	if ! is_log_valid; then
		mkdir -p "$LOG_DIR"
		mktemp -d "$LOG_DIR/$SERVICE-XXXXXXXX" | if read logdir; then
			ln -sf "$logdir" "$DAEMON_DIR/logs"
		else
			return 1
		fi
	fi
	dir=$(readlink -f "$DAEMON_DIR/logs")
	[ -L "$dir/.repo" ] && rm -f "$dir/.repo"
	chgrp $(id -g "$VSTORAGE_USER") "$dir" &&
	chmod g+rwx "$dir" || return 1
	LOG_DIR="$DAEMON_DIR/logs"
	FATAL_FILE="$LOG_DIR/fatal.log"
}

make_dir() 
{
        local dir=$1
        [ -d "$dir" ] && return 0

        mkdir -p "$dir" && chgrp $(id -g "$VSTORAGE_USER") "$dir" &&
                chmod g+rwx "$dir" || return 1

        return 0
}

delete_repo()
{
	MSG="was deleted"
	SEV="-i"
	/usr/bin/vstorage -q -c "$CLUSTER_NAME" --timeout=10 rm-"$SERVICE" --local "$DAEMON_DIR"

	start_locate_repo_disk "$DAEMON_DIR"
}

check_dropped()
{
	dropped=
	[ -f "$DAEMON_DIR/control/.dropped" ] && dropped=yes
	[ -f "$DAEMON_DIR/.dropped" ] && dropped=yes

	if [ "$dropped" ]; then
		delete_repo
	fi
}


prepare_msg()
{
	if [ "$RUN" -eq 1 ]; then
		case "$EXIT_CODE" in
			0) # ok
				MSG="restarted"
				SEV="-i"
				;;
			*) # error
				MSG="died unexpectedly"
				;;
		esac
	else
		rl=$(runlevel | awk '{print $2}')
		MSG="was stopped"
		SEV="-w"
		[ -f "$PID_DIR/stop-reason" ] && MSG="$MSG "$(cat "$PID_DIR/stop-reason" 2>>$LOG_FILE) ||
		case "$rl" in
			0) # halt
				MSG="$MSG during host halt"
				;;
			6) # reboot
				MSG="$MSG during host reboot"
				;;
		esac
	fi
}

start_locate_repo_disk() {
	DAEMON_DIR="$1"
	/usr/bin/vstorage locate-disk "$DAEMON_DIR" >>$LOG_FILE 2>&1
}

stop_locate_repo_disk() {
	DAEMON_DIR="$1"
	/usr/bin/vstorage locate-disk -S "$DAEMON_DIR" >>$LOG_FILE 2>&1
}

get_preload_libs()
{
	local result
	result=""
	if [ ! -f "$CONFIG_DIR/.no-tcmalloc" -a -f /usr/lib64/libtcmalloc.so.4 ]; then
		result="/usr/lib64/libtcmalloc.so.4"
	fi
	echo "$result"
}

start_daemon() 
{	
	make_dir $VSTORAGE_SHM_DIR
	make_dir "$VSTORAGE_SHM_DIR/$CLUSTER_NAME"

	AUTH_OPT=""
	[ -n "$SECURE_AUTH" ] && AUTH_OPT="-a $SECURE_AUTH"

	LOG_ROTATION_OPT=""
	[ -n "$LOG_ROTATION" ] && LOG_ROTATION_OPT="-L $LOG_ROTATION"

	VERBOSITY_OPT=""
	[ -n "$VERBOSITY_LEVEL" ] && VERBOSITY_OPT="-d $VERBOSITY_LEVEL"

	[ -n "$LIMIT_NUM_FILES" ] && ulimit -n $LIMIT_NUM_FILES >>$LOG_FILE 2>&1
	[ -n "$LIMIT_MEM_LOCKED" ] && ulimit -l $LIMIT_MEM_LOCKED >dev/null 2>&1

	RDMA_OPT=""
	[ "$DAEMON_NAME" = "csd" -a "x$USE_RDMA" = "xyes" ] && RDMA_OPT="--rdma"

	LOG_MULTIPROC_OPT=""
	[ "x$LOG_MULTIPROC" = "xyes" ] && LOG_MULTIPROC_OPT="--log-multiproc"

	LD_PRELOAD="$(get_preload_libs)" "$DAEMON" -r "$DAEMON_DIR" --log-dir "$LOG_DIR" --log-prefix "$SERVICE" --log-compression "$LOG_COMPRESS" $LOG_MULTIPROC_OPT -u "$VSTORAGE_USER" $AUTH_OPT $LOG_ROTATION_OPT $VERBOSITY_OPT $RDMA_OPT >> "$FATAL_FILE" 2>&1 &

	PID=$!
	echo $PID > "$PID_FILE"

	echo -n $$ "started $SERVICE $PID " >>$LOG_FILE
	date >>$LOG_FILE

	stop_locate_repo_disk "$DAEMON_DIR"

	echo "$SERVICE started with pid $PID"
}

setup_scheduling()
{
	local NCPU=$(nproc)
	[ "$NO_SCHED_CPUS" = "" ] && NO_SCHED_CPUS="2"

	if [ "$NCPU" -gt "$NO_SCHED_CPUS" ] ; then
		# configure CPU affinity
		if [ "$CPU_LIST" != "" ] ; then
			if [ "$CPU_LIST" = "auto" ] ; then
				if [ "$NCPU" -lt 5 ] ; then
					CPU_LIST="0-1"
				else
					CPU_LIST="0-3"
				fi
			fi
			taskset -pc $CPU_LIST $$ 2>>$LOG_FILE 1>&2
		fi

		# configure real time scheduling if necessary
		if [ "$RT_SCHED" != "" ] ; then
			if [ "$RT_PRIO" = "" ] ; then
				RT_PRIO="1"
			fi
			chrt -$RT_SCHED --pid $RT_PRIO $$ 2>>$LOG_FILE
		fi
	fi
}

init_env() {
	SERVICE=$(basename "$DAEMON_NAME" d)
	case "$SERVICE" in
		  mds)
			CONTROL_DIR="."
			;;
		  cs)
			CONTROL_DIR="control"
			;;
		  *)
			echo "Unknown service $SERVICE"
			exit 1
	esac

	CLUSTER_DIR="${CLUSTERS_DIR}/$CLUSTER_NAME"
	DAEMON="/usr/bin/$DAEMON_NAME"
	CLUSTERS_DIR="${CONFIG_DIR}/clusters"
	CONFIG_FILE="${SERVICE}.config"
	PID_DIR="${DAEMON_DIR}/$CONTROL_DIR"
	PID_FILE="$PID_DIR/${DAEMON_NAME}.pid"
	SERVICE_UPPER=$(echo "$SERVICE" | tr [:lower:] [:upper:])
	EXITMSG_FILE="$DAEMON_DIR/.exit.msg"

	[ -f "$DAEMON_DIR/control/id" ] && SERVICEID=$(cat "$DAEMON_DIR/control/id" 2>>$LOG_FILE)
	[ -f "$DAEMON_DIR/id" ] && SERVICEID=$(cat "$DAEMON_DIR/id" 2>>$LOG_FILE)

	if ! load_config "$CLUSTER_DIR" "$DAEMON_DIR"; then
		exit 1;
	fi

	# initialize non-essential vars if necessary
	[ -z "$VSTORAGE_USER" ] && VSTORAGE_USER="vstorage"
	[ -z "$LOG_DIR" ] && LOG_DIR="/var/log/vstorage/${CLUSTER_NAME}"

	echo -n $$ "---------------------- " >>$LOG_FILE
	date >>$LOG_FILE
	echo "$@" >>$LOG_FILE

	if [ -x /sbin/virt-what ] ; then
		VIRT_WHAT=$(/sbin/virt-what 2>>$LOG_FILE)
		export VIRT_WHAT
	fi
}

report()
{
	if [ "$#" -ne 6 ]; then
		echo "Usage: $0 report CLUSTER DAEMON PATH LEVEL MSG"
		exit 1
	fi

	init_env "$@"

	SEV="$5"
	MSG="$6"

	check_dropped

	MSG="$SERVICE_UPPER#$SERVICEID ${MSG}"
	if [ -f "$EXITMSG_FILE" ]; then
		MSG="$MSG: "$(cat "$EXITMSG_FILE" 2>>$LOG_FILE)
	fi
	# send message to event log
	/usr/bin/vstorage -q -c "$CLUSTER_NAME" --timeout=5 put-event "$SEV" -s monitor "$MSG" 2>>$LOG_FILE

	echo -n $$ "completed successfully " >>$LOG_FILE
	date >>$LOG_FILE
	exit 0
}

vz_sysctl_enable() {
	local fname="$1"

	[ -f "$fname" ] &&
	if [ x$(cat "$fname" 2>>$LOG_FILE) != x1 ]; then
		echo "1" 2>>$LOG_FILE >"$fname" && return 0
		echo "Failed to fix sysctl $fname!"
		return 1
	fi
	return 0
}

vz_init() {
	# check if we are on a VZ-enabled machine
	[ -d /proc/vz ] || return 0
	# check if we are inside a VE
	[ ! -f /proc/vz/version ] || return 0
	# try to enable sysctls
	vz_sysctl_enable /proc/sys/fs/fsync-enable &&
	vz_sysctl_enable /proc/sys/fs/odirect_enable
}

prestart_hook() {
	if [ "$SERVICE" == "cs" ] ; then
		vz_init
	elif [ "$SERVICE" == "mds" ] ; then
		#do notnhing
		:
	fi
}

start_service()
{
	if [ "$#" -ne 4 ]; then
		echo "Usage: $0 start CLUSTER DAEMON PATH"
		exit 1
	fi

	init_env "$@"
	setup_scheduling

	echo "Starting ${SERVICE} service ${CLUSTER_NAME}:${DAEMON_DIR}"

	# check that DAEMON_DIR exists and is not marked for deletion
	if [ -d "$DAEMON_DIR" -a "$(ls -A "$DAEMON_DIR")" ]; then
		if [ -e "$DAEMON_DIR/.deleted" ]; then
			echo "Repository marked as deleted"
			delete_repo
			exit 1
		fi

		if [ ! -f "$DAEMON_DIR/control/location" ]; then
			if [ -f "$DAEMON_DIR/control/host_id" ]; then
				check_host_id "$DAEMON_DIR/control/host_id" "$DAEMON_DIR"
			fi
		fi
	else
		echo "Directory $DAEMON_DIR doesn't exists"
		exit 1
	fi

	if ! get_log_files; then
		echo "Failed to init log files"
		exit 1;
	fi

	prestart_hook
	start_daemon "$@"

	echo -n "completed successfully " >>$LOG_FILE
	date >>$LOG_FILE
	exit 0
}

handle_service()
{
	if [ "$#" -ge 4 ]; then
		CLUSTER_NAME=$2
		DAEMON_NAME=$3
		DAEMON_DIR=$4

		test_cl=
		arg="$CLUSTER_NAME"
		[ x"$arg" = x$(basename "$arg") -a -d "${CLUSTERS_DIR}/$arg" ] && test_cl=yes
		if [ ! "$test_cl"  ]; then
			echo "No such cluster or path: $arg"
			exit 1
		fi

		test_daemon=
		arg="$DAEMON_NAME"
		[ "$arg" == "csd" -o "$arg" == "mdsd" ] && test_daemon=yes
		if [ ! "$test_daemon"  ]; then
			echo "Unknown daemon: $arg"
			exit 1
		fi
		
		test_daemon_dir=
		arg="$DAEMON_DIR"
		[ -d "$arg" ] && test_daemon_dir=yes
		if [ ! "$test_daemon_dir" ]; then
			echo "No such path: $arg"
			exit 1
		fi

		case "$1" in
		  start)
			start_service "$@"
			;;
		  report)
			report "$@"
			;;
		  *)
			echo "Unknown command."
			echo "Usage: $0 {start|report} CLUSTER DAEMON PATH [OPTIONS...]"
			exit 1
		esac
	else
			echo "Usage: $0 {start|report} CLUSTER DAEMON PATH [OPTIONS...]"		
			exit 1;
	fi
}

handle_service "$@"
