Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 5 additions & 30 deletions .github/actions/pull_images/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,34 +66,9 @@ runs:
env:
PYTHONPATH: "."

- name: Login to Docker Hub
if: inputs.dockerhub_username != '' && inputs.dockerhub_token != ''
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ inputs.dockerhub_username }}
password: ${{ inputs.dockerhub_token }}

- name: Pull
- name: Login to Docker Hub and pull images
shell: bash
run: |
max_attempts=5
timeout_seconds=900
attempt=1
while true; do
echo "Running docker compose pull (attempt ${attempt}/${max_attempts}, timeout ${timeout_seconds}s)..."

if timeout "${timeout_seconds}" docker compose pull; then
break
fi

if [ "${attempt}" -ge "${max_attempts}" ]; then
echo "docker compose pull failed after ${attempt} attempts"
exit 1
fi

# Exponential backoff: 30s, 60s, 120s, 240s
retry_wait_seconds=$(( 30 * (1 << (attempt - 1)) ))
echo "docker compose pull failed (attempt ${attempt}/${max_attempts}), retrying in ${retry_wait_seconds}s..."
sleep "${retry_wait_seconds}"
attempt=$((attempt + 1))
done
run: .github/actions/pull_images/main.sh
Comment thread
cbeauchesne marked this conversation as resolved.
env:
DOCKERHUB_USERNAME: ${{ inputs.dockerhub_username }}
DOCKERHUB_TOKEN: ${{ inputs.dockerhub_token }}
77 changes: 77 additions & 0 deletions .github/actions/pull_images/main.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
# Logs in to Docker Hub (if credentials are provided) and pulls the images
# listed in compose.yaml, retrying on failure.
#
# When a command fails, unless the error is known to not be retryable, the command will be retried
#
# Expects DOCKERHUB_USERNAME / DOCKERHUB_TOKEN in the environment (may be empty).

set -euo pipefail

# Backoff delay (seconds) indexed by attempt number (1-based)
# since github action
BACKOFF_SECONDS=(10 20 40 80 160 320 320 320 320 320 320 320 320 320 320 320)
MAX_ATTEMPTS="${#BACKOFF_SECONDS[@]}"

# Error patterns that should never be retried (auth/permission/not-found errors
# won't fix themselves on a retry).
NON_RETRYABLE_PATTERNS=(
"incorrect username or password"
"unauthorized"
"unknown command: docker compose"
"no configuration file provided: not found"
"empty compose file"
"yaml: construct errors"
)

retry_with_timeout() {
local description="$1"
local timeout_seconds="$2"
shift 2

local attempt=1
local retry_wait_seconds
local output_file
output_file="$(mktemp)"
trap 'rm -f "${output_file}"' RETURN

while true; do
echo "${description} (attempt ${attempt}/${MAX_ATTEMPTS}, timeout ${timeout_seconds}s)..."

# Both save the output in output_file and print it to stdout.
# exit function if the command succeed
if timeout "${timeout_seconds}" "$@" 2>&1 | tee "${output_file}"; then
return 0
fi

for pattern in "${NON_RETRYABLE_PATTERNS[@]}"; do
if grep -q "${pattern}" "${output_file}"; then
echo "${description} failed with a non-retryable error: ${pattern}"
return 1
fi
done

echo "${description} failed (attempt ${attempt}/${MAX_ATTEMPTS})"
if [ "${attempt}" -ge "${MAX_ATTEMPTS}" ]; then
echo "${description} failed after ${attempt} attempts"
return 1
fi

retry_wait_seconds="${BACKOFF_SECONDS[attempt - 1]}"
attempt=$((attempt + 1))

echo "retrying in ${retry_wait_seconds}s..."
sleep "${retry_wait_seconds}"
done
}

docker_login() {
echo "${DOCKERHUB_TOKEN}" | docker login --username "${DOCKERHUB_USERNAME}" --password-stdin
}

if [ -n "${DOCKERHUB_USERNAME:-}" ] && [ -n "${DOCKERHUB_TOKEN:-}" ]; then
export -f docker_login # makes the function docker_login available in any child process spawned from it
retry_with_timeout "Logging in to Docker Hub" 60 bash -c docker_login
fi

retry_with_timeout "Running docker compose pull" 900 docker compose --progress plain pull
2 changes: 1 addition & 1 deletion utils/scripts/libraries_and_scenarios_rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ patterns:
# This section contains rules to apply to files related to GitHub Actions.
################################################################################

.github/actions/pull_images/action.yml:
.github/actions/pull_images/*:
scenario_groups: end_to_end
.github/chainguard/*:
scenario_groups: null
Expand Down
Loading