API to retrive tag's digests
Add an interface alongside TagStore that provides API to retreive digests of all manifests that a tag historically pointed to. It also includes currently linked tag. Signed-off-by: Manish Tomar <manish.tomar@docker.com>
This commit is contained in:
parent
1cb4180b1a
commit
9ebf151ac2
3 changed files with 128 additions and 1 deletions
|
@ -196,3 +196,37 @@ func (ts *tagStore) Lookup(ctx context.Context, desc distribution.Descriptor) ([
|
|||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func (ts *tagStore) Indexes(ctx context.Context, tag string) ([]digest.Digest, error) {
|
||||
var tagLinkPath = func(name string, dgst digest.Digest) (string, error) {
|
||||
return pathFor(manifestTagIndexEntryLinkPathSpec{
|
||||
name: name,
|
||||
tag: tag,
|
||||
revision: dgst,
|
||||
})
|
||||
}
|
||||
lbs := &linkedBlobStore{
|
||||
blobStore: ts.blobStore,
|
||||
blobAccessController: &linkedBlobStatter{
|
||||
blobStore: ts.blobStore,
|
||||
repository: ts.repository,
|
||||
linkPathFns: []linkPathFunc{manifestRevisionLinkPath},
|
||||
},
|
||||
repository: ts.repository,
|
||||
ctx: ctx,
|
||||
linkPathFns: []linkPathFunc{tagLinkPath},
|
||||
linkDirectoryPathSpec: manifestTagIndexPathSpec{
|
||||
name: ts.repository.Named().Name(),
|
||||
tag: tag,
|
||||
},
|
||||
}
|
||||
var dgsts []digest.Digest
|
||||
err := lbs.Enumerate(ctx, func(dgst digest.Digest) error {
|
||||
dgsts = append(dgsts, dgst)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dgsts, nil
|
||||
}
|
||||
|
|
|
@ -2,15 +2,22 @@ package storage
|
|||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
type tagsTestEnv struct {
|
||||
ts distribution.TagService
|
||||
bs distribution.BlobStore
|
||||
ms distribution.ManifestService
|
||||
gbs distribution.BlobStatter
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
|
@ -27,10 +34,17 @@ func testTagStore(t *testing.T) *tagsTestEnv {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ms, err := repo.Manifests(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &tagsTestEnv{
|
||||
ctx: ctx,
|
||||
ts: repo.Tags(ctx),
|
||||
bs: repo.Blobs(ctx),
|
||||
gbs: reg.BlobStatter(),
|
||||
ms: ms,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,5 +219,75 @@ func TestTagLookup(t *testing.T) {
|
|||
if len(tags) != 2 {
|
||||
t.Errorf("Lookup of descB returned %d tags, expected 2", len(tags))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestTagIndexes(t *testing.T) {
|
||||
env := testTagStore(t)
|
||||
tagStore := env.ts
|
||||
ctx := env.ctx
|
||||
|
||||
indexes, ok := tagStore.(distribution.TagIndexes)
|
||||
if !ok {
|
||||
t.Fatal("tagStore does not implement TagIndexes interface")
|
||||
}
|
||||
|
||||
conf, err := env.bs.Put(ctx, "application/octet-stream", []byte{0})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dgstsSet := make(map[digest.Digest]bool)
|
||||
for i := 0; i < 3; i++ {
|
||||
layer, err := env.bs.Put(ctx, "application/octet-stream", []byte{byte(i + 1)})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m := schema2.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 2,
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
},
|
||||
Config: distribution.Descriptor{
|
||||
Digest: conf.Digest,
|
||||
Size: 1,
|
||||
MediaType: schema2.MediaTypeImageConfig,
|
||||
},
|
||||
Layers: []distribution.Descriptor{
|
||||
{
|
||||
Digest: layer.Digest,
|
||||
Size: 1,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
},
|
||||
}
|
||||
dm, err := schema2.FromStruct(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dgst, err := env.ms.Put(ctx, dm)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
desc, err := env.gbs.Stat(ctx, dgst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = tagStore.Tag(ctx, "t", desc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dgstsSet[dgst] = true
|
||||
}
|
||||
|
||||
gotDgsts, err := indexes.Indexes(ctx, "t")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gotDgstsSet := make(map[digest.Digest]bool)
|
||||
for _, dgst := range gotDgsts {
|
||||
gotDgstsSet[dgst] = true
|
||||
}
|
||||
if !reflect.DeepEqual(dgstsSet, gotDgstsSet) {
|
||||
t.Fatalf("Expected digests: %v but got digests: %v", dgstsSet, gotDgstsSet)
|
||||
}
|
||||
}
|
||||
|
|
9
tags.go
9
tags.go
|
@ -2,6 +2,8 @@ package distribution
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
// TagService provides access to information about tagged objects.
|
||||
|
@ -25,3 +27,10 @@ type TagService interface {
|
|||
// Lookup returns the set of tags referencing the given digest.
|
||||
Lookup(ctx context.Context, digest Descriptor) ([]string, error)
|
||||
}
|
||||
|
||||
// TagIndexes proves method to retreive all the digests that a tag historically pointed to
|
||||
type TagIndexes interface {
|
||||
// Indexes returns set of digests that this tag historically pointed to. This also includes
|
||||
// currently linked digest. There is no ordering guaranteed
|
||||
Indexes(ctx context.Context, tag string) ([]digest.Digest, error)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue