#!/bin/bash

LIZARDFS_URAFT_OK=0
LIZARDFS_URAFT_ERROR=1
LIZARDFS_DATA_DIR="/var/lib/mfs"
METADATA_LOCK="/var/lib/mfs/metadata.mfs.lock"
LIZARDFS_URAFT_CONFIG="/etc/mfs/lizardfs-uraft.cfg"
LIZARDFS_MASTER_CONFIG="/etc/mfs/mfsmaster.cfg"

metadata_location=


print_missing_config() {
	echo "$1 file is missing, it looks like a clean installation."
	echo "You can use example configuration and fill it with appropriate data:"
	echo "cp 'usr/share/doc/lizardfs-uraft/examples/$1' '/etc/mfs/$1'"
	exit $LIZARDFS_URAFT_ERROR
}

load_config() {
	if [ -f $LIZARDFS_MASTER_CONFIG ] ; then
		. <(sed "s:\ *=\ *:=:g" $LIZARDFS_MASTER_CONFIG | grep "ADMIN_PASSWORD")
		. <(sed "s:\ *=\ *:=:g" $LIZARDFS_MASTER_CONFIG | grep "DATA_PATH")
	else
		print_missing_config $LIZARDFS_MASTER_CONFIG
	fi

	if [ -f $LIZARDFS_URAFT_CONFIG ] ; then
		. <(sed "s:\ *=\ *:=:g" $LIZARDFS_URAFT_CONFIG)
	else
		print_missing_config $LIZARDFS_URAFT_CONFIG
	fi

	matocl_host=${LOCAL_MASTER_ADDRESS:=0}
	matocl_port=${LOCAL_MASTER_MATOCL_PORT:=9421}

	ipaddr=$(getent hosts ${URAFT_FLOATING_IP} | awk '{print $1}')
	netmask=${URAFT_FLOATING_NETMASK}
	iface=${URAFT_FLOATING_IFACE}

	ipaddr2=${URAFT_FLOATING_IP_SECONDARY:=}
	netmask2=${URAFT_FLOATING_NETMASK_SECONDARY:=}
	iface2=${URAFT_FLOATING_IFACE_SECONDARY:=}

	LIZARDFS_DATA_DIR=${DATA_PATH:="/var/lib/mfs"}

	if [[ $ipaddr == "" || $netmask == "" || $iface == "" ]] ; then
		echo "Configuration file $LIZARDFS_URAFT_CONFIG does not contain valid network information."
		echo "See example usr/share/doc/lizardfs-uraft/examples/lizardfs-uraft.cfg file for reference."
		exit $LIZARDFS_URAFT_ERROR
	fi

	if [[ ! $ADMIN_PASSWORD ]] ; then
		echo "LizardFS admin password must be set in order to authenticate to master server."
		echo "See example usr/share/doc/lizardfs-master/examples/mfsmaster.cfg file for reference."
		exit $LIZARDFS_URAFT_ERROR
	fi
}

log() {
	logger -t lizardfs-uraft $@
}

lizardfs_master() {
	mfsmaster -o ha-cluster-managed "$@"
}

lizardfs_admin() {
	lizardfs-admin "$@"
}

get_metadata_version_from_file() {
	local version=$(/usr/sbin/mfsmetarestore -g -d "${LIZARDFS_DATA_DIR}" | grep -v warn 2> /dev/null)
	if [[ $? == 0 && ${version} =~ ^[0-9]+$ ]]; then
		echo -n "${version}"
	else
		echo -n 0
	fi
}

lizardfs_promote() {
	lizardfs_metadata_version 2> /dev/null
	if [[ ${metadata_location} == "disk" ]] ; then
		log "metadata is on disk instead of ram"
		lizardfs_master stop
		unlink "${METADATA_LOCK}"
		lizardfs_master -o initial-personality=master -o auto-recovery restart
		if [[ $? != 0 ]]; then
			log "promotion to master failed"
			exit $LIZARDFS_URAFT_ERROR
		fi
	else
		echo -n "${ADMIN_PASSWORD}" | \
			lizardfs_admin promote-shadow "${matocl_host}" ${matocl_port}
	fi
	lizardfs_assign_ip
}

lizardfs_demote() {
	# drop ip
	lizardfs_drop_ip
	# restart shadow
	lizardfs_master -o initial-personality=shadow restart
}

lizardfs_quick_stop() {
	echo -n "${ADMIN_PASSWORD}" | \
			lizardfs_admin stop-master-without-saving-metadata "${matocl_host}" ${matocl_port}
}

lizardfs_metadata_version() {
	# metadata-version can take arguments or read config file
	if [[ $# == 3 ]] ; then
		matocl_host=$2
		matocl_port=$3
	else
		load_config
	fi
	local probe_result=$(lizardfs_admin metadataserver-status --porcelain "${matocl_host}" "$matocl_port")
	if [[ $? != 0 ]] ; then
		log "failed to query LizardFS master status"
		return $LIZARDFS_URAFT_ERROR
	fi
	local personality=$(echo "$probe_result" | cut -f1)
	local connection=$(echo "$probe_result" | cut -f2)
	local metadata_version_in_ram=$(echo "$probe_result" | cut -f3)
	case "$personality/$connection" in
		master/running)
			metadata_location="ram"
			echo -n ${metadata_version_in_ram}
			return $LIZARDFS_URAFT_OK
		;;
		shadow/connected|shadow/disconnected)
			if (( metadata_version_in_ram > 0 )) ; then
				metadata_location="ram"
				echo -n ${metadata_version_in_ram}
				return $LIZARDFS_URAFT_OK
			else
				local metadata_version_on_disk=$(get_metadata_version_from_file)
				# Failing to read version from file results in metadata version 0,
				# which means that no metadata is available.
				metadata_location="disk"
				echo -n ${metadata_version_on_disk}
				return $LIZARDFS_URAFT_OK
			fi
		;;
		*)
			log "unexpected output from lizardfs-admin: $probe_result"
			return $LIZARDFS_URAFT_OK
		;;
	esac
}

lizardfs_isalive() {
	lizardfs_master isalive
	if [[ $? == 0 ]] ; then
		echo -n alive
	else
		echo -n dead
	fi
}

lizardfs_assign_ip() {
	load_config
	sudo ip -f inet addr add $ipaddr/$netmask dev $iface
	iface_base=$(echo $iface | cut -f1 -d':') # for alias handling
	arping -q -U -c5 -w1 $ipaddr -I $iface_base

	if [[ "$ipaddr2" != "" ]]; then
		sudo ip -f inet addr add $ipaddr2/$netmask2 dev $iface2
		iface_base2=$(echo $iface2 | cut -f1 -d':') # for alias handling
		arping -q -U -c5 -w1 $ipaddr2 -I $iface_base2
	fi
}

lizardfs_drop_ip() {
	load_config
	sudo ip -f inet addr delete $ipaddr/$netmask dev $iface
	if [[ "$ipaddr2" != "" ]]; then
		sudo ip -f inet addr delete $ipaddr2/$netmask2 dev $iface2
	fi
}

lizardfs_dead() {
	lizardfs_drop_ip
}

print_help() {
	echo "LizardFS uraft helper script"
	echo "Available commands:"
	echo "isalive"
	echo "metadata-version"
	echo "quick-stop"
	echo "promote"
	echo "demote"
	echo "assign-ip"
	echo "drop-ip"
	echo "dead"
}

case "$1" in
	isalive)           lizardfs_isalive;;
	metadata-version)  lizardfs_metadata_version $@;;
	quick-stop)        lizardfs_quick_stop;;
	promote)           lizardfs_promote;;
	demote)            lizardfs_demote;;
	assign-ip)         lizardfs_assign_ip;;
	drop-ip)           lizardfs_drop_ip;;
	dead)              lizardfs_dead;;
	*)                 print_help;;

esac
