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>master
							parent
							
								
									1cb4180b1a
								
							
						
					
					
						commit
						9ebf151ac2
					
				| 
						 | 
					@ -196,3 +196,37 @@ func (ts *tagStore) Lookup(ctx context.Context, desc distribution.Descriptor) ([
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tags, nil
 | 
						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 (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/distribution"
 | 
						"github.com/docker/distribution"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/manifest"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/manifest/schema2"
 | 
				
			||||||
	"github.com/docker/distribution/reference"
 | 
						"github.com/docker/distribution/reference"
 | 
				
			||||||
	"github.com/docker/distribution/registry/storage/driver/inmemory"
 | 
						"github.com/docker/distribution/registry/storage/driver/inmemory"
 | 
				
			||||||
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type tagsTestEnv struct {
 | 
					type tagsTestEnv struct {
 | 
				
			||||||
	ts  distribution.TagService
 | 
						ts  distribution.TagService
 | 
				
			||||||
 | 
						bs  distribution.BlobStore
 | 
				
			||||||
 | 
						ms  distribution.ManifestService
 | 
				
			||||||
 | 
						gbs distribution.BlobStatter
 | 
				
			||||||
	ctx context.Context
 | 
						ctx context.Context
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,10 +34,17 @@ func testTagStore(t *testing.T) *tagsTestEnv {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ms, err := repo.Manifests(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &tagsTestEnv{
 | 
						return &tagsTestEnv{
 | 
				
			||||||
		ctx: ctx,
 | 
							ctx: ctx,
 | 
				
			||||||
		ts:  repo.Tags(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 {
 | 
						if len(tags) != 2 {
 | 
				
			||||||
		t.Errorf("Lookup of descB returned %d tags, expected 2", len(tags))
 | 
							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 (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TagService provides access to information about tagged objects.
 | 
					// 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 returns the set of tags referencing the given digest.
 | 
				
			||||||
	Lookup(ctx context.Context, digest Descriptor) ([]string, error)
 | 
						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 New Issue