Managing a slave server

A successful master slave setup requires an effective way for nodes to communicate

/root/.bashrc

[[ -f "/root/slave.sh" ]] && source /root/slave.sh || echo "Cannot find /root/slave.sh"

/etc/slave.conf

SLAVE="dns2"
SSHKEY="/root/.ssh/id_rsa"

/root/slave.sh

#!/bin/bash
#
# Useful functions for maintaining a Master/Slave relationship
#
# Copyright 2020 ASBRA AB <j@asbra.nu>
#

help()
{
	case "$1" in
		conn)     printf "[FAIL] \nConnection to slave failed or you are missing remote root privileges on ${SLAVE}!\n" ;;
		copy)     printf "[HELP] \nCopy a file or directory from master to slave using rsync -avz.\nAlias: cp\n" ;;
		reload)   printf "[HELP] \nReload script in /etc/init.d on both master and slave.\nAlias: rl\n" ;;
		checksum) printf "[HELP] \nCompare files or directories on slave\nAlias: cs\n" ;;
		run)      printf "[HELP] \nRun command on slave\n" ;;
		diff)     printf "[HELP] \nRun command on both master and slave, then compare output\n" ;;
		config) cat <<-EOF

			Example config, copy to /etc/slave.conf or use the export command to set globaly.

			    SLAVE="host or ipaddress here!"
			    SSHKEY="/root/.ssh/id_rsa"

			To generate a new ssh-key please run the following command and then paste
			your key into /root/.ssh/authorized_keys on the slave server.

			    # ssh-keygen

			EOF
			;;
		*)      cat <<-EOF

			Slave:   $SLAVE
			SSH key: $SSHKEY

			COMMAND   PARAMETER  DESCRIPTION
			    help  <function> Detailed command info.
			      cp  <path>     Copy file or directory to the same location on slave.
			  reload  <service>  Reload a service (/etc/init.d) on both master and on slave.
			checksum  <path>     Checksum compare files or directories.
			     run  <command>  Run command on slave.
			    diff  <command>  Run command on both master and slave, then compare output.

			EOF
			;;
	esac
	return 0
}

# Read config
[[ -f /etc/slave.conf ]] && source /etc/slave.conf

# Validate config
[[ -z "$SLAVE" || -z "$SSHKEY" ]] && help "config" && return

# Check if we have root on slave
[[ $(ssh $SLAVE "id -u") != 0 ]] && help "conn" && return # slave does not respond or remote uid is not 0

echo "[OK] Slave $SLAVE responded!"

slave() {
	case "$1" in
	cp|copy)      slave_cp "${*:2}" ;;
	h|help)       help "${*:2}" ;;
	rl|reload)    slave_reload "${*:2}" ;;
	cs|checksum)  slave_checksum "${*:2}" ;;
	run)          ssh -i $SSHKEY $SLAVE "${*:2}" ;;
	diff)         slave_diff "${*:2}" ;;
	*)            help "usage" ;;
	esac
}

alias s=slave

slave_diff()
{
	if [[ -z "$1" ]]
	then
		read -p "Enter command: " CMD
	else
		CMD=$*
	fi

	echo "$CMD | tee /tmp/master.diff > /dev/null && ssh $SLAVE $CMD | tee /tmp/slave.diff > /dev/null ; vimdiff /tmp/master.diff /tmp/slave.diff"
}

slave_cp()
{
	IN="$*" ; [[ ! -f "$IN" ]] && [[ ! -d "$IN" ]] && read -e -p "Filename (auto complete): " IN

	FILENAME=$(basename $IN)
	FILEPATH=$(dirname $IN)
	REALPATH=$(realpath $FILEPATH)

	[[ $REALPATH == "/" ]] && REALPATH=""; # Prevent // in path

	[[ -d "$IN" ]] && echo "rsync -e 'ssh -i $SSHKEY' -avz ${REALPATH}/${FILENAME}/ ${SLAVE}:${REALPATH}/${FILENAME}/"
	[[ -f "$IN" ]] && echo "rsync -e 'ssh -i $SSHKEY' -avz ${REALPATH}/${FILENAME} ${SLAVE}:${REALPATH}/${FILENAME}"
}

slave_reload()
{
	if [[ -f "/etc/init.d/$1" ]]
	then
		echo "/etc/init.d/${1} reload && ssh $SLAVE /etc/init.d/${1} reload"
	else
		printf "\nPick a service to reload:\n"
		select SERVICE in $(ls /etc/init.d/) ; do
			echo "/etc/init.d/${SERVICE} reload && ssh $SLAVE /etc/init.d/${SERVICE} reload"
		done
	fi
}
slave_checksum()
{
	IN="$*" ; [[ ! -f "$IN" ]] && [[ ! -d "$IN" ]] && read -e -p "Filename (auto complete): " IN

	FILENAME=$(basename $IN)
	FILEPATH=$(dirname $IN)
	REALPATH=$(realpath $FILEPATH)

	[[ $REALPATH == "/" ]] && REALPATH=""; # Prevent // in path
	[[ -d "$IN" ]] && echo "rsync -e 'ssh -i $SSHKEY' -ac --dry-run --out-format='[DIFF] %f' ${REALPATH}/${FILENAME}/ ${SLAVE}:${REALPATH}/${FILENAME}/"
	[[ -f "$IN" ]] && echo "rsync -e 'ssh -i $SSHKEY' -ac --dry-run --out-format='[DIFF] %f' ${REALPATH}/${FILENAME} ${SLAVE}:${REALPATH}/${FILENAME}"

}

help