From 4bbdc0b8f7b2faa3354738c300cfedb2b77c7316 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Tue, 20 Jun 2017 10:56:13 -0700 Subject: [PATCH] Update "download-frozen-image-v2.sh" such that redirects are optional If the registry responds directly with blob contents, use them, otherwise follow the redirect without Authorization headers (which likely aren't valid for the server being redirected to). This preserves the basic structure of the previous output with up to one additional progress bar per-layer (for the redirect request and then the following blob request). Signed-off-by: Tianon Gravi --- contrib/download-frozen-image-v2.sh | 58 ++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/contrib/download-frozen-image-v2.sh b/contrib/download-frozen-image-v2.sh index ee0b8b41f7..232679019d 100755 --- a/contrib/download-frozen-image-v2.sh +++ b/contrib/download-frozen-image-v2.sh @@ -44,16 +44,41 @@ if [ "$(go env GOHOSTOS)" = 'windows' ]; then fi fi -fetch_blob() { - url=$1 - token=$2 - dest=$3 - echo "Attempting to download blob $url" - target=$(curl -sS -v -H "Authorization: Bearer $token" "$url" 2>&1 | grep "Location:" | sed 's/< Location: \(.*\)\r/\1/') - # curl blob (exclude auth token) - curl -fsS --progress "${target}" -o "$dest" -} +registryBase='https://registry-1.docker.io' +authBase='https://auth.docker.io' +authService='registry.docker.io' +# https://github.com/moby/moby/issues/33700 +fetch_blob() { + local token="$1"; shift + local image="$1"; shift + local digest="$1"; shift + local targetFile="$1"; shift + local curlArgs=( "$@" ) + + local curlHeaders="$( + curl -S "${curlArgs[@]}" \ + -H "Authorization: Bearer $token" \ + "$registryBase/v2/$image/blobs/$digest" \ + -o "$targetFile" \ + -D- + )" + curlHeaders="$(echo "$curlHeaders" | tr -d '\r')" + if [ "$(echo "$curlHeaders" | awk 'NR == 1 { print $2; exit }')" != '200' ]; then + rm -f "$targetFile" + + local blobRedirect="$(echo "$curlHeaders" | awk -F ': ' 'tolower($1) == "location" { print $2; exit }')" + if [ -z "$blobRedirect" ]; then + echo >&2 "error: failed fetching '$image' blob '$digest'" + echo "$curlHeaders" | head -1 >&2 + return 1 + fi + + curl -fSL "${curlArgs[@]}" \ + "$blobRedirect" \ + -o "$targetFile" + fi +} while [ $# -gt 0 ]; do imageTag="$1" @@ -70,14 +95,14 @@ while [ $# -gt 0 ]; do imageFile="${image//\//_}" # "/" can't be in filenames :) - token="$(curl -fsSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull" | jq --raw-output '.token')" + token="$(curl -fsSL "$authBase/token?service=$authService&scope=repository:$image:pull" | jq --raw-output '.token')" manifestJson="$( curl -fsSL \ -H "Authorization: Bearer $token" \ -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \ -H 'Accept: application/vnd.docker.distribution.manifest.v1+json' \ - "https://registry-1.docker.io/v2/$image/manifests/$digest" + "$registryBase/v2/$image/manifests/$digest" )" if [ "${manifestJson:0:1}" != '{' ]; then echo >&2 "error: /v2/$image/manifests/$digest returned something unexpected:" @@ -98,7 +123,7 @@ while [ $# -gt 0 ]; do imageId="${configDigest#*:}" # strip off "sha256:" configFile="$imageId.json" - fetch_blob "https://registry-1.docker.io/v2/$image/blobs/$configDigest" $token "$dir/$configFile" + fetch_blob "$token" "$image" "$configDigest" "$dir/$configFile" -s layersFs="$(echo "$manifestJson" | jq --raw-output --compact-output '.layers[]')" IFS="$newlineIFS" @@ -165,8 +190,8 @@ while [ $# -gt 0 ]; do echo "skipping existing ${layerId:0:12}" continue fi - token="$(curl -fsSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull" | jq --raw-output '.token')" - fetch_blob "https://registry-1.docker.io/v2/$image/blobs/$layerDigest" $token "$dir/$layerTar" + token="$(curl -fsSL "$authBase/token?service=$authService&scope=repository:$image:pull" | jq --raw-output '.token')" + fetch_blob "$token" "$image" "$layerDigest" "$dir/$layerTar" --progress ;; *) @@ -235,9 +260,8 @@ while [ $# -gt 0 ]; do echo "skipping existing ${layerId:0:12}" continue fi - token="$(curl -fsSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull" | jq --raw-output '.token')" - # find redirect using token: - fetch_blob "https://registry-1.docker.io/v2/$image/blobs/$imageLayer" $token "$dir/$layerId/layer.tar" + token="$(curl -fsSL "$authBase/token?service=$authService&scope=repository:$image:pull" | jq --raw-output '.token')" + fetch_blob "$token" "$image" "$imageLayer" "$dir/$layerId/layer.tar" --progress done ;;