Skip to content

Commit

Permalink
TWS with IBC running in an rdesktop container. (#45)
Browse files Browse the repository at this point in the history
* TWS with IBC running in an rdesktop container.

first running version

 Changes to be committed:
	modified:   .gitignore
	modified:   .pre-commit-config.yaml
	new file:   Dockerfile.tws.template
	new file:   image-files/tws-scripts/start_session.sh
	new file:   latest/Dockerfile.tws
	new file:   latest/tws-scripts/start_session.sh
	new file:   tws-docker-compose.yml

* consolidated changes from PR #43

Changes to be committed:
	modified:   docker-compose.yml
	modified:   image-files/config/ibc/config.ini.tmpl

* add new environment variables to template_README.md

* fixed several missing components

- logic to switch from user to abc user
- defined common logic between ibgateway and tws in common.sh
- defined logic to default ports based on image type ibgateway/tws and paper/live trading mode
- implemented CUSTOM_CONFIG logic for tws
On branch tws-desktop
Changes to be committed:
	modified:   docker-compose.yml
	modified:   latest/Dockerfile
	modified:   latest/Dockerfile.tws
	new file:   latest/scripts/common.sh
	modified:   latest/scripts/port_forwarding.sh
	modified:   latest/scripts/run.sh
	new file:   latest/tws-scripts/run_tws.sh
	modified:   latest/tws-scripts/start_session.sh
	modified:   tws-docker-compose.yml

Changes not staged for commit:
	modified:   image-files/tws-scripts/start_session.sh
	modified:   latest/scripts/run.sh
	modified:   latest/tws-scripts/start_session.sh

* implement SSH for rdp
fix socat

* align templates for Docker
update image-files scripts and config files

Changes to be committed:
	modified:   Dockerfile.template
	modified:   Dockerfile.tws.template
	new file:   image-files/scripts/common.sh
	modified:   image-files/scripts/port_forwarding.sh
	modified:   image-files/scripts/run.sh
	new file:   image-files/tws-scripts/run_tws.sh
	modified:   image-files/tws-scripts/start_session.sh
	modified:   update.sh

* update template_README and docker-compose with new environment variables

* fix typo on template_README

* disable gpg-agent and ssh-agent
update github actions to support ibgateway and tws-rdesktop images
Changes to be committed:
	new file:   .github/workflows/build.yml
	new file:   .github/workflows/on-push-n-pr.yml
	modified:   .github/workflows/publish.yml
	modified:   image-files/tws-scripts/run_tws.sh
	modified:   latest/tws-scripts/run_tws.sh
	modified:   tws-docker-compose.yml
	modified:   update.sh

* run linters

* kill agents
Changes to be committed:
	modified:   image-files/tws-scripts/run_tws.sh

* set timezone
kill xfce session ssh-agent and gpg-agent
include chromiun dependencies libnspr4 libnss3
avoid duplicate ssh tunnel and agent on tws restart

Changes to be committed:
	modified:   docker-compose.yml
	modified:   image-files/config/ibc/config.ini.tmpl
	modified:   latest/Dockerfile.tws
	modified:   latest/config/ibc/config.ini.tmpl
	modified:   latest/scripts/common.sh
	modified:   latest/scripts/port_forwarding.sh
	modified:   latest/tws-scripts/run_tws.sh
	modified:   latest/tws-scripts/start_session.sh
	modified:   tws-docker-compose.yml

* update workflows
align image-files with latest

* set on-push-n-pr workflows trigget as workflow_dispatch

* fix ssh-agent env file, store it in $HOME rather than hardcoded home
fix socat start after tws restart. don't re-start if already running
add messages to run.sh
Changes to be committed:
	modified:   latest/scripts/common.sh
	modified:   latest/scripts/port_forwarding.sh
	modified:   latest/scripts/run.sh

* set tws-docker-compose.yml

Changes to be committed:
	modified:   tws-docker-compose.yml
  • Loading branch information
gnzsnz authored Nov 26, 2023
1 parent 2ab05e1 commit b47990d
Show file tree
Hide file tree
Showing 18 changed files with 805 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint
- id: hadolint-docker
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.37.0
hooks:
Expand Down
15 changes: 9 additions & 6 deletions Dockerfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,17 @@ ENV IB_GATEWAY_VERSION=$VERSION
ARG USER_ID="${USER_ID:-1000}"
ARG USER_GID="${USER_GID:-1000}"
# IBC env vars
ENV HOME=/home/ibgateway
ENV TWS_MAJOR_VRSN=${IB_GATEWAY_VERSION}
ENV TWS_PATH=/home/ibgateway/Jts
ENV TWS_PATH=${HOME}/Jts
ENV TWS_INI=jts.ini
ENV IBC_PATH=/home/ibgateway/ibc
ENV IBC_INI=/home/ibgateway/ibc/config.ini
ENV IBC_PATH=${HOME}/ibc
ENV IBC_INI=${HOME}/ibc/config.ini
ENV SCRIPT_PATH=${HOME}/scripts
ENV GATEWAY_OR_TWS=gateway
# Copy files
COPY --from=setup /usr/local/i4j_jres/ /usr/local/i4j_jres
COPY --chown=${USER_ID}:${USER_GID} --from=setup /root/ /home/ibgateway/
COPY --chown=${USER_ID}:${USER_GID} --from=setup /root/ ${HOME}

# Prepare system
RUN apt-get update -y && \
Expand All @@ -70,10 +73,10 @@ RUN apt-get update -y && \
rm -rf /var/lib/apt/lists/* && \
groupadd --gid ${USER_GID} ibgateway && \
useradd -ms /bin/bash --uid ${USER_ID} --gid ${USER_GID} ibgateway && \
chmod a+x /home/ibgateway/scripts/*.sh
chmod a+x ${SCRIPT_PATH}/*.sh

USER ${USER_ID}:${USER_GID}
WORKDIR /home/ibgateway/
WORKDIR ${HOME}

# Start run script
CMD ["/home/ibgateway/scripts/run.sh"]
Expand Down
54 changes: 54 additions & 0 deletions Dockerfile.tws.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
##############################################################################
# Setup Stage: install apps
#
# This is a dedicated stage used as source for needed files.
#
##############################################################################
ARG IB_VERSION=$VERSION
FROM ghcr.io/gnzsnz/ib-gateway:${IB_VERSION} as setup

WORKDIR /

##############################################################################
# Build Stage: build production image
##############################################################################

FROM lscr.io/linuxserver/rdesktop:ubuntu-xfce

ENV IB_GATEWAY_VERSION=$VERSION
ENV IB_GATEWAY_RELEASE_CHANNEL=$CHANNEL
ENV IBC_VERSION=3.18.0

# IB Gateway user constants
# IBC env vars
ENV TWS_MAJOR_VRSN=${IB_GATEWAY_VERSION}
ENV TWS_PATH=/opt/ibkr
ENV TWS_INI=jts.ini
ENV IBC_PATH=/opt/ibc
ENV IBC_INI=${IBC_PATH}/config.ini
ENV SCRIPT_PATH=/defaults
ENV GATEWAY_OR_TWS=tws

ARG DEBIAN_FRONTEND=noninteractive

RUN \
apt-get update -y && \
apt-get install --no-install-recommends --yes socat sshpass gettext-base \
libnspr4 libnss3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* # end

# Copy files
COPY --from=setup /usr/local/i4j_jres/ /usr/local/i4j_jres
COPY --chown=abc:abc --from=setup /home/ibgateway/Jts ${TWS_PATH}
COPY --chown=abc:abc --from=setup /home/ibgateway/ibc ${IBC_PATH}
COPY ./tws-scripts/start_session.sh /custom-services.d/start_session.sh
COPY ./tws-scripts/run_tws.sh ${SCRIPT_PATH}
COPY ./scripts/* ${SCRIPT_PATH}

# labels
LABEL org.opencontainers.image.source=https://github.com/gnzsnz/ib-gateway-docker
LABEL org.opencontainers.image.url=https://github.com/gnzsnz/ib-gateway-docker/pkgs/container/tws-rdesktop
LABEL org.opencontainers.image.description="Docker image with XFCE, TWS & IBC"
LABEL org.opencontainers.image.licenses="Apache License Version 2.0"
LABEL org.opencontainers.image.version=${IB_GATEWAY_VERSION}-${IB_GATEWAY_RELEASE_CHANNEL}
118 changes: 118 additions & 0 deletions image-files/scripts/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/bash
# shellcheck disable=SC1091

setup_ssh() {
# setup SSH Tunnel
if [ "$SSH_TUNNEL" = "yes" ]; then
echo ".> Setting SSH tunnel"

_SSH_OPTIONS="-o ServerAliveInterval=${SSH_ALIVE_INTERVAL:-20}"
_SSH_OPTIONS+=" -o ServerAliveCountMax=${SSH_ALIVE_COUNT:-3}"

if [ -n "$SSH_OPTIONS" ]; then
_SSH_OPTIONS+=" $SSH_OPTIONS"
fi
SSH_ALL_OPTIONS="$_SSH_OPTIONS"
export SSH_ALL_OPTIONS
echo ".> SSH options: $SSH_ALL_OPTIONS"

if [ -n "$SSH_PASSPHRASE" ]; then
if ! pgrep ssh-agent >/dev/null; then
# start agent if it's not already running
# https://wiki.archlinux.org/title/SSH_keys#SSH_agents
echo ".> Starting ssh-agent."
ssh-agent >"/config/.ssh-agent.env"
source "/config/.ssh-agent.env"
echo ".> ssh-agent sock: ${SSH_AUTH_SOCK}"
else
echo ".> ssh-agent already running"
if [ -z "${SSH_AUTH_SOCK}" ]; then
echo ".> Loading agent environment"
source "/config/.ssh-agent.env"
fi
echo ".> ssh-agent sock: ${SSH_AUTH_SOCK}"
fi

echo ".> Adding keys to ssh-agent."
export SSH_ASKPASS_REQUIRE=never
SSHPASS="${SSH_PASSPHRASE}" sshpass -e -P "passphrase" ssh-add
echo ".> ssh-agent identities: $(ssh-add -l)"
fi
else
echo ".> SSH tunnel disabled"
fi
}

apply_settings() {
# apply env variables into IBC and gateway/TWS config files
if [ "$CUSTOM_CONFIG" != "yes" ]; then
echo ".> Appling settings to IBC's config.ini"
# replace env variables
envsubst <"${IBC_INI}.tmpl" >"${IBC_INI}"

# where are settings stored
if [ -n "$TWS_SETTINGS_PATH" ]; then
echo ".> Settings directory set to: $TWS_SETTINGS_PATH"
_JTS_PATH=$TWS_SETTINGS_PATH
if [ ! -d "$TWS_SETTINGS_PATH" ]; then
# if TWS_SETTINGS_PATH does not exists, create it
echo ".> Creating directory: $TWS_SETTINGS_PATH"
mkdir "$TWS_SETTINGS_PATH"
fi
else
echo ".> Settings directory NOT set, defaulting to: $TWS_PATH"
_JTS_PATH=$TWS_PATH
fi
# only if jts.ini does not exists
if [ ! -f "$_JTS_PATH/$TWS_INI" ]; then
echo ".> Setting timezone in ${_JTS_PATH}/${TWS_INI}"
envsubst <"${TWS_PATH}/${TWS_INI}.tmpl" >"${_JTS_PATH}/${TWS_INI}"
else
echo ".> File jts.ini already exists, not setting timezone"
fi
else
echo ".> Using CUSTOM_CONFIG, (value:${CUSTOM_CONFIG})"
fi
}

set_ports() {
# set ports for API and SOCAT

# ibgateway ports
if [ "${GATEWAY_OR_TWS}" = "gateway" ]; then
if [ "$TRADING_MODE" = "paper" ]; then
# paper ibgateway ports
API_PORT=4002
SOCAT_PORT=4004
export API_PORT SOCAT_PORT
elif [ "$TRADING_MODE" = "live" ]; then
# live ibgateway ports
API_PORT=4001
SOCAT_PORT=4003
export API_PORT SOCAT_PORT
else
# invalid option
echo ".> Invalid TRADING_MODE: $TRADING_MODE"
exit 1
fi
elif [ "${GATEWAY_OR_TWS}" = "tws" ]; then
if [ "$TRADING_MODE" = "paper" ]; then
# paper TWS ports
API_PORT=7497
SOCAT_PORT=7499
export API_PORT SOCAT_PORT
elif [ "$TRADING_MODE" = "live" ]; then
# live TWS ports
API_PORT=7496
SOCAT_PORT=7498
export API_PORT SOCAT_PORT
else
# invalid option
echo ".> Invalid TRADING_MODE: $TRADING_MODE"
exit 1
fi
fi
echo ".> API_PORT set to: ${API_PORT}"
echo ".> SOCAT_PORT set to: ${SOCAT_PORT}"

}
57 changes: 36 additions & 21 deletions image-files/scripts/port_forwarding.sh
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
#!/bin/bash

# validate API port
if [ -z "${API_PORT}" ]; then
echo ".> API_PORT not set, port: ${API_PORT}"
exit 1
fi

if [ "$SSH_TUNNEL" = "yes" ]; then

if [ "$TRADING_MODE" = "paper" ]; then
SSH_LOCAL_PORT=4002
else
SSH_LOCAL_PORT=4001
if [ -n "$(pgrep -x ssh)" ]; then
# if this script is already running don't start it
echo ".> SSH tunnel already active. Not starting a new one"
exit 0
fi

if [ -z "$SSH_REMOTE_PORT" ]; then
SSH_REMOTE_PORT="$SSH_LOCAL_PORT"
# by default remote port is same than API_PORT
SSH_REMOTE_PORT="$API_PORT"
fi
echo ".> SSH_REMOTE_PORT set to :${SSH_REMOTE_PORT}"

# set vnc ssh tunnel
if [ "$GATEWAY_OR_TWS" = "gateway" ] && [ -n "$SSH_VNC_PORT" ] && [ -n "$VNC_SERVER_PASSWORD" ]; then
# set ssh tunnel for vnc
SSH_SCREEN="-R 127.0.0.1:5900:localhost:$SSH_VNC_PORT"
echo ".> SSH_VNC_TUNNEL set to :${SSH_SCREEN}"
fi

if [ -n "$SSH_VNC_PORT" ] && [ -n "$VNC_SERVER_PASSWORD" ]; then
SSH_VNC_TUNNEL="-R 127.0.0.1:5900:localhost:$SSH_VNC_PORT"
# set rdp ssh tunnel
if [ "$GATEWAY_OR_TWS" = "tws" ] && [ -n "$SSH_RDP_PORT" ]; then
# set ssh tunnel for rdp
SSH_SCREEN="-R 127.0.0.1:3389:localhost:$SSH_RDP_PORT"
echo ".> SSH_RDP_TUNNEL set to :${SSH_SCREEN}"
fi

while true; do
echo "> ssh sock: $SSH_AUTH_SOCK"
bash -c "ssh ${SSH_ALL_OPTIONS} -TNR 127.0.0.1:${SSH_LOCAL_PORT}:localhost:${SSH_REMOTE_PORT} ${SSH_VNC_TUNNEL:-} ${SSH_USER_TUNNEL}"
echo ".> Starting ssh tunnel with ssh sock: $SSH_AUTH_SOCK"
bash -c "ssh ${SSH_ALL_OPTIONS} -TNR 127.0.0.1:${API_PORT}:localhost:${SSH_REMOTE_PORT} ${SSH_SCREEN:-} ${SSH_USER_TUNNEL}"
sleep "${SSH_RESTART:-5}"
done

else
if [ -z "${SOCAT_PORT}" ]; then
echo ".> SOCAT_PORT not set, port: ${SOCAT_PORT}"
exit 1
fi
# no ssh tunnel, start socat
echo ".> Waiting for socat to start"
sleep 30

#
if [ "$TRADING_MODE" = "paper" ]; then
# paper
printf "Forking :::4002 onto 0.0.0.0:4004 > trading mode %s \n" \
"${TRADING_MODE}"
socat TCP-LISTEN:4004,fork TCP:127.0.0.1:4002
else
# live
printf "Forking :::4001 onto 0.0.0.0:4003 > trading mode %s \n" \
"${TRADING_MODE}"
socat TCP-LISTEN:4003,fork TCP:127.0.0.1:4001
fi
printf "Forking :::%d onto 0.0.0.0:%d > trading mode %s \n" \
"${API_PORT}" "${SOCAT_PORT}" "${TRADING_MODE}"
socat TCP-LISTEN:"${SOCAT_PORT}",fork TCP:127.0.0.1:"${API_PORT}"
fi
Loading

0 comments on commit b47990d

Please sign in to comment.