Skip to content

Commit

Permalink
Tests: new tool to build a no-history image
Browse files Browse the repository at this point in the history
Script crafts a custom image with multiple layers but
no history; used in tests/bud.bats:bud-implicit-no-history test.

Signed-off-by: Ed Santiago <santiago@redhat.com>
  • Loading branch information
edsantiago committed Apr 29, 2024
1 parent ee70428 commit d30786a
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 2 deletions.
8 changes: 7 additions & 1 deletion tests/bud.bats
Original file line number Diff line number Diff line change
Expand Up @@ -4433,7 +4433,13 @@ EOM
}

@test "bud-implicit-no-history" {
_prefetch nixery.dev/shell
testimage=quay.io/libpod/buildah-testimage-nohistory:20240429
_prefetch $testimage busybox
run_buildah tag $testimage fakeregistry.podman.io/notreal

# Before #5473, running build with a no-history image barfed with:
# initializing source containers-storage:xxx-working-container: \
# internal error: history lists 2 non-empty layers, but we have 6 layers on disk
run_buildah build $WITH_POLICY_JSON --layers=false $BUDFILES/no-history
run_buildah build $WITH_POLICY_JSON --layers=true $BUDFILES/no-history
}
Expand Down
3 changes: 2 additions & 1 deletion tests/bud/no-history/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# The important thing about that first base image is that it has no history
# entries, but it does have at least one layer.

FROM nixery.dev/shell AS first-stage
FROM fakeregistry.podman.io/notreal AS first-stage
COPY --from=busybox / /
RUN date > /date1.txt
RUN sleep 1 > /sleep1.txt

Expand Down
241 changes: 241 additions & 0 deletions tests/build-nohistory-image
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
#!/bin/bash
#
# build-no-history-image - craft a custom image used in bud-implicit-no-history test.
#
# This script does not run in CI, or automated tests, or gating. In fact
# it is meant to be run once, only once, by a human, and then (with luck)
# never again. The purpose is to create a custom test image with certain
# very specific attributes. This image will be used in one specific test.
# Maybe some day other tests. The image should be static and immutable.
# This creation script is checked into the buildah source tree simply
# as reference for how the image was created, and as a tool should there
# ever be a need to update that test image in some way.
#
# See https://github.com/containers/buildah/pull/5473
#
set -e

# Name of the resulting image. (Never pushed automatically).
# If image build is successful, a human can push it to quay.
IMAGE=quay.io/libpod/buildah-testimage-nohistory:$(date +%Y%m%d)
podman rmi -f $IMAGE &> /dev/null

# Arches for which we want to build images
declare -a arches=(amd64 arm:v7 arm64:v8 ppc64le s390x)

# Working directory; we'll be filling it up with layer files and
# manifests and whatnot
workdir=$(mktemp --tmpdir --directory $(basename $0).XXXXXXX)
ocidir=oci/blobs/sha256
mkdir -p $workdir/$ocidir

# First layer is a copy of this script. Copy it before we cd.
cp $0 $workdir/
cd $workdir
echo $workdir

#
# PASS 1: Create some layers (content)
#
declare -a layerid layersize

# Helper for creating one layer. If called with an argument, use
# that as input file; otherwise create random content
function createlayer() {
local inputfile
if [[ -n "$*" ]]; then
inputfile=$1
shift
else
inputfile=myfile
dd if=/dev/urandom bs=1 count=$((RANDOM+1024)) of=$inputfile status=none
fi

# Tar it. Once we tar it, we have no further need for the original
tarfile=mylayer.tar
tar -cf $tarfile $inputfile
rm -f $inputfile

# Move tarfile into blob dir; name = digest
sha=$(sha256sum $tarfile | awk '{print $1}')
layerid+=($sha)
layersize+=($(stat -c %s $tarfile))

mv $tarfile oci/blobs/sha256/$sha
}

createlayer $(basename $0)
for i in $(seq 3); do
# Content for the layer
createlayer
done

#
# PASS 2: Create json files for each desired arch
#
cat >mlist.json <<EOF
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
EOF

mlistcomma=
for tuple in "${arches[@]}"; do
arch=$tuple
variant=
if [[ $arch =~ : ]]; then
variant=$(expr "$arch" : ".*:\(.*\)")
arch=${arch%%:*}
fi

# >>>>> config.json
config=config-$tuple.json
cat >$config <<EOF
{
"created": "$(date --utc +'%Y-%m-%dT%H:%M:%S.%NZ')",
"architecture": "$arch",
"os": "linux",
"config": {
"Cmd": ["/bin/sh"],
"Env": [ "PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin" ]
},
"rootfs": {
"type": "layers",
"diff_ids": [
EOF
comma=
for layer in "${layerid[@]}";do
test -n "$comma" && echo $comma >> $config
echo -n ' "sha256:'${layer}'"' >> $config
comma=","
done

cat >>$config <<EOF
]
}
}
EOF

confdigest=$(sha256sum $config | awk '{print $1}')
confsize=$(stat -c %s $config)
ln $config $ocidir/$confdigest

# >>>>> manifest.json references config.json
manifest=manifest-$tuple.json
cat >$manifest <<EOF
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:$confdigest",
"size": $confsize
},
"layers": [
EOF

comma=
for i in $(seq 0 $((${#layerid[*]} - 1))); do
test -n "$comma" && echo $comma >>$manifest
cat >>$manifest <<EOF
{
"mediaType": "application/vnd.oci.image.layer.v1.tar",
"digest": "sha256:${layerid[$i]}",
"size": ${layersize[$i]}
EOF
echo -n ' }' >>$manifest

comma=","
done
echo >>$manifest
echo " ]" >>$manifest
echo "}" >>$manifest

manifestdigest=$(sha256sum $manifest | awk '{print $1}')
manifestsize=$(stat -c %s $manifest)
ln $manifest $ocidir/$manifestdigest

# >>>>> top-level manifest list.json references this arch's manifest.json
test -n "$mlistcomma" && echo $comma >>mlist.json
cat >>mlist.json <<EOF
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:${manifestdigest}",
"size": ${manifestsize},
"platform": {
"architecture": "${arch}",
"os": "linux",
"variant": "${variant}"
}
EOF
echo -n ' }' >>mlist.json
mlistcomma=","
done

cat >>mlist.json <<EOF
]
}
EOF

# Finally, the starting point is index.json which points
# to the all-arch manifest list.
mlistdigest=$(sha256sum mlist.json | awk '{print $1}')
mlistsize=$(stat -c %s mlist.json)
ln mlist.json $ocidir/$mlistdigest

cat >oci/index.json <<EOF
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.index.v1+json",
"digest": "sha256:${mlistdigest}",
"size": ${mlistsize}
}
]
}
EOF

# Write the "this is an OCI layout directory" identifier.
echo '{"imageLayoutVersion":"1.0.0"}' > oci/oci-layout

####################################################################################

# Import the image from the OCI layout into buildah's normal storage.
# Complicated horrible loop because 'skopeo copy --all' barfs:
# containers-storage" does not support copying multiple images as a group
podman manifest create $IMAGE
for tuple in "${arches[@]}"; do
arch=$tuple
override_variant=
if [[ $arch =~ : ]]; then
v=$(expr "$arch" : ".*:\(.*\)")
override_variant="--override-variant=$v"
arch=${arch%%:*}
fi

tmpimage=localhost/foo$arch$variant:bar
podman rmi -f $tmpimage
skopeo copy --override-arch=$arch $override_variant oci:oci containers-storage:$tmpimage
podman manifest add $IMAGE containers-storage:$tmpimage
done

# Double-check that the image has no history, which is what we wanted to get
# out of all of this.
inspect_history=$(buildah inspect --format '{{.History}}' $IMAGE)
if [[ "$inspect_history" != '[]' ]]; then
echo "base image generated for test had history field that was not an empty slice:" >&2
echo "$inspect_history" >&2
exit 1
fi

# Worked. Clean up working directory
cd /
rm -rf $workdir

echo
echo "You may now run:"
echo " podman manifest push --all $IMAGE docker://$IMAGE"

0 comments on commit d30786a

Please sign in to comment.