diff --git a/pkg/v1/layout/puller.go b/pkg/v1/layout/puller.go index bf9eb07a0..e3279d1d4 100644 --- a/pkg/v1/layout/puller.go +++ b/pkg/v1/layout/puller.go @@ -48,7 +48,9 @@ func (p *puller) getDescriptor(ref name.Reference) (*v1.Descriptor, error) { if err != nil { return nil, err } - for _, manifest := range im.Manifests { + // Search for descriptors in reverse order to match most recent descriptors first + for i := len(im.Manifests) - 1; i >= 0; i-- { + manifest := im.Manifests[i] if rref, ok := manifest.Annotations[specsv1.AnnotationRefName]; ok { if ref.String() == rref { return &manifest, nil diff --git a/pkg/v1/layout/puller_test.go b/pkg/v1/layout/puller_test.go new file mode 100644 index 000000000..27f8e7cd8 --- /dev/null +++ b/pkg/v1/layout/puller_test.go @@ -0,0 +1,125 @@ +// Copyright 2019 The original author or authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package layout + +import ( + "context" + "path/filepath" + "testing" + + "github.com/google/go-containerregistry/pkg/name" +) + +var ( + testRefPath = filepath.Join("testdata", "test_with_ref") +) + +func TestPullerHeadWithDigest(t *testing.T) { + path, err := FromPath(testRefPath) + if err != nil { + t.Fatalf("FromPath() = %v", err) + } + digest := "sha256:32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720" + puller := NewPuller(path) + desc, err := puller.Head(context.TODO(), name.MustParseReference("reg.local/repo2@sha256:32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720")) + if err != nil { + t.Fatalf("puller.Head() = %v", err) + } + + if desc.Digest.String() != digest { + t.Fatalf("wrong descriptor returned, expected %s but got %s ", digest, desc.Digest) + } +} + +func TestPullerHeadWithTag(t *testing.T) { + path, err := FromPath(testRefPath) + if err != nil { + t.Fatalf("FromPath() = %v", err) + } + digest := "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" + puller := NewPuller(path) + desc, err := puller.Head(context.TODO(), name.MustParseReference("reg.local/repo4:latest")) + if err != nil { + t.Fatalf("puller.Head() = %v", err) + } + if desc.Digest.String() != digest { + t.Fatalf("wrong descriptor returned, expected %s but got %s ", digest, desc.Digest) + } +} + +func TestPullerArtifact(t *testing.T) { + path, err := FromPath(testRefPath) + if err != nil { + t.Fatalf("FromPath() = %v", err) + } + expectedDigest := "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" + + puller := NewPuller(path) + desc, err := puller.Artifact(context.TODO(), name.MustParseReference("reg.local/repo4:latest")) + if err != nil { + t.Fatalf("puller.Artifact() = %v", err) + } + + digest, err := desc.Digest() + if err != nil { + t.Fatalf("desc.Digest() = %v", err) + } + + mt, err := desc.MediaType() + if err != nil { + t.Fatalf("desc.MediaType() = %v", err) + } + + if digest.String() != expectedDigest { + t.Fatalf("wrong descriptor returned, expected %s but got %s ", expectedDigest, digest.String()) + } + + if !mt.IsIndex() { + t.Fatalf("expcted an image index but got %s", mt) + } +} + +func TestPullerLayer(t *testing.T) { + path, err := FromPath(testRefPath) + if err != nil { + t.Fatalf("FromPath() = %v", err) + } + + expectedDigest := "sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e" + puller := NewPuller(path) + + layer, err := puller.Layer(context.TODO(), name.MustParseReference("reg.local/repo4@sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e").(name.Digest)) + if err != nil { + t.Fatalf("puller.Layer() = %v", err) + } + + digest, err := layer.Digest() + if err != nil { + t.Fatalf("layer.Digest() = %v", err) + } + + if digest.String() != expectedDigest { + t.Fatalf("wrong descriptor returned, expected %s but got %s ", expectedDigest, digest.String()) + } + + size, err := layer.Size() + if err != nil { + t.Fatalf("layer.Size() = %v", err) + } + + if size != 320 { + t.Fatalf("wrong size returned, expected 320 but got %d", size) + } +} diff --git a/pkg/v1/layout/pusher.go b/pkg/v1/layout/pusher.go index a12481314..f159a83b7 100644 --- a/pkg/v1/layout/pusher.go +++ b/pkg/v1/layout/pusher.go @@ -253,8 +253,12 @@ func (lp *pusher) Push(ctx context.Context, ref name.Reference, t partial.WithRa if err != nil { return err } + repo := ref.Context().String() + if tag, ok := ref.(name.Tag); ok { + repo = fmt.Sprintf("%s:%s", repo, tag.TagStr()) + } desc.Annotations = map[string]string{ - specsv1.AnnotationRefName: ref.String(), + specsv1.AnnotationRefName: repo, } return lp.path.AppendDescriptor(*desc) } diff --git a/pkg/v1/layout/pusher_test.go b/pkg/v1/layout/pusher_test.go index 6fc91bee3..5dd8b2660 100644 --- a/pkg/v1/layout/pusher_test.go +++ b/pkg/v1/layout/pusher_test.go @@ -148,13 +148,13 @@ func TestCanPushImageIndex(t *testing.T) { path := mustOCILayout(t) pusher := NewPusher(path) - ref := name.MustParseReference("local/index:latest") + ref := name.MustParseReference("local.repo/index:latest") err = pusher.Push(context.TODO(), ref, img) if err != nil { t.Errorf("pusher.Push() = %v", err) } - mustHaveManifest(t, path, "local/index:latest") + mustHaveManifest(t, path, "local.repo/index:latest") mustHaveBlobs(t, path, enumerateImageBlobs(t, img)) } @@ -170,12 +170,33 @@ func TestCanPushImage(t *testing.T) { path := mustOCILayout(t) pusher := NewPusher(path) - ref := name.MustParseReference("local/index:latest") + ref := name.MustParseReference("local.repo/index:latest") err = pusher.Push(context.TODO(), ref, img) if err != nil { t.Errorf("pusher.Push() = %v", err) } - mustHaveManifest(t, path, "local/index:latest") + mustHaveManifest(t, path, "local.repo/index:latest") + mustHaveBlobs(t, path, enumerateImageBlobs(t, img)) +} + +func TestCanPushImageWithLatestTag(t *testing.T) { + lp, err := FromPath(testPath) + if err != nil { + t.Fatalf("FromPath() = %v", err) + } + img, err := lp.Image(manifestDigest) + if err != nil { + t.Fatalf("Image() = %v", err) + } + + path := mustOCILayout(t) + pusher := NewPusher(path) + + err = pusher.Push(context.TODO(), name.MustParseReference("reg.local.repo/index"), img) + if err != nil { + t.Errorf("pusher.Push() = %v", err) + } + mustHaveManifest(t, path, "reg.local.repo/index:latest") mustHaveBlobs(t, path, enumerateImageBlobs(t, img)) } diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5 b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5 new file mode 100644 index 000000000..1597d0721 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5 @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 423, + "digest": "sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650", + "annotations": { + "org.opencontainers.image.ref.name": "1" + } + } + ] +} diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb new file mode 100644 index 000000000..e6587e23e --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 423, + "digest": "sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650", + "annotations": { + "org.opencontainers.image.ref.name": "4" + } + } + ] +} diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/321460fa87fd42433950b42d04b7aff249f4ed960d43404a9f699886906cc9d3 b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/321460fa87fd42433950b42d04b7aff249f4ed960d43404a9f699886906cc9d3 new file mode 100644 index 000000000..096f21fb7 Binary files /dev/null and b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/321460fa87fd42433950b42d04b7aff249f4ed960d43404a9f699886906cc9d3 differ diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720 b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720 new file mode 100644 index 000000000..48609c6c6 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","size":330,"digest":"sha256:930705ce23e3b6ed4c08746b6fe880089c864fbaf62482702ae3fdd66b8c7fe9"},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","size":165,"digest":"sha256:321460fa87fd42433950b42d04b7aff249f4ed960d43404a9f699886906cc9d3"}]} \ No newline at end of file diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e new file mode 100644 index 000000000..4228c8902 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e @@ -0,0 +1 @@ +{"architecture": "amd64", "author": "Bazel", "config": {}, "created": "1970-01-01T00:00:00Z", "history": [{"author": "Bazel", "created": "1970-01-01T00:00:00Z", "created_by": "bazel build ..."}], "os": "linux", "rootfs": {"diff_ids": ["sha256:8897395fd26dc44ad0e2a834335b33198cb41ac4d98dfddf58eced3853fa7b17"], "type": "layers"}} diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/930705ce23e3b6ed4c08746b6fe880089c864fbaf62482702ae3fdd66b8c7fe9 b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/930705ce23e3b6ed4c08746b6fe880089c864fbaf62482702ae3fdd66b8c7fe9 new file mode 100644 index 000000000..425c2d0b2 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/930705ce23e3b6ed4c08746b6fe880089c864fbaf62482702ae3fdd66b8c7fe9 @@ -0,0 +1 @@ +{"architecture": "amd64", "author": "Bazel", "config": {}, "created": "1970-01-01T00:00:00Z", "history": [{"author": "Bazel", "created": "1970-01-01T00:00:00Z", "created_by": "bazel build ..."}], "os": "linux", "rootfs": {"diff_ids": ["sha256:3610aa5267a210147ba6ca02cdd87610dfc08522de9c5f5015edd8ee14853fd8"], "type": "layers"}} diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b new file mode 100644 index 000000000..05c63217b Binary files /dev/null and b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b differ diff --git a/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650 b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650 new file mode 100644 index 000000000..21dc412c3 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","size":330,"digest":"sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e"},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","size":167,"digest":"sha256:dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b"}]} \ No newline at end of file diff --git a/pkg/v1/layout/testdata/test_with_ref/index.json b/pkg/v1/layout/testdata/test_with_ref/index.json new file mode 100644 index 000000000..2a7261ca2 --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/index.json @@ -0,0 +1,45 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 423, + "digest": "sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650", + "annotations": { + "org.opencontainers.image.ref.name": "reg.local/repo1@sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650" + } + }, + { + "mediaType": "application/vnd.oci.descriptor.v1+json", + "size": 423, + "digest": "sha256:32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720", + "annotations": { + "org.opencontainers.image.ref.name": "reg.local/repo2@sha256:32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720" + } + }, + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": 314, + "digest": "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5", + "annotations": { + "org.opencontainers.image.ref.name": "reg.local/repo3@sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "size": 314, + "digest": "sha256:2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb", + "annotations": { + "org.opencontainers.image.ref.name": "reg.local/repo4@sha256:2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "size": 314, + "digest": "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5", + "annotations": { + "org.opencontainers.image.ref.name": "reg.local/repo4:latest" + } + } + ] +} diff --git a/pkg/v1/layout/testdata/test_with_ref/oci-layout b/pkg/v1/layout/testdata/test_with_ref/oci-layout new file mode 100644 index 000000000..10ff2f3ce --- /dev/null +++ b/pkg/v1/layout/testdata/test_with_ref/oci-layout @@ -0,0 +1,3 @@ +{ + "imageLayoutVersion": "1.0.0" +}