Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ docker-in-docker ] - buildx can fallback to previous version if latest artifact not found #869

2 changes: 1 addition & 1 deletion src/docker-in-docker/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "docker-in-docker",
"version": "2.9.0",
"version": "2.9.1",
"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.",
Expand Down
30 changes: 26 additions & 4 deletions src/docker-in-docker/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ else
fi

# Install dependencies
check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget
check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget jq
if ! type git > /dev/null 2>&1; then
check_packages git
fi
Expand Down Expand Up @@ -332,14 +332,36 @@ fi

usermod -aG docker ${USERNAME}

# 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) | .[1].tag_name' # this would del the assets key and then get the second encountered tag_name's value from the filtered array of objects
}

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
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}
else
echo "(!) Failed to download docker buildx with exit code: $wget_exit_code"
exit 1
fi
}

if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then
buildx_version="latest"
find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "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}"


cd /tmp
wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || install_previous_version_artifacts

docker_home="/usr/libexec/docker"
cli_plugins_dir="${docker_home}/cli-plugins"

Expand Down
95 changes: 95 additions & 0 deletions test/docker-in-docker/docker_build_fallback_buildx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/bash

set -e

# Optional: Import test library
source dev-container-features-test-lib

# Definition specific tests before test for fallback
HL="\033[1;33m"
N="\033[0;37m"
echo -e "\n👉${HL} docker/buildx version as installed by docker-in-docker feature${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"

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)"

# Function to fetch the latest version of the plugin
get_latest_version() {
curl -s "$repo_url/latest" | jq -r '.tag_name'
}

# Function to fetch the previous version of the plugin
get_previous_version() {
curl -s "$repo_url" | jq -r 'del(.[].assets) | .[1].tag_name' # this would del the assets key and then get the second encountered tag_name's value from the filtered array of objects
}

# 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"
}

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}"
}

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
fi
}

test_version=$(change_version_to_fail "$(get_latest_version)")
buildx_file_name="buildx-${test_version}.linux-${architecture}"
buildx_version=$test_version

# 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

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

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

# 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
11 changes: 11 additions & 0 deletions test/docker-in-docker/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@
}
}
},
"docker_build_fallback_buildx": {
"image": "ubuntu:focal",
"features": {
"docker-in-docker": {
"version": "latest",
"installDockerBuildx": true,
"moby": "false",
"dockerDashComposeVersion": "v2"
}
}
},
// DO NOT REMOVE: This scenario is used by the docker-in-docker-stress-test workflow
"docker_with_on_create_command": {
"image": "mcr.microsoft.com/devcontainers/base:debian",
Expand Down
Loading