From 70e64bb6adc4558239b75ea7c36a2c1f770b11d1 Mon Sep 17 00:00:00 2001 From: gauravsaini04 <147703805+gauravsaini04@users.noreply.github.com> Date: Sat, 16 Mar 2024 23:47:47 +0000 Subject: [PATCH 1/8] [docker-in-docker]-docker_compose-fallback-github api --- src/docker-in-docker/install.sh | 74 +++++++- .../docker_build_fallback_compose.sh | 169 ++++++++++++++++++ test/docker-in-docker/scenarios.json | 9 + 3 files changed, 248 insertions(+), 4 deletions(-) create mode 100644 test/docker-in-docker/docker_build_fallback_compose.sh diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index dbe34e2ea..dc1d9d1ba 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -109,10 +109,68 @@ find_version_from_git_tags() { echo "${variable_name}=${!variable_name}" } +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + + # Function to fetch the version released prior to the latest version get_previous_version() { repo_url=$1 - curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name' + # Fetch the response headers for the rate limit information and store them in a variable + headers=$(curl -s --head -H "Accept: application/json" "$repo_url") + # Extract the rate limit information from the headers + limit=$(echo "$headers" | awk '/x-ratelimit-limit/{print $2}') + remaining=$(echo "$headers" | awk '/x-ratelimit-remaining/{print $2}') + reset_epoch=$(echo "$headers" | awk '/x-ratelimit-reset/{print $2}') + reset_time=$(date -d@"$reset_epoch" +"%Y-%m-%d %H:%M:%S" 2>/dev/null) + # remove trailing \r from $remaining + remaining=$(echo "$remaining" | tr -d '[:space:]') + # convert remaining to an int value for comparison to be greater than or less than 0 + remaining_int=$(printf "%d" "$remaining") + if [[ $remaining_int -gt 0 ]]; then + curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') + echo "version: ${curl_output}" + else + echo "Rate limit exceeded. Fallback implemented." + fi } install_compose_switch_fallback() { @@ -307,9 +365,17 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then if grep -q "Not Found" "${docker_compose_path}"; then echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - previous_version=$(get_previous_version "https://api.github.com/repos/docker/compose/releases") - echo -e "\nAttempting to install ${previous_version}" - compose_version=${previous_version#v} + output=$(get_previous_version "https://api.github.com/repos/docker/compose/releases") + if [[ $output == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Error: Getting Previous Version by using github api failed!" + find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" + else + echo "Success: Fetched fallback version from GitHub Api successfully!" + filtered_output=$(echo $output | grep "version:"); + previous_version=$(echo "$filtered_output" | sed -n 's/version: //p'); + compose_version=${previous_version#v} + fi + echo -e "\nAttempting to install ${compose_version}" curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} fi diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh new file mode 100644 index 000000000..dd184dce3 --- /dev/null +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +# Optional: Import test library +source dev-container-features-test-lib + +HL="\033[1;33m" +N="\033[0;37m" +echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker feature${N}" +check "docker-compose" bash -c "docker-compose version" + +architecture="$(dpkg --print-architecture)" +case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 +esac + +docker_compose_path="/usr/local/bin/docker-compose" +cli_plugins_dir="${docker_home}/cli-plugins" + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + +# Function to fetch the version released prior to the latest version +get_previous_version() { + repo_url=$1 + try_api=$2 + # Fetch the response headers for the rate limit information and store them in a variable + headers=$(curl -s --head -H "Accept: application/json" "$repo_url") + # Extract the rate limit information from the headers + limit=$(echo "$headers" | awk '/x-ratelimit-limit/{print $2}') + remaining=$(echo "$headers" | awk '/x-ratelimit-remaining/{print $2}') + reset_epoch=$(echo "$headers" | awk '/x-ratelimit-reset/{print $2}') + reset_time=$(date -d@"$reset_epoch" +"%Y-%m-%d %H:%M:%S" 2>/dev/null) + # remove trailing \r from $remaining + remaining=$(echo "$remaining" | tr -d '[:space:]') + # convert remaining to an int value for comparison to be greater than or less than 0 + remaining_int=$(printf "%d" "$remaining") + if [[ "$try_api" != "try_valid_from_api" ]]; then + remaining_int=0 + fi + if [[ $remaining_int -gt 0 ]]; then + curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') + echo "version: ${curl_output}" + else + echo "Rate limit exceeded. Fallback implemented." + fi +} + +install_using_get_previous_version() { + mode=$1 + output=$(get_previous_version "https://api.github.com/repos/docker/compose/releases" "$mode") + if [[ $output == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Error: Getting Previous Version by using github api failed!" + find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" + else + echo "Success: Fetched fallback version from GitHub Api successfully!" + filtered_output=$(echo $output | grep "version:"); + previous_version=$(echo "$filtered_output" | sed -n 's/version: //p'); + compose_version=${previous_version#v} + fi + echo -e "\nAttempting to install ${compose_version}" + curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + +install_docker_compose() { + mode=$1 + compose_version="2.25.xyz" + echo "(*) Installing docker-compose ${compose_version}..." + curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} + if grep -q "Not Found" "${docker_compose_path}"; then + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + install_using_get_previous_version "$mode" + fi +} + +chmod +x ${docker_compose_path} + +# Download the SHA256 checksum +DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" +echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum +sha256sum -c docker-compose.sha256sum --ignore-missing + +mkdir -p ${cli_plugins_dir} +cp ${docker_compose_path} ${cli_plugins_dir} + +echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by github api ) ${N}" +install_docker_compose "try_valid_from_api" + +check "docker-compose" bash -c "docker-compose version" + +echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" +install_docker_compose + +check "docker-compose" bash -c "docker-compose version" diff --git a/test/docker-in-docker/scenarios.json b/test/docker-in-docker/scenarios.json index e209f3453..0f0d9740f 100644 --- a/test/docker-in-docker/scenarios.json +++ b/test/docker-in-docker/scenarios.json @@ -1,4 +1,13 @@ { + "docker_build_fallback_compose": { + "image": "ubuntu:focal", + "features": { + "docker-in-docker": { + "version": "latest", + "dockerDashComposeVersion": "latest" + } + } + }, "dockerDefaultAddressPool": { "image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:0-18", "remoteUser": "node", From 2e990776a75fb53cab8d0d8e7f3d1ffec970a7ad Mon Sep 17 00:00:00 2001 From: gauravsaini04 <147703805+gauravsaini04@users.noreply.github.com> Date: Mon, 18 Mar 2024 01:56:42 +0000 Subject: [PATCH 2/8] changes misc. --- src/docker-in-docker/install.sh | 48 +++++++++++++------ .../docker_build_fallback_compose.sh | 30 +++++++----- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index dc1d9d1ba..359d89786 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -154,6 +154,8 @@ find_prev_version_from_git_tags() { # Function to fetch the version released prior to the latest version get_previous_version() { repo_url=$1 + variable_name=$2 + err_msg=$3 # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "$repo_url") # Extract the rate limit information from the headers @@ -167,17 +169,25 @@ get_previous_version() { remaining_int=$(printf "%d" "$remaining") if [[ $remaining_int -gt 0 ]]; then curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') - echo "version: ${curl_output}" + declare -g ${variable_name}="${curl_output}" + echo "${variable_name}=${!variable_name}" else - echo "Rate limit exceeded. Fallback implemented." + declare -g ${err_msg}="Rate limit exceeded. Fallback implemented." fi } install_compose_switch_fallback() { echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." - previous_version=$(get_previous_version "https://api.github.com/repos/docker/compose-switch/releases") - echo -e "\nAttempting to install ${previous_version}" - compose_switch_version=${previous_version#v} + err_msg="" + get_previous_version "https://api.github.com/repos/docker/compose-switch/releases" compose_switch_version err_msg + if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Failure: Getting Previous Version by using github api failed!" + find_prev_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" "tags/v" + else + echo "Success: Fetched fallback version from GitHub Api successfully!" + compose_switch_version="${compose_switch_version#v}" + fi + echo -e "\nAttempting to install ${compose_switch_version}" curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch } @@ -365,15 +375,14 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then if grep -q "Not Found" "${docker_compose_path}"; then echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - output=$(get_previous_version "https://api.github.com/repos/docker/compose/releases") - if [[ $output == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Error: Getting Previous Version by using github api failed!" + err_msg="" + get_previous_version "https://api.github.com/repos/docker/compose/releases" compose_version err_msg + if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Failure: Getting Previous Version by using github api failed!" find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" else echo "Success: Fetched fallback version from GitHub Api successfully!" - filtered_output=$(echo $output | grep "version:"); - previous_version=$(echo "$filtered_output" | sed -n 's/version: //p'); - compose_version=${previous_version#v} + compose_version=${compose_version#v} fi echo -e "\nAttempting to install ${compose_version}" curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} @@ -431,10 +440,18 @@ install_previous_version_artifacts() { if [ $wget_exit_code -eq 8 ]; then # failure due to 404: Not Found. echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." repo_url="https://api.github.com/repos/docker/buildx/releases" # GitHub repository URL - previous_version=$(get_previous_version "${repo_url}") - buildx_file_name="buildx-${previous_version}.linux-${architecture}" - echo -e "\nAttempting to install ${previous_version}" - wget https://github.com/docker/buildx/releases/download/${previous_version}/${buildx_file_name} + err_msg="" + get_previous_version "${repo_url}" buildx_version err_msg + if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Failure: Getting Previous Version by using github api failed!" + find_prev_version_from_git_tags buildx_version "https://github.com/docker/buildx" "tags/v" + buildx_version="v${buildx_version}" + else + echo "Success: Fetched fallback version from GitHub Api successfully!" + fi + buildx_file_name="buildx-${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install ${buildx_version}" + wget https://github.com/docker/buildx/releases/download/${buildx_version}/${buildx_file_name} else echo "(!) Failed to download docker buildx with exit code: $wget_exit_code" exit 1 @@ -444,6 +461,7 @@ install_previous_version_artifacts() { if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_version="latest" find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "refs/tags/v" + buildx_version="2.5.8" echo "(*) Installing buildx ${buildx_version}..." buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh index dd184dce3..bc21cb5f8 100644 --- a/test/docker-in-docker/docker_build_fallback_compose.sh +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -3,6 +3,11 @@ # Optional: Import test library source dev-container-features-test-lib +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + HL="\033[1;33m" N="\033[0;37m" echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker feature${N}" @@ -98,7 +103,9 @@ find_prev_version_from_git_tags() { # Function to fetch the version released prior to the latest version get_previous_version() { repo_url=$1 - try_api=$2 + variable_name=$2 + err_msg=$3 + try_api=$4 # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "$repo_url") # Extract the rate limit information from the headers @@ -115,25 +122,26 @@ get_previous_version() { fi if [[ $remaining_int -gt 0 ]]; then curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') - echo "version: ${curl_output}" + declare -g ${variable_name}="${curl_output}" + echo "${variable_name}=${!variable_name}" else - echo "Rate limit exceeded. Fallback implemented." + declare -g ${err_msg}="Rate limit exceeded. Fallback implemented." fi } install_using_get_previous_version() { mode=$1 - output=$(get_previous_version "https://api.github.com/repos/docker/compose/releases" "$mode") - if [[ $output == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Error: Getting Previous Version by using github api failed!" - find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + err_msg="" + get_previous_version "https://api.github.com/repos/docker/compose/releases" compose_version err_msg "$mode" + if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then + echo "Failure: Getting Previous Version by using github api failed!" + find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" else echo "Success: Fetched fallback version from GitHub Api successfully!" - filtered_output=$(echo $output | grep "version:"); - previous_version=$(echo "$filtered_output" | sed -n 's/version: //p'); - compose_version=${previous_version#v} + compose_version=${compose_version#v} fi - echo -e "\nAttempting to install ${compose_version}" + echo -e "\nAttempting to install v${compose_version}" curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} } From e1e06de55d35c20539c6dfa6a6292002c52c24b5 Mon Sep 17 00:00:00 2001 From: gauravsaini04 <147703805+gauravsaini04@users.noreply.github.com> Date: Mon, 18 Mar 2024 02:55:25 +0000 Subject: [PATCH 3/8] misc. change --- src/docker-in-docker/install.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 359d89786..773b420b9 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -461,7 +461,6 @@ install_previous_version_artifacts() { if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_version="latest" find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "refs/tags/v" - buildx_version="2.5.8" echo "(*) Installing buildx ${buildx_version}..." buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" From bd68b638f5b03e19d8b31c9bf507d5ed723f4127 Mon Sep 17 00:00:00 2001 From: gauravsaini04 <147703805+gauravsaini04@users.noreply.github.com> Date: Wed, 20 Mar 2024 02:53:37 +0000 Subject: [PATCH 4/8] changes as required in review comments --- .../devcontainer-feature.json | 2 +- src/docker-in-docker/install.sh | 137 ++++++----- .../docker_build_fallback_buildx.sh | 217 +++++++++++++----- .../docker_build_fallback_compose.sh | 81 ++++--- test/docker-in-docker/scenarios.json | 4 +- 5 files changed, 275 insertions(+), 166 deletions(-) diff --git a/src/docker-in-docker/devcontainer-feature.json b/src/docker-in-docker/devcontainer-feature.json index 671f4e2ed..812db444c 100644 --- a/src/docker-in-docker/devcontainer-feature.json +++ b/src/docker-in-docker/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "docker-in-docker", - "version": "2.10.1", + "version": "2.10.2", "name": "Docker (Docker-in-Docker)", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 773b420b9..cbdd2a081 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -150,45 +150,49 @@ find_prev_version_from_git_tags() { set -e } +fetch_use_local_function() { + local repo_url=$1 + local version=$2 + vers=${!version} + trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') + find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + declare -g ${version}="${vers}" +} -# Function to fetch the version released prior to the latest version -get_previous_version() { - repo_url=$1 - variable_name=$2 - err_msg=$3 - # Fetch the response headers for the rate limit information and store them in a variable - headers=$(curl -s --head -H "Accept: application/json" "$repo_url") - # Extract the rate limit information from the headers - limit=$(echo "$headers" | awk '/x-ratelimit-limit/{print $2}') - remaining=$(echo "$headers" | awk '/x-ratelimit-remaining/{print $2}') - reset_epoch=$(echo "$headers" | awk '/x-ratelimit-reset/{print $2}') - reset_time=$(date -d@"$reset_epoch" +"%Y-%m-%d %H:%M:%S" 2>/dev/null) - # remove trailing \r from $remaining - remaining=$(echo "$remaining" | tr -d '[:space:]') - # convert remaining to an int value for comparison to be greater than or less than 0 - remaining_int=$(printf "%d" "$remaining") +fetch_use_github_api() { + local repo_url=$1 + local version=$2 + given_version=${!version} + # Fetch the response headers for the rate limit information and store them in a variable + headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") + # Extract the rate limit information from the headers + read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') + # convert remaining to an int value for comparison to be greater than or less than 0 + remaining_int=$(printf "%d" "$remaining") if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') - declare -g ${variable_name}="${curl_output}" - echo "${variable_name}=${!variable_name}" + curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') + declare -g ${version}="${curl_output#v}" else - declare -g ${err_msg}="Rate limit exceeded. Fallback implemented." + fetch_use_local_function "${repo_url}" given_version + declare -g ${version}="${given_version}" fi } -install_compose_switch_fallback() { - echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." - err_msg="" - get_previous_version "https://api.github.com/repos/docker/compose-switch/releases" compose_switch_version err_msg - if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Failure: Getting Previous Version by using github api failed!" - find_prev_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" "tags/v" - else - echo "Success: Fetched fallback version from GitHub Api successfully!" - compose_switch_version="${compose_switch_version#v}" +# Function to fetch the version released prior to the latest version +get_previous_version() { + local repo_url=$1 + local variable_name=$2 + prev_version=${!variable_name} + response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") + # check if github api url is not found i.e 403 error code returned + if [ "$response" -eq 403 ]; then + # if github api url is not found, then simply fetch using find_prev_version_from_git_tags + fetch_use_local_function "${repo_url}" prev_version + else + # continue fetching from github api + fetch_use_github_api "${repo_url}" prev_version fi - echo -e "\nAttempting to install ${compose_switch_version}" - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch + declare -g ${variable_name}="${prev_version}" } ########################################### @@ -333,6 +337,15 @@ echo "Finished installing docker / moby!" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" +# fallback for docker-compose +fallback_compose(){ + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + repo_url="https://api.github.com/repos/docker/compose/releases/latest" + get_previous_version "${repo_url}" compose_version + echo -e "\nAttempting to install v${compose_version}" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + # If 'docker-compose' command is to be included if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then case "${architecture}" in @@ -371,23 +384,7 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} find_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" echo "(*) Installing docker-compose ${compose_version}..." - curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} - - if grep -q "Not Found" "${docker_compose_path}"; then - echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - err_msg="" - get_previous_version "https://api.github.com/repos/docker/compose/releases" compose_version err_msg - if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Failure: Getting Previous Version by using github api failed!" - find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" - else - echo "Success: Fetched fallback version from GitHub Api successfully!" - compose_version=${compose_version#v} - fi - echo -e "\nAttempting to install ${compose_version}" - curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} - fi - + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || fallback_compose chmod +x ${docker_compose_path} # Download the SHA256 checksum @@ -400,6 +397,15 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then fi fi +# fallback method for compose-switch +fallback_compose-switch() { + echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." + repo_url="https://api.github.com/repos/docker/compose-switch/releases/latest" + get_previous_version "${repo_url}" compose_switch_version + echo -e "\nAttempting to install v${compose_switch_version}" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch +} + # Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then if type docker-compose > /dev/null 2>&1; then @@ -408,7 +414,7 @@ if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /d target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" compose_switch_version="latest" find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || install_compose_switch_fallback + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch chmod +x /usr/local/bin/compose-switch # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) @@ -435,27 +441,14 @@ fi usermod -aG docker ${USERNAME} -install_previous_version_artifacts() { - wget_exit_code=$? - if [ $wget_exit_code -eq 8 ]; then # failure due to 404: Not Found. - echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." - repo_url="https://api.github.com/repos/docker/buildx/releases" # GitHub repository URL - err_msg="" - get_previous_version "${repo_url}" buildx_version err_msg - if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Failure: Getting Previous Version by using github api failed!" - find_prev_version_from_git_tags buildx_version "https://github.com/docker/buildx" "tags/v" - buildx_version="v${buildx_version}" - else - echo "Success: Fetched fallback version from GitHub Api successfully!" - fi - buildx_file_name="buildx-${buildx_version}.linux-${architecture}" - echo -e "\nAttempting to install ${buildx_version}" - wget https://github.com/docker/buildx/releases/download/${buildx_version}/${buildx_file_name} - else - echo "(!) Failed to download docker buildx with exit code: $wget_exit_code" - exit 1 - fi +# fallback for docker/buildx +fallback_buildx() { + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + repo_url="https://api.github.com/repos/docker/buildx/releases/latest" + get_previous_version "${repo_url}" buildx_version + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} } if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then @@ -465,7 +458,7 @@ if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" cd /tmp - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_previous_version_artifacts + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" diff --git a/test/docker-in-docker/docker_build_fallback_buildx.sh b/test/docker-in-docker/docker_build_fallback_buildx.sh index 707e0a68a..0e3f3ce3c 100644 --- a/test/docker-in-docker/docker_build_fallback_buildx.sh +++ b/test/docker-in-docker/docker_build_fallback_buildx.sh @@ -14,83 +14,190 @@ check "docker-build" docker build ./ check "docker-buildx" bash -c "docker buildx version" check "docker-buildx-path" bash -c "ls -la /usr/libexec/docker/cli-plugins/docker-buildx" -echo -e "\nšŸ‘‰${HL} Creating a scenario for fallback${N}\n" # Code to test the made up scenario when latest version of docker/buildx fails on wget command for fetching the artifacts -repo_url="https://api.github.com/repos/docker/buildx/releases" # GitHub repository URL architecture="$(dpkg --print-architecture)" +case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 +esac -# Function to fetch the latest version of the plugin -get_latest_version() { - curl -s "$repo_url/latest" | jq -r '.tag_name' +docker_home="/usr/libexec/docker" +cli_plugins_dir="${docker_home}/cli-plugins" + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" } -# Function to fetch the previous version of the plugin -get_previous_version() { - # this would del the assets key and then get the first encountered tag_name's value from the filtered array of objects - curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name' +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e } -# Function to change the patch number in a semver version -change_patch_number() { - local version="$1" # Input version - local new_patch="$2" # New patch number - # Extract major, minor, and current patch numbers - local major=$(echo "$version" | cut -d. -f1) - local minor=$(echo "$version" | cut -d. -f2) - local current_patch=$(echo "$version" | cut -d. -f3) - # Construct the new version with the updated patch number - local new_version="$major.$minor.$new_patch" - echo "$new_version" +fetch_use_local_function() { + local repo_url=$1 + local version=$2 + try_api=$4 + vers=${!version} + trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') + find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + declare -g ${version}="${vers}" } -change_version_to_fail() { - latest_version=$1 - new_patch_number="xyz" # for testing a tag not found scenario for docker/buildx plugin - latest_version=$(get_latest_version) # can take latest_version from fn get_latest_version - buildx_version_fallback_test=$(change_patch_number "$latest_version" "$new_patch_number") # for testing a tag not found scenario for docker/buildx plugin - echo "${buildx_version_fallback_test}" +fetch_use_github_api() { + local repo_url=$1 + local version=$2 + local try_api=$3 + given_version=${!version} + # Fetch the response headers for the rate limit information and store them in a variable + headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") + # Extract the rate limit information from the headers + read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') + # convert remaining to an int value for comparison to be greater than or less than 0 + remaining_int=$(printf "%d" "$remaining") + if [[ "$try_api" != "try_valid_from_api" ]]; then + remaining_int=0 + fi + if [[ $remaining_int -gt 0 ]]; then + curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') + declare -g ${version}="${curl_output#v}" + else + fetch_use_local_function "${repo_url}" given_version + declare -g ${version}="${given_version}" + fi } -install_previous_version_artifacts() { - wget_exit_code=$? - if [ $wget_exit_code -ne 0 ]; then # means wget command to fetch latest version failed - if [ $wget_exit_code -eq 8 ]; then # failure due to 404: Not Found. - echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx ${buildx_version}..." - previous_version=$(get_previous_version) - echo -e "\nAttempting to install ${previous_version}" - buildx_file_name="buildx-${previous_version}.linux-${architecture}" - wget https://github.com/docker/buildx/releases/download/${previous_version}/${buildx_file_name} - else - echo "(!) Failed to download docker buildx with exit code: $wget_exit_code" - exit 1 - fi +# Function to fetch the version released prior to the latest version +get_previous_version() { + local repo_url=$1 + local variable_name=$2 + local mode=$3 + prev_version=${!variable_name} + response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") + # check if github api url is not found i.e 403 error code returned + if [ "$response" -eq 403 ]; then + # if github api url is not found, then simply fetch using find_prev_version_from_git_tags + fetch_use_local_function "${repo_url}" prev_version + else + # continue fetching from github api + fetch_use_github_api "${repo_url}" prev_version "${mode}" fi + declare -g ${variable_name}="${prev_version}" +} + +install_using_get_previous_version() { + mode=$1 + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + repo_url="https://api.github.com/repos/docker/buildx/releases/latest" + get_previous_version "${repo_url}" buildx_version "${mode}" + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} } -test_version=$(change_version_to_fail "$(get_latest_version)") -buildx_file_name="buildx-${test_version}.linux-${architecture}" -buildx_version=$test_version +install_docker_buildx() { + mode=$1 + echo -e "\nšŸ‘‰${HL} Creating a scenario for fallback${N}\n" -# This wget command will fail as the wrong version won't fetch artifact -wget https://github.com/docker/buildx/releases/download/${buildx_version}/${buildx_file_name} || install_previous_version_artifacts + buildx_version="0.13.xyz" + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + cd /tmp + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_using_get_previous_version "${mode}" + + docker_home="/usr/libexec/docker" + cli_plugins_dir="${docker_home}/cli-plugins" -docker_home="/usr/libexec/docker" -cli_plugins_dir="${docker_home}/cli-plugins" + mkdir -p ${cli_plugins_dir} + mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx + chmod +x ${cli_plugins_dir}/docker-buildx -mkdir -p ${cli_plugins_dir} -mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx -chmod +x ${cli_plugins_dir}/docker-buildx + chown -R "${USERNAME}:docker" "${docker_home}" + chmod -R g+r+w "${docker_home}" + find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +} -chown -R "${USERNAME}:docker" "${docker_home}" -chmod -R g+r+w "${docker_home}" -find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by github api ) ${N}" +install_docker_buildx "try_valid_from_api" + +# Definition specific tests after test for fallback +check "docker-buildx" docker buildx version +check "docker-buildx" bash -c "docker buildx version" + +echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" +install_docker_buildx # Definition specific tests after test for fallback -echo -e "\nšŸ‘‰${HL} docker/buildx version as installed by test for fallback${N}" check "docker-buildx" docker buildx version -check "docker-build" docker build ./ check "docker-buildx" bash -c "docker buildx version" -check "docker-buildx-path" bash -c "ls -la /usr/libexec/docker/cli-plugins/docker-buildx" # Report result reportResults diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh index bc21cb5f8..156fc8387 100644 --- a/test/docker-in-docker/docker_build_fallback_compose.sh +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -100,60 +100,71 @@ find_prev_version_from_git_tags() { set -e } -# Function to fetch the version released prior to the latest version -get_previous_version() { - repo_url=$1 - variable_name=$2 - err_msg=$3 +fetch_use_local_function() { + local repo_url=$1 + local version=$2 try_api=$4 - # Fetch the response headers for the rate limit information and store them in a variable - headers=$(curl -s --head -H "Accept: application/json" "$repo_url") - # Extract the rate limit information from the headers - limit=$(echo "$headers" | awk '/x-ratelimit-limit/{print $2}') - remaining=$(echo "$headers" | awk '/x-ratelimit-remaining/{print $2}') - reset_epoch=$(echo "$headers" | awk '/x-ratelimit-reset/{print $2}') - reset_time=$(date -d@"$reset_epoch" +"%Y-%m-%d %H:%M:%S" 2>/dev/null) - # remove trailing \r from $remaining - remaining=$(echo "$remaining" | tr -d '[:space:]') - # convert remaining to an int value for comparison to be greater than or less than 0 + vers=${!version} + trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') + find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + declare -g ${version}="${vers}" +} + +fetch_use_github_api() { + local repo_url=$1 + local version=$2 + local try_api=$3 + given_version=${!version} + # Fetch the response headers for the rate limit information and store them in a variable + headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") + # Extract the rate limit information from the headers + read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') + # convert remaining to an int value for comparison to be greater than or less than 0 remaining_int=$(printf "%d" "$remaining") if [[ "$try_api" != "try_valid_from_api" ]]; then remaining_int=0 - fi + fi if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "$repo_url" | jq -r 'del(.[].assets) | .[0].tag_name') - declare -g ${variable_name}="${curl_output}" - echo "${variable_name}=${!variable_name}" + curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') + declare -g ${version}="${curl_output#v}" else - declare -g ${err_msg}="Rate limit exceeded. Fallback implemented." + fetch_use_local_function "${repo_url}" given_version + declare -g ${version}="${given_version}" fi } +# Function to fetch the version released prior to the latest version +get_previous_version() { + local repo_url=$1 + local variable_name=$2 + local mode=$3 + prev_version=${!variable_name} + response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") + # check if github api url is not found i.e 403 error code returned + if [ "$response" -eq 403 ]; then + # if github api url is not found, then simply fetch using find_prev_version_from_git_tags + fetch_use_local_function "${repo_url}" prev_version + else + # continue fetching from github api + fetch_use_github_api "${repo_url}" prev_version "${mode}" + fi + declare -g ${variable_name}="${prev_version}" +} + install_using_get_previous_version() { mode=$1 echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - err_msg="" - get_previous_version "https://api.github.com/repos/docker/compose/releases" compose_version err_msg "$mode" - if [[ "${err_msg}" == *"Rate limit exceeded. Fallback implemented."* ]]; then - echo "Failure: Getting Previous Version by using github api failed!" - find_prev_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" - else - echo "Success: Fetched fallback version from GitHub Api successfully!" - compose_version=${compose_version#v} - fi + repo_url="https://api.github.com/repos/docker/compose/releases/latest" + get_previous_version "${repo_url}" compose_version "${mode}" echo -e "\nAttempting to install v${compose_version}" - curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} } install_docker_compose() { mode=$1 compose_version="2.25.xyz" echo "(*) Installing docker-compose ${compose_version}..." - curl -L "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} - if grep -q "Not Found" "${docker_compose_path}"; then - echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - install_using_get_previous_version "$mode" - fi + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || install_using_get_previous_version "$mode" } chmod +x ${docker_compose_path} diff --git a/test/docker-in-docker/scenarios.json b/test/docker-in-docker/scenarios.json index 0f0d9740f..33333583d 100644 --- a/test/docker-in-docker/scenarios.json +++ b/test/docker-in-docker/scenarios.json @@ -121,9 +121,7 @@ "features": { "docker-in-docker": { "version": "latest", - "installDockerBuildx": true, - "moby": "false", - "dockerDashComposeVersion": "v2" + "installDockerBuildx": true } } }, From a30338cf6502901654bf4539b13ff2b7d08312fd Mon Sep 17 00:00:00 2001 From: Gaurav Saini Date: Wed, 20 Mar 2024 23:36:50 +0000 Subject: [PATCH 5/8] changes miscellaneous --- src/docker-in-docker/install.sh | 60 ++++++++++------- .../docker_build_fallback_buildx.sh | 67 +++++++++++++------ .../docker_build_fallback_compose.sh | 63 +++++++++++------ 3 files changed, 123 insertions(+), 67 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index cbdd2a081..c07a4effa 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -151,17 +151,17 @@ find_prev_version_from_git_tags() { } fetch_use_local_function() { - local repo_url=$1 + local url=$1 local version=$2 vers=${!version} - trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') - find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + find_prev_version_from_git_tags vers "$url" "tags/v" declare -g ${version}="${vers}" } fetch_use_github_api() { - local repo_url=$1 - local version=$2 + local url=$1 + local repo_url=$2 + local version=$3 given_version=${!version} # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") @@ -170,31 +170,39 @@ fetch_use_github_api() { # convert remaining to an int value for comparison to be greater than or less than 0 remaining_int=$(printf "%d" "$remaining") if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') + curl_output=$(curl -s "$repo_url" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "${repo_url}" given_version + fetch_use_local_function "$url" given_version declare -g ${version}="${given_version}" fi } # Function to fetch the version released prior to the latest version get_previous_version() { - local repo_url=$1 - local variable_name=$2 + local url=$1 + local repo_url=$2 + local variable_name=$3 prev_version=${!variable_name} response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") # check if github api url is not found i.e 403 error code returned if [ "$response" -eq 403 ]; then # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "${repo_url}" prev_version + fetch_use_local_function "$url" prev_version else # continue fetching from github api - fetch_use_github_api "${repo_url}" prev_version + fetch_use_github_api "$url" "$repo_url" prev_version fi declare -g ${variable_name}="${prev_version}" } +form_url() { + local url=$1 + api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} + api_url="$api_url/releases/latest" + echo "$api_url" +} + ########################################### # Start docker-in-docker installation ########################################### @@ -339,9 +347,10 @@ cli_plugins_dir="${docker_home}/cli-plugins" # fallback for docker-compose fallback_compose(){ + local url=$1 + local repo_url=$(form_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - repo_url="https://api.github.com/repos/docker/compose/releases/latest" - get_previous_version "${repo_url}" compose_version + get_previous_version "${url}" "${repo_url}" compose_version echo -e "\nAttempting to install v${compose_version}" curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} } @@ -382,9 +391,10 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then fi else compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} - find_version_from_git_tags compose_version "https://github.com/docker/compose" "tags/v" + url_1="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$url_1" "tags/v" echo "(*) Installing docker-compose ${compose_version}..." - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || fallback_compose + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || fallback_compose "$url_1" chmod +x ${docker_compose_path} # Download the SHA256 checksum @@ -399,9 +409,10 @@ fi # fallback method for compose-switch fallback_compose-switch() { + local url=$1 + local repo_url=$(form_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." - repo_url="https://api.github.com/repos/docker/compose-switch/releases/latest" - get_previous_version "${repo_url}" compose_switch_version + get_previous_version "$url" "$repo_url" compose_switch_version echo -e "\nAttempting to install v${compose_switch_version}" curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch } @@ -413,8 +424,9 @@ if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /d current_compose_path="$(which docker-compose)" target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" compose_switch_version="latest" - find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch + url_1="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$url_1" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$url_1" chmod +x /usr/local/bin/compose-switch # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) @@ -443,9 +455,10 @@ usermod -aG docker ${USERNAME} # fallback for docker/buildx fallback_buildx() { + local url=$1 + local repo_url=$(form_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." - repo_url="https://api.github.com/repos/docker/buildx/releases/latest" - get_previous_version "${repo_url}" buildx_version + get_previous_version "$url" "$repo_url" buildx_version buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" echo -e "\nAttempting to install v${buildx_version}" wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} @@ -453,12 +466,13 @@ fallback_buildx() { if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_version="latest" - find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "refs/tags/v" + url_1="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$url_1" "refs/tags/v" echo "(*) Installing buildx ${buildx_version}..." buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" cd /tmp - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$url_1" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" diff --git a/test/docker-in-docker/docker_build_fallback_buildx.sh b/test/docker-in-docker/docker_build_fallback_buildx.sh index 0e3f3ce3c..0982bf399 100644 --- a/test/docker-in-docker/docker_build_fallback_buildx.sh +++ b/test/docker-in-docker/docker_build_fallback_buildx.sh @@ -103,61 +103,75 @@ find_prev_version_from_git_tags() { } fetch_use_local_function() { - local repo_url=$1 + local url=$1 local version=$2 - try_api=$4 vers=${!version} - trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') - find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + find_prev_version_from_git_tags vers "${url}" "tags/v" declare -g ${version}="${vers}" } fetch_use_github_api() { - local repo_url=$1 - local version=$2 - local try_api=$3 + local url=$1 + local repo_url=$2 + local version=$3 + local mode=$4 given_version=${!version} # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") # Extract the rate limit information from the headers read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') # convert remaining to an int value for comparison to be greater than or less than 0 - remaining_int=$(printf "%d" "$remaining") - if [[ "$try_api" != "try_valid_from_api" ]]; then + local remaining_int=$(printf "%d" "$remaining") + + if [[ "$mode" = "install_from_local_fn" ]]; then remaining_int=0 fi + if [[ $remaining_int -gt 0 ]]; then curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "${repo_url}" given_version + fetch_use_local_function "${url}" given_version declare -g ${version}="${given_version}" fi } + # Function to fetch the version released prior to the latest version get_previous_version() { - local repo_url=$1 - local variable_name=$2 - local mode=$3 + local url=$1 + local repo_url=$2 + local variable_name=$3 + local mode=$4 prev_version=${!variable_name} response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") + if [[ "${mode}" = "install_from_failing_api" ]]; then + response=403 + fi # check if github api url is not found i.e 403 error code returned if [ "$response" -eq 403 ]; then # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "${repo_url}" prev_version + fetch_use_local_function "${url}" prev_version else # continue fetching from github api - fetch_use_github_api "${repo_url}" prev_version "${mode}" + fetch_use_github_api "${url}" "${repo_url}" prev_version "${mode}" fi declare -g ${variable_name}="${prev_version}" } +form_url() { + local url=$1 + api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} + api_url="$api_url/releases/latest" + echo "$api_url" +} + install_using_get_previous_version() { - mode=$1 + local url=$1 + local mode=$2 + local repo_url=$(form_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." - repo_url="https://api.github.com/repos/docker/buildx/releases/latest" - get_previous_version "${repo_url}" buildx_version "${mode}" + get_previous_version "${url}" "${repo_url}" buildx_version "${mode}" buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" echo -e "\nAttempting to install v${buildx_version}" wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} @@ -165,13 +179,15 @@ install_using_get_previous_version() { install_docker_buildx() { mode=$1 - echo -e "\nšŸ‘‰${HL} Creating a scenario for fallback${N}\n" + echo -e "\n${HL} Creating a scenario for fallback${N}\n" buildx_version="0.13.xyz" echo "(*) Installing buildx ${buildx_version}..." buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" cd /tmp - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_using_get_previous_version "${mode}" + + url_1="https://github.com/docker/buildx" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_using_get_previous_version "${url_1}" "${mode}" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" @@ -185,15 +201,22 @@ install_docker_buildx() { find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s } +echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags api when github api-url fails with 403 ) ${N}" +install_docker_buildx "install_from_failing_api" + +# Definition specific tests after test for fallback +check "docker-buildx" docker buildx version +check "docker-buildx" bash -c "docker buildx version" + echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by github api ) ${N}" -install_docker_buildx "try_valid_from_api" +install_docker_buildx "install_from_github_api_valid" # Definition specific tests after test for fallback check "docker-buildx" docker buildx version check "docker-buildx" bash -c "docker buildx version" echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" -install_docker_buildx +install_docker_buildx "install_from_local_fn" # Definition specific tests after test for fallback check "docker-buildx" docker buildx version diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh index 156fc8387..79a02f2bf 100644 --- a/test/docker-in-docker/docker_build_fallback_compose.sh +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -101,61 +101,74 @@ find_prev_version_from_git_tags() { } fetch_use_local_function() { - local repo_url=$1 + local url=$1 local version=$2 - try_api=$4 vers=${!version} - trimmed_url=$(echo $repo_url | sed 's|api.github.com/repos|github.com|' | sed 's|/releases/latest||') - find_prev_version_from_git_tags vers "${trimmed_url}" "tags/v" + find_prev_version_from_git_tags vers "${url}" "tags/v" declare -g ${version}="${vers}" } fetch_use_github_api() { - local repo_url=$1 - local version=$2 - local try_api=$3 + local url=$1 + local repo_url=$2 + local version=$3 + local mode=$4 given_version=${!version} # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") # Extract the rate limit information from the headers read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') # convert remaining to an int value for comparison to be greater than or less than 0 - remaining_int=$(printf "%d" "$remaining") - if [[ "$try_api" != "try_valid_from_api" ]]; then + local remaining_int=$(printf "%d" "$remaining") + + if [[ "$mode" = "install_from_local_fn" ]]; then remaining_int=0 - fi + fi + if [[ $remaining_int -gt 0 ]]; then curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "${repo_url}" given_version + fetch_use_local_function "${url}" given_version declare -g ${version}="${given_version}" fi } # Function to fetch the version released prior to the latest version get_previous_version() { - local repo_url=$1 - local variable_name=$2 - local mode=$3 + local url=$1 + local repo_url=$2 + local variable_name=$3 + local mode=$4 prev_version=${!variable_name} response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") + if [[ "${mode}" = "install_from_failing_api" ]]; then + response=403 + fi # check if github api url is not found i.e 403 error code returned if [ "$response" -eq 403 ]; then # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "${repo_url}" prev_version + fetch_use_local_function "${url}" prev_version else # continue fetching from github api - fetch_use_github_api "${repo_url}" prev_version "${mode}" + fetch_use_github_api "${url}" "${repo_url}" prev_version "${mode}" fi declare -g ${variable_name}="${prev_version}" } +form_url() { + local url=$1 + api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} + api_url="$api_url/releases/latest" + echo "$api_url" +} + install_using_get_previous_version() { - mode=$1 + local url=$1 + local mode=$2 + local repo_url=$(form_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." - repo_url="https://api.github.com/repos/docker/compose/releases/latest" - get_previous_version "${repo_url}" compose_version "${mode}" + get_previous_version "$url" "$repo_url" compose_version "$mode" echo -e "\nAttempting to install v${compose_version}" curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} } @@ -163,8 +176,9 @@ install_using_get_previous_version() { install_docker_compose() { mode=$1 compose_version="2.25.xyz" + url_1="https://github.com/docker/compose" echo "(*) Installing docker-compose ${compose_version}..." - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || install_using_get_previous_version "$mode" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || install_using_get_previous_version "$url_1" "$mode" } chmod +x ${docker_compose_path} @@ -177,12 +191,17 @@ sha256sum -c docker-compose.sha256sum --ignore-missing mkdir -p ${cli_plugins_dir} cp ${docker_compose_path} ${cli_plugins_dir} +echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags api when github api-url fails with 403 ) ${N}" +install_docker_compose "install_from_failing_api" + +check "docker-compose" bash -c "docker-compose version" + echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by github api ) ${N}" -install_docker_compose "try_valid_from_api" +install_docker_compose "install_from_github_api_valid" check "docker-compose" bash -c "docker-compose version" echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" -install_docker_compose +install_docker_compose "install_from_local_fn" check "docker-compose" bash -c "docker-compose version" From 27c38ab827658325c1b2f1adee0e61ad9cb59690 Mon Sep 17 00:00:00 2001 From: Gaurav Saini Date: Thu, 21 Mar 2024 09:15:20 +0000 Subject: [PATCH 6/8] suggested changes --- src/docker-in-docker/install.sh | 56 +++++++++---------- .../docker_build_fallback_buildx.sh | 14 ++--- .../docker_build_fallback_compose.sh | 24 +++----- 3 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index c07a4effa..4669bf43f 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -111,6 +111,7 @@ find_version_from_git_tags() { # Use semver logic to decrement a version number then look for the closest match find_prev_version_from_git_tags() { + echo -e "\nAttempting to find latest version using Github Tags" local variable_name=$1 local current_version=${!variable_name} local repository=$2 @@ -150,19 +151,12 @@ find_prev_version_from_git_tags() { set -e } -fetch_use_local_function() { - local url=$1 - local version=$2 - vers=${!version} - find_prev_version_from_git_tags vers "$url" "tags/v" - declare -g ${version}="${vers}" -} - -fetch_use_github_api() { +find_prev_version_from_github_api() { local url=$1 local repo_url=$2 local version=$3 given_version=${!version} + echo -e "\nAttempting to find latest version using Github Api" # Fetch the response headers for the rate limit information and store them in a variable headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") # Extract the rate limit information from the headers @@ -173,7 +167,8 @@ fetch_use_github_api() { curl_output=$(curl -s "$repo_url" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "$url" given_version + echo -e "\nAttempting to find latest version using Github Api Failed" + find_prev_version_from_git_tags given_version "$url" "tags/v" declare -g ${version}="${given_version}" fi } @@ -188,19 +183,17 @@ get_previous_version() { # check if github api url is not found i.e 403 error code returned if [ "$response" -eq 403 ]; then # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "$url" prev_version + find_prev_version_from_git_tags prev_version "$url" "tags/v" else # continue fetching from github api - fetch_use_github_api "$url" "$repo_url" prev_version + find_prev_version_from_github_api "$url" "$repo_url" prev_version fi declare -g ${variable_name}="${prev_version}" } -form_url() { +get_github_api_repo_url() { local url=$1 - api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} - api_url="$api_url/releases/latest" - echo "$api_url" + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" } ########################################### @@ -348,7 +341,7 @@ cli_plugins_dir="${docker_home}/cli-plugins" # fallback for docker-compose fallback_compose(){ local url=$1 - local repo_url=$(form_url "$url") + local repo_url=$(get_github_api_repo_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." get_previous_version "${url}" "${repo_url}" compose_version echo -e "\nAttempting to install v${compose_version}" @@ -391,10 +384,17 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then fi else compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} - url_1="https://github.com/docker/compose" - find_version_from_git_tags compose_version "$url_1" "tags/v" + docker_compose_url="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" echo "(*) Installing docker-compose ${compose_version}..." - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || fallback_compose "$url_1" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then + fallback_compose "$docker_compose_url" + else + echo -e "Error: Failed to install docker-compose with v${compose_version}" + fi + } + chmod +x ${docker_compose_path} # Download the SHA256 checksum @@ -410,7 +410,7 @@ fi # fallback method for compose-switch fallback_compose-switch() { local url=$1 - local repo_url=$(form_url "$url") + local repo_url=$(get_github_api_repo_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." get_previous_version "$url" "$repo_url" compose_switch_version echo -e "\nAttempting to install v${compose_switch_version}" @@ -424,9 +424,9 @@ if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /d current_compose_path="$(which docker-compose)" target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" compose_switch_version="latest" - url_1="https://github.com/docker/compose-switch" - find_version_from_git_tags compose_switch_version "$url_1" - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$url_1" + compose_switch_url="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$compose_switch_url" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" chmod +x /usr/local/bin/compose-switch # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) @@ -456,7 +456,7 @@ usermod -aG docker ${USERNAME} # fallback for docker/buildx fallback_buildx() { local url=$1 - local repo_url=$(form_url "$url") + local repo_url=$(get_github_api_repo_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." get_previous_version "$url" "$repo_url" buildx_version buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" @@ -466,13 +466,13 @@ fallback_buildx() { if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_version="latest" - url_1="https://github.com/docker/buildx" - find_version_from_git_tags buildx_version "$url_1" "refs/tags/v" + docker_buildx_url="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$docker_buildx_url" "refs/tags/v" echo "(*) Installing buildx ${buildx_version}..." buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" cd /tmp - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$url_1" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" diff --git a/test/docker-in-docker/docker_build_fallback_buildx.sh b/test/docker-in-docker/docker_build_fallback_buildx.sh index 0982bf399..b297efe22 100644 --- a/test/docker-in-docker/docker_build_fallback_buildx.sh +++ b/test/docker-in-docker/docker_build_fallback_buildx.sh @@ -131,7 +131,7 @@ fetch_use_github_api() { curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "${url}" given_version + find_prev_version_from_git_tags given_version "${url}" "tags/v" declare -g ${version}="${given_version}" fi } @@ -159,17 +159,15 @@ get_previous_version() { declare -g ${variable_name}="${prev_version}" } -form_url() { +get_github_api_repo_url() { local url=$1 - api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} - api_url="$api_url/releases/latest" - echo "$api_url" + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" } install_using_get_previous_version() { local url=$1 local mode=$2 - local repo_url=$(form_url "$url") + local repo_url=$(get_github_api_repo_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." get_previous_version "${url}" "${repo_url}" buildx_version "${mode}" buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" @@ -186,8 +184,8 @@ install_docker_buildx() { buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" cd /tmp - url_1="https://github.com/docker/buildx" - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_using_get_previous_version "${url_1}" "${mode}" + docker_buildx_url="https://github.com/docker/buildx" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_using_get_previous_version "${docker_buildx_url}" "${mode}" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh index 79a02f2bf..2f217d7cc 100644 --- a/test/docker-in-docker/docker_build_fallback_compose.sh +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -100,14 +100,6 @@ find_prev_version_from_git_tags() { set -e } -fetch_use_local_function() { - local url=$1 - local version=$2 - vers=${!version} - find_prev_version_from_git_tags vers "${url}" "tags/v" - declare -g ${version}="${vers}" -} - fetch_use_github_api() { local url=$1 local repo_url=$2 @@ -129,7 +121,7 @@ fetch_use_github_api() { curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') declare -g ${version}="${curl_output#v}" else - fetch_use_local_function "${url}" given_version + find_prev_version_from_git_tags given_version "${url}" "tags/v" declare -g ${version}="${given_version}" fi } @@ -148,7 +140,7 @@ get_previous_version() { # check if github api url is not found i.e 403 error code returned if [ "$response" -eq 403 ]; then # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "${url}" prev_version + find_prev_version_from_git_tags prev_version "${url}" "tags/v" else # continue fetching from github api fetch_use_github_api "${url}" "${repo_url}" prev_version "${mode}" @@ -156,17 +148,15 @@ get_previous_version() { declare -g ${variable_name}="${prev_version}" } -form_url() { +get_github_api_repo_url() { local url=$1 - api_url=${url/https:\/\/github.com/https:\/\/api.github.com\/repos} - api_url="$api_url/releases/latest" - echo "$api_url" + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" } install_using_get_previous_version() { local url=$1 local mode=$2 - local repo_url=$(form_url "$url") + local repo_url=$(get_github_api_repo_url "$url") echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." get_previous_version "$url" "$repo_url" compose_version "$mode" echo -e "\nAttempting to install v${compose_version}" @@ -176,9 +166,9 @@ install_using_get_previous_version() { install_docker_compose() { mode=$1 compose_version="2.25.xyz" - url_1="https://github.com/docker/compose" + docker_compose_url="https://github.com/docker/compose" echo "(*) Installing docker-compose ${compose_version}..." - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || install_using_get_previous_version "$url_1" "$mode" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || install_using_get_previous_version "$docker_compose_url" "$mode" } chmod +x ${docker_compose_path} From d79526bce54dba5cc5c09f8a4bfcd892263b5604 Mon Sep 17 00:00:00 2001 From: Gaurav Saini Date: Fri, 22 Mar 2024 05:46:41 +0000 Subject: [PATCH 7/8] changes as requested by review comments on pr --- src/docker-in-docker/install.sh | 46 ++++-------- .../docker_build_fallback_buildx.sh | 74 +++++-------------- .../docker_build_fallback_compose.sh | 63 +++++----------- 3 files changed, 55 insertions(+), 128 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 4669bf43f..51bbffd8b 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -111,7 +111,6 @@ find_version_from_git_tags() { # Use semver logic to decrement a version number then look for the closest match find_prev_version_from_git_tags() { - echo -e "\nAttempting to find latest version using Github Tags" local variable_name=$1 local current_version=${!variable_name} local repository=$2 @@ -151,44 +150,29 @@ find_prev_version_from_git_tags() { set -e } -find_prev_version_from_github_api() { - local url=$1 - local repo_url=$2 - local version=$3 - given_version=${!version} - echo -e "\nAttempting to find latest version using Github Api" - # Fetch the response headers for the rate limit information and store them in a variable - headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") - # Extract the rate limit information from the headers - read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') - # convert remaining to an int value for comparison to be greater than or less than 0 - remaining_int=$(printf "%d" "$remaining") - if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "$repo_url" | jq -r '.tag_name') - declare -g ${version}="${curl_output#v}" - else - echo -e "\nAttempting to find latest version using Github Api Failed" - find_prev_version_from_git_tags given_version "$url" "tags/v" - declare -g ${version}="${given_version}" - fi -} - # Function to fetch the version released prior to the latest version get_previous_version() { local url=$1 local repo_url=$2 local variable_name=$3 prev_version=${!variable_name} - response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") - # check if github api url is not found i.e 403 error code returned - if [ "$response" -eq 403 ]; then - # if github api url is not found, then simply fetch using find_prev_version_from_git_tags + + echo -e "\nAttempting to find latest version using Github Api." + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAttempting to find latest version using Github Api Failed. Exceeded API Rate Limit." + echo -e "\nAttempting to find latest version using Github Tags." find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" else - # continue fetching from github api - find_prev_version_from_github_api "$url" "$repo_url" prev_version - fi - declare -g ${variable_name}="${prev_version}" + echo -e "\nAttempting to find latest version using Github Api Succeeded." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" } get_github_api_repo_url() { diff --git a/test/docker-in-docker/docker_build_fallback_buildx.sh b/test/docker-in-docker/docker_build_fallback_buildx.sh index b297efe22..e139613a0 100644 --- a/test/docker-in-docker/docker_build_fallback_buildx.sh +++ b/test/docker-in-docker/docker_build_fallback_buildx.sh @@ -102,41 +102,6 @@ find_prev_version_from_git_tags() { set -e } -fetch_use_local_function() { - local url=$1 - local version=$2 - vers=${!version} - find_prev_version_from_git_tags vers "${url}" "tags/v" - declare -g ${version}="${vers}" -} - -fetch_use_github_api() { - local url=$1 - local repo_url=$2 - local version=$3 - local mode=$4 - given_version=${!version} - # Fetch the response headers for the rate limit information and store them in a variable - headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") - # Extract the rate limit information from the headers - read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') - # convert remaining to an int value for comparison to be greater than or less than 0 - local remaining_int=$(printf "%d" "$remaining") - - if [[ "$mode" = "install_from_local_fn" ]]; then - remaining_int=0 - fi - - if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') - declare -g ${version}="${curl_output#v}" - else - find_prev_version_from_git_tags given_version "${url}" "tags/v" - declare -g ${version}="${given_version}" - fi -} - - # Function to fetch the version released prior to the latest version get_previous_version() { local url=$1 @@ -144,19 +109,27 @@ get_previous_version() { local variable_name=$3 local mode=$4 prev_version=${!variable_name} - response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") - if [[ "${mode}" = "install_from_failing_api" ]]; then - response=403 + + echo -e "\nAttempting to find latest version using Github Api." + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $mode != "install_from_github_api_valid" ]]; then + message="API rate limit exceeded" fi - # check if github api url is not found i.e 403 error code returned - if [ "$response" -eq 403 ]; then - # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - fetch_use_local_function "${url}" prev_version + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAttempting to find latest version using Github Api Failed. Exceeded API Rate Limit." + echo -e "\nAttempting to find latest version using Github Tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" else - # continue fetching from github api - fetch_use_github_api "${url}" "${repo_url}" prev_version "${mode}" - fi - declare -g ${variable_name}="${prev_version}" + echo -e "\nAttempting to find latest version using Github Api Succeeded." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" } get_github_api_repo_url() { @@ -199,13 +172,6 @@ install_docker_buildx() { find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s } -echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags api when github api-url fails with 403 ) ${N}" -install_docker_buildx "install_from_failing_api" - -# Definition specific tests after test for fallback -check "docker-buildx" docker buildx version -check "docker-buildx" bash -c "docker buildx version" - echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by github api ) ${N}" install_docker_buildx "install_from_github_api_valid" @@ -214,7 +180,7 @@ check "docker-buildx" docker buildx version check "docker-buildx" bash -c "docker buildx version" echo -e "\nšŸ‘‰${HL} docker-buildx version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" -install_docker_buildx "install_from_local_fn" +install_docker_buildx # Definition specific tests after test for fallback check "docker-buildx" docker buildx version diff --git a/test/docker-in-docker/docker_build_fallback_compose.sh b/test/docker-in-docker/docker_build_fallback_compose.sh index 2f217d7cc..4a18640f0 100644 --- a/test/docker-in-docker/docker_build_fallback_compose.sh +++ b/test/docker-in-docker/docker_build_fallback_compose.sh @@ -100,32 +100,6 @@ find_prev_version_from_git_tags() { set -e } -fetch_use_github_api() { - local url=$1 - local repo_url=$2 - local version=$3 - local mode=$4 - given_version=${!version} - # Fetch the response headers for the rate limit information and store them in a variable - headers=$(curl -s --head -H "Accept: application/json" "${repo_url}") - # Extract the rate limit information from the headers - read -r limit remaining reset_epoch <<<$(echo "$headers" | grep -oP 'x-ratelimit-(limit|remaining|reset): \K\d+' | tr '\n' ' ') - # convert remaining to an int value for comparison to be greater than or less than 0 - local remaining_int=$(printf "%d" "$remaining") - - if [[ "$mode" = "install_from_local_fn" ]]; then - remaining_int=0 - fi - - if [[ $remaining_int -gt 0 ]]; then - curl_output=$(curl -s "${repo_url}" | jq -r '.tag_name') - declare -g ${version}="${curl_output#v}" - else - find_prev_version_from_git_tags given_version "${url}" "tags/v" - declare -g ${version}="${given_version}" - fi -} - # Function to fetch the version released prior to the latest version get_previous_version() { local url=$1 @@ -133,19 +107,27 @@ get_previous_version() { local variable_name=$3 local mode=$4 prev_version=${!variable_name} - response=$(curl -s -o /dev/null -w "%{http_code}" "$repo_url") - if [[ "${mode}" = "install_from_failing_api" ]]; then - response=403 + + echo -e "\nAttempting to find latest version using Github Api." + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $mode != "install_from_github_api_valid" ]]; then + message="API rate limit exceeded" fi - # check if github api url is not found i.e 403 error code returned - if [ "$response" -eq 403 ]; then - # if github api url is not found, then simply fetch using find_prev_version_from_git_tags - find_prev_version_from_git_tags prev_version "${url}" "tags/v" + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAttempting to find latest version using Github Api Failed. Exceeded API Rate Limit." + echo -e "\nAttempting to find latest version using Github Tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" else - # continue fetching from github api - fetch_use_github_api "${url}" "${repo_url}" prev_version "${mode}" - fi - declare -g ${variable_name}="${prev_version}" + echo -e "\nAttempting to find latest version using Github Api Succeeded." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" } get_github_api_repo_url() { @@ -181,17 +163,12 @@ sha256sum -c docker-compose.sha256sum --ignore-missing mkdir -p ${cli_plugins_dir} cp ${docker_compose_path} ${cli_plugins_dir} -echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags api when github api-url fails with 403 ) ${N}" -install_docker_compose "install_from_failing_api" - -check "docker-compose" bash -c "docker-compose version" - echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by github api ) ${N}" install_docker_compose "install_from_github_api_valid" check "docker-compose" bash -c "docker-compose version" echo -e "\nšŸ‘‰${HL} docker-compose version as installed by docker-in-docker test ( installing by find_prev_version_from_git_tags ) ${N}" -install_docker_compose "install_from_local_fn" +install_docker_compose check "docker-compose" bash -c "docker-compose version" From 1b8e5c0d2fa613104697ed449f9b2650007d849e Mon Sep 17 00:00:00 2001 From: Gaurav Saini Date: Tue, 26 Mar 2024 02:55:45 +0000 Subject: [PATCH 8/8] Minor changes as suggested... --- src/docker-in-docker/install.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 51bbffd8b..0dc9e52d1 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -157,18 +157,16 @@ get_previous_version() { local variable_name=$3 prev_version=${!variable_name} - echo -e "\nAttempting to find latest version using Github Api." - output=$(curl -s "$repo_url"); message=$(echo "$output" | jq -r '.message') if [[ $message == "API rate limit exceeded"* ]]; then - echo -e "\nAttempting to find latest version using Github Api Failed. Exceeded API Rate Limit." - echo -e "\nAttempting to find latest version using Github Tags." + echo -e "\nAn attempt to find latest version using GitHub Api Failed... \nReason: ${message}" + echo -e "\nAttempting to find latest version using GitHub tags." find_prev_version_from_git_tags prev_version "$url" "tags/v" declare -g ${variable_name}="${prev_version}" else - echo -e "\nAttempting to find latest version using Github Api Succeeded." + echo -e "\nAttempting to find latest version using GitHub Api." version=$(echo "$output" | jq -r '.tag_name') declare -g ${variable_name}="${version#v}" fi @@ -375,7 +373,7 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then fallback_compose "$docker_compose_url" else - echo -e "Error: Failed to install docker-compose with v${compose_version}" + echo -e "Error: Failed to install docker-compose v${compose_version}" fi }