#!/bin/bash
#
# HA-Step: 1
#
# ha-config
#
# This script is executed when the user presses the Save button on the
# Automatic Failover Config panel.
#
# If needed, the script will perform the following tasks:
#    1. Update the hostname to the proper format
#    2. Change the IP address to the private cluster address
#    3. Change the server IP address to the shared IP address
#
# (C) Copyright 2020-2024, Bogen Communications LLC. All rights reserved.
#

function itoa
{
	#returns the dotted-decimal ascii form of an IP arg passed in integer format
	echo -n $(($(($(($((${1}/256))/256))/256))%256)).
	echo -n $(($(($((${1}/256))/256))%256)).
	echo -n $(($((${1}/256))%256)).
	echo $((${1}%256))
}

# Make sure PATH includes /sbin
if [[ $PATH != *"/sbin"* ]]; then
	export PATH="$PATH:/sbin:/usr/sbin"
fi

SCRIPT_DEBUG=0

if [ $SCRIPT_DEBUG -eq 1 ]; then
	CMD_OUTPUT="/dev/stdout"
	function debug_out { echo $@; }
else
	CMD_OUTPUT="/var/log/nyquist_af_setup.log"
	function debug_out { echo $@ &>> $CMD_OUTPUT; }
fi

echo $(date) Started: $0 $@ >> $CMD_OUTPUT

read -d . DEBIAN_VERSION < /etc/debian_version

if [ $# -eq 7 ]; then
	CLUSTER_PWD="$1"
	CLUSTER_NAME="$2"
	CLUSTER_SHARED_IP="$3"
	CLUSTER_MASTER_IP="$4"
	CLUSTER_MASTER_HOST="$5"
	CLUSTER_SLAVE_IP="$6"
	CLUSTER_SLAVE_HOST="$7"
else
	#
	# Call ha-get-config to get the following variables:
	#
	#   CLUSTER_NAME                "Nyquist"
	#   CLUSTER_PWD                 hacluster user's password
	#   CLUSTER_MODE                Clusters current mode
	#   CLUSTER_SHARED_IP           The shared Nyquist Server IP address
	#   CLUSTER_MASTER_IP           Master node's IP Address
	#   CLUSTER_SLAVE_IP            Slave (standby) node's IP Address
	#   CLUSTER_MASTER_HOST         Master node's hostname
	#   CLUSTER_SLAVE_HOST          Slave node's hostname
	#   THIS_NODES_IPADDR           Current node's IP Address
	#   THIS_NODES_HOSTNAME         Current node's hostname
	#   SERVER_IPADDR               Nyquist Server IP Address
	#
	. /usr/local/bin/ha-get-config
fi

#
# Ensure that a password has been provided.
#
if [ "$CLUSTER_PWD" = "" ]; then
	echo "0:Authentication Password must be supplied."
	exit 1
fi

{
debug_out "Remove dpkg installed corosync config file"

rm -f /etc/corosync/corosync.conf &>> $CMD_OUTPUT

debug_out "Setup password and authentication"

if [ "$DEBIAN_VERSION" = "11" ]; then
   PASSWD="$(mkpasswd "$CLUSTER_PWD")"
else
   PASSWD="$(mkpasswd "$CLUSTER_PWD" 90)"
fi

usermod -p "$PASSWD" hacluster

} &>> $CMD_OUTPUT

#
# Get Port-A's device name
#
PORT_A_IFACE=$(nmcli --terse -f connection.interface-name con show Port-A 2>/dev/null)

if [ $? -ne 0 ]; then
	debug_out "Can't get Port-A's device name, terminating."
	echo "0:Can't get Port-A's device name"
	exit 1
fi

PORT_A_IFACE=${PORT_A_IFACE#connection.interface-name:} # strip header

#
# Save configuration data to files for use by other scripts
#
mkdir -p --mode=755 /var/opt/nyquist/ha &>> $CMD_OUTPUT
chmod 755 /var/opt/nyquist/ha &>> $CMD_OUTPUT

if [ $? -ne 0 ]; then

	echo "0:Can't create nyquist ha directory"

	exit 1
fi

echo $CLUSTER_MASTER_HOST > /var/opt/nyquist/ha/master_host
echo $CLUSTER_MASTER_IP   > /var/opt/nyquist/ha/master_ip
echo $CLUSTER_SLAVE_HOST  > /var/opt/nyquist/ha/slave_host
echo $CLUSTER_SLAVE_IP    > /var/opt/nyquist/ha/slave_ip
echo $CLUSTER_SHARED_IP   > /var/opt/nyquist/ha/shared_ip
echo $PORT_A_IFACE        > /var/opt/nyquist/ha/port_a_name

#
# Get this node's current IP address and hostname
#

HOST_ADDRS=$(hostname -I)
HOST_ADDR_ARRAY=(${HOST_ADDRS})
THIS_NODES_IPADDR=${HOST_ADDR_ARRAY[0]}

THIS_NODES_HOSTNAME="$(hostname)"

#
# Get Current Nyquist Server IP Address
#

SERVER_IPADDR=$(/usr/local/bin/nysql -q system.server_ipaddr 2> /dev/null)

if [ $? -ne 0 ]; then
	debug_out "Can't get Server IP Address from database, terminating."
	echo "0:Can't get Server IP Address from database"
	exit 1
fi

#
# Enable pcsd service, install alert scripts, setup alert log file,
# update /etc/mysql/debian-start.
#
{

sed -i '/^PCMK_logpriority=warning/d' /etc/default/pacemaker
echo "PCMK_logpriority=warning" >> /etc/default/pacemaker

systemctl enable pcsd.service
systemctl start pcsd.service
systemctl enable pcsd-ruby
systemctl start pcsd-ruby

install --mode=0755 /var/opt/nyquist/etc/nyquist_alerts.sh /var/lib/pacemaker/nyquist_alerts.sh

touch /var/log/nyquist_af_alerts.log
chown hacluster:haclient /var/log/nyquist_af_alerts.log
chmod 600 /var/log/nyquist_af_alerts.log
touch /var/log/nyquist_af_status.log
chown hacluster:haclient /var/log/nyquist_af_status.log
chmod 600 /var/log/nyquist_af_status.log

sed -i -e 's/^MYUPGRADE="\/usr\/bin\/mysql_upgrade --defaults-extra-file=\/etc\/mysql\/debian.cnf --version-check"$/MYUPGRADE="\/usr\/bin\/mysql_upgrade --defaults-extra-file=\/etc\/mysql\/debian.cnf --version-check --password=BogenNyq1"/' /etc/mysql/debian-start

} &>> $CMD_OUTPUT

#
# If Server IP Address is not set, go ahead and set it
#
if [ "$SERVER_IPADDR" != "" ]; then

	SERVER_IPADDR=$(itoa $SERVER_IPADDR) # Convert integer value to ASCII dotted IP address

else
	export MYSQL_PWD=BogenNyq1

	debug_out "Setting system.server_ipaddr to $CLUSTER_SHARED_IP"

	echo "UPDATE system SET server_ipaddr=INET_ATON('$CLUSTER_SHARED_IP');" | mysql --user=root asterisk &>> $CMD_OUTPUT

	if [ $? -ne 0 ]; then

		echo "0:Error setting Server IP Address in database"

		exit 1
	fi

	SERVER_IPADDR=$CLUSTER_SHARED_IP
fi


debug_out "Node's Hostname  : $THIS_NODES_HOSTNAME"
debug_out "Node's IP Address: $THIS_NODES_IPADDR"
debug_out "Master IP Address: $CLUSTER_SHARED_IP"
debug_out "Server's IP Addr : $SERVER_IPADDR"
debug_out "Cluster Password : $CLUSTER_PWD"

#
# If running on Nyquist System Controller, update hostname to proper format if needed.
#
# Format: nq-sysctrl-<MAC-Address>
#

if [ -e /home/bogen/serial_number ]; then

	if [[ $THIS_NODES_HOSTNAME != "nq-sysctrl"* ]]; then

		debug_out "Updating hostname"

		#
		# Note: If Master and Slave hostnames are both equal to 'debian',
		# ha-config is performed on the Master first, so the following code will still work.
		#
		if [ "$THIS_NODES_HOSTNAME" = "$CLUSTER_MASTER_HOST" ]; then
			UPDATING_MASTER=1
		else
			UPDATING_MASTER=0
		fi

		/usr/local/bin/ha-update-hostname &>> $CMD_OUTPUT

		#
		# If return status is not equal to 0, ha-update-hostname failed and
		# it has already printed a valid error status for the web interface
		# so we should just exit.
		#
		if [ $? -ne 0 ]; then

			debug_out "ha-update-hostname returned error code, bailing out"
			echo "0:Update hostname failed"

			exit 1
		fi

		THIS_NODES_HOSTNAME="$(hostname)"

		if [[ $THIS_NODES_HOSTNAME != "nq-sysctrl"* ]]; then

			debug_out "ha-update-hostname failed, bailing out"
			echo "0:Update hostname failed"

			exit 1
		fi

		export MYSQL_PWD=BogenNyq1

		#
		# Update automatic_failover_config.master_hostname
		#

		if [ $UPDATING_MASTER -eq 1 ]; then

			debug_out "Updating automatic_failover_config.master_hostname to $THIS_NODES_HOSTNAME"

			echo "UPDATE automatic_failover_config SET master_hostname='$THIS_NODES_HOSTNAME'" | mysql --user=root asterisk &>> $CMD_OUTPUT

			if [ $? -ne 0 ]; then

				echo "0:Error updating master_hostname in database"

				exit 1
			fi

			CLUSTER_MASTER_HOST=$THIS_NODES_HOSTNAME

			echo $CLUSTER_MASTER_HOST > /var/opt/nyquist/ha/master_host
		else

			debug_out "Updating automatic_failover_config.standby_hostname to $THIS_NODES_HOSTNAME"

			echo "UPDATE automatic_failover_config SET standby_hostname='$THIS_NODES_HOSTNAME'" | mysql --user=root asterisk &>> $CMD_OUTPUT

			if [ $? -ne 0 ]; then

				echo "0:Error updating standby_hostname in database"

				exit 1
			fi

			CLUSTER_SLAVE_HOST=$THIS_NODES_HOSTNAME

			echo $CLUSTER_SLAVE_HOST > /var/opt/nyquist/ha/slave_host
		fi
	fi
fi

if [ "$THIS_NODES_HOSTNAME" = "$CLUSTER_SLAVE_HOST" ]; then
	AF_LIC_ENABLED=$(/usr/local/bin/licinfo -x 2>/dev/null)

	if [ "$AF_LIC_ENABLED" = "0" ]; then
		rm -f /var/opt/nyquist/ha/* > /dev/null 2>&1
		systemctl stop pcsd.service > /dev/null 2>&1
		systemctl disable pcsd.service > /dev/null 2>&1
		debug_out "Automatic Failover feature not licensed"
		echo "0:Automatic Failover feature not licensed"
		exit 1
	fi
fi

if [ "$THIS_NODES_HOSTNAME" != "$CLUSTER_MASTER_HOST" ]; then
	AF_LIC_ENABLED=$(/usr/local/bin/licinfo -x 2>/dev/null)

	if [ "$AF_LIC_ENABLED" = "0" ]; then
		rm -f /var/opt/nyquist/ha/* > /dev/null 2>&1
		systemctl stop pcsd.service > /dev/null 2>&1
		systemctl disable pcsd.service > /dev/null 2>&1
		debug_out "Automatic Failover feature not licensed"
		echo "0:Automatic Failover feature not licensed"
		exit 1
	fi
fi

NEW_IPADDR=""

FOUND_HOSTNAME_MATCH=0

if [ "$THIS_NODES_HOSTNAME" = "$CLUSTER_MASTER_HOST" ]; then

	FOUND_HOSTNAME_MATCH=1

	if [ "$THIS_NODES_IPADDR" != "$CLUSTER_MASTER_IP" ]; then
		NEW_IPADDR=$CLUSTER_MASTER_IP
	fi
fi

if [ "$THIS_NODES_HOSTNAME" = "$CLUSTER_SLAVE_HOST" ]; then

	FOUND_HOSTNAME_MATCH=1

	if [ "$THIS_NODES_IPADDR" != "$CLUSTER_SLAVE_IP" ]; then
		NEW_IPADDR=$CLUSTER_SLAVE_IP
	fi
fi

if [ $FOUND_HOSTNAME_MATCH = 0 ]; then

	debug_out "Node's hostname does not match any in configuration, terminating."
	echo "0:Node's hostname does not match any in configuration"

	exit 1
fi

debug_out "New IPAddr = $NEW_IPADDR"

#
# Change system.server_ipaddr if needed.
#

if [ "$SERVER_IPADDR" != "$CLUSTER_SHARED_IP" ]; then

	export MYSQL_PWD=BogenNyq1

	debug_out "Updating system.server_ipaddr to $CLUSTER_SHARED_IP"

	echo "UPDATE system SET server_ipaddr=INET_ATON('$CLUSTER_SHARED_IP');" | mysql --user=root asterisk &>> $CMD_OUTPUT

	if [ $? -ne 0 ]; then

		debug_out "Error updating Server IP Address in database, terminating."
		echo "0:Error updating Server IP Address in database"

		exit 1
	fi
fi

#
# Update pjsip.conf transports to prefer the HA shared IP
#
awk "
/^\[transport-tls\]/ { transport=\"tls\" }
/^\[transport-ws\]/ { transport=\"ws\" }
/^\[transport-wss\]/ { transport=\"wss\" }
/^\[transport-udp\]/ { transport=\"udp\" }
/^\[transport-tcp\]/ { transport=\"tcp\" }

transport==\"tls\" && /^bind=/ { print \"bind=$CLUSTER_SHARED_IP:5061\"; next }
transport==\"ws\" && /^bind=/ { print \"bind=$CLUSTER_SHARED_IP:8088\"; next }
transport==\"wss\" && /^bind=/ { print \"bind=$CLUSTER_SHARED_IP:8089\"; next }
( transport==\"udp\" || transport==\"tcp\" ) && /^bind=/ { print \"bind=$CLUSTER_SHARED_IP:5060\"; next }

{ print }
" /etc/asterisk/pjsip.conf > /tmp/tmp && mv /tmp/tmp /etc/asterisk/pjsip.conf;

#
# Create hacluster user's sudo entry for executing dash-text
#
{
debug_out "Create hacluster sudo entry"

echo "hacluster ALL = NOPASSWD: /usr/local/bin/dash-text, /usr/local/bin/routine-trigger" > /etc/sudoers.d/nyquist-ha
chmod 0440 /etc/sudoers.d/nyquist-ha
chown root:root /etc/sudoers.d/nyquist-ha

} &>> $CMD_OUTPUT

#
# If the node's current IP Address is already equal to the cluster IP address
# for the node's role, we are done and can return successful status code.
#

if [ "$NEW_IPADDR" = "" ]; then

	#
	# Make sure that both ports have auto-negotiate enabled
	#
	{
	nmcli con modify Port-A 802-3.auto-negotiate true
	nmcli con modify Port-B 802-3.auto-negotiate true
	nmcli dev modify enp3s0 802-3.auto-negotiate true
	nmcli dev modify eth0 802-3.auto-negotiate true
	nmcli dev modify enp4s0 802-3.auto-negotiate true
	nmcli dev modify eth1 802-3.auto-negotiate true
	nmcli dev modify enp2s0 802-3.auto-negotiate true
	} &>> $CMD_OUTPUT

	echo $(date) Finished: $0 $@ >> $CMD_OUTPUT

	echo "1:Success"

	exit 0
fi

#
# Need to change the IP Address, schedule a job to do the work so that the script
# does not get killed when the IP address changes. Tell the web interface that
# we are changing the IP address.
#

at -M now >/dev/null 2>&1 <<EOF
sleep 20
/usr/local/bin/ha-update-ipaddr $THIS_NODES_IPADDR $NEW_IPADDR > /dev/null 2>&1
EOF

echo $(date) Finished: $0 $@ >> $CMD_OUTPUT

echo "1:Changing IP Address to $NEW_IPADDR"

exit 0
