From: sourabh_sourabh Date: Fri, 6 Jun 2025 16:31:16 +0000 (+0100) Subject: Feature(setup): add Docker image digest verification before container startup X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=ba9895415a56aed71be008fee1fd2393d7a486d4;p=cps.git Feature(setup): add Docker image digest verification before container startup - Integrated image validation into setup.sh using verify-docker-image-digests.sh - Pre-checks Docker image digests before running docker-compose - Logs detailed pull diagnostics, fallback to local images if pull fails Issue-ID: CPS-2837 Change-Id: Iec5fb12091dcac853031fa8d083c51792f240eb4 Signed-off-by: sourabh_sourabh --- diff --git a/k6-tests/setup.sh b/k6-tests/setup.sh index 6a233ce1f2..92abb2aa86 100755 --- a/k6-tests/setup.sh +++ b/k6-tests/setup.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright 2024-2025 OpenInfra Foundation Europe. +# Copyright 2024-2025 OpenInfra Foundation Europe. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,10 +15,21 @@ # limitations under the License. # +# Load image check and logging functions +source "$(dirname "$0")/verify-docker-image-digests.sh" + testProfile=$1 ENV_FILE="../docker-compose/env/${testProfile}.env" COMPOSE_FILE="../docker-compose/cps-base.yml" +# Define images to pre-check (add more if needed) +IMAGES_TO_CHECK=( + "nexus3.onap.org:10003/onap/dmi-stub:latest" +) + +# Run the image checks before anything else +check_images "${IMAGES_TO_CHECK[@]}" + # Define a function to encapsulate docker-compose command compose() { docker-compose \ diff --git a/k6-tests/verify-docker-image-digests.sh b/k6-tests/verify-docker-image-digests.sh new file mode 100644 index 0000000000..618035c15d --- /dev/null +++ b/k6-tests/verify-docker-image-digests.sh @@ -0,0 +1,126 @@ +#!/bin/bash +# +# Copyright 2025 OpenInfra Foundation Europe. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Exit on error, undefined variable, or pipefail +set -euo pipefail + +# List of Docker images to check - passed via environment or hardcoded +IMAGES_TO_CHECK=("${IMAGES_TO_CHECK[@]:-}") + +# Directory to store digest files +DIGEST_DIR="${WORKSPACE:-.}/image/digest" +mkdir -p "$DIGEST_DIR" + +# Function to sanitize image names for filenames +sanitize_image_name() { + local image="$1" + echo "$image" | sed 's/[:\/]/_/g' +} + +# Function to retrieve the digest of a local image +get_local_digest() { + local image="$1" + docker inspect --format='{{index .RepoDigests 0}}' "$image" 2>/dev/null || echo "none" +} + +# Function to pull the latest image and retrieve its digest +pull_image_and_get_digest() { + local image="$1" + local pull_output + + # Capture pull output and error + if ! pull_output=$(docker pull "$image" 2>&1); then + echo "⛔ Failed to pull image: $image" + if echo "$pull_output" | grep -q "toomanyrequests:"; then + echo " ❗ Detected Docker Hub rate limit (toomanyrequests:)" + fi + echo " ⚠️ Possible reasons:" + echo " - Network issues" + echo " - Image does not exist" + echo " - Docker Hub rate limit exceeded" + echo " 🔄 Attempting to retrieve local digest (if available)..." + get_local_digest "$image" + return 1 + fi + + get_local_digest "$image" +} + +# Main image validation logic +check_images() { + echo + echo "🔍 Starting Docker image verification..." + echo "⏱️ Started at : $(date -u)" + + for IMAGE in "${IMAGES_TO_CHECK[@]}"; do + echo -e "\n🧪 Verifying Docker image: $IMAGE" + echo " 🕒 Timestamp: $(date -u)" + + local SANITIZED_IMAGE_NAME + SANITIZED_IMAGE_NAME=$(sanitize_image_name "$IMAGE") + local DIGEST_FILE="$DIGEST_DIR/${SANITIZED_IMAGE_NAME}.digest" + + local PREVIOUS_DIGEST="none" + if [[ -f "$DIGEST_FILE" ]]; then + PREVIOUS_DIGEST=$(<"$DIGEST_FILE") + fi + + local NEW_DIGEST + if ! NEW_DIGEST=$(pull_image_and_get_digest "$IMAGE"); then + echo " ⚠️ Using local image (if available)." + continue + fi + + if [[ "$PREVIOUS_DIGEST" != "$NEW_DIGEST" ]]; then + echo "⚠️ Digest changed for $IMAGE" + echo " 🔖 Previous digest: $PREVIOUS_DIGEST" + echo " 🆕 New digest : $NEW_DIGEST" + echo "$NEW_DIGEST" > "$DIGEST_FILE" + log_image_info "$IMAGE" + else + echo "✅ Image content is unchanged. Digest remains:" + echo " 🔖 $NEW_DIGEST" + fi + done + + echo -e "\n✅ Docker image verification completed for all specified images." + echo "🕒 Finished at: $(date -u)" +} + +# Function: Display local metadata for an image +# Function: Display detailed metadata for a local Docker image with styled output +log_image_info() { + local IMAGE_NAME="$1" + echo "🖼️ Docker Image Metadata for: $IMAGE_NAME" + + local IMAGE_ID CREATED SIZE DIGEST + IMAGE_ID=$(docker inspect --format='{{.Id}}' "$IMAGE_NAME" 2>/dev/null || echo "❓ unknown") + CREATED=$(docker inspect --format='{{.Created}}' "$IMAGE_NAME" 2>/dev/null || echo "❓ unknown") + SIZE=$(docker inspect --format='{{.Size}}' "$IMAGE_NAME" 2>/dev/null || echo "❓ unknown") + DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_NAME" 2>/dev/null || echo "❓ unknown") + + echo " 🆔 Image ID : $IMAGE_ID" + echo " 📅 Created : $CREATED" + + if [[ "$SIZE" != "❓ unknown" && "$SIZE" =~ ^[0-9]+$ ]]; then + # Using awk to avoid bc dependency + SIZE_MB=$(awk "BEGIN { printf \"%.2f\", $SIZE/1024/1024 }") + echo " 📦 Size : ${SIZE_MB} MB" + else + echo " 📦 Size : ❓ unknown" + fi + echo " 🔖 Digest : $DIGEST" +} \ No newline at end of file