Skip to content

Commit

Permalink
image/save: Fix missing layers in manifest
Browse files Browse the repository at this point in the history
The new OCI-compatible archive export relies on the Descriptors returned
by the layer (`distribution.Describable` interface implementation).

The issue with that is that the `roLayer` and the `referencedCacheLayer`
types don't implement this interface. Implementing that interface for
them based on their `descriptor` doesn't work though, because that
descriptor is empty.

To workaround this issue, just create a new descriptor if the one
provided by the layer is empty.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
  • Loading branch information
vvoland committed Jan 12, 2024
1 parent 92cc0d6 commit 2c45df2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
8 changes: 8 additions & 0 deletions image/tarexport/save.go
Expand Up @@ -523,5 +523,13 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
if fs, ok := l.(distribution.Describable); ok {
src = fs.Descriptor()
}

if src.Digest == "" {
src = distribution.Descriptor{
MediaType: ocispec.MediaTypeImageLayer,
Digest: lDgst,
Size: l.Size(),
}
}
return src, nil
}
36 changes: 36 additions & 0 deletions integration/image/save_test.go
Expand Up @@ -15,11 +15,13 @@ import (

"github.com/cpuguy83/tar2go"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration/internal/build"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/testutil/fakecontext"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"
is "gotest.tools/v3/assert/cmp"
Expand Down Expand Up @@ -85,6 +87,40 @@ func TestSaveCheckTimes(t *testing.T) {
}
}

// Regression test for https://github.com/moby/moby/issues/47065
func TestSaveCheckManifestLayers(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.44"), "OCI layout support was introduced in v25")
t.Parallel()

ctx := setupTest(t)
client := testEnv.APIClient()

const repoName = "busybox:latest"
img, _, err := client.ImageInspectWithRaw(ctx, repoName)
assert.NilError(t, err)

rdr, err := client.ImageSave(ctx, []string{repoName})
assert.NilError(t, err)

tarfs := tarIndexFS(t, rdr)

indexData, err := fs.ReadFile(tarfs, "index.json")
assert.NilError(t, err)

var index ocispec.Index
assert.NilError(t, json.Unmarshal(indexData, &index))

assert.Assert(t, is.Len(index.Manifests, 1))

manifestData, err := fs.ReadFile(tarfs, "blobs/sha256/"+index.Manifests[0].Digest.Encoded())
assert.NilError(t, err)

var manifest ocispec.Manifest
assert.NilError(t, json.Unmarshal(manifestData, &manifest))

assert.Check(t, is.Len(manifest.Layers, len(img.RootFS.Layers)))
}

func TestSaveRepoWithMultipleImages(t *testing.T) {
ctx := setupTest(t)
client := testEnv.APIClient()
Expand Down

0 comments on commit 2c45df2

Please sign in to comment.