distcc propagator

Helper to propagate a distcc configuration on a compilation network/cluster
distcc Bash JCZD

distcc propagator is a helper script to help propagate a configuration on hosts and clients in a distcc-enabled network ; its features are:

It makes use of a single /etc/distcc/cluster.conf file that specifies, for each client (whether it will act as a distcc host or not), the number of local cores to use for compilation. It makes two passes on the clients file, first computing the total number of cores available, then propagating the config on all machines.

#!/bin/bash

# small helper script to ease adding participating hosts in a distcc network
#
# Author: 	JCZD <jczd@engrenage.ch>
# Date:		2021-12-04
#
# format of /etc/distcc/cluster.conf:
# 
# n,hostname_or_ip
#
# one per line, where n is the numer of local cores to use for compilation
#
# TODO
# - fix the (slight) redundancy between /etc/distcc/{hosts,clients}
# - use a specific authorized_hosts? this adds complexity..
# - read the comments below for more
# 
# Bugs/Limitations
# - does not support any sort of NAT
# - still requires quite a bit of manual file post-processing on each host
# - 

NETMASK=24

total_cores=0

echo -e "#\n# cluster status\n#"

while read line
do
	# TODO ignore lines starting with '#'
	local_cores=`echo ${line} | cut -f 1 -d ','`
	hostname=`echo ${line} | cut -f 2 -d ','`
	# TODO check host is up and responding
	# TODO test network connectivity, ie. with nmap ; port number should be set in /etc/distcc/cluster.conf
	#ssh $hostname /usr/bin/distcc-config --get-hosts	# TODO kills the script.. why?
	# TODO check gcc version
	echo "sharing ${local_cores} cores:	${hostname}"
	let "total_cores=total_cores+local_cores"
done < /etc/distcc/cluster.conf

echo -e "\ndistcc cluster has ${total_cores} cores available total\n"

let "N=2*total_cores+1"

echo -e "\n#\n# pushing config...\n#"

while read line
do
	local_cores=`echo ${line} | cut -f 1 -d ','`
	hostname=`echo ${line} | cut -f 2 -d ','`
	if [ $hostname != `hostname` ]
	then
		echo -n "remote: ${hostname}"
		# the line below works once,, then script exits.. why?!? the point was to make sure reverse-connection works
		#ssh $hostname ssh `hostname` echo "Hello from $hostname"

		scp ~/.ssh/authorized_keys $hostname:.ssh >/dev/null
		# TODO this is quite dirty security-wise ; also, some sort of authentication is required to already work at this stage
		# TODO not good because it relies from a hosts file of an arbitrary host, not network-architecture-aware
		scp ~/.ssh/authorized_keys $hostname:.ssh >/dev/null
		scp /etc/hosts $hostname:/etc/ >/dev/null

		rm /tmp/distcc-hosts
		echo -n "DISTCCD_OPTS=\"\${DISTCCD_OPTS} --listen `grep ${hostname} /etc/hosts | tr -s ' ' | cut -f 1 -d ' ' | cut -f 1 -d '	'`"  > /tmp/distccd.allow
		while read line2
		do
			# TODO ignore lines starting with '#'
			helper_cores=`echo ${line2} | cut -f 1 -d ','`
			helper=`echo ${line2} | cut -f 2 -d ','`
			if [[ $helper_cores -gt 0 ]]
			then
				if [ $helper != $hostname ]
				then
					echo ${helper} >> /tmp/distcc-hosts
					echo -n " --allow "`grep ${helper} /etc/hosts | tr -s ' ' | cut -f 1 -d ' ' | cut -f 1 -d '	'`"/${NETMASK}" >> /tmp/distccd.allow
				else
					echo 127.0.0.1 >> /tmp/distcc-hosts
					echo -n " --allow 127.0.0.1/${NETMASK}" >> /tmp/distccd.allow
				fi
			fi
		done < /etc/distcc/cluster.conf
		scp /tmp/distcc-hosts $hostname:/etc/distcc/hosts >/dev/null
		# TODO merge with /etc/conf.d/distcc
		echo "\""  >> /tmp/distccd.allow
		scp /tmp/distccd.allow $hostname:/etc/conf.d/distccd.allow >/dev/null	# see Note1
		# alternative, if distccd is already running:
		#scp /tmp/distccd.allow $hostname:/tmp/distccd.allow >/dev/null	# see Note1
		#ssh $hostname /usr/bin/distcc-config --set-hosts `cat /tmp/distccd.allow`

		echo "FEATURES=\"distcc\"" > /tmp/distcc-propagator-makeopts
		echo "MAKEOPTS=\"-j${N} -l${local_cores}\"" >> /tmp/distcc-propagator-makeopts
		#cat /tmp/distcc-propagator-makeopts
		# TODO merge with /etc/portage/make.conf
		scp /tmp/distcc-propagator-makeopts $hostname:/etc/distcc/makeopts >/dev/null	# see Note1
		echo "	:-)"
	else
		echo "local: ${hostname}"
		echo "MAKEOPTS=\"-j${N} -l${local_cores}\"" > /etc/distcc/makeopts	# see Note1
		echo -n "DISTCCD_OPTS=\"\${DISTCCD_OPTS} --listen `grep ${hostname} /etc/hosts | tr -s ' ' | cut -f 1 -d ' ' | cut -f 1 -d '	'`"  > /etc/conf.d/distccd.allow
		while read line2
		do
			# TODO ignore lines starting with '#'
			helper_cores=`echo ${line2} | cut -f 1 -d ','`
			helper=`echo ${line2} | cut -f 2 -d ','`
			if [[ $helper_cores -gt 0 ]]
			then
				if [ $helper != $hostname ]
				then
					echo ${helper} >> /etc/distcc/hosts
					echo -n " --allow "`grep ${helper} /etc/hosts | tr -s ' ' | cut -f 1 -d ' ' | cut -f 1 -d '	'`"/${NETMASK}" >> /etc/conf.d/distccd.allow
				else
					echo 127.0.0.1 >> /etc/distcc/hosts
					echo -n " --allow 127.0.0.1/${NETMASK}" >> /etc/conf.d/distccd.allow
				fi
			fi
		done < /etc/distcc/cluster.conf
		echo "\""  >> /etc/conf.d/distccd.allow
	fi
done < /etc/distcc/cluster.conf

echo -e "\n\n#\n# Finalization: on every host, merge contents of /etc/distcc/makeopts /etc/portage/make.conf /etc/conf.d/distccd.allow /etc/conf.d/distccd"
	
# Note1:
# these should be used to set : 
# 	MAKEOPTS in /etc/portage/make.conf
# 	DISTCC_OPTS in /etc/conf.d/distccd
# but I am trying to avoid too much parsing and replacing.. any suggestion?