Skip to content

Commit 9df2381

Browse files
committed
lib/release: Add image validation
Here we add 'release::docker::validate_remote_manifests()', a function which validates the existence of image manifests on a remote registry by doing the following: - Using 'skopeo inspect' to retrieve an image manifest - Looping through the architectures and checking for an architecture-specific digest within the manifest using jq We do some minor cleanup by using 'find' and 'basename' to populate arrays for 'for' loops. Additionally, we validate the correct amount of arguments for 'release::docker::validate_remote_manifests()' and 'release::docker::release()' using 'common::argc_validate'. This function closely resembles 'release::docker::release()' and could probably be consolidated. We make the decision to not do this refactor here to minimize the changes to surrounding functions. Signed-off-by: Stephen Augustus <saugustus@vmware.com>
1 parent 29b8e1d commit 9df2381

File tree

2 files changed

+99
-16
lines changed

2 files changed

+99
-16
lines changed

anago

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,10 +1454,8 @@ push_all_artifacts () {
14541454
$KUBE_DOCKER_REGISTRY $version $BUILD_OUTPUT-$version || return 1
14551455
fi
14561456

1457-
# TODO(vdf): Add image manifest validation logic
1458-
# Maybe consider adding this to release::docker::release
1459-
# and renaming that function.
1460-
logecho "Validating image manifests (# TODO(vdf): currently a no-op)..." || return 1
1457+
common::runstep release::docker::validate_remote_manifests \
1458+
$KUBE_DOCKER_REGISTRY $version $BUILD_OUTPUT-$version || return 1
14611459

14621460
common::runstep release::gcs::publish_version \
14631461
$BUCKET_TYPE $version $BUILD_OUTPUT-$version $RELEASE_BUCKET || return 1

lib/releaselib.sh

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ readonly CI_BUCKET="kubernetes-release-dev"
3131

3232
# TODO(vdf): Need to reference K8s Infra registries here
3333
readonly GCRIO_PATH_PROD="k8s.gcr.io"
34+
# TODO(vdf): Remove all GCRIO_PATH_PROD_PUSH logic once the k8s.gcr.io vanity
35+
# domain flip (VDF) is successful
3436
readonly GCRIO_PATH_PROD_PUSH="gcr.io/google-containers"
3537
readonly GCRIO_PATH_TEST="gcr.io/k8s-staging-kubernetes"
3638

@@ -650,7 +652,6 @@ release::gcs::locally_stage_release_artifacts() {
650652
# --release-kind used by push-build.sh
651653
local release_kind=${4:-"kubernetes"}
652654
local platform
653-
local platforms
654655
local release_stage=$build_output/release-stage
655656
local release_tars=$build_output/release-tars
656657
local gcs_stage=$build_output/gcs-stage/$version
@@ -745,7 +746,7 @@ release::gcs::locally_stage_release_artifacts() {
745746

746747
# Upload the "naked" binaries to GCS. This is useful for install scripts that
747748
# download the binaries directly and don't need tars.
748-
platforms=($(cd "$release_stage/client"; echo *))
749+
mapfile -t platforms < <(find "${release_stage}/client" -maxdepth 1 -mindepth 1 -type f -exec basename {} \;)
749750
for platform in "${platforms[@]}"; do
750751
src="$release_stage/client/$platform/$release_kind/client/bin/*"
751752
dst="bin/${platform/-//}/"
@@ -1020,30 +1021,31 @@ release::gcs::publish () {
10201021
# @param build_output - build output directory
10211022
# @return 1 on failure
10221023
release::docker::release () {
1023-
local registry=$1
1024-
local push_registry=$registry
1025-
local version=$2
1026-
local build_output=$3
1027-
local release_images=$build_output/release-images
1028-
local docker_target
1024+
local registry="$1"
1025+
local push_registry="$registry"
1026+
local version="$2"
1027+
local build_output="$3"
1028+
local release_images="$build_output/release-images"
10291029
local arch
1030-
local -a arches
10311030
local tarfile
10321031
local orig_tag
1033-
local -a new_tags
10341032
local new_tag
10351033
local binary
10361034
local -A manifest_images
10371035

1036+
common::argc_validate 3
1037+
1038+
# TODO(vdf): Remove all GCRIO_PATH_PROD_PUSH logic once the k8s.gcr.io vanity
1039+
# domain flip (VDF) is successful
10381040
if [[ "$registry" == "$GCRIO_PATH_PROD" ]]; then
10391041
# Switch to the push alias if using the $GCRIO_PATH_PROD alias
10401042
push_registry="$GCRIO_PATH_PROD_PUSH"
10411043
fi
10421044

10431045
logecho "Send docker containers from release-images to $push_registry..."
10441046

1045-
arches=($(cd "$release_images"; echo *))
1046-
for arch in ${arches[@]}; do
1047+
mapfile -t arches < <(find "${release_images}" -maxdepth 1 -mindepth 1 -type d -exec basename {} \;)
1048+
for arch in "${arches[@]}"; do
10471049
for tarfile in $release_images/$arch/*.tar; do
10481050
# There may be multiple tags; just get the first
10491051
orig_tag=$(tar xf $tarfile manifest.json -O | jq -r '.[0].RepoTags[0]')
@@ -1099,6 +1101,89 @@ release::docker::release () {
10991101
return 0
11001102
}
11011103

1104+
# TODO(vdf): Consider collapsing this into release::docker::release and renaming
1105+
# that function AFTER the k8s.gcr.io Vanity Domain Flip (VDF).
1106+
###############################################################################
1107+
# Validates that image manifests have been pushed to a specified remote registry.
1108+
# Uses 'skopeo inspect'.
1109+
#
1110+
# @param registry - docker registry
1111+
# @param version - version tag
1112+
# @param build_output - build output directory
1113+
# @return 1 on failure
1114+
release::docker::validate_remote_manifests () {
1115+
local registry="$1"
1116+
local push_registry="$registry"
1117+
local version="$2"
1118+
local build_output="$3"
1119+
local release_images="$build_output/release-images"
1120+
local arch
1121+
local tarfile
1122+
local orig_tag
1123+
local new_tag
1124+
local binary
1125+
local -A manifest_images
1126+
1127+
common::argc_validate 3
1128+
1129+
# TODO(vdf): Remove all GCRIO_PATH_PROD_PUSH logic once the k8s.gcr.io vanity
1130+
# domain flip (VDF) is successful
1131+
if [[ "$registry" == "$GCRIO_PATH_PROD" ]]; then
1132+
# Switch to the push alias if using the $GCRIO_PATH_PROD alias
1133+
push_registry="$GCRIO_PATH_PROD_PUSH"
1134+
fi
1135+
1136+
logecho "Validating image manifests in $push_registry..."
1137+
1138+
mapfile -t arches < <(find "${release_images}" -maxdepth 1 -mindepth 1 -type d -exec basename {} \;)
1139+
for arch in "${arches[@]}"; do
1140+
for tarfile in $release_images/$arch/*.tar; do
1141+
# There may be multiple tags; just get the first
1142+
orig_tag=$(tar xf $tarfile manifest.json -O | jq -r '.[0].RepoTags[0]')
1143+
if [[ ! "$orig_tag" =~ ^.+/(.+):.+$ ]]; then
1144+
logecho "$FAILED: malformed tag in $tarfile:"
1145+
logecho $orig_tag
1146+
return 1
1147+
fi
1148+
binary=${BASH_REMATCH[1]}
1149+
1150+
new_tag="$push_registry/${binary/-$arch/}"
1151+
manifest_images["${new_tag}"]+=" $arch"
1152+
done
1153+
done
1154+
1155+
for image in "${!manifest_images[@]}"; do
1156+
local archs
1157+
local manifest
1158+
local digest
1159+
1160+
logecho "Validating manifest list exists for ${image}:${version}..."
1161+
1162+
archs=$(echo "${manifest_images[$image]}" | sed -e 's/^[[:space:]]*//')
1163+
1164+
if ! manifest=$(skopeo inspect "docker://${image}:${version}" --raw); then
1165+
logecho "Could not find manifest list for ${image}:${version}"
1166+
return 1
1167+
fi
1168+
1169+
for arch in ${archs}; do
1170+
logecho "Checking image digest for ${image} on ${arch} architecture..."
1171+
1172+
digest=$(echo -n "${manifest}" \
1173+
| jq --arg a "${arch}" -r '.manifests[] | select(.platform.architecture==$a)' \
1174+
| jq -r '.digest')
1175+
1176+
if [[ -n "$digest" ]]; then
1177+
logecho "Digest for ${image} on ${arch}: ${digest}"
1178+
else
1179+
logecho "Could not find the image digest for ${image} on ${arch}. Exiting..."
1180+
return 1
1181+
fi
1182+
done
1183+
done
1184+
1185+
return 0
1186+
}
11021187

11031188
###############################################################################
11041189
# Get the kubecross image version for a given release branch.

0 commit comments

Comments
 (0)