#!/bin/sh
# Deploy and run the cryptlib test suite on selected cfarm hosts.
# Arguments:
#
#	-h host = Use non-cfarm host name.
#	-r restart-point-host = Restart the run from $restart-point-host,
#							used when a run stops due to an error.
#	-u user = Use non-default user name.
#
# Without args it'll run on the cfarm hosts, with -h and -u it can be
# run on other systems for testing.
#
# The SSH_ARGS are required to deal with the fact that some build farm
# servers are running very old versions of SSH that don't do SHA2
# signatures, and to deal with SSH server keys changing.
#
# Machine list at https://portal.cfarm.net/machines/list.
#
# Former hosts:
#	cfarm23 = MIPS64, vanished mid-2025, using cfarm230.
#	cfarm92 = RiscV64 SiFive, vanished mid-2025.
#	cfarm93 = RiscV64 JH7110, vanished mid-2025, using cfarm94.
#	cfarm110 = PPC64 big-endian Linux clang, retired early 2026.
#	cfarm111 = PPC64 big-endian AIX xlc, retired early 2026.
#	cfarm119 = PPC32 big-ending AIX xlc, moved to clang with complex custom
#			   path configuration early 2026.
#	cfarm203 = PPC64, retired late 2025, using cfarm121

HOSTS="27 70 94 95 104 112 121 185 210 211 215 216 220 230 231 240 400 439 440"
HOSTPREFIX="cfarm"
HOSTSUFFIX="cfarm.net"
USER="peter"
SSH_PRIVKEYPATH="$HOME/.ssh/cfarm.pri"
SSH_ARGS="-o PubkeyAcceptedAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group-exchange-sha1 -o HostKeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no"
SSH_PORTARG_SCP=
SSH_PORTARG_SSH=
DATA="beta.zip"
DEFAULT_NCORES="-j4"
NCORES=$DEFAULT_NCORES
DO_RESTART=0
RESTART_POINT=""
CFARM_HOST=1

# Process any optional flags.

while getopts "h:r:u:" options ; do
	case "${options}" in
		h) HOSTS=${OPTARG} ;
		   CFARM_HOST=0 ;;
		r) DO_RESTART=1 ;
		   RESTART_POINT=${OPTARG} ;
		   if [ "$(echo "$HOSTS" | grep -cw "$RESTART_POINT")" -le 0 ] ; then
		   		echo "Error: Invalid restart point $RESTART_POINT" >&2 ;
		   		exit 1 ;
		   fi ;;
		u) USER=${OPTARG} ;;
		*) echo "Error: Invalid option -${OPTARG}" >&2 ;
		   exit 1 ;;
	esac
done
shift $(( OPTIND - 1 ))

# Make sure that the required files are ready to go.

if [ ! -s ./beta.zip ] ; then
	echo "Error: Couldn't find beta.zip in the current directory." >&2 ;
	exit 1 ;
fi
if [ ! -s $SSH_PRIVKEYPATH ] ; then
	echo "Error: Couldn't find SSH key $SSH_PRIVKEYPATH." >&2 ;
	exit 1 ;
fi

# Some tests hang, install a Ctrl-C handler that lets us know how far we got.

DISPLAYHOST=""
trap ctrlc INT

ctrlc()
	{
	printf "\n**** Error testing on %s: Ctrl-C ****\n" "$DISPLAYHOST" >&2 ;
	exit ;
	}

# Upload and build the code on each host.  We use a here document for this
# rather than pulling it in from another file with 'ssh [...] < commands.sh'
# to keep everything in one place.  The script is fairly conservative in
# order to minimise interference with other users, for example it limits
# itself to -j4 rather than `getconf _NPROCESSORS_ONLN` and hogging all the
# cores.

for host in $HOSTS ; do
	# Check for whether we're restarting at a given point.
	if [ $DO_RESTART -gt 0 ] ; then
		if [ "$RESTART_POINT" != "$host" ] ; then
			continue ;
		fi ;
		DO_RESTART=0 ;
		echo "Restarting from cfarm$host" ;
	fi

	# Build the full hostname for cfarm hosts.
	if [ $CFARM_HOST -eq 1 ] ; then
		HOSTNAME=$HOSTPREFIX$host.$HOSTSUFFIX ;
	else
		HOSTNAME=$host ;
	fi

	# Remember which host we got to
	DISPLAYHOST=$HOSTNAME

	# A few hosts only allow for -j2 rather than the default -j4.  In theory
	# we could do a per-host lookup for number of cores vs. host but that's
	# tricky to do in sh/bash/whatever and not really worth the hassle.
	#
	# Similarly, a few hosts need nonstandard port configs.
	case $host in
		'23'|'70')
			NCORES="-j2" ;;

		'210'|'211'|'215'|'216')
			# Solaris tools don't support -j.  cfarm215 and 216 have a crazy
			# mix of Sun and GNU/LLVM tools so make and ld are Sun, cc is
			# GNU or LLVM.
			NCORES= ;;

		'400')
			SSH_PORTARG_SCP="-P 25465" ;
			SSH_PORTARG_SSH="-p 25465" ;;
	esac

	# Print information on the host that we're about to build on.
	case $host in
#		'23') echo "cfarm23: MIPS64 big-endian Linux gcc." ;;
		'27') echo "cfarm27: Intel x86 little-endian Linux clang." ;;
		'70') echo "cfarm70: Xeon x86-64 little-endian Linux clang." ;;
#		'92') echo "cfarm92: RiscV64 (SiFive) little-endian Linux clang." ;;
#		'93') echo "cfarm93: RiscV64 (VisionFive) little-endian Linux clang." ;;
		'94') echo "cfarm94: RiscV64 (JH7110) little-endian Linux clang." ;;
		'95') echo "cfarm95: RiscV64 (X60) little-endian Linux clang." ;;
		'104') echo "cfarm104: Apple M1 Arm64 little-endian OS X clang." ;;
#		'110') echo "cfarm110: PPC64 big-endian Linux clang." ;;
#		'111') echo "cfarm111: PPC64 big-endian AIX xlc." ;;
		'112') echo "cfarm112: PPC64 little-endian Linux gcc. Broken clang install." ;;
#		'119') echo "cfarm119: PPC32 big-endian AIX xlc.  32-bit time_t" ;;
		'121') echo "cfarm121: PPC64 big-endian Linux clang." ;;
		'185') echo "cfarm185: Arm64 little-endian Linux clang." ;;
#		'203') echo "cfarm203: PPC64 big-endian Linux clang." ;;
		'210') echo "cfarm210: Sparc64 big-endian Solaris 10 SunPro. OpenCSW." ;;
		'211') echo "cfarm211: Sparc64 32-bit big-endian Solaris 11 SunPro. OpenCSW. 32-bit time_t" ;;
		'215') echo "cfarm215: Intel x86-64 little-endian Solaris 11 clang." ;;
		'216') echo "cfarm216: Sparc64 big-endian Solaris 11 clang." ;;
		'220') echo "cfarm220: Xeon x86-64 little-endian OpenBSD clang." ;;
		'230') echo "cfarm230: MIPS64 32-bit big-endian Linux clang. 32-bit time_t" ;;
		'231') echo "cfarm231: MIPS64 big-endian OpenBSD clang" ;;
		'240') echo "cfarm240: ARM Morello CheriBSD/FreeBSD, 64-bit word, 128-bit pointers." ;;
		'400') echo "cfarm400: Loongson64 little-endian Linux clang." ;;
		'439') echo "cfarm439: PPC64 little-endian FreeBSD clang." ;;
		'440') echo "cfarm440: PPC64 big-endian FreeBSD clang." ;;
		*) echo "Error: Unknown host $host" >&2 ;
		   exit 1 ;;
	esac

	# Copy the code across and build it.  Note that $PORTARG has to be
	# unquoted otherwise ssh will see a blank string arg and think it's a
	# file argument, and $SSH_ARGS and $NCORES similarly for distinct
	# strings.  In addition EOL has to be unquoted because we need $NCORES
	# to be expanded on the client side, not the server side.
	#
	# The Sun hosts are OpenCSW machines which are actually Solaris zones on
	# a single server so need paths to tools explicitly set depending on the
	# zone.  Note that tools/buildall.sh will check for the newest installed
	# version of the tools and try and select those, so the two path settings
	# for Solaris 10 and 11 below will need to match what the build script is
	# expecting.
	echo "Deploying to $HOSTNAME"
	scp -B $SSH_ARGS -i "$SSH_PRIVKEYPATH" $SSH_PORTARG_SCP $DATA $USER@$HOSTNAME: || exit
	ssh $SSH_ARGS -i "$SSH_PRIVKEYPATH" $SSH_PORTARG_SSH $USER@$HOSTNAME <<EOL
		set -e ;
		if [ -d ./CLIB ] ; then
			if [ -n "\$(ls ./CLIB)" ] ; then
				echo "Removing old cryptlib files." ;
				rm -r ./CLIB/* ;
			fi ;
		else
			mkdir ./CLIB ;
		fi ;
		cd ./CLIB ;
		unzip -a ../beta.zip ;
		rm ../beta.zip ;
		touch ../.ISDEVELOPMENT ;
		if [ \$(uname -n | cut -f1 -d'.') = "gcc-solaris10" ] ; then
			PATH=/opt/developerstudio12.6/bin:\$PATH ; export PATH ;
		fi ;
		if [ \$(uname -n | cut -f1 -d'.') = "gcc-solaris11" ] ; then
			PATH=/opt/developerstudio12.6/bin:\$PATH ; export PATH ;
		fi ;
		make touch ;
		make $NCORES ;
		make testlib ;
		./testlib ;
EOL

	# Exit if there was a problem.
	status=$?
	if [ $status -ne 0 ] ; 	then
		printf "\n**** Error testing on %s: %d ****\n" "$HOSTNAME" "$status" >&2 ;
		case $host in
			'112')
				echo "(If the problem was due to a broken clang install, restart with '-r 121')" >&2 ;;

			'119')
				echo "(If the problem was due to a missing xlc, restart with '-r 121')" >&2 ;;
		esac ;
		exit 1 ;
	fi

	# Reset any variables to their defaults
	NCORES=$DEFAULT_NCORES
done
