Skip to content

Commit

Permalink
Support <version>-immutable tagged stable images
Browse files Browse the repository at this point in the history
There are circumstances where it's consequential to have image digests
that change constantly.  Add a "flavor" of podman/buildah/skopeo image
with a unique tag, that's only ever pushed once.  Update documentation.

Signed-off-by: Chris Evich <cevich@redhat.com>
  • Loading branch information
cevich committed Apr 17, 2024
1 parent c8d70ca commit 44b3dbe
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 36 deletions.
3 changes: 3 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ test_image_build_task:
- env:
FLAVOR_NAME: stable
matrix: *pbs_images
- env:
FLAVOR_NAME: immutable
matrix: *pbs_images
script: &pbs_script |
source /etc/automation_environment
# The '.' prefix to repo URL is significant - it means do not clone.
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ The container images are tagged as follows, where `*` represents either `podman`
or `skopeo`:

* `quay.io/containers/*:<version>` and `quay.io/*/stable:<version>` -
These images are built daily. They are intended to contain an unchanging
and stable version of their container image. For the most recent `<version>` tags (`vX`,
These images are built daily. They are intended to contain the latest stable
versions of their container tool. For the most recent `<version>` tags (`vX`,
`vX.Y`, and `vX.Y.Z`) the image contents will be updated daily to incorporate
(especially) security updates.
* `quay.io/containers/*:<version>-immutable` - Uses the same source as the 'stable'
images, is built daily, but version-tags are never overwritten once pushed. This is
intended for users that value an unchanging image tag and digest over having daily
security updates. All three `<version>` values are available, `vX-immutable`,
`vX.Y-immutable` and `vX.Y.Z-immutable`.
* `quay.io/containers/*:latest` and `quay.io/*/stable:latest` -
Built daily using the same `Containerfile` as above. The tool versions
will remain the "latest" available in Fedora.
Expand Down
26 changes: 19 additions & 7 deletions ci/containers_build_push.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ if [[ "$CTX_SUB" =~ testing ]]; then
fi

REPO_FQIN="$_REG/$CTX_SUB/$FLAVOR_NAME"
if [[ "$FLAVOR_NAME" == "immutable" ]]; then
# Only the image version-tag varies
REPO_FQIN="$_REG/$CTX_SUB/stable"
fi
req_env_vars REPO_URL CTX_SUB FLAVOR_NAME

# Common library defines SCRIPT_FILENAME
Expand All @@ -110,7 +114,11 @@ fi
### MAIN

declare -a build_args
build_args=("--build-arg=FLAVOR=$FLAVOR_NAME")
if [[ "$FLAVOR_NAME" == "immutable" ]]; then
build_args=("--build-arg=FLAVOR=stable")
else
build_args=("--build-arg=FLAVOR=$FLAVOR_NAME")
fi

head_sha=$(git rev-parse HEAD)
dbg "HEAD is $head_sha"
Expand Down Expand Up @@ -163,9 +171,9 @@ done
modcmdarg="$SCRIPT_PATH/tag_version.sh $FLAVOR_NAME"

# For stable images, the version number of the command is needed for tagging and labeling.
if [[ "$FLAVOR_NAME" == "stable" ]]; then
if [[ "$FLAVOR_NAME" == "stable" || "$FLAVOR_NAME" == "immutable" ]]; then
# only native arch is needed to extract the version
dbg "Building temporary local-arch image to extract stable version number"
dbg "Building temporary local-arch image to extract $FLAVOR_NAME version number"
fqin_tmp="$CTX_SUB:temp"
showrun podman build --arch=amd64 -t $fqin_tmp "${build_args[@]}" ./$CTX_SUB

Expand All @@ -191,13 +199,15 @@ if [[ "$FLAVOR_NAME" == "stable" ]]; then
# tag-version.sh expects this arg. when FLAVOR_NAME=stable
modcmdarg+=" $img_cmd_version"

dbg "Building stable-flavor manifest-list '$_REG/containers/$CTX_SUB'"
dbg "Building $FLAVOR_NAME manifest-list '$_REG/containers/$CTX_SUB'"

for arg in "--label" "--annotation"; do
label_args+=("$arg=org.opencontainers.image.url=https://$_REG/containers/$CTX_SUB")
done

# Stable images get pushed to 'containers' namespace as latest & version-tagged
# Stable images get pushed to 'containers' namespace as latest & version-tagged.
# Immutable images are only version-tagged, and are never pushed if they already
# exist.
showrun build-push.sh \
$_DRNOPUSH \
--arches="$ARCHES" \
Expand All @@ -220,8 +230,10 @@ for arg in "--label" "--annotation"; do
label_args+=("$arg=org.opencontainers.image.url=https://${REPO_FQIN}")
done

# All images are pushed to quay.io/<reponame>, both
# latest and version-tagged (if available).
# All flavors are pushed to quay.io/<reponame>/<flavor>, both
# latest and version-tagged (if available). Stable + Immutable
# images are only version-tagged, and are never pushed if they
# already exist.
showrun build-push.sh \
$_DRNOPUSH \
--arches="$ARCHES" \
Expand Down
54 changes: 46 additions & 8 deletions ci/tag_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,46 @@ elif [[ -z "$VERSION" ]]; then
warn "$SCRIPT_FILENAME received empty version argument."
fi

# Given the image tag as an argument, apply the tag as appropriate given $FLAVOR_NAME
# N/B: For the "immutable" flavor, the tag will have `-immutable` appended to it.
handle_tagging() {
local existing
local tag
tag="$1"

[[ -n "$tag" ]] || \
die "handle_tagging() received an empty tag argument."

# Images are always tagged using the source $FQIN:latest
[[ "$tag" != "latest" ]] || \
die "handle_tagging() must never be run with tag argument 'latest'."

if [[ "$FLAVOR_NAME" == "immutable" ]]; then
tag="${tag}-immutable"

# ci/test.sh tests never push, there's never any remote image to check.
# The FQIN envar is defined by the build-push.sh caller
# shellcheck disable=SC2154
if [[ ! "$FQIN" =~ testing ]]; then
existing=$(skopeo list-tags docker://$FQIN | jq -e -r '.Tags[]')
if grep -F -x -q "$tag" <<<"$existing"; then
msg "Skipping; $FQIN:$tag already exists in registry."
return 0
fi
fi
fi

dbg "Tagging $FQIN:latest $FQIN:$tag"
# The RUNTIME envar is defined by the build-push.sh caller
# shellcheck disable=SC2154
$RUNTIME tag $FQIN:latest $FQIN:$tag
msg "Successfully tagged $FQIN:$tag"
}

# shellcheck disable=SC2154
dbg "$SCRIPT_FILENAME operating on '$FLAVOR_NAME' flavor of '$FQIN' with tool version '$VERSION' (optional)"

if [[ "$FLAVOR_NAME" == "stable" ]]; then
if [[ "$FLAVOR_NAME" == "stable" || "$FLAVOR_NAME" == "immutable" ]]; then
# Stable images must all be tagged with a version number.
# Confirm this value is passed in by caller.
if grep -E -q '^v[0-9]+\.[0-9]+\.[0-9]+'<<<"$VERSION"; then
Expand All @@ -58,19 +94,21 @@ if [[ "$FLAVOR_NAME" == "stable" ]]; then
die "Encountered unexpected/non-conforming version '$VERSION'"
fi

# shellcheck disable=SC2154
$RUNTIME tag $FQIN:latest $FQIN:$VERSION
msg "Successfully tagged $FQIN:$VERSION"
handle_tagging $VERSION

# Tag as x.y to provide a consistent tag even for a future z+1
xy_ver=$(awk -F '.' '{print $1"."$2}'<<<"$VERSION")
$RUNTIME tag $FQIN:latest $FQIN:$xy_ver
msg "Successfully tagged $FQIN:$xy_ver"
handle_tagging $xy_ver

# Tag as x to provide consistent tag even for a future y+1
x_ver=$(awk -F '.' '{print $1}'<<<"$xy_ver")
$RUNTIME tag $FQIN:latest $FQIN:$x_ver
msg "Successfully tagged $FQIN:$x_ver"
handle_tagging $x_ver

# handle_tagging() uses $FQIN:latest as the source, but there can never be an immutable 'latest'.
if [[ "$FLAVOR_NAME" == "immutable" ]]; then
$RUNTIME manifest rm $FQIN:latest || $RUNTIME rm $FQIN:latest
msg "Successfully removed non-immutable $FQIN:latest"
fi
else
warn "$SCRIPT_FILENAME not version-tagging for '$FLAVOR_NAME' flavor'$FQIN'"
fi
50 changes: 31 additions & 19 deletions ci/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ TEST_REPO_URL="file://$SRC_TMP"

# Given the flavor-name as the first argument, verify built image
# expectations. For 'stable' image, verify that containers_build_push.sh will properly
# version-tagged both FQINs. For other flavors, verify expected labels
# on the `latest` tagged FQINs.
# version-tagged both FQINs. For 'immutable' verify version tags only for TEST_FQIN2.
# For other flavors, verify expected labels on the `latest` tagged FQINs.
verify_built_images() {
local _fqin _arch xy_ver x_ver img_ver img_src img_rev _fltr
local _test_tag expected_flavor _test_fqins img_docs
Expand All @@ -82,6 +82,12 @@ verify_built_images() {
test_tag="v$FAKE_VERSION"
xy_ver="v$FAKE_VER_X.$FAKE_VER_Y"
x_ver="v$FAKE_VER_X"
elif [[ "$expected_flavor" == "immutable" ]]; then
expected_flavor="stable" # Only the tags are different
_test_fqins=("$TEST_FQIN" "$TEST_FQIN2")
test_tag="v$FAKE_VERSION-immutable"
xy_ver="v$FAKE_VER_X.$FAKE_VER_Y-immutable"
x_ver="v$FAKE_VER_X-immutable"
else
test_tag="latest"
xy_ver="latest"
Expand Down Expand Up @@ -156,11 +162,20 @@ verify_built_images() {
}

remove_built_images() {
local fqin tag
local -a tags

buildah --version
for _fqin in $TEST_FQIN $TEST_FQIN2; do
for tag in latest v$FAKE_VERSION v$FAKE_VER_X.$FAKE_VER_Y v$FAKE_VER_X; do
# Don't care if this fails
podman manifest rm $_fqin:$tag || true

tags=( latest )
for tag in v$FAKE_VERSION v$FAKE_VER_X.$FAKE_VER_Y v$FAKE_VER_X; do
tags+=( "$tag" "${tag}-immutable" )
done

for fqin in $TEST_FQIN $TEST_FQIN2; do
for tag in "${tags[@]}"; do
# Not all tests produce every possible tag
podman manifest rm $fqin:$tag || true
done
done
}
Expand All @@ -171,16 +186,13 @@ _cbp=$CIRRUS_WORKING_DIR/ci/containers_build_push.sh

cd $SRC_TMP

msg "
##### Testing build-push stable flavor run of '$TEST_FQIN' & '$TEST_FQIN2' #####"
export DRYRUN=1 # Force containers_build_push.sh not to push anything
req_env_vars ARCHES DRYRUN
# containers_build_push.sh is sensitive to 'testing' value.
env A_DEBUG=1 $_cbp $TEST_REPO_URL testing stable
verify_built_images stable

msg "
##### Testing build-push non-stable flavour run for '$TEST_FQIN' & '$TEST_FQIN2' #####"
remove_built_images
env A_DEBUG=1 $_cbp $TEST_REPO_URL testing foobarbaz
verify_built_images foobarbaz
for flavor_arg in stable foobarbaz immutable; do
msg "
##### Testing build-push $flavor_arg flavor run of '$TEST_FQIN' & '$TEST_FQIN2' #####"
remove_built_images
export DRYRUN=1 # Force containers_build_push.sh not to push anything
req_env_vars ARCHES DRYRUN flavor_arg
# containers_build_push.sh is sensitive to 'testing' value.
env A_DEBUG=1 $_cbp $TEST_REPO_URL testing $flavor_arg
verify_built_images $flavor_arg
done

0 comments on commit 44b3dbe

Please sign in to comment.