#!/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.config.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 ]] \ || echo.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 ) ;; * ) echo.error "invalid setting for '--use-bastion' (must be 'true' or 'false')" ;; esac ;; * ) echo.error "unrecognized argument '$1'" ;; esac [[ $_S -le $# ]] \ && shift $_S \ || echo.error "missing argument for '$1'" \ || shift $# done [ $CONNECTION_STRING ] \ || echo.error "unable to determine connection string" [ $USE_BASTION ] || { USE_BASTION=$(\ remote.config.query-connection-with-fallback \ ".sessions.$REMOTE_NAME.bastion.preferred" \ 'false' \ ; ) } utils.check-errors --fail ########################################## local BASTION_HOST [[ $USE_BASTION =~ true ]] && { BASTION_HOST=$(\ remote.config.query-connection-with-fallback \ ".sessions.$REMOTE_NAME.bastion.session" \ ) } [[ $USE_BASTION =~ true ]] && { [ $BASTION_HOST ] \ || echo.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 ]] && { echo.debug "MAIN -n $BASTION_HOST -c \"$(remote.bastion.get-passthrough-prefix) remote test -- -n $REMOTE_NAME -c \"$COMMAND\"\"" BASTION_TARGET="$REMOTE_NAME" MAIN -n $BASTION_HOST -c "$(remote.bastion.get-passthrough-prefix) remote test -- -n $REMOTE_NAME -c \"$COMMAND\"" return $? } CONNECTION_TEST() { [ $REMOTE_NAME ] && { [[ $(remote.config.query-connection .sessions.$REMOTE_NAME.enabled) =~ false ]] && { return 1 } } local REMOTE_ARGS=() REMOTE_ARGS+=($(remote.config.get-ssh-args --type ssh $REMOTE_NAME)) REMOTE_ARGS+=(-o BatchMode=yes) echo.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 echo.status "testing connection $CONNECTION_STRING ($REMOTE_NAME$([ $BASTION_TARGET ] && echo " -> $BASTION_TARGET"))" \ && CONNECTION_TEST \ && echo.success "successfully connected to '$CONNECTION_STRING' ($REMOTE_NAME)" \ || echo.error "connection to '$CONNECTION_STRING ($REMOTE_NAME)' failed" \ }