#!/bin/sh
# Ensure a multiplexed SSH master to Aspire is up, authenticating unattended if
# it is not. Cheap and idempotent: call it before any ssh/scp/rsync to the
# cluster. Exits 0 when the connection is usable.
#
#   ./bin/aspire-connect          # ensure connected
#   ./bin/aspire-connect status   # report without connecting
#   ./bin/aspire-connect down     # tear the master down
#
# Requires OpenSSH >= 8.4 for SSH_ASKPASS_REQUIRE, and a Host block with
# ControlMaster/ControlPath/ControlPersist set (see README).

set -eu

HOST="${ASPIRE_HOST:-aspire}"
BIN=$(cd -P "$(dirname "$0")" && pwd)
ASKPASS="$BIN/aspire-askpass"

alive() { ssh -O check "$HOST" >/dev/null 2>&1; }

case "${1:-up}" in
    status)
        if alive; then
            echo "aspire-connect: master is up ($HOST)"
        else
            echo "aspire-connect: master is down ($HOST)"
            exit 1
        fi
        exit 0
        ;;
    down)
        ssh -O exit "$HOST" >/dev/null 2>&1 || true
        echo "aspire-connect: master closed ($HOST)"
        exit 0
        ;;
    up) ;;
    *)
        echo "usage: aspire-connect [up|status|down]" >&2
        exit 2
        ;;
esac

if alive; then
    exit 0
fi

# A dead master can leave its socket behind; clear it so ssh does not try to
# reuse a corpse and silently fall back to an interactive prompt.
ssh -O exit "$HOST" >/dev/null 2>&1 || true

if [ ! -x "$ASKPASS" ]; then
    echo "aspire-connect: $ASKPASS missing or not executable" >&2
    exit 1
fi

echo "aspire-connect: master down, authenticating to $HOST..." >&2

# -f -N: background a master that runs no command.
# NumberOfPasswordPrompts=1: fail fast on a bad password instead of retrying.
#
# ssh's own stdout/stderr are redirected to a temp file rather than left inherited:
# once authenticated, -f backgrounds the master, and ControlPersist keeps it running
# indefinitely. A caller that reads this script's output as a pipe (Node's
# child_process, waiting for stdio EOF) would otherwise never see EOF, because the
# still-open pipe fd lives on in a background process that never exits. This
# script's own stdout/stderr close normally either way, so failures are still
# reported by replaying the log below.
connect_log=$(mktemp)
if ! SSH_ASKPASS="$ASKPASS" SSH_ASKPASS_REQUIRE=force \
        ssh -f -N -o NumberOfPasswordPrompts=1 "$HOST" >"$connect_log" 2>&1; then
    echo "aspire-connect: failed to connect to $HOST" >&2
    cat "$connect_log" >&2
    rm -f "$connect_log"
    echo "aspire-connect: check the password in the credential file, and that" >&2
    echo "aspire-connect: bin/aspire-setup-credentials has been run on this machine" >&2
    exit 1
fi
rm -f "$connect_log"

if ! alive; then
    echo "aspire-connect: ssh returned success but no master socket appeared" >&2
    exit 1
fi

echo "aspire-connect: connected ($HOST)" >&2
