From 757ad41c9b20f0d91de7b2ec569dc43f31e305a5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Jul 2026 22:25:00 -0400 Subject: [PATCH] add image pull to production --- production/README.md | 4 ++ production/deploy-production.sh | 57 ++++++++++++++++++++++++ production/fetch-image-through-vpn.sh | 13 +++++- production/scripts/docker-prod-common.sh | 13 +++++- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/production/README.md b/production/README.md index d25a617..71af968 100644 --- a/production/README.md +++ b/production/README.md @@ -80,6 +80,10 @@ missing archive automatically if `VPN_CONTAINER` is set: VPN_CONTAINER="6c5dca44e1c2" ./deploy-production.sh ``` +If `VPN_CONTAINER` is not set, the deploy script tries to auto-detect one +running container with a common VPN name or image such as `vpn`, `gluetun`, +`wireguard`, `openvpn`, `tailscale`, or `wg-easy`. + Equivalent manual command: ```bash diff --git a/production/deploy-production.sh b/production/deploy-production.sh index cc1e6ff..b520e47 100755 --- a/production/deploy-production.sh +++ b/production/deploy-production.sh @@ -102,6 +102,8 @@ fetch_release_archive_through_vpn() { return 0 fi + detect_vpn_container_if_unset + if [[ -z "${VPN_CONTAINER:-}" ]]; then echo "VPN_CONTAINER is required to fetch the image archive through VPN." >&2 usage >&2 @@ -115,6 +117,60 @@ fetch_release_archive_through_vpn() { "${ROOT_DIR}/fetch-image-through-vpn.sh" "${IMAGE_TAG}" } +detect_vpn_container_if_unset() { + local candidates + local candidate_count + + if [[ -n "${VPN_CONTAINER:-}" ]]; then + return 0 + fi + + candidates="$( + docker ps --format '{{.ID}} {{.Names}} {{.Image}}' 2>/dev/null \ + | awk 'BEGIN { IGNORECASE = 1 } /(vpn|gluetun|wireguard|openvpn|tailscale|wg-easy)/ { print $1 }' + )" + + candidate_count="$(printf '%s\n' "${candidates}" | sed '/^$/d' | wc -l | tr -d ' ')" + + if [[ "${candidate_count}" == "1" ]]; then + VPN_CONTAINER="$(printf '%s\n' "${candidates}" | sed '/^$/d' | sed -n '1p')" + export VPN_CONTAINER + echo "Auto-detected VPN container: ${VPN_CONTAINER}" + fi +} + +ensure_archive_source_ready() { + if [[ "${IMAGE_ARCHIVE_DISABLED:-false}" == "true" || "${IMAGE_ARCHIVE_DISABLED:-0}" == "1" ]]; then + return 0 + fi + + if [[ "${IMAGE_ARCHIVE_REQUIRED:-false}" != "true" && "${IMAGE_ARCHIVE_REQUIRED:-0}" != "1" ]]; then + return 0 + fi + + if release_archive_exists; then + return 0 + fi + + detect_vpn_container_if_unset + + if [[ -n "${VPN_CONTAINER:-}" ]]; then + echo "No local image archive found; deploy will fetch it through VPN container ${VPN_CONTAINER}." + return 0 + fi + + echo "IMAGE_ARCHIVE_REQUIRED=true and no matching archive exists in ${IMAGE_ARCHIVE_DIR:-}." >&2 + echo "Direct docker pull is disabled in this mode, and VPN_CONTAINER is not set." >&2 + echo "No single VPN container could be auto-detected from common VPN names/images." >&2 + echo "Find the VPN container with:" >&2 + echo " docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Image}}'" >&2 + echo "Run one of:" >&2 + echo " VPN_CONTAINER= ./deploy-production.sh --fetch-through-vpn" >&2 + echo " VPN_CONTAINER= ./fetch-image-through-vpn.sh ${IMAGE_TAG}" >&2 + echo "Or set VPN_CONTAINER in .env.docker.production and rerun ./deploy-production.sh." >&2 + exit 1 +} + release_archive_exists() { local archive_dir="${IMAGE_ARCHIVE_DIR:-}" @@ -385,6 +441,7 @@ ensure_env_file load_prod_env_exports require_release_image normalize_archive_dir +ensure_archive_source_ready print_release_summary ensure_traefik_network diff --git a/production/fetch-image-through-vpn.sh b/production/fetch-image-through-vpn.sh index 98d8d77..3724cf3 100755 --- a/production/fetch-image-through-vpn.sh +++ b/production/fetch-image-through-vpn.sh @@ -15,8 +15,17 @@ read_env_value() { value="$( awk -F= -v key="$key" ' - $1 == key { - value = substr($0, index($0, "=") + 1) + /^[[:space:]]*#/ || index($0, "=") == 0 { + next + } + { + name = $1 + sub(/^[[:space:]]*export[[:space:]]+/, "", name) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", name) + if (name == key) { + value = substr($0, index($0, "=") + 1) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) + } } END { if (value != "") { diff --git a/production/scripts/docker-prod-common.sh b/production/scripts/docker-prod-common.sh index ec5eec1..b44838b 100755 --- a/production/scripts/docker-prod-common.sh +++ b/production/scripts/docker-prod-common.sh @@ -27,8 +27,17 @@ read_env_value() { value="$( awk -F= -v key="$key" ' - $1 == key { - value = substr($0, index($0, "=") + 1) + /^[[:space:]]*#/ || index($0, "=") == 0 { + next + } + { + name = $1 + sub(/^[[:space:]]*export[[:space:]]+/, "", name) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", name) + if (name == key) { + value = substr($0, index($0, "=") + 1) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) + } } END { if (value != "") {