From 35f2bf9aa048d22606643c3e37550a6dd3f3bb21 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Tue, 26 May 2026 15:22:49 +0800 Subject: [PATCH] Support multiple IBKR gateway instances --- .github/workflows/main.yml | 69 +++++++++++++++------ .github/workflows/remote-maintenance.yml | 74 ++++++++++++++++------- README.md | 25 ++++++++ docker-compose.yml | 8 +-- scripts/ibkr_gateway_units.sh | 48 +++++++++++++++ scripts/install_2fa_bot_watcher.sh | 16 +++-- scripts/install_gateway_health_watcher.sh | 32 +++++++--- scripts/recover_ib_gateway_ready.sh | 7 ++- scripts/restart_ib_gateway_daily.sh | 6 +- tests/test_docker_compose_ports.sh | 6 +- tests/test_gateway_recovery_scripts.sh | 30 ++++++--- tests/test_install_2fa_bot_watcher.sh | 11 ++-- tests/test_workflow_shared_config.sh | 34 ++++++++--- 13 files changed, 277 insertions(+), 89 deletions(-) create mode 100755 scripts/ibkr_gateway_units.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de7c33f..3c3a340 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,6 +49,14 @@ jobs: GCE_ZONE: ${{ vars.IB_GATEWAY_ZONE }} DEPLOY_PATH: ${{ vars.IB_GATEWAY_DEPLOY_PATH }} IB_GATEWAY_MODE: ${{ vars.IB_GATEWAY_MODE }} + IB_GATEWAY_CONTAINER_NAME: ${{ vars.IB_GATEWAY_CONTAINER_NAME }} + IB_GATEWAY_COMPOSE_PROJECT_NAME: ${{ vars.IB_GATEWAY_COMPOSE_PROJECT_NAME }} + IB_GATEWAY_COMPOSE_SERVICE_NAME: ${{ vars.IB_GATEWAY_COMPOSE_SERVICE_NAME }} + IB_GATEWAY_UNIT_SUFFIX: ${{ vars.IB_GATEWAY_UNIT_SUFFIX }} + IB_GATEWAY_LIVE_HOST_PORT: ${{ vars.IB_GATEWAY_LIVE_HOST_PORT }} + IB_GATEWAY_PAPER_HOST_PORT: ${{ vars.IB_GATEWAY_PAPER_HOST_PORT }} + IB_GATEWAY_VNC_HOST_ADDRESS: ${{ vars.IB_GATEWAY_VNC_HOST_ADDRESS }} + IB_GATEWAY_VNC_HOST_PORT: ${{ vars.IB_GATEWAY_VNC_HOST_PORT }} CLOUD_RUN_EGRESS_CIDR: ${{ vars.IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR }} ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY: ${{ vars.IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY }} TWS_ACCEPT_INCOMING: ${{ vars.IB_GATEWAY_TWS_ACCEPT_INCOMING }} @@ -243,6 +251,17 @@ jobs: "IBKR_2FA_MAX_SUBMISSIONS_PER_WINDOW": os.environ.get("IBKR_2FA_MAX_SUBMISSIONS_PER_WINDOW") or "1", "IBKR_2FA_SUBMISSION_RESET_SECONDS": os.environ.get("IBKR_2FA_SUBMISSION_RESET_SECONDS") or "0", } + optional_values = { + "IB_GATEWAY_CONTAINER_NAME": os.environ.get("IB_GATEWAY_CONTAINER_NAME", ""), + "COMPOSE_PROJECT_NAME": os.environ.get("IB_GATEWAY_COMPOSE_PROJECT_NAME", ""), + "IB_GATEWAY_COMPOSE_SERVICE_NAME": os.environ.get("IB_GATEWAY_COMPOSE_SERVICE_NAME", ""), + "IB_GATEWAY_UNIT_SUFFIX": os.environ.get("IB_GATEWAY_UNIT_SUFFIX", ""), + "IB_GATEWAY_LIVE_HOST_PORT": os.environ.get("IB_GATEWAY_LIVE_HOST_PORT", ""), + "IB_GATEWAY_PAPER_HOST_PORT": os.environ.get("IB_GATEWAY_PAPER_HOST_PORT", ""), + "IB_GATEWAY_VNC_HOST_ADDRESS": os.environ.get("IB_GATEWAY_VNC_HOST_ADDRESS", ""), + "IB_GATEWAY_VNC_HOST_PORT": os.environ.get("IB_GATEWAY_VNC_HOST_PORT", ""), + } + values.update({key: value for key, value in optional_values.items() if value}) def quote(value: str) -> str: return "'" + value.replace("'", "'\"'\"'") + "'" @@ -360,15 +379,23 @@ jobs: set -euo pipefail cd '${DEPLOY_PATH}' echo "[\$(date -u +%FT%TZ)] Scheduled keepalive mode: skip docker build" - sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true + set -a + . ./.env + set +a + . ./scripts/ibkr_gateway_units.sh + container_name="\${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}" + compose_service_name="\${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}" + resolve_ibkr_gateway_unit_names "\${container_name}" "\${IB_GATEWAY_UNIT_SUFFIX:-}" + sudo systemctl stop "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "\${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true + sudo systemctl stop "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "\${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true sudo bash ./scripts/ensure_host_swap.sh - sudo bash ./scripts/install_2fa_bot_watcher.sh - sudo bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}' - sudo bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}' + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_2fa_bot_watcher.sh + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}' + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}' sudo docker compose ps - sudo systemctl status ibkr-2fa-bot.timer --no-pager - sudo systemctl status ibkr-gateway-healthcheck.timer --no-pager - sudo systemctl status ibkr-gateway-daily-restart.timer --no-pager + sudo systemctl status "\${IBKR_2FA_BOT_TIMER}" --no-pager + sudo systemctl status "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" --no-pager + sudo systemctl status "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" --no-pager echo "[\$(date -u +%FT%TZ)] Keepalive complete." EOF ) @@ -377,22 +404,30 @@ jobs: set -euo pipefail cd '${DEPLOY_PATH}' echo "[\$(date -u +%FT%TZ)] Full deploy mode: rebuilding container" - sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true + set -a + . ./.env + set +a + . ./scripts/ibkr_gateway_units.sh + container_name="\${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}" + compose_service_name="\${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}" + resolve_ibkr_gateway_unit_names "\${container_name}" "\${IB_GATEWAY_UNIT_SUFFIX:-}" + sudo systemctl stop "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "\${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true + sudo systemctl stop "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "\${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true sudo bash ./scripts/ensure_host_swap.sh - sudo docker compose build + sudo docker compose build "\${compose_service_name}" sudo docker compose down - sudo docker compose up -d + sudo docker compose up -d "\${compose_service_name}" - sudo bash ./scripts/install_2fa_bot_watcher.sh - sudo bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}' - sudo bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}' + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_2fa_bot_watcher.sh + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}' + sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}' sudo docker compose ps - sudo systemctl status ibkr-2fa-bot.timer --no-pager - sudo systemctl status ibkr-gateway-healthcheck.timer --no-pager - sudo systemctl status ibkr-gateway-daily-restart.timer --no-pager + sudo systemctl status "\${IBKR_2FA_BOT_TIMER}" --no-pager + sudo systemctl status "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" --no-pager + sudo systemctl status "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" --no-pager echo "Deployment complete. Bot is monitoring the login window." - echo "Run 'docker exec ib-gateway tail -f /home/ibgateway/2fa.log' for real-time status." + echo "Run 'docker exec \${container_name} tail -f /home/ibgateway/2fa.log' for real-time status." EOF ) fi diff --git a/.github/workflows/remote-maintenance.yml b/.github/workflows/remote-maintenance.yml index 2f19c24..49bbe5f 100644 --- a/.github/workflows/remote-maintenance.yml +++ b/.github/workflows/remote-maintenance.yml @@ -33,6 +33,9 @@ jobs: GCE_ZONE: ${{ vars.IB_GATEWAY_ZONE }} DEPLOY_PATH: ${{ vars.IB_GATEWAY_DEPLOY_PATH }} IB_GATEWAY_MODE: ${{ vars.IB_GATEWAY_MODE }} + IB_GATEWAY_CONTAINER_NAME: ${{ vars.IB_GATEWAY_CONTAINER_NAME }} + IB_GATEWAY_COMPOSE_SERVICE_NAME: ${{ vars.IB_GATEWAY_COMPOSE_SERVICE_NAME }} + IB_GATEWAY_UNIT_SUFFIX: ${{ vars.IB_GATEWAY_UNIT_SUFFIX }} SSH_PRIVATE_KEY_SECRET_NAME: ${{ vars.IB_GATEWAY_SSH_PRIVATE_KEY_SECRET_NAME }} MAINTENANCE_ACTION: ${{ github.event.inputs.action }} steps: @@ -92,25 +95,34 @@ jobs: ) deploy_path_quoted="$(printf '%q' "${DEPLOY_PATH}")" gateway_mode_quoted="$(printf '%q' "${IB_GATEWAY_MODE:-paper}")" + container_name_quoted="$(printf '%q' "${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}")" + compose_service_name_quoted="$(printf '%q' "${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}")" + unit_suffix_quoted="$(printf '%q' "${IB_GATEWAY_UNIT_SUFFIX:-}")" case "${MAINTENANCE_ACTION}" in stop-2fa-bot) REMOTE_COMMAND=$(cat <<'EOF' set -euo pipefail - sudo systemctl stop ibkr-2fa-bot.timer ibkr-2fa-bot.service 2>/dev/null || true - sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true - sudo docker exec ib-gateway pgrep -a -f 2fa_bot.py 2>/dev/null || echo "2FA bot stopped" - sudo systemctl status ibkr-2fa-bot.timer ibkr-2fa-bot.service --no-pager || true + cd __DEPLOY_PATH__ + container_name=__IB_GATEWAY_CONTAINER_NAME__ + unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__ + . ./scripts/ibkr_gateway_units.sh + resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}" + sudo systemctl stop "${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" 2>/dev/null || true + sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true + sudo docker exec "${container_name}" pgrep -a -f 2fa_bot.py 2>/dev/null || echo "2FA bot stopped" + sudo systemctl status "${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" --no-pager || true EOF ) ;; restart-2fa-bot) REMOTE_COMMAND=$(cat <<'EOF' set -euo pipefail - sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true - sudo /usr/local/bin/ensure-ibkr-2fa-bot-running - sudo docker exec ib-gateway pgrep -a -f 2fa_bot.py - sudo docker exec ib-gateway tail -n 40 /home/ibgateway/2fa.log 2>/dev/null || true + container_name=__IB_GATEWAY_CONTAINER_NAME__ + sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true + sudo env CONTAINER_NAME="${container_name}" /usr/local/bin/ensure-ibkr-2fa-bot-running + sudo docker exec "${container_name}" pgrep -a -f 2fa_bot.py + sudo docker exec "${container_name}" tail -n 40 /home/ibgateway/2fa.log 2>/dev/null || true EOF ) ;; @@ -118,12 +130,16 @@ jobs: REMOTE_COMMAND=$(cat <<'EOF' set -euo pipefail cd __DEPLOY_PATH__ + container_name=__IB_GATEWAY_CONTAINER_NAME__ + unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__ + . ./scripts/ibkr_gateway_units.sh + resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}" sudo systemctl disable --now \ - ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service \ - ibkr-gateway-daily-restart.timer ibkr-gateway-daily-restart.service \ - ibkr-2fa-bot.timer ibkr-2fa-bot.service 2>/dev/null || true - sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true - sudo docker update --restart=no ib-gateway 2>/dev/null || true + "${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" \ + "${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" \ + "${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" 2>/dev/null || true + sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true + sudo docker update --restart=no "${container_name}" 2>/dev/null || true sudo docker compose down sudo docker compose ps EOF @@ -133,12 +149,17 @@ jobs: REMOTE_COMMAND=$(cat <<'EOF' set -euo pipefail cd __DEPLOY_PATH__ - sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true - sudo systemctl stop ibkr-gateway-daily-restart.timer ibkr-gateway-daily-restart.service 2>/dev/null || true - sudo docker compose up -d --no-build ib-gateway - sudo bash ./scripts/install_2fa_bot_watcher.sh - sudo bash ./scripts/recover_ib_gateway_ready.sh __IB_GATEWAY_MODE__ - sudo bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__ + container_name=__IB_GATEWAY_CONTAINER_NAME__ + compose_service_name=__IB_GATEWAY_COMPOSE_SERVICE_NAME__ + unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__ + . ./scripts/ibkr_gateway_units.sh + resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}" + sudo systemctl stop "${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true + sudo systemctl stop "${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true + sudo docker compose up -d --no-build "${compose_service_name}" + sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_UNIT_SUFFIX="${unit_suffix}" bash ./scripts/install_2fa_bot_watcher.sh + sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh __IB_GATEWAY_MODE__ + sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="${unit_suffix}" bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__ sudo docker compose ps EOF ) @@ -147,11 +168,15 @@ jobs: REMOTE_COMMAND=$(cat <<'EOF' set -euo pipefail cd __DEPLOY_PATH__ + container_name=__IB_GATEWAY_CONTAINER_NAME__ + unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__ + . ./scripts/ibkr_gateway_units.sh + resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}" sudo docker compose ps - sudo systemctl status ibkr-gateway-healthcheck.timer ibkr-gateway-daily-restart.timer ibkr-2fa-bot.timer --no-pager || true - sudo docker exec ib-gateway pgrep -a -f "2fa_bot.py|ibgateway|socat|Xvfb|x11vnc|ibcstart" 2>/dev/null || true - sudo docker exec ib-gateway bash -lc 'ss -ltnp 2>/dev/null | grep -E ":(4001|4002|4003|4004|5900)\b" || true' || true - sudo docker exec ib-gateway tail -n 80 /home/ibgateway/2fa.log 2>/dev/null || true + sudo systemctl status "${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_2FA_BOT_TIMER}" --no-pager || true + sudo docker exec "${container_name}" pgrep -a -f "2fa_bot.py|ibgateway|socat|Xvfb|x11vnc|ibcstart" 2>/dev/null || true + sudo docker exec "${container_name}" bash -lc 'ss -ltnp 2>/dev/null | grep -E ":(4001|4002|4003|4004|5900)\b" || true' || true + sudo docker exec "${container_name}" tail -n 80 /home/ibgateway/2fa.log 2>/dev/null || true EOF ) ;; @@ -162,5 +187,8 @@ jobs: esac REMOTE_COMMAND="${REMOTE_COMMAND//__DEPLOY_PATH__/${deploy_path_quoted}}" REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_MODE__/${gateway_mode_quoted}}" + REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_CONTAINER_NAME__/${container_name_quoted}}" + REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_COMPOSE_SERVICE_NAME__/${compose_service_name_quoted}}" + REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_UNIT_SUFFIX__/${unit_suffix_quoted}}" gcloud compute ssh "${REMOTE_TARGET}" "${SSH_FLAGS[@]}" --command "${REMOTE_COMMAND}" diff --git a/README.md b/README.md index 0d8d449..1370a3b 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,9 @@ IB_GATEWAY_MODE=paper IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR=10.128.0.0/20 IB_GATEWAY_GCE_USER=zwlddx0815 IB_GATEWAY_DEPLOY_PATH=/home/zwlddx0815/ib-docker +IB_GATEWAY_CONTAINER_NAME=ib-gateway +IB_GATEWAY_LIVE_HOST_PORT=4001 +IB_GATEWAY_PAPER_HOST_PORT=4002 IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY=no IB_GATEWAY_TWS_ACCEPT_INCOMING=accept IB_GATEWAY_READ_ONLY_API=no @@ -109,6 +112,8 @@ The workflow maps these shared values to the gateway container's `.env`: - `IB_GATEWAY_ZONE` -> `GCE_ZONE` - `IB_GATEWAY_GCE_USER` -> `GCE_USER` - `IB_GATEWAY_DEPLOY_PATH` -> `DEPLOY_PATH` +- `IB_GATEWAY_CONTAINER_NAME` -> Docker container name +- `IB_GATEWAY_LIVE_HOST_PORT` / `IB_GATEWAY_PAPER_HOST_PORT` -> host API ports - `IB_GATEWAY_TWOFA_DEVICE` -> `TWOFA_DEVICE` - `IB_GATEWAY_2FA_AUTOFILL` -> `IBKR_2FA_AUTOFILL` @@ -128,6 +133,20 @@ sudo bash ./scripts/install_gateway_health_watcher.sh > Manual `workflow_dispatch` defaults to `keepalive`. If you really need to rebuild the image, choose `deploy_mode=full` when dispatching it. +### Multiple Gateway Sessions on One VM + +The default deployment remains one container named `ib-gateway` exposing live/paper API ports `4001`/`4002`. To run another IBKR username on the same VM, use a separate deploy directory or `COMPOSE_PROJECT_NAME`, and give that instance unique container and host ports: + +```bash +IB_GATEWAY_CONTAINER_NAME=ib-gateway-u1234567 +COMPOSE_PROJECT_NAME=ib-gateway-u1234567 +IB_GATEWAY_LIVE_HOST_PORT=4011 +IB_GATEWAY_PAPER_HOST_PORT=4012 +IB_GATEWAY_UNIT_SUFFIX=u1234567 +``` + +The compose service name stays `ib-gateway` unless you intentionally change the YAML service key. The scripts use `IB_GATEWAY_COMPOSE_SERVICE_NAME` for compose operations and `IB_GATEWAY_CONTAINER_NAME` for `docker exec`/health checks. Systemd watcher units are suffixed automatically when the container name is not the default, so multiple Gateway sessions do not overwrite each other's timers. + ### 4. Verify on GCE VM ```bash @@ -208,6 +227,12 @@ If you temporarily keep the values in GitHub Secrets during migration, you can r | `IB_GATEWAY_INSTANCE_NAME` | VM instance name | | `IB_GATEWAY_ZONE` | VM zone | | `IB_GATEWAY_MODE` | `paper` or `live` | +| `IB_GATEWAY_CONTAINER_NAME` | Optional Docker container name. Defaults to `ib-gateway`. Use a unique value per Gateway session. | +| `IB_GATEWAY_COMPOSE_PROJECT_NAME` | Optional compose project name. Use this or a unique deploy path when running multiple sessions on one VM. | +| `IB_GATEWAY_COMPOSE_SERVICE_NAME` | Optional compose service name. Defaults to `ib-gateway`; only change it if the compose service key changes. | +| `IB_GATEWAY_UNIT_SUFFIX` | Optional systemd suffix. Inferred from non-default container names when unset. | +| `IB_GATEWAY_LIVE_HOST_PORT` | Optional host port mapped to container live API port `4003`. Defaults to `4001`. | +| `IB_GATEWAY_PAPER_HOST_PORT` | Optional host port mapped to container paper API port `4004`. Defaults to `4002`. | | `IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR` | Cloud Run Direct VPC egress or connector CIDR (example `10.8.0.0/26`) | | `IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY` | Set to `no` for Cloud Run private IP access | | `IB_GATEWAY_TWS_ACCEPT_INCOMING` | Optional. Recommended `accept`. | diff --git a/docker-compose.yml b/docker-compose.yml index 9d6ac65..0897bee 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: ib-gateway: build: . - container_name: ib-gateway + container_name: ${IB_GATEWAY_CONTAINER_NAME:-ib-gateway} restart: always environment: # Read variables from the host's .env file @@ -42,9 +42,9 @@ services: ports: # The base image exposes remote API access through socat on container # ports 4003/4004 while keeping IB Gateway itself localhost-only. - - "4001:4003" - - "4002:4004" + - "${IB_GATEWAY_LIVE_HOST_PORT:-4001}:4003" + - "${IB_GATEWAY_PAPER_HOST_PORT:-4002}:4004" # VNC Desktop Port for visual monitoring (Default: 5900) # Strongly recommended to keep blocked by firewall or tunnel only. - - "127.0.0.1:5900:5900" + - "${IB_GATEWAY_VNC_HOST_ADDRESS:-127.0.0.1}:${IB_GATEWAY_VNC_HOST_PORT:-5900}:5900" diff --git a/scripts/ibkr_gateway_units.sh b/scripts/ibkr_gateway_units.sh new file mode 100755 index 0000000..31a2e61 --- /dev/null +++ b/scripts/ibkr_gateway_units.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +sanitize_ibkr_systemd_suffix() { + local raw_suffix="${1:-}" + local sanitized + sanitized="$(printf '%s' "$raw_suffix" | tr -cs 'A-Za-z0-9_.@-' '-' | sed -e 's/^-//' -e 's/-$//')" + printf '%s' "$sanitized" +} + +resolve_ibkr_gateway_unit_suffix() { + local container_name="${1:-ib-gateway}" + local configured_suffix="${2:-}" + local raw_suffix="" + + if [ -n "$configured_suffix" ]; then + raw_suffix="$configured_suffix" + elif [ "$container_name" != "ib-gateway" ]; then + raw_suffix="$container_name" + fi + + sanitize_ibkr_systemd_suffix "$raw_suffix" +} + +resolve_ibkr_gateway_unit_names() { + local container_name="${1:-ib-gateway}" + local configured_suffix="${2:-}" + local unit_suffix + local unit_infix="" + + unit_suffix="$(resolve_ibkr_gateway_unit_suffix "$container_name" "$configured_suffix")" + if [ -n "$unit_suffix" ]; then + unit_infix="-$unit_suffix" + fi + + IBKR_2FA_BOT_SERVICE="ibkr-2fa-bot${unit_infix}.service" + IBKR_2FA_BOT_TIMER="ibkr-2fa-bot${unit_infix}.timer" + IBKR_GATEWAY_HEALTHCHECK_SERVICE="ibkr-gateway-healthcheck${unit_infix}.service" + IBKR_GATEWAY_HEALTHCHECK_TIMER="ibkr-gateway-healthcheck${unit_infix}.timer" + IBKR_GATEWAY_DAILY_RESTART_SERVICE="ibkr-gateway-daily-restart${unit_infix}.service" + IBKR_GATEWAY_DAILY_RESTART_TIMER="ibkr-gateway-daily-restart${unit_infix}.timer" + + export IBKR_2FA_BOT_SERVICE + export IBKR_2FA_BOT_TIMER + export IBKR_GATEWAY_HEALTHCHECK_SERVICE + export IBKR_GATEWAY_HEALTHCHECK_TIMER + export IBKR_GATEWAY_DAILY_RESTART_SERVICE + export IBKR_GATEWAY_DAILY_RESTART_TIMER +} diff --git a/scripts/install_2fa_bot_watcher.sh b/scripts/install_2fa_bot_watcher.sh index 2052a0d..a02b418 100755 --- a/scripts/install_2fa_bot_watcher.sh +++ b/scripts/install_2fa_bot_watcher.sh @@ -5,12 +5,16 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" bin_dir="${BIN_DIR:-/usr/local/bin}" systemd_dir="${SYSTEMD_DIR:-/etc/systemd/system}" systemctl_bin="${SYSTEMCTL_BIN:-systemctl}" -container_name="${CONTAINER_NAME:-ib-gateway}" +container_name="${CONTAINER_NAME:-${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}}" +unit_suffix="${IB_GATEWAY_UNIT_SUFFIX:-}" + +. "$script_dir/ibkr_gateway_units.sh" +resolve_ibkr_gateway_unit_names "$container_name" "$unit_suffix" install -d "$bin_dir" "$systemd_dir" install -m 0755 "$script_dir/ensure_2fa_bot_running.sh" "$bin_dir/ensure-ibkr-2fa-bot-running" -cat >"$systemd_dir/ibkr-2fa-bot.service" <"$systemd_dir/$IBKR_2FA_BOT_SERVICE" <"$systemd_dir/ibkr-2fa-bot.timer" <<'EOF' +cat >"$systemd_dir/$IBKR_2FA_BOT_TIMER" <"$systemd_dir/ibkr-gateway-healthcheck.service" <"$systemd_dir/$IBKR_GATEWAY_HEALTHCHECK_SERVICE" <"$systemd_dir/ibkr-gateway-healthcheck.timer" <"$systemd_dir/$IBKR_GATEWAY_HEALTHCHECK_TIMER" <"$systemd_dir/ibkr-gateway-daily-restart.service" <"$systemd_dir/$IBKR_GATEWAY_DAILY_RESTART_SERVICE" <"$systemd_dir/ibkr-gateway-daily-restart.timer" <"$systemd_dir/$IBKR_GATEWAY_DAILY_RESTART_TIMER" <&2 docker compose ps >&2 || true -docker compose restart "${container_name}" +docker compose restart "${compose_service_name}" ensure_2fa_bot_running if wait_for_ready "${restart_wait_seconds}"; then @@ -56,7 +57,7 @@ if wait_for_ready "${restart_wait_seconds}"; then fi echo "IB gateway API is still not ready; recreating ${container_name} and retrying." >&2 -docker compose up -d --force-recreate --no-build "${container_name}" +docker compose up -d --force-recreate --no-build "${compose_service_name}" ensure_2fa_bot_running if wait_for_ready "${recreate_wait_seconds}"; then diff --git a/scripts/restart_ib_gateway_daily.sh b/scripts/restart_ib_gateway_daily.sh index d234753..bb3580a 100755 --- a/scripts/restart_ib_gateway_daily.sh +++ b/scripts/restart_ib_gateway_daily.sh @@ -4,16 +4,18 @@ set -euo pipefail script_dir="$(cd "$(dirname "$0")" && pwd)" repo_dir="$(cd "${script_dir}/.." && pwd)" container_name="${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}" +compose_service_name="${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}" gateway_mode="${1:-${IB_GATEWAY_MODE:-paper}}" ready_wait_seconds="${IB_GATEWAY_DAILY_RESTART_READY_WAIT_SECONDS:-240}" cd "${repo_dir}" echo "Restarting ${container_name} for scheduled IB Gateway refresh (mode=${gateway_mode})." -docker compose up -d --no-build -docker compose restart "${container_name}" +docker compose up -d --no-build "${compose_service_name}" +docker compose restart "${compose_service_name}" IB_GATEWAY_CONTAINER_NAME="${container_name}" \ +IB_GATEWAY_COMPOSE_SERVICE_NAME="${compose_service_name}" \ IB_GATEWAY_RECOVERY_INITIAL_WAIT_SECONDS="${ready_wait_seconds}" \ bash "${script_dir}/recover_ib_gateway_ready.sh" "${gateway_mode}" diff --git a/tests/test_docker_compose_ports.sh b/tests/test_docker_compose_ports.sh index 97f5871..fae582a 100644 --- a/tests/test_docker_compose_ports.sh +++ b/tests/test_docker_compose_ports.sh @@ -31,8 +31,10 @@ grep -Fq 'IB_GATEWAY_PARALLEL_GC_THREADS:-2' "$run_override" grep -Fq 'IB_GATEWAY_CONC_GC_THREADS:-1' "$run_override" grep -Fq 'Java GC threads set to ParallelGCThreads=${parallel_threads}, ConcGCThreads=${conc_threads}' "$run_override" -grep -Fq ' - "4001:4003"' "$compose_file" -grep -Fq ' - "4002:4004"' "$compose_file" +grep -Fq 'container_name: ${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}' "$compose_file" +grep -Fq ' - "${IB_GATEWAY_LIVE_HOST_PORT:-4001}:4003"' "$compose_file" +grep -Fq ' - "${IB_GATEWAY_PAPER_HOST_PORT:-4002}:4004"' "$compose_file" +grep -Fq ' - "${IB_GATEWAY_VNC_HOST_ADDRESS:-127.0.0.1}:${IB_GATEWAY_VNC_HOST_PORT:-5900}:5900"' "$compose_file" grep -Fq ' - TWS_ACCEPT_INCOMING=${TWS_ACCEPT_INCOMING:-accept}' "$compose_file" grep -Fq ' - READ_ONLY_API=${READ_ONLY_API:-no}' "$compose_file" grep -Fq ' - TWOFA_DEVICE=${TWOFA_DEVICE:-}' "$compose_file" diff --git a/tests/test_gateway_recovery_scripts.sh b/tests/test_gateway_recovery_scripts.sh index 3362981..0a40f37 100644 --- a/tests/test_gateway_recovery_scripts.sh +++ b/tests/test_gateway_recovery_scripts.sh @@ -6,15 +6,18 @@ recover_script="$repo_dir/scripts/recover_ib_gateway_ready.sh" swap_script="$repo_dir/scripts/ensure_host_swap.sh" daily_restart_script="$repo_dir/scripts/restart_ib_gateway_daily.sh" health_watcher_script="$repo_dir/scripts/install_gateway_health_watcher.sh" +unit_helper_script="$repo_dir/scripts/ibkr_gateway_units.sh" test -f "$recover_script" test -f "$swap_script" test -f "$daily_restart_script" test -f "$health_watcher_script" +test -f "$unit_helper_script" test -x "$recover_script" test -x "$swap_script" test -x "$daily_restart_script" test -x "$health_watcher_script" +test -x "$unit_helper_script" grep -Fq 'IB_GATEWAY_RECOVERY_INITIAL_WAIT_SECONDS:-240' "$recover_script" grep -Fq 'IB_GATEWAY_RECOVERY_RESTART_WAIT_SECONDS:-300' "$recover_script" @@ -23,8 +26,9 @@ grep -Fq 'IB_GATEWAY_RECOVERY_LOCK_FILE:-/var/lock/ib_gateway_recovery.lock' "$r grep -Fq 'IB_GATEWAY_RECOVERY_LOCK_WAIT_SECONDS:-900' "$recover_script" grep -Fq 'flock -n 9' "$recover_script" grep -Fq 'flock -w "${lock_wait_seconds}" 9' "$recover_script" -grep -Fq 'docker compose restart "${container_name}"' "$recover_script" -grep -Fq 'docker compose up -d --force-recreate --no-build "${container_name}"' "$recover_script" +grep -Fq 'compose_service_name="${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}"' "$recover_script" +grep -Fq 'docker compose restart "${compose_service_name}"' "$recover_script" +grep -Fq 'docker compose up -d --force-recreate --no-build "${compose_service_name}"' "$recover_script" grep -Fq 'IB_GATEWAY_READY_TIMEOUT_SECONDS="${timeout_seconds}"' "$recover_script" grep -Fq 'CONTAINER_NAME="${container_name}" bash "${script_dir}/ensure_2fa_bot_running.sh"' "$recover_script" ensure_count="$(grep -c 'ensure_2fa_bot_running' "$recover_script")" @@ -36,21 +40,29 @@ grep -Fq 'swapon "${swap_file}"' "$swap_script" grep -Fq 'grep -Fq "${swap_file} none swap sw 0 0" /etc/fstab' "$swap_script" grep -Fq 'printf '\''%s none swap sw 0 0\n'\'' "${swap_file}" >>/etc/fstab' "$swap_script" -grep -Fq 'docker compose restart "${container_name}"' "$daily_restart_script" +grep -Fq 'compose_service_name="${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}"' "$daily_restart_script" +grep -Fq 'docker compose restart "${compose_service_name}"' "$daily_restart_script" grep -Fq 'recover_ib_gateway_ready.sh" "${gateway_mode}"' "$daily_restart_script" -grep -Fq 'ibkr-gateway-healthcheck.service' "$health_watcher_script" -grep -Fq 'ibkr-gateway-healthcheck.timer' "$health_watcher_script" -grep -Fq 'ibkr-gateway-daily-restart.service' "$health_watcher_script" -grep -Fq 'ibkr-gateway-daily-restart.timer' "$health_watcher_script" +grep -Fq 'resolve_ibkr_gateway_unit_names "$container_name" "$unit_suffix"' "$health_watcher_script" +grep -Fq '$IBKR_GATEWAY_HEALTHCHECK_SERVICE' "$health_watcher_script" +grep -Fq '$IBKR_GATEWAY_HEALTHCHECK_TIMER' "$health_watcher_script" +grep -Fq '$IBKR_GATEWAY_DAILY_RESTART_SERVICE' "$health_watcher_script" +grep -Fq '$IBKR_GATEWAY_DAILY_RESTART_TIMER' "$health_watcher_script" grep -Fq 'IB_GATEWAY_HEALTHCHECK_INTERVAL_SECONDS:-300' "$health_watcher_script" grep -Fq 'IB_GATEWAY_DAILY_RESTART_ON_CALENDAR:-*-*-* 10:30:00 UTC' "$health_watcher_script" +grep -Fq 'compose_service_name="${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}"' "$health_watcher_script" grep -Fq 'gateway_mode="${1:-${IB_GATEWAY_MODE:-paper}}"' "$health_watcher_script" grep -Fq 'compose_file="${COMPOSE_FILE:-docker-compose.yml}"' "$health_watcher_script" +grep -Fq 'Environment=IB_GATEWAY_COMPOSE_SERVICE_NAME=$compose_service_name' "$health_watcher_script" grep -Fq 'Environment=COMPOSE_FILE=$compose_file' "$health_watcher_script" +grep -Fq 'Environment=IB_GATEWAY_RECOVERY_LOCK_FILE=$recovery_lock_file' "$health_watcher_script" grep -Fq 'Environment=IB_GATEWAY_RECOVERY_LOCK_WAIT_SECONDS=0' "$health_watcher_script" grep -Fq 'OnActiveSec=$health_interval_seconds' "$health_watcher_script" ! grep -Fq 'OnBootSec=5min' "$health_watcher_script" -grep -Fq 'enable --now ibkr-gateway-healthcheck.timer' "$health_watcher_script" -grep -Fq 'enable --now ibkr-gateway-daily-restart.timer' "$health_watcher_script" +grep -Fq 'enable --now "$IBKR_GATEWAY_HEALTHCHECK_TIMER"' "$health_watcher_script" +grep -Fq 'enable --now "$IBKR_GATEWAY_DAILY_RESTART_TIMER"' "$health_watcher_script" ! grep -Fq 'start ibkr-gateway-healthcheck.service' "$health_watcher_script" + +grep -Fq 'resolve_ibkr_gateway_unit_suffix()' "$unit_helper_script" +grep -Fq 'IBKR_2FA_BOT_SERVICE="ibkr-2fa-bot${unit_infix}.service"' "$unit_helper_script" diff --git a/tests/test_install_2fa_bot_watcher.sh b/tests/test_install_2fa_bot_watcher.sh index 9c5fd59..b1fd54e 100644 --- a/tests/test_install_2fa_bot_watcher.sh +++ b/tests/test_install_2fa_bot_watcher.sh @@ -23,8 +23,9 @@ CONTAINER_NAME="ib-gateway-test" \ bash "$repo_dir/scripts/install_2fa_bot_watcher.sh" test -x "$tmpdir/bin/ensure-ibkr-2fa-bot-running" -grep -Fq 'Environment=CONTAINER_NAME=ib-gateway-test' "$tmpdir/systemd/ibkr-2fa-bot.service" -grep -Fq 'ExecStart='"$tmpdir"'/bin/ensure-ibkr-2fa-bot-running' "$tmpdir/systemd/ibkr-2fa-bot.service" -grep -Fq 'OnUnitActiveSec=1min' "$tmpdir/systemd/ibkr-2fa-bot.timer" -grep -Fq 'enable --now ibkr-2fa-bot.timer' "$systemctl_log" -grep -Fq 'start ibkr-2fa-bot.service' "$systemctl_log" +grep -Fq 'Environment=CONTAINER_NAME=ib-gateway-test' "$tmpdir/systemd/ibkr-2fa-bot-ib-gateway-test.service" +grep -Fq 'ExecStart='"$tmpdir"'/bin/ensure-ibkr-2fa-bot-running' "$tmpdir/systemd/ibkr-2fa-bot-ib-gateway-test.service" +grep -Fq 'OnUnitActiveSec=1min' "$tmpdir/systemd/ibkr-2fa-bot-ib-gateway-test.timer" +grep -Fq 'Unit=ibkr-2fa-bot-ib-gateway-test.service' "$tmpdir/systemd/ibkr-2fa-bot-ib-gateway-test.timer" +grep -Fq 'enable --now ibkr-2fa-bot-ib-gateway-test.timer' "$systemctl_log" +grep -Fq 'start ibkr-2fa-bot-ib-gateway-test.service' "$systemctl_log" diff --git a/tests/test_workflow_shared_config.sh b/tests/test_workflow_shared_config.sh index ccbdb41..fccfedd 100644 --- a/tests/test_workflow_shared_config.sh +++ b/tests/test_workflow_shared_config.sh @@ -19,6 +19,14 @@ grep -Fq "WORKFLOW_DISPATCH_MODE: \${{ github.event.inputs.deploy_mode }}" "$wor grep -Fq 'vars.IB_GATEWAY_INSTANCE_NAME' "$workflow_file" grep -Fq 'vars.IB_GATEWAY_ZONE' "$workflow_file" grep -Fq 'vars.IB_GATEWAY_MODE' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_CONTAINER_NAME' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_COMPOSE_PROJECT_NAME' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_COMPOSE_SERVICE_NAME' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_UNIT_SUFFIX' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_LIVE_HOST_PORT' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_PAPER_HOST_PORT' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_VNC_HOST_ADDRESS' "$workflow_file" +grep -Fq 'vars.IB_GATEWAY_VNC_HOST_PORT' "$workflow_file" grep -Fq 'vars.IB_GATEWAY_GCE_USER' "$workflow_file" grep -Fq 'vars.IB_GATEWAY_DEPLOY_PATH' "$workflow_file" grep -Fq 'vars.IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR' "$workflow_file" @@ -57,15 +65,16 @@ grep -Fq 'gcloud compute instances reset "${GCE_INSTANCE_NAME}"' "$workflow_file grep -Fq 'run_remote_ssh "Repository sync" "${REMOTE_SYNC_COMMAND}"' "$workflow_file" grep -Fq 'copy_remote_file "${ENV_FILE}" "${DEPLOY_PATH}/.env"' "$workflow_file" grep -Fq 'sudo bash ./scripts/ensure_host_swap.sh' "$workflow_file" -grep -Fq 'sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true' "$workflow_file" -grep -Fq 'sudo bash ./scripts/install_gateway_health_watcher.sh' "$workflow_file" -grep -Fq "sudo bash ./scripts/recover_ib_gateway_ready.sh '\${IB_GATEWAY_MODE}'" "$workflow_file" -grep -Fq 'sudo systemctl status ibkr-gateway-healthcheck.timer --no-pager' "$workflow_file" -grep -Fq 'sudo systemctl status ibkr-gateway-daily-restart.timer --no-pager' "$workflow_file" +grep -Fq 'resolve_ibkr_gateway_unit_names "\${container_name}" "\${IB_GATEWAY_UNIT_SUFFIX:-}"' "$workflow_file" +grep -Fq 'sudo systemctl stop "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "\${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true' "$workflow_file" +grep -Fq 'bash ./scripts/install_gateway_health_watcher.sh' "$workflow_file" +grep -Fq "sudo env IB_GATEWAY_CONTAINER_NAME=\"\\\${container_name}\" IB_GATEWAY_COMPOSE_SERVICE_NAME=\"\\\${compose_service_name}\" bash ./scripts/recover_ib_gateway_ready.sh '\${IB_GATEWAY_MODE}'" "$workflow_file" +grep -Fq 'sudo systemctl status "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" --no-pager' "$workflow_file" +grep -Fq 'sudo systemctl status "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" --no-pager' "$workflow_file" grep -Fq 'Full deploy mode: rebuilding container' "$workflow_file" -mapfile -t recover_lines < <(grep -nF "sudo bash ./scripts/recover_ib_gateway_ready.sh '\${IB_GATEWAY_MODE}'" "$workflow_file" | cut -d: -f1) -mapfile -t health_watcher_lines < <(grep -nF 'sudo bash ./scripts/install_gateway_health_watcher.sh' "$workflow_file" | cut -d: -f1) +mapfile -t recover_lines < <(grep -nF "bash ./scripts/recover_ib_gateway_ready.sh '\${IB_GATEWAY_MODE}'" "$workflow_file" | cut -d: -f1) +mapfile -t health_watcher_lines < <(grep -nF 'bash ./scripts/install_gateway_health_watcher.sh' "$workflow_file" | cut -d: -f1) test "${#recover_lines[@]}" -eq 2 test "${#health_watcher_lines[@]}" -eq 2 for i in 0 1; do @@ -77,6 +86,9 @@ done grep -Fq '"TRADING_MODE": os.environ["IB_GATEWAY_MODE"]' "$workflow_file" grep -Fq '"ACCEPT_API_FROM_IP": os.environ["CLOUD_RUN_EGRESS_CIDR"]' "$workflow_file" +grep -Fq '"IB_GATEWAY_CONTAINER_NAME": os.environ.get("IB_GATEWAY_CONTAINER_NAME", "")' "$workflow_file" +grep -Fq '"COMPOSE_PROJECT_NAME": os.environ.get("IB_GATEWAY_COMPOSE_PROJECT_NAME", "")' "$workflow_file" +grep -Fq '"IB_GATEWAY_LIVE_HOST_PORT": os.environ.get("IB_GATEWAY_LIVE_HOST_PORT", "")' "$workflow_file" grep -Fq '"TWOFA_DEVICE": os.environ.get("TWOFA_DEVICE", "")' "$workflow_file" grep -Fq '"IBKR_2FA_AUTOFILL": os.environ.get("IBKR_2FA_AUTOFILL", "")' "$workflow_file" grep -Fq '"IBKR_2FA_MAX_SUBMISSIONS": os.environ.get("IBKR_2FA_MAX_SUBMISSIONS") or "3"' "$workflow_file" @@ -116,8 +128,10 @@ grep -Fq 'restart-gateway' "$maintenance_workflow_file" grep -Fq 'status' "$maintenance_workflow_file" grep -Fq 'DEPLOY_PATH: ${{ vars.IB_GATEWAY_DEPLOY_PATH }}' "$maintenance_workflow_file" grep -Fq 'IB_GATEWAY_MODE: ${{ vars.IB_GATEWAY_MODE }}' "$maintenance_workflow_file" +grep -Fq 'IB_GATEWAY_CONTAINER_NAME: ${{ vars.IB_GATEWAY_CONTAINER_NAME }}' "$maintenance_workflow_file" +grep -Fq 'IB_GATEWAY_COMPOSE_SERVICE_NAME: ${{ vars.IB_GATEWAY_COMPOSE_SERVICE_NAME }}' "$maintenance_workflow_file" grep -Fq 'sudo systemctl disable --now' "$maintenance_workflow_file" -grep -Fq 'sudo docker update --restart=no ib-gateway' "$maintenance_workflow_file" +grep -Fq 'sudo docker update --restart=no "${container_name}"' "$maintenance_workflow_file" grep -Fq 'sudo docker compose down' "$maintenance_workflow_file" -grep -Fq 'sudo docker compose up -d --no-build ib-gateway' "$maintenance_workflow_file" -grep -Fq 'sudo bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__' "$maintenance_workflow_file" +grep -Fq 'sudo docker compose up -d --no-build "${compose_service_name}"' "$maintenance_workflow_file" +grep -Fq 'bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__' "$maintenance_workflow_file"