From 8e141c4322f578511c8fb5d8918fc4e6de5c665a Mon Sep 17 00:00:00 2001 From: Shiming Zhang Date: Fri, 10 Sep 2021 20:21:22 +0800 Subject: [PATCH] Add diff-image.sh --- scripts/diff-image.sh | 145 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100755 scripts/diff-image.sh diff --git a/scripts/diff-image.sh b/scripts/diff-image.sh new file mode 100755 index 0000000..9d30329 --- /dev/null +++ b/scripts/diff-image.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +IMAGE1="${1:-}" +IMAGE2="${2:-}" + +# Output more information that is out of sync +DEBUG="${DEBUG:-}" + +# Allow image2 to have more tags than image1 +INCREMENTAL="${INCREMENTAL:-}" + +SELF="$(basename "${BASH_SOURCE[0]}")" + +function check() { + local image1="${1:-}" + local image2="${2:-}" + + if [[ "${image1}" == "" ]] || [[ "${image2}" == "" ]]; then + echo "Compares whether the synchronization of the two images is exactly the same" + echo "Need to install jq and skopeo" + echo "Usage:" + echo " ${SELF}: " + echo " ${SELF}: " + echo "Env:" + echo " DEBUG=true # Output more information that is out of sync" + echo " INCREMENTAL=true # Allow image2 to have more tags than image1" + return 2 + fi + + if [[ "${image1}" =~ ":" ]]; then + if [[ "${image2}" =~ ":" ]]; then + return 0 + else + echo "${SELF}: ERROR: ${image1} and ${image2} must both be full images or not be tag references" >&2 + return 2 + fi + else + if [[ "${image2}" =~ ":" ]]; then + echo "${SELF}: ERROR: ${image1} and ${image2} must both be full images or not be tag references" >&2 + return 2 + else + return 0 + fi + fi +} + +function inspect() { + local image="${1:-}" + if [[ "${DEBUG}" == "true" ]]; then + echo skopeo inspect --retry-times=3 --raw --tls-verify=false "docker://${image}" >&2 + fi + skopeo inspect --retry-times=3 --raw --tls-verify=false "docker://${image}" +} + +function list-tags() { + local image="${1:-}" + if [[ "${DEBUG}" == "true" ]]; then + echo skopeo list-tags --retry-times=3 --tls-verify=false "docker://${image}" >&2 + fi + skopeo list-tags --retry-times=3 --tls-verify=false "docker://${image}" +} + +function diff-image() { + local image1="${1:-}" + local image2="${2:-}" + + if [[ "$image1" =~ ":" ]]; then + local inspect1="$(inspect ${image1} | jq -S 'del( .manifests[]?.mediaType, .layers[]?.mediaType, .config?, .mediaType?, .schemaVersion?, .signatures?)')" + local inspect2="$(inspect ${image2} | jq -S 'del( .manifests[]?.mediaType, .layers[]?.mediaType, .config?, .mediaType?, .schemaVersion?, .signatures?)')" + local diff_raw=$(diff --unified <(echo "${inspect1}") <(echo "${inspect2}")) + + if [[ "${diff_raw}" != "" ]]; then + echo "${SELF}: UNSYNC: ${image1} and ${image2} are not in synchronized" >&2 + if [[ "${DEBUG}" == "true" ]]; then + echo "DEBUG: image1 ${image1}:" >&2 + echo "${inspect1}" >&2 + echo "DEBUG: image2 ${image2}:" >&2 + echo "${inspect2}" >&2 + echo "diff:" >&2 + echo "${diff_raw}" >&2 + fi + return 1 + fi + echo "${SELF}: SYNC: ${image1} and ${image2} are in synchronized" >&2 + echo "${inspect1}" + else + local inspect1="$(list-tags ${image1} | jq -S '.')" + local inspect2="$(list-tags ${image2} | jq -S '.')" + local diff_raw="$(diff --unified <(echo "${inspect1}" | jq -S '.Tags[]' | tr -d '"') <(echo "${inspect2}" | jq -S '.Tags[]' | tr -d '"'))" + local diff_data="$(echo "${diff_raw}" | grep -v ' ' | grep -v -E '^---' | grep -v -E '^\+\+\+')" + + if [[ "${INCREMENTAL}" == "true" ]]; then + diff_data="$(echo "${diff_data}" | grep -v -E '^\+')" + fi + + if [[ "${diff_data}" != "" ]]; then + echo "${SELF}: UNSYNC: ${image1} and ${image2} are not in synchronized" >&2 + if [[ "${DEBUG}" == "true" ]]; then + echo "DEBUG: image1 ${image1}:" >&2 + echo "${inspect1}" >&2 + echo "DEBUG: image2 ${image2}:" >&2 + echo "${inspect2}" >&2 + echo "DEBUG: diff:" >&2 + echo "${diff_data}" >&2 + fi + return 1 + fi + echo "${SELF}: SYNC: ${image1} and ${image2} are in synchronized" >&2 + echo "${inspect1}" + fi + return 0 +} + +function main() { + local image1="${1:-}" + local image2="${2:-}" + + raw=$(diff-image "${image1}" "${image2}") + if [[ "${image1}" =~ ":" ]]; then + return 0 + fi + + local list=$(echo "${raw}" | jq '.Tags[]' | tr -d '"') + local total=$(echo "${list}" | wc -l | tr -d ' ') + local count=0 + local unsync=() + + for tag in ${list}; do + count=$((count + 1)) + echo "${SELF}: DIFF ${count}/${total}: ${tag}" + diff-image "${image1}:${tag}" "${image2}:${tag}" >/dev/null || unsync+=("${tag}") + done + + if [[ "${#unsync[@]}" -gt 0 ]]; then + echo "${SELF}: UNSYNC: ${image1} and ${image2} are not in synchronized, there are unsynchronized tags ${#unsync[@]}/${total}: ${unsync[*]}" >&2 + return 1 + fi +} + +check "${IMAGE1}" "${IMAGE2}" +main "${IMAGE1}" "${IMAGE2}"