Skip to content

Commit

Permalink
Merge pull request #130: CI: Validate images across platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
victorlin authored Mar 21, 2023
2 parents 1cfbe73 + 1856139 commit b8ce22b
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 2 deletions.
22 changes: 20 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ jobs:
env:
DOCKER_DEFAULT_PLATFORM: ${{ matrix.platform }}

validate-platforms:
name: Validate platforms
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: docker/setup-qemu-action@v2

- uses: docker/login-action@v2
with:
registry: ghcr.io
username: nextstrain-bot
password: ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}

- name: Validate final images
run: ./devel/validate-platforms -r ghcr.io -t ${{ needs.build.outputs.tag }}

# "Push" (copy) the builder and final images from GitHub Container Registry to
# Docker Hub, where they will persist. Do this regardless of test results.
push-branch:
Expand Down Expand Up @@ -110,7 +128,7 @@ jobs:
# Docker Hub, where they will persist. Only do this if tests pass.
push-build:
if: startsWith(needs.build.outputs.tag, 'build-')
needs: [build, test]
needs: [build, test, validate-platforms]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -134,7 +152,7 @@ jobs:
# Delete the builder and final images from GitHub Container Registry.
cleanup-registry:
if: always()
needs: [build, test, push-branch, push-build]
needs: [build, test, validate-platforms, push-branch, push-build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ RUN pip3 install pysam==0.19.1

# Allow caching to be avoided from here on out by calling
# docker build --build-arg CACHE_DATE="$(date)"
# NOTE: All versioned software added below should be checked in
# devel/validate-platforms.
ARG CACHE_DATE

# Install our own CLI so builds can do things like `nextstrain deploy`
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ variable to a new timestamp first:
Otherwise, letting the build process use the cached layers will save you time
during development iterations.

### Validate the images

Before using the images, they should be checked for any inconsistencies.

./devel/validate-platforms

The output and exit code will tell you whether validation is successful.

### Using the images locally

Since the images are pushed directly to the local registry, they are not
Expand Down
112 changes: 112 additions & 0 deletions devel/validate-platforms
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/bin/bash
#
# Validate different platform builds of the final Nextstrain image.
#
set -euo pipefail

# Set default values.
registry=localhost:5000
tag=latest

# Read command-line arguments.
while getopts "r:t:" opt; do
case "$opt" in
r) registry="$OPTARG";;
t) tag="$OPTARG";;
*) echo "Usage: $0 [-r <registry>] [-t <tag>]" 1>&2; exit 1;;
esac
done

IMAGE="$registry/nextstrain/base:$tag"
PLATFORMS=(linux/amd64 linux/arm64)

main() {
# Check that every platform image got the same versions of important (e.g.
# first-party) software for which we don't pin a specific version (e.g. we
# install whatever the latest version is at build time).

local report_dir
report_dir="$(mktemp -dt "$(basename "$0")"-XXXXXX)"

for platform in "${PLATFORMS[@]}"; do
echo "[$platform] Pulling image..."
docker pull -q --platform "$platform" "$IMAGE"

echo "[$platform] Checking that the platform is expected..."
check-platform "$platform"

# Initialize a directory for the report file, ensuring slashes in the
# platform name are subdirs.
report="$report_dir/$platform"
echo "[$platform] Generating report file: $report"
mkdir -p "$(dirname "$report")"

# Create a report file for the platform.
# This should include all software below ARG CACHE_DATE in the Dockerfile
# in addition to other important software.
echo "[$platform] Determining software versions..."
docker-run "$platform" bash -c '
function echo-command {
echo "$ $BASH_COMMAND"
}
trap echo-command DEBUG
nextstrain --version
nextalign --version
nextclade --version
augur --version
auspice --version
python3 -c "from importlib.metadata import version; print(version(\"evofr\"))"
datasets --version
dataformat version
python3 -c "from importlib.metadata import version; print(version(\"phylo-treetime\"))"
' >"$report"
done

# Compare contents of the first platform's report file against others.
first_report="$report_dir/${PLATFORMS[0]}"
echo "The report for ${PLATFORMS[0]} has the following contents:"
cat "$first_report"

echo "Comparing against other platforms..."
# NOTE: if running on macOS ≥13, you may need to install GNU diff for the
# --from-file option.
if cd "$report_dir" && diff --unified=1 --from-file="${PLATFORMS[0]}" "${PLATFORMS[@]:1}"; then
echo "Success! All versions the same." >&2
else
echo "Failure!" >&2
exit 1
fi
}

check-platform() {
# Check that the platform is actually what we expect it to be.
local platform="$1"

python_platform_string="$(docker-run "$platform" python -c "import platform; print(platform.platform())")"

case "$platform" in
linux/amd64)
if [[ "$python_platform_string" != *"x86_64"* ]]; then
echo "Platform $platform not detected." 1>&2; exit 1
fi;;
linux/arm64)
if [[ "$python_platform_string" != *"aarch64"* ]]; then
echo "Platform $platform not detected." 1>&2; exit 1
fi;;
*)
echo "Platform $platform not supported." 1>&2; exit 1;;
esac
}

docker-run() {
# Run a command under the final Nextstrain image built for a specific
# platform.
local platform="$1"
local command=("${@:2}")

docker run --rm --platform "$platform" "$IMAGE" "${command[@]}"
}

main

0 comments on commit b8ce22b

Please sign in to comment.