#!/usr/bin/env bash set -e SQL_PROXY_HOST="${SQL_PROXY_HOST:-localhost}" SSH_SQL_PROXY_HOST="sqlproxy.${SQL_PROXY_HOST}" CONNECTION_CACHE="$HOME/.cache/sqlproxy_${SQL_PROXY_HOST}" HELP="Usage: myssh [ls|connect]\n SUBCOMMANDS:\n ls: list available database hosts\n connect: connect to a database host\n disconnect: Quit existing ssh master session\n \n SYNTAX connect host [-u user] [-p password] [-c client] " # Detect Pipe if ! [ -t 1 ] then USE_CLI=true fi ssh_status() { ssh -n -O check -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" > /dev/null 2>&1 } connect() { mkdir -p "${HOME}/.ssh/controlmasters" if ! ssh_status then echo "" > "${CONNECTION_CACHE}" ssh -n -o "ControlPersist=10m" -M -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" q fi } disconnect() { if ssh_status then ssh -n -O stop -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" q fi } # Establishes a port forward to the target host # args: # $1 - target ip # $2 - target port port_forward() { ACTIVE_HOST=$(cat "${CONNECTION_CACHE}") if [ -z "${ACTIVE_HOST}" ] || [ "${ACTIVE_HOST}" != "$1:$2" ] then if [ -n "${ACTIVE_HOST}" ] then ssh -n -O cancel -L "6033:${ACTIVE_HOST}" -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" q fi ssh -n -O forward -L "6033:$1:$2" -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" fi echo "$1:$2" > "${CONNECTION_CACHE}" } ls_hosts() { ssh -n -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" ls } get_host() { if [ "$1" = '' ] then printf 'Please specify the host to connect to.\nRun "myssh ls" to list all available hosts.\n' exit 1 else TARGET_HOST_DATA=$(ssh -n -S "${HOME}/.ssh/controlmasters/%r@%h:%p" "${SSH_SQL_PROXY_HOST}" "get $1") if [ "${TARGET_HOST_DATA}" = '' ] then printf 'No such host: "%s"\n' "$1" exit 1 fi fi } # Checks and sets sql login variables # args: # $1 - sql type (mysql or psql) # $2 - target ip # $3 - target port # $4 - username (optional) # $5 - password (optional) set_host_env() { # Unquote argument ARG="${1//\"/}" if [ "${ARG}" = 'mysql' ] || [ "${ARG}" = 'postgres' ] then TARGET_HOST_TYPE="${ARG}" else printf 'Invalid Database type: "%s"\n' "$T" exit 1 fi ARG="${2//\"/}" if [[ "${ARG}" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] then TARGET_HOST_IP="${ARG}" else printf 'Invalid Host IP "%s" given.\n' "${ARG}" exit 1 fi ARG="${3//\"/}" if [[ "${ARG}" =~ ^[0-9]+$ ]] then TARGET_HOST_PORT="${ARG}" else printf 'Invalid Host Port "%s" given.\n' "${ARG}" exit 1 fi ARG="${4//\"/}" if [ -z "${TARGET_HOST_DBNAME}" ] && [ -n "${ARG}" ] then TARGET_HOST_DBNAME="${ARG}" fi ARG="${5//\"/}" if [ -z "${TARGET_HOST_USERNAME}" ] && [ -n "${ARG}" ] then TARGET_HOST_USERNAME="${ARG}" fi ARG="${6//\"/}" if [ -z "${TARGET_HOST_PASSWORD}" ] && [ -n "${ARG}" ] then TARGET_HOST_PASSWORD="${ARG}" fi } # Runs the sql client for an active connection # args: # $1 - sql type (mysql or psql) # $2 - username # $3 - password # $4 - dbname (optional) run_client() { if [ "$1" = 'mysql' ] then if [ -d "/Applications/Sequel Ace.app" ] && [ "${USE_CLI}" != true ] then open "mysql://$2:$3@${SQL_PROXY_HOST}:6033" -a "Sequel Ace" elif which mysql >/dev/null 2>&1 then mysql --protocol=TCP -u "$2" -p"$3" -h "${SQL_PROXY_HOST}" "${4:+-D$4}" -P 6033 else SHOW_CLI_HELP=true fi elif [ "$1" = 'postgres' ] then if which psql >/dev/null 2>&1 then psql "postgresql://$2:$3@${SQL_PROXY_HOST}:6033/${4:-postgres}" else SHOW_CLI_HELP=true fi fi if [ "${SHOW_CLI_HELP}" = true ] then printf 'No %s client binary found.\nYou can maually establish a connection using the following data.\n' "$1" printf 'host:\t%s\nport:\t%s\nuser:\t%s\npassword:\t%s\n' "${SQL_PROXY_HOST}" '6033' "$2" "$3" fi } MAIN_OPTION="$1" if [ -n "$1" ] then shift fi # ensure connection connect case "${MAIN_OPTION}" in ls) ls_hosts;; connect) # check if host is valid TARGET_HOST="$1" if [ -n "$1" ] then shift else printf 'No host specified.\n' exit 1 fi while getopts "u:p:" o do case "$o" in u) TARGET_HOST_USERNAME="${OPTARG}" ;; p) TARGET_HOST_PASSWORD="${OPTARG}" ;; d) TARGET_HOST_DBNAME="${OPTARG}" ;; c) USE_CLI=true ;; esac done get_host "${TARGET_HOST}" # Do not quote this. set_host_env ${TARGET_HOST_DATA} port_forward "${TARGET_HOST_IP}" "$TARGET_HOST_PORT" if [ -n "${TARGET_HOST_USERNAME}" ] && [ -n "${TARGET_HOST_PASSWORD}" ] then run_client "${TARGET_HOST_TYPE}" "${TARGET_HOST_USERNAME}" "${TARGET_HOST_PASSWORD}" "${TARGET_HOST_DBNAME}" fi ;; disconnect) disconnect;; *) echo -e "${HELP}";; esac