From 43735478577eff35687434d5134bc5d536e6647e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 13 Apr 2023 12:16:27 +0200 Subject: [PATCH 1/4] Add testenv.UsingSnapshotter utility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow skipping integration tests that don't apply to the containerd snapshotter. Signed-off-by: Sebastiaan van Stijn Signed-off-by: Paweł Gronowski --- testutil/environment/environment.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/testutil/environment/environment.go b/testutil/environment/environment.go index 7007008fec..fda7cf1265 100644 --- a/testutil/environment/environment.go +++ b/testutil/environment/environment.go @@ -193,6 +193,13 @@ func (e *Execution) IsUserNamespaceInKernel() bool { return true } +// UsingSnapshotter returns whether containerd snapshotters are used for the +// tests by checking if the "TEST_INTEGRATION_USE_SNAPSHOTTER" is set to a +// non-empty value. +func (e *Execution) UsingSnapshotter() bool { + return os.Getenv("TEST_INTEGRATION_USE_SNAPSHOTTER") != "" +} + // HasExistingImage checks whether there is an image with the given reference. // Note that this is done by filtering and then checking whether there were any // results -- so ambiguous references might result in false-positives. From 3a31f81838ba80d533e6156c7e571a56a575e4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Mon, 22 May 2023 11:47:28 +0200 Subject: [PATCH 2/4] hack/ensure-emptyfs: Create dangling image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Gronowski --- hack/make/.ensure-emptyfs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/hack/make/.ensure-emptyfs b/hack/make/.ensure-emptyfs index db15aabd53..db14275850 100644 --- a/hack/make/.ensure-emptyfs +++ b/hack/make/.ensure-emptyfs @@ -1,7 +1,12 @@ #!/usr/bin/env bash set -e -if ! docker image inspect emptyfs > /dev/null; then +function imageNotPresent { + local img="$1" + ! docker image inspect "$img" > /dev/null 2> /dev/null +} + +if imageNotPresent "emptyfs"; then # build a "docker save" tarball for "emptyfs" # see https://github.com/docker/docker/pull/5262 # and also https://github.com/docker/docker/issues/4242 @@ -24,3 +29,27 @@ if ! docker image inspect emptyfs > /dev/null; then ) rm -rf "$dir" fi + +# without c8d image store, image id is the config's id +dangling_cfg=0df1207206e5288f4a989a2f13d1f5b3c4e70467702c1d5d21dfc9f002b7bd43 +# with c8d image store, image id is the id of manifest/manifest list. +dangling_mfst=16d365089e5c10e1673ee82ab5bba38ade9b763296ad918bd24b42a1156c5456 +if imageNotPresent "$dangling_cfg" && imageNotPresent "$dangling_mfst"; then + dir="$DEST/dangling" + mkdir -p "$dir" + ( + cd "$dir" + printf '{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"sha256:16d365089e5c10e1673ee82ab5bba38ade9b763296ad918bd24b42a1156c5456","size":264,"annotations":{"org.opencontainers.image.created":"2023-05-19T08:00:44Z"},"platform":{"architecture":"amd64","os":"linux"}}]}' > index.json + printf '[{"Config":"blobs/sha256/0df1207206e5288f4a989a2f13d1f5b3c4e70467702c1d5d21dfc9f002b7bd43","RepoTags":null,"Layers":null}]' > manifest.json + mkdir -p blobs/sha256 + printf '{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:0df1207206e5288f4a989a2f13d1f5b3c4e70467702c1d5d21dfc9f002b7bd43","size":390},"layers":[]}' > blobs/sha256/$dangling_mfst + printf '{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","Labels":{"org.mobyproject.test.specialimage":"1"},"OnBuild":null},"created":null,"history":[{"created_by":"LABEL org.mobyproject.test.specialimage=1","comment":"buildkit.dockerfile.v0","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":null}}' > blobs/sha256/$dangling_cfg + tar -cf layer.tar --files-from /dev/null + ) + ( + [ -n "$TESTDEBUG" ] && set -x + tar -cC "$dir" . | docker load + ) + rm -rf "$dir" + +fi From a93aadc2e60ee8b824a26391ff82c35cde2b0cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Mon, 22 May 2023 11:53:14 +0200 Subject: [PATCH 3/4] hack: Rename .ensure-emptyfs to .build-empty-images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Gronowski --- Dockerfile.e2e | 4 ++-- hack/make/{.ensure-emptyfs => .build-empty-images} | 0 hack/make/.integration-daemon-setup | 2 +- hack/test/e2e-run.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename hack/make/{.ensure-emptyfs => .build-empty-images} (100%) diff --git a/Dockerfile.e2e b/Dockerfile.e2e index 9dc49e845a..2b41a7e65e 100644 --- a/Dockerfile.e2e +++ b/Dockerfile.e2e @@ -71,8 +71,8 @@ RUN apk --no-cache add \ tar \ xz -COPY hack/test/e2e-run.sh /scripts/run.sh -COPY hack/make/.ensure-emptyfs /scripts/ensure-emptyfs.sh +COPY hack/test/e2e-run.sh /scripts/run.sh +COPY hack/make/.build-empty-images /scripts/build-empty-images.sh COPY integration/testdata /tests/integration/testdata COPY integration/build/testdata /tests/integration/build/testdata diff --git a/hack/make/.ensure-emptyfs b/hack/make/.build-empty-images similarity index 100% rename from hack/make/.ensure-emptyfs rename to hack/make/.build-empty-images diff --git a/hack/make/.integration-daemon-setup b/hack/make/.integration-daemon-setup index c130e23560..4bcc816c2c 100644 --- a/hack/make/.integration-daemon-setup +++ b/hack/make/.integration-daemon-setup @@ -3,5 +3,5 @@ set -e source "$MAKEDIR/.detect-daemon-osarch" if [ "$DOCKER_ENGINE_GOOS" != "windows" ]; then - bundle .ensure-emptyfs + bundle .build-empty-images fi diff --git a/hack/test/e2e-run.sh b/hack/test/e2e-run.sh index 57127c0d18..545504fa0e 100755 --- a/hack/test/e2e-run.sh +++ b/hack/test/e2e-run.sh @@ -81,5 +81,5 @@ set_platform_timeout() { fi } -sh /scripts/ensure-emptyfs.sh +sh /scripts/build-empty-images.sh run_test_integration From 6506579e18f7880b2f3db1966fa728f91a102514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Mon, 22 May 2023 11:48:50 +0200 Subject: [PATCH 4/4] integration: Add TestImageInspectEmptyTagsAndDigests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Gronowski --- integration/image/inspect_test.go | 41 ++++++++++++++++++++++++++ testutil/environment/clean.go | 3 ++ testutil/environment/protect.go | 1 + testutil/environment/special_images.go | 7 +++++ 4 files changed, 52 insertions(+) create mode 100644 integration/image/inspect_test.go create mode 100644 testutil/environment/special_images.go diff --git a/integration/image/inspect_test.go b/integration/image/inspect_test.go new file mode 100644 index 0000000000..519e824c47 --- /dev/null +++ b/integration/image/inspect_test.go @@ -0,0 +1,41 @@ +package image + +import ( + "context" + "encoding/json" + "testing" + + "github.com/docker/docker/testutil/environment" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" + "gotest.tools/v3/skip" +) + +// Regression test for: https://github.com/moby/moby/issues/45556 +func TestImageInspectEmptyTagsAndDigests(t *testing.T) { + skip.If(t, testEnv.OSType == "windows", "build-empty-images is not called on Windows") + defer setupTest(t)() + + client := testEnv.APIClient() + ctx := context.Background() + + danglingId := environment.DanglingImageIdGraphDriver + if testEnv.UsingSnapshotter() { + danglingId = environment.DanglingImageIdSnapshotter + } + + inspect, raw, err := client.ImageInspectWithRaw(ctx, danglingId) + assert.NilError(t, err) + + // Must be a zero length array, not null. + assert.Check(t, is.Len(inspect.RepoTags, 0)) + assert.Check(t, is.Len(inspect.RepoDigests, 0)) + + var rawJson map[string]interface{} + err = json.Unmarshal(raw, &rawJson) + assert.NilError(t, err) + + // Check if the raw json is also an array, not null. + assert.Check(t, is.Len(rawJson["RepoTags"], 0)) + assert.Check(t, is.Len(rawJson["RepoDigests"], 0)) +} diff --git a/testutil/environment/clean.go b/testutil/environment/clean.go index 29448bb7b5..e837427655 100644 --- a/testutil/environment/clean.go +++ b/testutil/environment/clean.go @@ -98,6 +98,9 @@ func deleteAllImages(t testing.TB, apiclient client.ImageAPIClient, protectedIma ctx := context.Background() for _, image := range images { tags := tagsFromImageSummary(image) + if _, ok := protectedImages[image.ID]; ok { + continue + } if len(tags) == 0 { removeImage(ctx, t, apiclient, image.ID) continue diff --git a/testutil/environment/protect.go b/testutil/environment/protect.go index 2a0d5281b6..a84dccc9a5 100644 --- a/testutil/environment/protect.go +++ b/testutil/environment/protect.go @@ -95,6 +95,7 @@ func ProtectImages(t testing.TB, testEnv *Execution) { images = append(images, frozenImages...) } testEnv.ProtectImage(t, images...) + testEnv.ProtectImage(t, DanglingImageIdGraphDriver, DanglingImageIdSnapshotter) } func getExistingImages(t testing.TB, testEnv *Execution) []string { diff --git a/testutil/environment/special_images.go b/testutil/environment/special_images.go new file mode 100644 index 0000000000..b486e0498c --- /dev/null +++ b/testutil/environment/special_images.go @@ -0,0 +1,7 @@ +package environment + +// Graph driver image store identifies images by the ID of their config. +const DanglingImageIdGraphDriver = "sha256:0df1207206e5288f4a989a2f13d1f5b3c4e70467702c1d5d21dfc9f002b7bd43" + +// The containerd image store identifies images by the ID of their manifest/manifest list. +const DanglingImageIdSnapshotter = "sha256:16d365089e5c10e1673ee82ab5bba38ade9b763296ad918bd24b42a1156c5456"