#!/bin/sh
#
# Copyright (c) Matthew Grant <matthewgrant5@gmail.com> 2006-2013
#               Net24 Limited, Christchurch, New Zealand 2011-2012
#       and     Voyager Internet Ltd, New Zealand, 2012-2013
#
#    This file is part of py-magcode-core.
#
#    Py-magcode-core is free software: you can redistribute it and/or modify
#    it under the terms of the GNU  General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Py-magcode-core is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU  General Public License for more details.
#
#    You should have received a copy of the GNU  General Public License
#    along with py-magcode-core.  If not, see <http://www.gnu.org/licenses/>.
#

PGVERSION=""
PGCLUSTER="dms"
PGPASSWORDFILE="/etc/dms/pgpassfile"
BIND9DYNAMICDIR="/var/lib/bind/dynamic"
PROGNAME="`basename $0`"

APACHE2_DEFAULT="/etc/default/apache2"
BIND9_EXTRA_OPTIONS=""
BIND9_DR_SERVER_OPTIONS=""
BIND9_NAMED_CONF="/etc/dms/bind/named.conf"
BIND9_DR_NAMED_CONF="/etc/dms/bind/named-dr-replica.conf"
BIND9_DEFAULT="/etc/default/bind9"
BIND9_SYSTEMD_D="/etc/systemd/system/bind9.service.d"
BIND9_DR_NAMED_REPLICA_CONF="/var/lib/dms/rsync-config/bind9-replica.conf"
DMSDMD_DEFAULT="/etc/default/dmsdmd"
DMS_CRONTAB="/etc/cron.d/dms-core"
RSYSLOG_PGSQL="/etc/rsyslog.d/pgsql.conf"
DMSDRIF_FILE="/etc/netscript/network.conf"
DMSDRIF=''
DMSDRIF_TYPE=''
DMSDRIF_FILE=''

SETTINGSFILE="/etc/dms/dr-settings.sh"

# Read in settings
[ -f "$SETTINGSFILE" ] && . "$SETTINGSFILE"

# Work out PGVERSION
get_pgversion () {
	if [ -n "$PGVERSION" ]; then
		echo "$PGVERSION"
		return 0
	fi
	local VER=`pg_lsclusters -h| grep "$PGCLUSTER" | cut -f 1 -d ' '`
	local SUPPORTED_VERS=`/usr/share/postgresql-common/supported-versions`
	if [ -n "$VER" ]; then
		if echo "$SUPPORTED_VERS" | fgrep -q "$VER"; then
			echo "$VER"
			return 0
		fi
	fi
	VER=`/usr/share/postgresql-common/supported-versions | tail -1`
	echo "$VER"
	return 0
}
PGVERSION=`get_pgversion`

# Settings that depend on configuration file
PGDATADIR="/var/lib/postgresql/${PGVERSION}/${PGCLUSTER}"
PGPIDFILE="/var/run/postgresql/${PGVERSION}-${PGCLUSTER}.pid"
PGETCDIR="/etc/postgresql/${PGVERSION}/${PGCLUSTER}"
RECOVERYCONF="${PGDATADIR}/recovery.conf"

NAMEDPIDFILE="/var/run/named/named.pid"

PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"

# Pad out BIND9 options stuff
if [ -n "$BIND9_EXTRA_OPTIONS" ] ; then
	BIND9_EXTRA_OPTIONS="$BIND9_EXTRA_OPTIONS "
fi
if [ -n "$BIND9_DR_SERVER_OPTIONS" ] ; then
	BIND9_DR_SERVER_OPTIONS="$BIND9_DR_SERVER_OPTIONS "
fi

# determine if running under systemd
UNDER_SYSTEMD=0
[ -x /bin/systemctl ] && test -d /run/systemd/system \
        && UNDER_SYSTEMD=1

do_dms_wsgi () {
	case $DMSWSGI in
	[Tt]rue|[Yy]es|[Oo]n|1)
		return 0
		;;
	*)
		return 1
		;;
	esac
}

fix_up_apache2_default () {
	if ! do_dms_wsgi; then
		return 0
	fi
	if ! egrep -q '^#?[[:space:]]*exit.*$' $APACHE2_DEFAULT; then
		local EXIT_STUFF='
# Exit inserted to turn off apache2 for DMS
#exit 0
'		
		echo "$EXIT_STUFF" >> $APACHE2_DEFAULT
	fi
}

service_do () {
	if [ $UNDER_SYSTEMD -eq 0 ]; then
		invoke-rc.d "$@"
		return $?
	else
		systemctl --quiet "$2" "$1"
		return $?
	fi
}

service_disable_apache2 () {
	[ $UNDER_SYSTEMD -gt 0 ] && systemctl --quiet disable apache2
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	perl -pe 's/^#(\s*exit\s+0.*$)/\1/' -i $APACHE2_DEFAULT
	[ $UNDER_SYSTEMD -eq 0 ] && set +x || true
}

service_enable_apache2 () {
	[ $UNDER_SYSTEMD -gt 0 ] && systemctl --quiet enable apache2
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	perl -pe 's/^(\s*exit\s+0.*$)/#\1/' -i $APACHE2_DEFAULT
	[ $UNDER_SYSTEMD -eq 0 ] && set +x || true
}

service_disable_dmsdmd () {
	[ $UNDER_SYSTEMD -gt 0 ] && systemctl --quiet disable dmsdmd
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	[ -f "$DMSDMD_DEFAULT" ] && \
		perl -pe 's/^DMSDMD_ENABLE=.*$/DMSDMD_ENABLE=false/' -i "$DMSDMD_DEFAULT"
	[ $UNDER_SYSTEMD -eq 0 ] && set +x || true
}

service_enable_dmsdmd () {
	[ $UNDER_SYSTEMD -gt 0 ] && systemctl --quiet enable dmsdmd
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	[ -f "$DMSDMD_DEFAULT" ] && \
		perl -pe 's/^DMSDMD_ENABLE=.*$/DMSDMD_ENABLE=true/' -i "$DMSDMD_DEFAULT"
	[ $UNDER_SYSTEMD -eq 0 ] && set +x || true
}

service_bind9_dr_config () {
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	perl -pe "s@^OPTIONS=.*\$@OPTIONS=\"${BIND9_EXTRA_OPTIONS}${BIND9_DR_SERVER_OPTIONS}-u bind -c ${BIND9_DR_NAMED_CONF}\"@" -i $BIND9_DEFAULT
	[ $UNDER_SYSTEMD -eq 0 ] && set +x
	[ $UNDER_SYSTEMD -eq 0 ] && return 0

	if [ ! -e "$BIND9_SYSTEMD_D" ] ; then
		mkdir "$BIND9_SYSTEMD_D"
	fi

	local BIND9_STUFF="
# Alter Bind9 start up command line
[Service]
ExecStart=
ExecStart=/usr/sbin/named -f ${BIND9_EXTRA_OPTIONS}${BIND9_DR_SERVER_OPTIONS}-u bind -c ${BIND9_DR_NAMED_CONF}
"
	echo "$BIND9_STUFF" > "${BIND9_SYSTEMD_D}/bind9_exec.conf"
	systemctl --quiet daemon-reload
	return 0
}

service_bind9_master_config () {
	[ $UNDER_SYSTEMD -eq 0 ] && set -x
	perl -pe "s@^OPTIONS=.*\$@OPTIONS=\"${BIND9_EXTRA_OPTIONS}-u bind -c ${BIND9_NAMED_CONF}\"@" -i $BIND9_DEFAULT
	[ $UNDER_SYSTEMD -eq 0 ] && set +x
	[ $UNDER_SYSTEMD -eq 0 ] && return 0

	if [ ! -e "$BIND9_SYSTEMD_D" ] ; then
		mkdir "$BIND9_SYSTEMD_D"
	fi

	local BIND9_STUFF="
# Alter Bind9 start up command line
[Service]
ExecStart=
ExecStart=/usr/sbin/named -f ${BIND9_EXTRA_OPTIONS}-u bind -c ${BIND9_NAMED_CONF}
"
	echo "$BIND9_STUFF" > "${BIND9_SYSTEMD_D}/bind9_exec.conf"
	systemctl --quiet daemon-reload
	return 0
}

do_dms_drif () {
	[ -n "$DMSDRIF" ] && return 0	
	# if DMSDRIF var empty, don't do anything
	return 1
}

get_dms_drif_type () {
	if [ -n "$DMSDRIF_TYPE" ] ; then
		echo "$DMSDRIF_TYPE"
		return 0
	fi
	# Check that dpkg is on the system
	if [ ! -x "`which dpkg`" ] ; then
		echo "$DMSDRIF_TYPE"
		return 0
	fi
	if dpkg --status netscript-2.4 2>/dev/null | grep 'Status:' | grep -q installed ; then
		echo "netscript"
		return 0
	fi
	echo "ifupdown"
	return 0
}

get_dms_drif_file () {
	local DRIF_CONF_FILE=''
	local NUM_IF=''

	if ! do_dms_drif; then
		echo ''
		return 0
	fi
	case $DMSDRIF_TYPE in
		netscript)
			DRIF_CONF_FILE=`grep -Ezrl "IF_AUTO=.*${DMSDRIF}_IPADDR" /etc/netscript/network.conf /etc/netscript/network.conf.d`
			;;
		ifupdown)
			DRIF_CONF_FILE=`grep -Ezrl "auto.*iface[[:space:]]+${DMSDRIF}" /etc/network/interfaces /etc/network/interfaces.d`
			;;
		*)
			echo "$PROGNAME: get_dms_drif_file() Bad setting for DMSDRIF_TYPE: '$DMSDRIF_TYPE'" 1>&2
			exit 2
			;;
	esac
	NUM_IF=`echo -n "$DRIF_CONF_FILE" | wc -w`
       	if [ $NUM_IF -gt 1 ]; then
		DRIF_CONF_FILE=`echo -n $DRIF_CONF_FILE | perl -pe 's/\n/ /gm'`
		echo "$PROGNAME: More than one file set for DMSDRIF_FILE: '${DRIF_CONF_FILE}'" 1>&2
		exit 2
	fi

	DMSDRIF_FILE="$DRIF_CONF_FILE"
}

# Fill out DMSDRIF variables...
DMSDRIF_TYPE=`get_dms_drif_type`
get_dms_drif_file

dms_drif_auto_up () {
	case $DMSDRIF_TYPE in
		netscript)
			set -x
			perl -pe "s/^(IF_AUTO=.*)\"\$/\1 $DMSDRIF\"/g" -i $DMSDRIF_FILE
			set +x
			;;
		ifupdown)
			perl -pe "s/^#\s*(auto\s+${DMSDRIF}\s*.*)$/\1/g" -i $DMSDRIF_FILE
			;;
		*)
			echo "$PROGNAME: dms_drif_auto_up() Bad setting for DMSDRIF_TYPE: '$DMSDRIF_TYPE'" 1>&2
			exit 2
			;;
	esac
}

dms_drif_noauto_up () {
	case $DMSDRIF_TYPE in
		netscript)
			set -x
			perl -pe "s/^(IF_AUTO.*)\s+${DMSDRIF}(.*$)/\1\2/g" -i $DMSDRIF_FILE
			# Extra line to deal with how humans can twiddle...
			perl -pe "s/^(IF_AUTO=\")${DMSDRIF}\s+(.*$)/\1\2/g" -i $DMSDRIF_FILE
			set +x
			;;
		ifupdown)
			perl -pe "s/^\s*(auto\s+${DMSDRIF}\s*.*)$/#\1/g" -i $DMSDRIF_FILE
			;;
		*)
			echo "$PROGNAME: dms_drif_noauto_up() Bad setting for DMSDRIF_TYPE: '$DMSDRIF_TYPE'" 1>&2
			exit 2
			;;
	esac
}

dms_drif_up () {
	case $DMSDRIF_TYPE in
		netscript)
			netscript ifup "$DMSDRIF"
			;;
		ifupdown)
			ifup "$DMSDRIF"
			;;
		*)
			echo "$PROGNAME: dms_drif_up() Bad setting for DMSDRIF_TYPE: '$DMSDRIF_TYPE'" 1>&2
			exit 2
			;;
	esac
}

dms_drif_down () {
	case $DMSDRIF_TYPE in
		netscript)
			netscript ifdown "$DMSDRIF"
			;;
		ifupdown)
			ifdown "$DMSDRIF"
			;;
		*)
			echo "$PROGNAME: dms_drif_down() Bad setting for DMSDRIF_TYPE: '$DMSDRIF_TYPE'" 1>&2
			exit 2
			;;
	esac
}

get_pgport () {
	grep '^port' $PGETCDIR/postgresql.conf | perl -pe 's/^.* (\d+)\s*.*$/$1/' || true
}

check_with_user () {
	if [ $1 -le 0 ]; then
		if [ -z "$2" ]; then
			echo -n "Operation will destroy all data."
		else
			echo -n "$2"
		fi
		echo -n " Proceed? (y/N)"
		read ANS
		case $ANS in
		y|Y)
			# Proceeding
			;;
		*)
			exit 1
			;;
		esac
	fi
}

dms_prepare_binddata_usage () {
	echo "Usage: [-f] $PROGNAME" 1>&2
	exit 1
}

dms_prepare_binddata () {
	local FORCE=0
	OPTIND=1
	while getopts fh F; do
		case $F in
		h)
			dms_prepare_binddata_usage
			;;
		f)
			FORCE=1
			;;
		\?)	
			dms_prepare_binddata_usage
			;;
		esac
	done	
	shift $(( $OPTIND - 1 ))

	if [ $# -ne 0 ]; then
		dms_prepare_binddata_usage
	fi
	set -e
	check_if_named_running
	check_with_user $FORCE "Operation will destroy bind9 .jnl files."
	# Fix bind9-recovery.conf missing
	if [ ! -f "$BIND9_DR_NAMED_REPLICA_CONF" ]; then
		touch "$BIND9_DR_NAMED_REPLICA_CONF"
		chown bind:bind "$BIND9_DR_NAMED_REPLICA_CONF"
	fi
	# Remove journal files and chown zone files so that DR replica 
	# secondary will update zone files
	# * is needed in following ls - watch it!  Its to detect if files
 	# exist in the directory
	if ls -1 ${BIND9DYNAMICDIR}/* > /dev/null 2>&1; then 
		find ${BIND9DYNAMICDIR}/ -name '*.jnl' -print0 | xargs -n 10000 -0 rm -f
		find ${BIND9DYNAMICDIR}/ -type f -print0 | xargs -n 10000 -0 chown bind:dmsdmd
		find ${BIND9DYNAMICDIR}/ -type f -print0 | xargs -n 10000 -0 chmod 644
	fi
}

rsyslog_restart () {
	service_do rsyslog stop
	sleep 3
	service_do rsyslog start
}

turn_on_replica_services () {
	do_dms_drif && dms_drif_noauto_up
	service_disable_dmsdmd
	do_dms_wsgi && service_disable_apache2
	set -x
	perl -pe 's/^(local7.* :ompgsql:\S+,dms,rsyslog,.*$)/#\1/' -i $RSYSLOG_PGSQL
	perl -pe 's/^([^#].*zone_tool vacuum_all)$/#\1/' -i $DMS_CRONTAB
	set +x
	service_bind9_dr_config
}

dms_start_as_replica_usage () {
	echo "$PROGNAME: [-f] [master-server]" 1>&2
	exit 1
}

dms_start_as_replica () {
	local FORCE=0
	OPTIND=1
	while getopts fh F; do
		case $F in
		h)
			dms_start_as_replica_usage
			;;
		f)
			FORCE=1
			;;
		\?)	
			dms_start_as_replica_usage
			;;
		esac
	done	
	shift $(( $OPTIND - 1 ))

	if [ $# -ne 1 -a $# -ne 0 ]; then
		dms_start_as_replica_usage
	fi;

	if [ -n "$1" ]; then
		local MASTER_SERVER="$1"
	elif [ -n "$DR_PARTNER" ]; then
		local MASTER_SERVER="$DR_PARTNER"
	else
		echo "$PROGNAME: No master server given to replicate from." 1>&2
		exit 2
	fi

	set -e
	check_if_pgsql_running
	echo "$PROGNAME: Will replicate from '$MASTER_SERVER'"
	check_with_user $FORCE
	fix_up_apache2_default
	echo "$PROGNAME: replicating from '$MASTER_SERVER'"
	dms_pg_basebackup -f "$MASTER_SERVER"
	dms_prepare_binddata -f
	dms_write_recovery_conf "$MASTER_SERVER"
	do_dms_drif && dms_drif_down
	do_dms_wsgi && service_do apache2 stop
	service_do dmsdmd stop
	turn_on_replica_services
	service_do postgresql start
	service_do bind9 start
}


dms_promote_replica_usage () {
	echo "Usage: $PROGNAME" 1>&2
	exit 1
}

dms_promote_replica () {
	
	if [ $# -ne 0 ]; then
		dms_promote_replica_usage
	fi;

	set -e
	fix_up_apache2_default
	pg_ctlcluster $PGVERSION $PGCLUSTER promote
	set -x
	perl -pe 's/^#(\s*local7.* :ompgsql:\S+,dms,rsyslog,.*$)/\1/' -i $RSYSLOG_PGSQL
	set +x
	rsyslog_restart
	service_enable_dmsdmd
	service_bind9_master_config
	service_do bind9 restart
	# Settle time
	sleep 7
	service_do dmsdmd start
	set -x
	zone_tool write_rndc_conf
	zone_tool reconfig_all
	perl -pe 's/^#+(.*zone_tool vacuum_all)$/\1/' -i $DMS_CRONTAB
	do_dms_wsgi && service_enable_apache2
	set +x
	if do_dms_wsgi; then
		service_do apache2 start
	fi
	do_dms_drif && dms_drif_auto_up
	do_dms_drif && dms_drif_up
	# dms_update_wsgi_dns done in dmsdmd init script
}

dms_master_down_usage () {
	echo "Usage: $PROGNAME" 1>&2
	exit 1
}

dms_master_down () {

	if [ $# -ne 0 ]; then
		dms_master_down_usage
	fi;

	set -e
	fix_up_apache2_default
	do_dms_drif && dms_drif_down
	if do_dms_wsgi; then
		service_do apache2 stop
	fi
	do_dms_wsgi && service_disable_apache2
	do_dms_drif && dms_drif_noauto_up
	set -x
	perl -pe 's/^([^#].*zone_tool vacuum_all)$/#\1/' -i $DMS_CRONTAB
	set +x
	# Settle time
	sleep 5
	service_do dmsdmd stop
	service_do bind9 stop
	set -x
	perl -pe 's/^(local7.* :ompgsql:\S+,dms,rsyslog,.*$)/#\1/' -i $RSYSLOG_PGSQL
	set +x
	rsyslog_restart
	service_do postgresql stop
	service_disable_dmsdmd
	service_bind9_dr_config
}

dms_master_up_usage () {
	echo "Usage: $PROGNAME" 1>&2
	exit 1
}

dms_master_up () {

	if [ $# -ne 0 ]; then
		dms_master_up_usage
	fi;

	set -e
	fix_up_apache2_default
	service_enable_dmsdmd
	service_bind9_master_config
	set -x
	perl -pe 's/^#(\s*local7.* :ompgsql:\S+,dms,rsyslog,.*$)/\1/' -i $RSYSLOG_PGSQL
	set +x
	service_do postgresql start
	rsyslog_restart
	service_do bind9 start
	sleep 3
	service_do dmsdmd start
	# Settle time
	sleep 5
	set -x
	zone_tool write_rndc_conf
	zone_tool reconfig_all
	perl -pe 's/^#+(.*zone_tool vacuum_all)$/\1/' -i $DMS_CRONTAB
	do_dms_wsgi && service_enable_apache2
	set +x
	if do_dms_wsgi; then
		service_do apache2 start
	fi
	do_dms_drif && dms_drif_auto_up
	do_dms_drif && dms_drif_up
	dms_update_wsgi_dns

}

do_dms_drdns () {
	case $DMSDRDNS in
	[Tt]rue|[Yy]es|[Oo]n|1)
		return 0
		;;
	*)
		return 1
		;;
	esac
}


dms_update_wsgi_dns_usage () {
	echo "Usage: $PROGNAME" 1>&2
	exit 1
}


dms_update_wsgi_dns () {
	local DMS_SERVER

	if [ $# -ne 0 ]; then
		dms_update_wsgi_dns_usage
	fi;

	set -e

	if ! do_dms_drdns; then
		exit 0
	fi

	# Fill in update template
	if [ -z "$DMS_MASTER" ]; then
		DMS_SERVER="`hostname -f`."
	else
		DMS_SERVER="$DMS_MASTER"
	fi
	if echo "${DMS_FAILOVER_DOMAIN}" | grep -q '[^.]$'; then
		DMS_FAILOVER_DOMAIN="${DMS_FAILOVER_DOMAIN}."
	fi
	local UPDATE_TEXT="`echo "$DMS_UPDATE_RRS_TEMPLATE" | \
		perl -pe "s/\@\@DMS_MASTER\@\@/${DMS_SERVER}/g" |\
		perl -pe "s/\@\@DMS_FAILOVER_DOMAIN\@\@/${DMS_FAILOVER_DOMAIN}/g" |\
		perl -pe "s/\@\@DMS_WSGI_LABEL\@\@/${DMS_WSGI_LABEL}/g" |\
		perl -pe "s/\@\@DMS_WSGI_TTL\@\@/${DMS_WSGI_TTL}/g"`"

	echo "$UPDATE_TEXT" | zone_tool update_rrs -
}


check_if_pgsql_running () {

	if [ -f $PGPIDFILE ] && kill -0 `cat $PGPIDFILE` > /dev/null 2>&1; then
		echo 1>&2
		echo "  `basename $0`: postgresql is active - already master or replica?" 1>&2
		echo 1>&2
		exit 123
	fi
}

check_if_named_running () {

	if [ -f $NAMEDPIDFILE ] && kill -0 `cat $NAMEDPIDFILE` > /dev/null 2>&1; then
		echo 1>&2
		echo "  `basename $0`: named is active - already master or replica?" 1>&2
		echo 1>&2
		exit 123
	fi
}

# bail out if we are not root
if [ "`id -un`" != "root" ] ; then
        echo 1>&2
        echo "  `basename $0`: you must be root to run this command." 1>&2
        echo 1>&2
        exit 1
fi


case $PROGNAME in
        dms_start_as_replica)
		dms_start_as_replica "$@"
		;;
	dms_prepare_binddata)
		dms_prepare_binddata "$@"
		;;
	dms_update_wsgi_dns)
		dms_update_wsgi_dns "$@"
		;;
	dms_promote_replica)
		dms_promote_replica "$@"
		;;
	dms_master_down)
		dms_master_down "$@"
		;;
	dms_master_up)
		dms_master_up "$@"
		;;
	*)
		echo "$PROGNAME: Blowing up !@#$^%#&" 1>&2
		exit 123
		;;
esac

