#!/bin/zsh use bastion --group remote use config --group remote DEPENDENCIES+=(timeout ssh) ##################################################################### USAGE__options=' -n, --name session name to test -s, --connection-string explicit session host / ssh connection string to test -t, --maximum-timeout maximum connection timeout before failure (in seconds) -c, --command testing command; performs echo by default --use-bastion true / false override for bastion preference (default: session.name.bastion.preferred or "false") ' USAGE__description=' Tests whether you can connect to a particular session or host string. ' ##################################################################### MAIN() { local CONNECTION_STRING REMOTE_NAME local TIMEOUT_SECONDS=3 local COMMAND='echo OK &>/dev/null' local USE_BASTION while [[ $# -gt 0 ]] do local _S=1 case $1 in -n | --name ) ((_S+=1)) REMOTE_NAME=$2 CONNECTION_STRING=$(REMOTE__GET_CONNECTION_STRING $REMOTE_NAME) ;; -s | --connection_string ) ((_S+=1)) CONNECTION_STRING="$2" ;; -t | --maximum-timout ) ((_S+=1)) TIMEOUT_SECONDS=$2 [[ $TIMEOUT_SECONDS -gt 0 ]] \ || ERROR "invalid timeout seconds '$TIMEOUT_SECONDS'" ;; -c | --command ) ((_S+=1)) COMMAND=$2 ;; --use-bastion ) ((_S+=1)) USE_BASTION=$2 case $USE_BASTION in true | false ) ;; * ) ERROR "invalid setting for '--use-bastion' (must be 'true' or 'false')" ;; esac ;; * ) ERROR "unrecognized argument '$1'" ;; esac shift $_S done [ $CONNECTION_STRING ] \ || ERROR "unable to determine connection string" [ $USE_BASTION ] || { USE_BASTION=$(\ REMOTE__QUERY_CONNECTION_WITH_FALLBACK \ ".sessions.$REMOTE_NAME.bastion.preferred" \ 'false' \ ; ) } CHECK_ERRORS ########################################## local BASTION_HOST [[ $USE_BASTION =~ true ]] && { BASTION_HOST=$(\ REMOTE__QUERY_CONNECTION_WITH_FALLBACK \ ".sessions.$REMOTE_NAME.bastion.session" \ ) } [[ $USE_BASTION =~ true ]] && { [ $BASTION_HOST ] \ || ERROR "cannot connect to $REMOTE_NAME; no configured bastion host" \ || return 1 } case $CONNECTION_STRING in localhost | $USER@localhost ) CONNECTION_TEST() { return 0; } # current user on local machine can always connect ;; * ) [[ $USE_BASTION =~ true ]] && { DEBUG "MAIN -n $BASTION_HOST -c \"$(GET_PASSTHROUGH_PREFIX) remote test -- -n $REMOTE_NAME -c \"$COMMAND\"\"" BASTION_TARGET="$REMOTE_NAME" MAIN -n $BASTION_HOST -c "$(GET_PASSTHROUGH_PREFIX) remote test -- -n $REMOTE_NAME -c \"$COMMAND\"" return $? } CONNECTION_TEST() { [ $REMOTE_NAME ] && { [[ $(REMOTE__QUERY_CONNECTION .sessions.$REMOTE_NAME) =~ false ]] && { return 1 } } local REMOTE_ARGS=() REMOTE_ARGS+=($(REMOTE__GET_SSH_ARGS --type ssh $REMOTE_NAME)) REMOTE_ARGS+=(-o BatchMode=yes) DEBUG "attempting\ntimeout $TIMEOUT_SECONDS ssh $REMOTE_ARGS $CONNECTION_STRING "'\'"\"$COMMAND"'\'"\"" >&2 timeout --foreground $TIMEOUT_SECONDS ssh ${REMOTE_ARGS[@]} "$CONNECTION_STRING" "$COMMAND" >&2 } ;; esac [ $REMOTE_NAME ] || REMOTE_NAME=explicit STATUS "testing connection $CONNECTION_STRING ($REMOTE_NAME$([ $BASTION_TARGET ] && echo " -> $BASTION_TARGET"))" \ && CONNECTION_TEST \ && SUCCESS "successfully connected to '$CONNECTION_STRING' ($REMOTE_NAME)" \ || ERROR "connection to '$CONNECTION_STRING ($REMOTE_NAME)' failed" \ }