Skip to content

Instantly share code, notes, and snippets.

@jtrive84
Last active February 11, 2019 02:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtrive84/cd43eda7e3399fb1642c29b0b76f7bd9 to your computer and use it in GitHub Desktop.
Save jtrive84/cd43eda7e3399fb1642c29b0b76f7bd9 to your computer and use it in GitHub Desktop.
Connect to remotely running Python kernel from localhost via Jupyter QtConsole.
#!/bin/bash
# <>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>
# Connect to a remote Python kernel via locally-running Jupyter QtConsole. |
# Created by James D. Triveri. |
# |
# Requirements: |
# |
# * Jupyter/IPython must be installed on both local and remote hosts. |
# |
# <>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>
# Configuration and Setup |
# <>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>
USERNAME="username"
LOCAL_JUPYTER="C:/Anaconda3/Scripts/jupyter.exe"
LOCAL_JUPYTER_QTCONSOLE="C:/Anaconda3/Scripts/jupyter-qtconsole.exe"
LOCAL_SSH_CONFIG="C:/cygwin64/home/username/.ssh/config"
REMOTEHOST="remotehost.com"
SSH_PORT="3337"
REMOTE_JUPYTER="/usr/bin/local/anaconda3/bin/jupyter"
REMOTE_IPYTHON="/usr/bin/local/anaconda3/bin/ipython"
# <>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>
# Do not modify variables below this point!!! |
# <>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>*<>
##### Bind reference to local and remote jupyter runtime directories #####
LOCAL_KERNEL_DIR="$(${LOCAL_JUPYTER} --runtime-dir | sed -e 's/\\/\//g' | tr -d '\r\n')"
LOCAL_KERNEL_DIR="${LOCAL_KERNEL_DIR%%/}"
REMOTE_KERNEL_DIR_CMD="${REMOTE_JUPYTER} --runtime-dir"
REMOTE_KERNEL_DIR="$(ssh -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} ${REMOTE_KERNEL_DIR_CMD})"
REMOTE_KERNEL_DIR="${REMOTE_KERNEL_DIR%%/}"
##### Initialize kernel daemon on remote host #####
ssh -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} "nohup ${REMOTE_IPYTHON} kernel > /dev/null &"
KERNEL_PID=$(ssh -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} "pgrep -n -u ${USERNAME} ipython")
##### Get most recently created file in remote jupyter directory #####
REMOTE_KERNEL_FULL_PATH="${REMOTE_KERNEL_DIR}/kernel-${KERNEL_PID}.json"
KERNEL_FILENAME="$(basename ${REMOTE_KERNEL_FULL_PATH})"
REMOTE_KERNEL_FULL_PATH="${REMOTE_KERNEL_DIR}/${KERNEL_FILENAME}"
LOCAL_KERNEL_FULL_PATH="${LOCAL_KERNEL_DIR}/kernel-${KERNEL_PID}.json"
##### Delay progress until KERNEL_FILENAME becomes visible on remotehost #####
KERNEL_FILE_IND=0
while [[ ${KERNEL_FILE_IND} -eq 0 ]]; do
FILE_CMP_CMD="pushd ${REMOTE_KERNEL_DIR} > /dev/null; ls -1tr | tail -1"
LATEST_KERNEL_FILENAME=$(ssh -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} "${FILE_CMP_CMD}")
if [[ "${LATEST_KERNEL_FILENAME}" == "${KERNEL_FILENAME}" ]]; then
KERNEL_FILE_IND=1
else
sleep 1s
fi
done
##### Copy kernel file from remotehost to localhost #####
TS=$(date)
echo " + [${TS}] Copying ${KERNEL_FILENAME} to localhost."
pushd "${LOCAL_KERNEL_DIR}" > /dev/null
scp -P ${SSH_PORT} ${USERNAME}@${REMOTEHOST}:"${REMOTE_KERNEL_FULL_PATH}" .
TS=$(date)
if [ -e "${LOCAL_KERNEL_FULL_PATH}" ]; then
echo " + [${TS}] ${KERNEL_FILENAME} copied to localhost."
else
echo " + [${TS}] ${KERNEL_FILENAME} not copied to Windows - Exiting."
exit 1
fi
##### Bind each port to support kernel connectivity #####
STDIN_PORT_REGEX='[[:space:]]+"stdin_port":[[:space:]]+\K[0-9]{2,5}'
IOPUB_PORT_REGEX='[[:space:]]+"iopub_port":[[:space:]]+\K[0-9]{2,5}'
SHELL_PORT_REGEX='[[:space:]]+"shell_port":[[:space:]]+\K[0-9]{2,5}'
CONTROL_PORT_REGEX='[[:space:]]+"control_port":[[:space:]]+\K[0-9]{2,5}'
HB_PORT_REGEX='[[:space:]]+"hb_port":[[:space:]]+\K[0-9]{2,5}'
STDIN_PORT_NBR=$(grep -Po ${STDIN_PORT_REGEX} ${KERNEL_FILENAME})
IOPUB_PORT_NBR=$(grep -Po ${IOPUB_PORT_REGEX} ${KERNEL_FILENAME})
SHELL_PORT_NBR=$(grep -Po ${SHELL_PORT_REGEX} ${KERNEL_FILENAME})
CONTROL_PORT_NBR=$(grep -Po ${CONTROL_PORT_REGEX} ${KERNEL_FILENAME})
HB_PORT_NBR=$(grep -Po ${HB_PORT_REGEX} ${KERNEL_FILENAME})
##### Initialize port forwarding #####
TS=$(date)
echo " + [${TS}] Binding/Forwarding stdin_port."
ssh -F "${LOCAL_SSH_CONFIG}" -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} -f -N -L ${STDIN_PORT_NBR}:127.0.0.1:${STDIN_PORT_NBR}
wait
TS=$(date)
echo " + [${TS}] Binding/Forwarding iopub_port."
ssh -F "${LOCAL_SSH_CONFIG}" -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} -f -N -L ${IOPUB_PORT_NBR}:127.0.0.1:${IOPUB_PORT_NBR}
wait
TS=$(date)
echo " + [${TS}] Binding/Forwarding shell_port."
ssh -F "${LOCAL_SSH_CONFIG}" -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} -f -N -L ${SHELL_PORT_NBR}:127.0.0.1:${SHELL_PORT_NBR}
wait
TS=$(date)
echo " + [${TS}] Binding/Forwarding control_port."
ssh -F "${LOCAL_SSH_CONFIG}" -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} -f -N -L ${CONTROL_PORT_NBR}:127.0.0.1:${CONTROL_PORT_NBR}
wait
TS=$(date)
echo " + [${TS}] Binding/Forwarding hb_port."
ssh -F "${LOCAL_SSH_CONFIG}" -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} -f -N -L ${HB_PORT_NBR}:127.0.0.1:${HB_PORT_NBR}
wait
##### Launch Jupyter QtConsole #####
TS=$(date)
echo " + [${TS}] Initializing Jupyter QtConsole."
"${LOCAL_JUPYTER_QTCONSOLE}" --existing "${LOCAL_KERNEL_FULL_PATH}"
wait
##### Shutdown remote once QtConsole session terminates #####
KILL_SPEC="kill -9 ${KERNEL_PID}"
ssh -p ${SSH_PORT} ${USERNAME}@${REMOTEHOST} "${KILL_SPEC}"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment