#!/bin/sh
# $Id: pbulk-cluster.sh,v 5.16 2016/02/18 23:53:52 asau Stab $
set -e

usage="usage: ${0##*/} [-a agent-script] [-n] [-c mk.conf.fragment] [-l limited-list] [-N node-list] [-p PKGSRCDIR] [-d DISTDIR] [-P PACKAGES] [-R report-base] [basedir]"

while getopts "a:nc:l:N:p:d:P:R:" opt; do
   case $opt in
       n) native=yes;;
       c) mk_fragment="${OPTARG}";;
       l) limited_list="${OPTARG}";;
       N) node_list="${OPTARG}";;
       a) agent_script="${OPTARG}";;
       p) PKGSRCDIR="${OPTARG}";;
       d) DISTDIR="${OPTARG}";;
       P) PACKAGES="${OPTARG}";;
       R) REPORTBASE="${OPTARG}";;
       \?) echo "$usage" 1>&2; exit 1;;
   esac
done
shift $(expr $OPTIND - 1)

if [ $# -gt 1 ]; then echo "$usage" 1>&2; exit 1; fi

case "$1" in
   */*) CLUSTERBASE="$1";; # path
   *)   CLUSTERNAME="$1";; # name
esac

: ${CLUSTERNAME:=pbulk-cluster}
: ${JAILBASE:=/usr/jail}
: ${CLUSTERBASE:=${JAILBASE}/${CLUSTERNAME}}
export JAILBASE="${CLUSTERBASE}/nodes" # from now on
NODES="${JAILBASE}"

: ${PKGSRCDIR:=${CLUSTERBASE}/pkgsrc}
: ${DISTDIR:=${CLUSTERBASE}/mnt/distfiles}
: ${PACKAGES:=${CLUSTERBASE}/packages}
: ${REPORTBASE:=${CLUSTERBASE}/mnt}

: ${agent_script:=${PKGSRCDIR}/mk/pbulk/pbulk.sh}

# Unset variables to prevent capturing them from user environment:
unset TMP
unset TEMP
unset TMPDIR

if [ ! -d ${PKGSRCDIR} ]; then # require pkgsrc tree
   echo "${0##*/}: pkgsrc tree required" 1>&2; exit 1
fi
if [ ! -f "${agent_script}" ]; then # require pbulk deployment script
   echo "${0##*/}: pbulk.sh script required" 1>&2; exit 1
fi

mkdir -p ${CLUSTERBASE}
mkdir -p ${CLUSTERBASE}/mnt
mkdir -p ${DISTDIR}
mkdir -p ${PACKAGES}
mkdir -p ${REPORTBASE}

hosts=${CLUSTERBASE}/hosts
if [ -r "${node_list}" ]; then
   cat "${node_list}" > "${hosts}"
elif [ ! -r "${hosts}" ]; then
   echo "${0##*/}: node list is required" 1>&2; exit 1
fi
nodes=""; while read addr name; do nodes="${nodes:+$nodes }${name}"; done < ${hosts}

if [ ! -e ${CLUSTERBASE}/pbulk.sh ]; then cat "${agent_script}" > ${CLUSTERBASE}/pbulk.sh; fi
if [ -n "$limited_list" ]; then cat "$limited_list" > ${CLUSTERBASE}/pbulk.list; fi
if [ -n "${mk_fragment}" ]; then cat "${mk_fragment}" > ${CLUSTERBASE}/mk.conf.frag; fi

for node in ${nodes}; do
   JAIL=${NODES}/${node}

   if [ ! -x ${JAIL}/bin/sh ]; then # create node, if missing
       create-root ${JAIL}
   fi

   start-root ${JAIL}
   mkdir -p ${JAIL}/usr/pkgsrc && mount -t null -o ro ${PKGSRCDIR} ${JAIL}/usr/pkgsrc
   mount -t null ${DISTDIR} ${JAIL}/usr/pkgsrc/distfiles
   mount -t null -o rw ${PACKAGES} ${JAIL}/usr/pkgsrc/packages
   mount -t null -o rw ${REPORTBASE} ${JAIL}/mnt

   cat ${CLUSTERBASE}/pbulk.sh > ${JAIL}/root/pbulk.sh
   if [ -n "${mk_fragment}" ]; then cat ${CLUSTERBASE}/mk.conf.frag > ${JAIL}/root/mk.conf.frag; fi
   cp /etc/resolv.conf ${JAIL}/etc/resolv.conf
   cp ${hosts} ${JAIL}/etc/hosts
   if [ ! -f ${JAIL}/usr/pbulk/etc/mk.conf ]; then
       (unset PKGSRCDIR; unset DISTDIR; PACKAGES=/usr/pkgsrc/packages exec chroot ${JAIL} /bin/sh /root/pbulk.sh ${native:+-n} ${limited_list:+-l} ${mk_fragment:+-c /root/mk.conf.frag} -d "${nodes}" >/tmp/${CLUSTERBASE##*/}-${node}.out 2>&1);
   fi

   { echo PACKAGES=/usr/pkgsrc/packages; echo WRKOBJDIR=/tmp; } > ${JAIL}/etc/profile;
   mkdir -p ${JAIL}/etc/rc.conf.d; { echo sshd=yes; echo sshd_flags="\"-oPort=122 -oListenAddress=${node} -oPermitRootLogin=yes -oAcceptEnv=WRKOBJDIR -oAcceptEnv=PACKAGES -oAcceptEnv=DISTDIR -oAcceptEnv=FETCH_TIMEOUT\""; } > ${JAIL}/etc/rc.conf.d/sshd;

   # Create keys and ssh client configuration:
   # - generate key on master node;
   # - generate client configuration;
   # - make slave nodes accept the key.
   master_node="${nodes%% *}"
   if [ "${node}" = "${master_node}" ]; then # master node
       chroot ${JAIL} /bin/sh -c "yes | ssh-keygen -t rsa -b 2048 -N \"\" -C \"root@localhost\" -f /root/.ssh/id_rsa && { echo Port 122; echo StrictHostKeyChecking no; echo SendEnv WRKOBJDIR PACKAGES DISTDIR FETCH_TIMEOUT; } > /root/.ssh/config"
   else # slave node
       mkdir -p -m 700 ${JAIL}/root/.ssh && cp -v ${NODES}/${master_node}/root/.ssh/id_rsa.pub ${JAIL}/root/.ssh/authorized_keys;
   fi
done

for node in ${nodes}; do JAIL=${NODES}/${node}; chroot ${JAIL} /bin/sh -c "ifconfig lo0 alias ${node}"; chroot ${JAIL} /etc/rc.d/sshd start; done
if [ -n "$limited_list" ]; then JAIL=${NODES}/${master_node}; cat ${CLUSTERBASE}/pbulk.list > ${JAIL}/usr/pbulk/etc/pbulk.list; fi
# Do it!
JAIL=${NODES}/${master_node}; (unset PKGSRCDIR; unset DISTDIR; FETCH_TIMEOUT=600 WRKOBJDIR=/tmp PACKAGES=/usr/pkgsrc/packages exec chroot ${JAIL} /usr/pbulk/bin/bulkbuild >/tmp/${CLUSTERBASE##*/}.out) 2>&1 ||:
for node in ${nodes}; do JAIL=${NODES}/${node}; chroot ${JAIL} /etc/rc.d/sshd stop; chroot ${JAIL} /bin/sh -c "ifconfig lo0 -alias ${node}"; done

# destructing:
for node in ${nodes}; do
   JAIL=${NODES}/${node}
   umount ${JAIL}/usr/pkgsrc/packages
   umount ${JAIL}/usr/pkgsrc/distfiles
   umount ${JAIL}/usr/pkgsrc
   umount ${JAIL}/mnt
   stop-root ${JAIL}
done