forked from TrueCloudLab/distribution
Use reference package internally
Most places in the registry were using string types to refer to repository names. This changes them to use reference.Named, so the type system can enforce validation of the naming rules. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
caa2001e1f
commit
4441333912
35 changed files with 323 additions and 246 deletions
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/libtrust"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
|
@ -39,10 +40,8 @@ type configManifestBuilder struct {
|
|||
// configJSON is configuration supplied when the ManifestBuilder was
|
||||
// created.
|
||||
configJSON []byte
|
||||
// name is the name provided to NewConfigManifestBuilder
|
||||
name string
|
||||
// tag is the tag provided to NewConfigManifestBuilder
|
||||
tag string
|
||||
// ref contains the name and optional tag provided to NewConfigManifestBuilder.
|
||||
ref reference.Named
|
||||
// descriptors is the set of descriptors referencing the layers.
|
||||
descriptors []distribution.Descriptor
|
||||
// emptyTarDigest is set to a valid digest if an empty tar has been
|
||||
|
@ -54,13 +53,12 @@ type configManifestBuilder struct {
|
|||
// schema version from an image configuration and a set of descriptors.
|
||||
// It takes a BlobService so that it can add an empty tar to the blob store
|
||||
// if the resulting manifest needs empty layers.
|
||||
func NewConfigManifestBuilder(bs distribution.BlobService, pk libtrust.PrivateKey, name, tag string, configJSON []byte) distribution.ManifestBuilder {
|
||||
func NewConfigManifestBuilder(bs distribution.BlobService, pk libtrust.PrivateKey, ref reference.Named, configJSON []byte) distribution.ManifestBuilder {
|
||||
return &configManifestBuilder{
|
||||
bs: bs,
|
||||
pk: pk,
|
||||
configJSON: configJSON,
|
||||
name: name,
|
||||
tag: tag,
|
||||
ref: ref,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,12 +188,17 @@ func (mb *configManifestBuilder) Build(ctx context.Context) (m distribution.Mani
|
|||
|
||||
history[0].V1Compatibility = string(transformedConfig)
|
||||
|
||||
tag := ""
|
||||
if tagged, isTagged := mb.ref.(reference.Tagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
|
||||
mfst := Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: mb.name,
|
||||
Tag: mb.tag,
|
||||
Name: mb.ref.Name(),
|
||||
Tag: tag,
|
||||
Architecture: img.Architecture,
|
||||
FSLayers: fsLayerList,
|
||||
History: history,
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
|
@ -194,7 +195,13 @@ func TestConfigBuilder(t *testing.T) {
|
|||
}
|
||||
|
||||
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
|
||||
builder := NewConfigManifestBuilder(bs, pk, "testrepo", "testtag", []byte(imgJSON))
|
||||
|
||||
ref, err := reference.ParseNamed("testrepo:testtag")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
||||
builder := NewConfigManifestBuilder(bs, pk, ref, []byte(imgJSON))
|
||||
|
||||
for _, d := range descriptors {
|
||||
if err := builder.AppendReference(d); err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
|
@ -20,13 +21,18 @@ type referenceManifestBuilder struct {
|
|||
|
||||
// NewReferenceManifestBuilder is used to build new manifests for the current
|
||||
// schema version using schema1 dependencies.
|
||||
func NewReferenceManifestBuilder(pk libtrust.PrivateKey, name, tag, architecture string) distribution.ManifestBuilder {
|
||||
func NewReferenceManifestBuilder(pk libtrust.PrivateKey, ref reference.Named, architecture string) distribution.ManifestBuilder {
|
||||
tag := ""
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
|
||||
return &referenceManifestBuilder{
|
||||
Manifest: Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: name,
|
||||
Name: ref.Name(),
|
||||
Tag: tag,
|
||||
Architecture: architecture,
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
|
@ -54,7 +55,16 @@ func TestReferenceBuilder(t *testing.T) {
|
|||
|
||||
handCrafted := makeSignedManifest(t, pk, []Reference{r1, r2})
|
||||
|
||||
b := NewReferenceManifestBuilder(pk, handCrafted.Manifest.Name, handCrafted.Manifest.Tag, handCrafted.Manifest.Architecture)
|
||||
ref, err := reference.ParseNamed(handCrafted.Manifest.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
ref, err = reference.WithTag(ref, handCrafted.Manifest.Tag)
|
||||
if err != nil {
|
||||
t.Fatalf("could not add tag: %v", err)
|
||||
}
|
||||
|
||||
b := NewReferenceManifestBuilder(pk, ref, handCrafted.Manifest.Architecture)
|
||||
_, err = b.Build(context.Background())
|
||||
if err == nil {
|
||||
t.Fatal("Expected error building zero length manifest")
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/uuid"
|
||||
)
|
||||
|
||||
|
@ -22,8 +23,8 @@ var _ Listener = &bridge{}
|
|||
|
||||
// URLBuilder defines a subset of url builder to be used by the event listener.
|
||||
type URLBuilder interface {
|
||||
BuildManifestURL(name, tag string) (string, error)
|
||||
BuildBlobURL(name string, dgst digest.Digest) (string, error)
|
||||
BuildManifestURL(name reference.Named, tag string) (string, error)
|
||||
BuildBlobURL(name reference.Named, dgst digest.Digest) (string, error)
|
||||
}
|
||||
|
||||
// NewBridge returns a notification listener that writes records to sink,
|
||||
|
@ -52,40 +53,40 @@ func NewRequestRecord(id string, r *http.Request) RequestRecord {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestPushed(repo string, sm distribution.Manifest) error {
|
||||
func (b *bridge) ManifestPushed(repo reference.Named, sm distribution.Manifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionPush, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestPulled(repo string, sm distribution.Manifest) error {
|
||||
func (b *bridge) ManifestPulled(repo reference.Named, sm distribution.Manifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionPull, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestDeleted(repo string, sm distribution.Manifest) error {
|
||||
func (b *bridge) ManifestDeleted(repo reference.Named, sm distribution.Manifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionDelete, repo, sm)
|
||||
}
|
||||
|
||||
func (b *bridge) BlobPushed(repo string, desc distribution.Descriptor) error {
|
||||
func (b *bridge) BlobPushed(repo reference.Named, desc distribution.Descriptor) error {
|
||||
return b.createBlobEventAndWrite(EventActionPush, repo, desc)
|
||||
}
|
||||
|
||||
func (b *bridge) BlobPulled(repo string, desc distribution.Descriptor) error {
|
||||
func (b *bridge) BlobPulled(repo reference.Named, desc distribution.Descriptor) error {
|
||||
return b.createBlobEventAndWrite(EventActionPull, repo, desc)
|
||||
}
|
||||
|
||||
func (b *bridge) BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error {
|
||||
func (b *bridge) BlobMounted(repo reference.Named, desc distribution.Descriptor, fromRepo reference.Named) error {
|
||||
event, err := b.createBlobEvent(EventActionMount, repo, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event.Target.FromRepository = fromRepo
|
||||
event.Target.FromRepository = fromRepo.Name()
|
||||
return b.sink.Write(*event)
|
||||
}
|
||||
|
||||
func (b *bridge) BlobDeleted(repo string, desc distribution.Descriptor) error {
|
||||
func (b *bridge) BlobDeleted(repo reference.Named, desc distribution.Descriptor) error {
|
||||
return b.createBlobEventAndWrite(EventActionDelete, repo, desc)
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEventAndWrite(action string, repo string, sm distribution.Manifest) error {
|
||||
func (b *bridge) createManifestEventAndWrite(action string, repo reference.Named, sm distribution.Manifest) error {
|
||||
manifestEvent, err := b.createManifestEvent(action, repo, sm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -94,9 +95,9 @@ func (b *bridge) createManifestEventAndWrite(action string, repo string, sm dist
|
|||
return b.sink.Write(*manifestEvent)
|
||||
}
|
||||
|
||||
func (b *bridge) createManifestEvent(action string, repo string, sm distribution.Manifest) (*Event, error) {
|
||||
func (b *bridge) createManifestEvent(action string, repo reference.Named, sm distribution.Manifest) (*Event, error) {
|
||||
event := b.createEvent(action)
|
||||
event.Target.Repository = repo
|
||||
event.Target.Repository = repo.Name()
|
||||
|
||||
mt, p, err := sm.Payload()
|
||||
if err != nil {
|
||||
|
@ -122,7 +123,7 @@ func (b *bridge) createManifestEvent(action string, repo string, sm distribution
|
|||
return event, nil
|
||||
}
|
||||
|
||||
func (b *bridge) createBlobEventAndWrite(action string, repo string, desc distribution.Descriptor) error {
|
||||
func (b *bridge) createBlobEventAndWrite(action string, repo reference.Named, desc distribution.Descriptor) error {
|
||||
event, err := b.createBlobEvent(action, repo, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -131,11 +132,11 @@ func (b *bridge) createBlobEventAndWrite(action string, repo string, desc distri
|
|||
return b.sink.Write(*event)
|
||||
}
|
||||
|
||||
func (b *bridge) createBlobEvent(action string, repo string, desc distribution.Descriptor) (*Event, error) {
|
||||
func (b *bridge) createBlobEvent(action string, repo reference.Named, desc distribution.Descriptor) (*Event, error) {
|
||||
event := b.createEvent(action)
|
||||
event.Target.Descriptor = desc
|
||||
event.Target.Length = desc.Size
|
||||
event.Target.Repository = repo
|
||||
event.Target.Repository = repo.Name()
|
||||
|
||||
var err error
|
||||
event.Target.URL, err = b.ub.BuildBlobURL(repo, desc.Digest)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/uuid"
|
||||
"github.com/docker/libtrust"
|
||||
|
@ -35,14 +36,14 @@ var (
|
|||
)
|
||||
|
||||
func TestEventBridgeManifestPulled(t *testing.T) {
|
||||
|
||||
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
||||
checkCommonManifest(t, EventActionPull, events...)
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
if err := l.ManifestPulled(repo, sm); err != nil {
|
||||
repoRef, _ := reference.ParseNamed(repo)
|
||||
if err := l.ManifestPulled(repoRef, sm); err != nil {
|
||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +55,8 @@ func TestEventBridgeManifestPushed(t *testing.T) {
|
|||
return nil
|
||||
}))
|
||||
|
||||
if err := l.ManifestPushed(repo, sm); err != nil {
|
||||
repoRef, _ := reference.ParseNamed(repo)
|
||||
if err := l.ManifestPushed(repoRef, sm); err != nil {
|
||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +68,8 @@ func TestEventBridgeManifestDeleted(t *testing.T) {
|
|||
return nil
|
||||
}))
|
||||
|
||||
if err := l.ManifestDeleted(repo, sm); err != nil {
|
||||
repoRef, _ := reference.ParseNamed(repo)
|
||||
if err := l.ManifestDeleted(repoRef, sm); err != nil {
|
||||
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +99,8 @@ func checkCommonManifest(t *testing.T, action string, events ...Event) {
|
|||
t.Fatalf("unexpected event action: %q != %q", event.Action, action)
|
||||
}
|
||||
|
||||
u, err := ub.BuildManifestURL(repo, dgst.String())
|
||||
repoRef, _ := reference.ParseNamed(repo)
|
||||
u, err := ub.BuildManifestURL(repoRef, dgst.String())
|
||||
if err != nil {
|
||||
t.Fatalf("error building expected url: %v", err)
|
||||
}
|
||||
|
|
|
@ -7,29 +7,30 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// ManifestListener describes a set of methods for listening to events related to manifests.
|
||||
type ManifestListener interface {
|
||||
ManifestPushed(repo string, sm distribution.Manifest) error
|
||||
ManifestPulled(repo string, sm distribution.Manifest) error
|
||||
ManifestPushed(repo reference.Named, sm distribution.Manifest) error
|
||||
ManifestPulled(repo reference.Named, sm distribution.Manifest) error
|
||||
|
||||
// TODO(stevvooe): Please note that delete support is still a little shaky
|
||||
// and we'll need to propagate these in the future.
|
||||
|
||||
ManifestDeleted(repo string, sm distribution.Manifest) error
|
||||
ManifestDeleted(repo reference.Named, sm distribution.Manifest) error
|
||||
}
|
||||
|
||||
// BlobListener describes a listener that can respond to layer related events.
|
||||
type BlobListener interface {
|
||||
BlobPushed(repo string, desc distribution.Descriptor) error
|
||||
BlobPulled(repo string, desc distribution.Descriptor) error
|
||||
BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error
|
||||
BlobPushed(repo reference.Named, desc distribution.Descriptor) error
|
||||
BlobPulled(repo reference.Named, desc distribution.Descriptor) error
|
||||
BlobMounted(repo reference.Named, desc distribution.Descriptor, fromRepo reference.Named) error
|
||||
|
||||
// TODO(stevvooe): Please note that delete support is still a little shaky
|
||||
// and we'll need to propagate these in the future.
|
||||
|
||||
BlobDeleted(repo string, desc distribution.Descriptor) error
|
||||
BlobDeleted(repo reference.Named, desc distribution.Descriptor) error
|
||||
}
|
||||
|
||||
// Listener combines all repository events into a single interface.
|
||||
|
@ -164,7 +165,7 @@ func (bsl *blobServiceListener) Create(ctx context.Context, options ...distribut
|
|||
wr, err := bsl.BlobStore.Create(ctx, options...)
|
||||
switch err := err.(type) {
|
||||
case distribution.ErrBlobMounted:
|
||||
if err := bsl.parent.listener.BlobMounted(bsl.parent.Repository.Name(), err.Descriptor, err.From.Name()); err != nil {
|
||||
if err := bsl.parent.listener.BlobMounted(bsl.parent.Repository.Name(), err.Descriptor, err.From); err != nil {
|
||||
context.GetLogger(ctx).Errorf("error dispatching blob mount to listener: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
|
@ -27,7 +28,8 @@ func TestListener(t *testing.T) {
|
|||
ops: make(map[string]int),
|
||||
}
|
||||
|
||||
repository, err := registry.Repository(ctx, "foo/bar")
|
||||
repoRef, _ := reference.ParseNamed("foo/bar")
|
||||
repository, err := registry.Repository(ctx, repoRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
@ -55,38 +57,38 @@ type testListener struct {
|
|||
ops map[string]int
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestPushed(repo string, m distribution.Manifest) error {
|
||||
func (tl *testListener) ManifestPushed(repo reference.Named, m distribution.Manifest) error {
|
||||
tl.ops["manifest:push"]++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestPulled(repo string, m distribution.Manifest) error {
|
||||
func (tl *testListener) ManifestPulled(repo reference.Named, m distribution.Manifest) error {
|
||||
tl.ops["manifest:pull"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) ManifestDeleted(repo string, m distribution.Manifest) error {
|
||||
func (tl *testListener) ManifestDeleted(repo reference.Named, m distribution.Manifest) error {
|
||||
tl.ops["manifest:delete"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) BlobPushed(repo string, desc distribution.Descriptor) error {
|
||||
func (tl *testListener) BlobPushed(repo reference.Named, desc distribution.Descriptor) error {
|
||||
tl.ops["layer:push"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) BlobPulled(repo string, desc distribution.Descriptor) error {
|
||||
func (tl *testListener) BlobPulled(repo reference.Named, desc distribution.Descriptor) error {
|
||||
tl.ops["layer:pull"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) BlobMounted(repo string, desc distribution.Descriptor, fromRepo string) error {
|
||||
func (tl *testListener) BlobMounted(repo reference.Named, desc distribution.Descriptor, fromRepo reference.Named) error {
|
||||
tl.ops["layer:mount"]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tl *testListener) BlobDeleted(repo string, desc distribution.Descriptor) error {
|
||||
func (tl *testListener) BlobDeleted(repo reference.Named, desc distribution.Descriptor) error {
|
||||
tl.ops["layer:delete"]++
|
||||
return nil
|
||||
}
|
||||
|
@ -107,7 +109,7 @@ func checkExerciseRepository(t *testing.T, repository distribution.Repository) {
|
|||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: repository.Name(),
|
||||
Name: repository.Name().Name(),
|
||||
Tag: tag,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package distribution
|
|||
|
||||
import (
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// Scope defines the set of items that match a namespace.
|
||||
|
@ -32,7 +33,7 @@ type Namespace interface {
|
|||
// Repository should return a reference to the named repository. The
|
||||
// registry may or may not have the repository but should always return a
|
||||
// reference.
|
||||
Repository(ctx context.Context, name string) (Repository, error)
|
||||
Repository(ctx context.Context, name reference.Named) (Repository, error)
|
||||
|
||||
// Repositories fills 'repos' with a lexigraphically sorted catalog of repositories
|
||||
// up to the size of 'repos' and returns the value 'n' for the number of entries
|
||||
|
@ -49,7 +50,7 @@ type ManifestServiceOption interface {
|
|||
// Repository is a named collection of manifests and layers.
|
||||
type Repository interface {
|
||||
// Name returns the name of the repository.
|
||||
Name() string
|
||||
Name() reference.Named
|
||||
|
||||
// Manifests returns a reference to this repository's manifest service.
|
||||
// with the supplied options applied.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
@ -113,10 +114,10 @@ func (ub *URLBuilder) BuildCatalogURL(values ...url.Values) (string, error) {
|
|||
}
|
||||
|
||||
// BuildTagsURL constructs a url to list the tags in the named repository.
|
||||
func (ub *URLBuilder) BuildTagsURL(name string) (string, error) {
|
||||
func (ub *URLBuilder) BuildTagsURL(name reference.Named) (string, error) {
|
||||
route := ub.cloneRoute(RouteNameTags)
|
||||
|
||||
tagsURL, err := route.URL("name", name)
|
||||
tagsURL, err := route.URL("name", name.Name())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -126,10 +127,10 @@ func (ub *URLBuilder) BuildTagsURL(name string) (string, error) {
|
|||
|
||||
// BuildManifestURL constructs a url for the manifest identified by name and
|
||||
// reference. The argument reference may be either a tag or digest.
|
||||
func (ub *URLBuilder) BuildManifestURL(name, reference string) (string, error) {
|
||||
func (ub *URLBuilder) BuildManifestURL(name reference.Named, reference string) (string, error) {
|
||||
route := ub.cloneRoute(RouteNameManifest)
|
||||
|
||||
manifestURL, err := route.URL("name", name, "reference", reference)
|
||||
manifestURL, err := route.URL("name", name.Name(), "reference", reference)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -138,10 +139,10 @@ func (ub *URLBuilder) BuildManifestURL(name, reference string) (string, error) {
|
|||
}
|
||||
|
||||
// BuildBlobURL constructs the url for the blob identified by name and dgst.
|
||||
func (ub *URLBuilder) BuildBlobURL(name string, dgst digest.Digest) (string, error) {
|
||||
func (ub *URLBuilder) BuildBlobURL(name reference.Named, dgst digest.Digest) (string, error) {
|
||||
route := ub.cloneRoute(RouteNameBlob)
|
||||
|
||||
layerURL, err := route.URL("name", name, "digest", dgst.String())
|
||||
layerURL, err := route.URL("name", name.Name(), "digest", dgst.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -151,10 +152,10 @@ func (ub *URLBuilder) BuildBlobURL(name string, dgst digest.Digest) (string, err
|
|||
|
||||
// BuildBlobUploadURL constructs a url to begin a blob upload in the
|
||||
// repository identified by name.
|
||||
func (ub *URLBuilder) BuildBlobUploadURL(name string, values ...url.Values) (string, error) {
|
||||
func (ub *URLBuilder) BuildBlobUploadURL(name reference.Named, values ...url.Values) (string, error) {
|
||||
route := ub.cloneRoute(RouteNameBlobUpload)
|
||||
|
||||
uploadURL, err := route.URL("name", name)
|
||||
uploadURL, err := route.URL("name", name.Name())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -166,10 +167,10 @@ func (ub *URLBuilder) BuildBlobUploadURL(name string, values ...url.Values) (str
|
|||
// including any url values. This should generally not be used by clients, as
|
||||
// this url is provided by server implementations during the blob upload
|
||||
// process.
|
||||
func (ub *URLBuilder) BuildBlobUploadChunkURL(name, uuid string, values ...url.Values) (string, error) {
|
||||
func (ub *URLBuilder) BuildBlobUploadChunkURL(name reference.Named, uuid string, values ...url.Values) (string, error) {
|
||||
route := ub.cloneRoute(RouteNameBlobUploadChunk)
|
||||
|
||||
uploadURL, err := route.URL("name", name, "uuid", uuid)
|
||||
uploadURL, err := route.URL("name", name.Name(), "uuid", uuid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
type urlBuilderTestCase struct {
|
||||
|
@ -13,6 +15,7 @@ type urlBuilderTestCase struct {
|
|||
}
|
||||
|
||||
func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
||||
fooBarRef, _ := reference.ParseNamed("foo/bar")
|
||||
return []urlBuilderTestCase{
|
||||
{
|
||||
description: "test base url",
|
||||
|
@ -23,35 +26,35 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||
description: "test tags url",
|
||||
expectedPath: "/v2/foo/bar/tags/list",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildTagsURL("foo/bar")
|
||||
return urlBuilder.BuildTagsURL(fooBarRef)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "test manifest url",
|
||||
expectedPath: "/v2/foo/bar/manifests/tag",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildManifestURL("foo/bar", "tag")
|
||||
return urlBuilder.BuildManifestURL(fooBarRef, "tag")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "build blob url",
|
||||
expectedPath: "/v2/foo/bar/blobs/sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildBlobURL("foo/bar", "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
|
||||
return urlBuilder.BuildBlobURL(fooBarRef, "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "build blob upload url",
|
||||
expectedPath: "/v2/foo/bar/blobs/uploads/",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildBlobUploadURL("foo/bar")
|
||||
return urlBuilder.BuildBlobUploadURL(fooBarRef)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "build blob upload url with digest and size",
|
||||
expectedPath: "/v2/foo/bar/blobs/uploads/?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
|
||||
return urlBuilder.BuildBlobUploadURL(fooBarRef, url.Values{
|
||||
"size": []string{"10000"},
|
||||
"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
|
||||
})
|
||||
|
@ -61,14 +64,14 @@ func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|||
description: "build blob upload chunk url",
|
||||
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
|
||||
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "build blob upload chunk url with digest and size",
|
||||
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
||||
build: func() (string, error) {
|
||||
return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
|
||||
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part", url.Values{
|
||||
"size": []string{"10000"},
|
||||
"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
|
||||
})
|
||||
|
|
|
@ -98,11 +98,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri
|
|||
}
|
||||
|
||||
// NewRepository creates a new Repository for the given repository name and base URL.
|
||||
func NewRepository(ctx context.Context, name, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
|
||||
if _, err := reference.ParseNamed(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewRepository(ctx context.Context, name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
|
||||
ub, err := v2.NewURLBuilderFromString(baseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -125,21 +121,21 @@ type repository struct {
|
|||
client *http.Client
|
||||
ub *v2.URLBuilder
|
||||
context context.Context
|
||||
name string
|
||||
name reference.Named
|
||||
}
|
||||
|
||||
func (r *repository) Name() string {
|
||||
func (r *repository) Name() reference.Named {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
|
||||
statter := &blobStatter{
|
||||
name: r.Name(),
|
||||
name: r.name,
|
||||
ub: r.ub,
|
||||
client: r.client,
|
||||
}
|
||||
return &blobs{
|
||||
name: r.Name(),
|
||||
name: r.name,
|
||||
ub: r.ub,
|
||||
client: r.client,
|
||||
statter: cache.NewCachedBlobStatter(memory.NewInMemoryBlobDescriptorCacheProvider(), statter),
|
||||
|
@ -149,7 +145,7 @@ func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
|
|||
func (r *repository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
|
||||
// todo(richardscothern): options should be sent over the wire
|
||||
return &manifests{
|
||||
name: r.Name(),
|
||||
name: r.name,
|
||||
ub: r.ub,
|
||||
client: r.client,
|
||||
etags: make(map[string]string),
|
||||
|
@ -170,7 +166,7 @@ type tags struct {
|
|||
client *http.Client
|
||||
ub *v2.URLBuilder
|
||||
context context.Context
|
||||
name string
|
||||
name reference.Named
|
||||
}
|
||||
|
||||
// All returns all tags
|
||||
|
@ -293,7 +289,7 @@ func (t *tags) Untag(ctx context.Context, tag string) error {
|
|||
}
|
||||
|
||||
type manifests struct {
|
||||
name string
|
||||
name reference.Named
|
||||
ub *v2.URLBuilder
|
||||
client *http.Client
|
||||
etags map[string]string
|
||||
|
@ -493,7 +489,7 @@ func (ms *manifests) Delete(ctx context.Context, dgst digest.Digest) error {
|
|||
}*/
|
||||
|
||||
type blobs struct {
|
||||
name string
|
||||
name reference.Named
|
||||
ub *v2.URLBuilder
|
||||
client *http.Client
|
||||
|
||||
|
@ -666,7 +662,7 @@ func (bs *blobs) Delete(ctx context.Context, dgst digest.Digest) error {
|
|||
}
|
||||
|
||||
type blobStatter struct {
|
||||
name string
|
||||
name reference.Named
|
||||
ub *v2.URLBuilder
|
||||
client *http.Client
|
||||
}
|
||||
|
|
|
@ -98,11 +98,11 @@ func addTestCatalog(route string, content []byte, link string, m *testutil.Reque
|
|||
func TestBlobDelete(t *testing.T) {
|
||||
dgst, _ := newRandomBlob(1024)
|
||||
var m testutil.RequestResponseMap
|
||||
repo := "test.example.com/repo1"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "DELETE",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
|
@ -137,7 +137,8 @@ func TestBlobFetch(t *testing.T) {
|
|||
defer c()
|
||||
|
||||
ctx := context.Background()
|
||||
r, err := NewRepository(ctx, "test.example.com/repo1", e, nil)
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
||||
r, err := NewRepository(ctx, repo, e, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -157,12 +158,12 @@ func TestBlobFetch(t *testing.T) {
|
|||
func TestBlobExistsNoContentLength(t *testing.T) {
|
||||
var m testutil.RequestResponseMap
|
||||
|
||||
repo := "biff"
|
||||
repo, _ := reference.ParseNamed("biff")
|
||||
dgst, content := newRandomBlob(1024)
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "GET",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -177,7 +178,7 @@ func TestBlobExistsNoContentLength(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "HEAD",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -216,7 +217,8 @@ func TestBlobExists(t *testing.T) {
|
|||
defer c()
|
||||
|
||||
ctx := context.Background()
|
||||
r, err := NewRepository(ctx, "test.example.com/repo1", e, nil)
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo1")
|
||||
r, err := NewRepository(ctx, repo, e, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -247,18 +249,18 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||
b1[512:513],
|
||||
b1[513:1024],
|
||||
}
|
||||
repo := "test.example.com/uploadrepo"
|
||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
||||
uuids := []string{uuid.Generate().String()}
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "POST",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/",
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/",
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
"Location": {"/v2/" + repo + "/blobs/uploads/" + uuids[0]},
|
||||
"Location": {"/v2/" + repo.Name() + "/blobs/uploads/" + uuids[0]},
|
||||
"Docker-Upload-UUID": {uuids[0]},
|
||||
"Range": {"0-0"},
|
||||
}),
|
||||
|
@ -271,14 +273,14 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "PATCH",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/" + uuids[i],
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/" + uuids[i],
|
||||
Body: chunk,
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
"Location": {"/v2/" + repo + "/blobs/uploads/" + uuids[i+1]},
|
||||
"Location": {"/v2/" + repo.Name() + "/blobs/uploads/" + uuids[i+1]},
|
||||
"Docker-Upload-UUID": {uuids[i+1]},
|
||||
"Range": {fmt.Sprintf("%d-%d", offset, newOffset-1)},
|
||||
}),
|
||||
|
@ -289,7 +291,7 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "PUT",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/" + uuids[len(uuids)-1],
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/" + uuids[len(uuids)-1],
|
||||
QueryParams: map[string][]string{
|
||||
"digest": {dgst.String()},
|
||||
},
|
||||
|
@ -306,7 +308,7 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "HEAD",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -362,18 +364,18 @@ func TestBlobUploadChunked(t *testing.T) {
|
|||
func TestBlobUploadMonolithic(t *testing.T) {
|
||||
dgst, b1 := newRandomBlob(1024)
|
||||
var m testutil.RequestResponseMap
|
||||
repo := "test.example.com/uploadrepo"
|
||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
||||
uploadID := uuid.Generate().String()
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "POST",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/",
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/",
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
"Location": {"/v2/" + repo + "/blobs/uploads/" + uploadID},
|
||||
"Location": {"/v2/" + repo.Name() + "/blobs/uploads/" + uploadID},
|
||||
"Docker-Upload-UUID": {uploadID},
|
||||
"Range": {"0-0"},
|
||||
}),
|
||||
|
@ -382,13 +384,13 @@ func TestBlobUploadMonolithic(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "PATCH",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/" + uploadID,
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/" + uploadID,
|
||||
Body: b1,
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"Location": {"/v2/" + repo + "/blobs/uploads/" + uploadID},
|
||||
"Location": {"/v2/" + repo.Name() + "/blobs/uploads/" + uploadID},
|
||||
"Docker-Upload-UUID": {uploadID},
|
||||
"Content-Length": {"0"},
|
||||
"Docker-Content-Digest": {dgst.String()},
|
||||
|
@ -399,7 +401,7 @@ func TestBlobUploadMonolithic(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "PUT",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/" + uploadID,
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/" + uploadID,
|
||||
QueryParams: map[string][]string{
|
||||
"digest": {dgst.String()},
|
||||
},
|
||||
|
@ -416,7 +418,7 @@ func TestBlobUploadMonolithic(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "HEAD",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -470,29 +472,22 @@ func TestBlobUploadMonolithic(t *testing.T) {
|
|||
func TestBlobMount(t *testing.T) {
|
||||
dgst, content := newRandomBlob(1024)
|
||||
var m testutil.RequestResponseMap
|
||||
repo := "test.example.com/uploadrepo"
|
||||
sourceRepo := "test.example.com/sourcerepo"
|
||||
repo, _ := reference.ParseNamed("test.example.com/uploadrepo")
|
||||
|
||||
namedRef, err := reference.ParseNamed(sourceRepo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
canonicalRef, err := reference.WithDigest(namedRef, dgst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sourceRepo, _ := reference.ParseNamed("test.example.com/sourcerepo")
|
||||
canonicalRef, _ := reference.WithDigest(sourceRepo, dgst)
|
||||
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "POST",
|
||||
Route: "/v2/" + repo + "/blobs/uploads/",
|
||||
QueryParams: map[string][]string{"from": {sourceRepo}, "mount": {dgst.String()}},
|
||||
Route: "/v2/" + repo.Name() + "/blobs/uploads/",
|
||||
QueryParams: map[string][]string{"from": {sourceRepo.Name()}, "mount": {dgst.String()}},
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusCreated,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
"Location": {"/v2/" + repo + "/blobs/" + dgst.String()},
|
||||
"Location": {"/v2/" + repo.Name() + "/blobs/" + dgst.String()},
|
||||
"Docker-Content-Digest": {dgst.String()},
|
||||
}),
|
||||
},
|
||||
|
@ -500,7 +495,7 @@ func TestBlobMount(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "HEAD",
|
||||
Route: "/v2/" + repo + "/blobs/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/blobs/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -531,7 +526,7 @@ func TestBlobMount(t *testing.T) {
|
|||
if ebm.From.Digest() != dgst {
|
||||
t.Fatalf("Unexpected digest: %s, expected %s", ebm.From.Digest(), dgst)
|
||||
}
|
||||
if ebm.From.Name() != sourceRepo {
|
||||
if ebm.From.Name() != sourceRepo.Name() {
|
||||
t.Fatalf("Unexpected from: %s, expected %s", ebm.From.Name(), sourceRepo)
|
||||
}
|
||||
} else {
|
||||
|
@ -539,7 +534,7 @@ func TestBlobMount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func newRandomSchemaV1Manifest(name, tag string, blobCount int) (*schema1.SignedManifest, digest.Digest, []byte) {
|
||||
func newRandomSchemaV1Manifest(name reference.Named, tag string, blobCount int) (*schema1.SignedManifest, digest.Digest, []byte) {
|
||||
blobs := make([]schema1.FSLayer, blobCount)
|
||||
history := make([]schema1.History, blobCount)
|
||||
|
||||
|
@ -551,7 +546,7 @@ func newRandomSchemaV1Manifest(name, tag string, blobCount int) (*schema1.Signed
|
|||
}
|
||||
|
||||
m := schema1.Manifest{
|
||||
Name: name,
|
||||
Name: name.String(),
|
||||
Tag: tag,
|
||||
Architecture: "x86",
|
||||
FSLayers: blobs,
|
||||
|
@ -574,11 +569,11 @@ func newRandomSchemaV1Manifest(name, tag string, blobCount int) (*schema1.Signed
|
|||
return sm, digest.FromBytes(sm.Canonical), sm.Canonical
|
||||
}
|
||||
|
||||
func addTestManifestWithEtag(repo, reference string, content []byte, m *testutil.RequestResponseMap, dgst string) {
|
||||
func addTestManifestWithEtag(repo reference.Named, reference string, content []byte, m *testutil.RequestResponseMap, dgst string) {
|
||||
actualDigest := digest.FromBytes(content)
|
||||
getReqWithEtag := testutil.Request{
|
||||
Method: "GET",
|
||||
Route: "/v2/" + repo + "/manifests/" + reference,
|
||||
Route: "/v2/" + repo.Name() + "/manifests/" + reference,
|
||||
Headers: http.Header(map[string][]string{
|
||||
"If-None-Match": {fmt.Sprintf(`"%s"`, dgst)},
|
||||
}),
|
||||
|
@ -610,11 +605,11 @@ func addTestManifestWithEtag(repo, reference string, content []byte, m *testutil
|
|||
*m = append(*m, testutil.RequestResponseMapping{Request: getReqWithEtag, Response: getRespWithEtag})
|
||||
}
|
||||
|
||||
func addTestManifest(repo, reference string, mediatype string, content []byte, m *testutil.RequestResponseMap) {
|
||||
func addTestManifest(repo reference.Named, reference string, mediatype string, content []byte, m *testutil.RequestResponseMap) {
|
||||
*m = append(*m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "GET",
|
||||
Route: "/v2/" + repo + "/manifests/" + reference,
|
||||
Route: "/v2/" + repo.Name() + "/manifests/" + reference,
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -629,7 +624,7 @@ func addTestManifest(repo, reference string, mediatype string, content []byte, m
|
|||
*m = append(*m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "HEAD",
|
||||
Route: "/v2/" + repo + "/manifests/" + reference,
|
||||
Route: "/v2/" + repo.Name() + "/manifests/" + reference,
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -671,7 +666,7 @@ func checkEqualManifest(m1, m2 *schema1.SignedManifest) error {
|
|||
|
||||
func TestV1ManifestFetch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := "test.example.com/repo"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo")
|
||||
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||
var m testutil.RequestResponseMap
|
||||
_, pl, err := m1.Payload()
|
||||
|
@ -743,7 +738,7 @@ func TestV1ManifestFetch(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestManifestFetchWithEtag(t *testing.T) {
|
||||
repo := "test.example.com/repo/by/tag"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo/by/tag")
|
||||
_, d1, p1 := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||
var m testutil.RequestResponseMap
|
||||
addTestManifestWithEtag(repo, "latest", p1, &m, d1.String())
|
||||
|
@ -773,14 +768,14 @@ func TestManifestFetchWithEtag(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestManifestDelete(t *testing.T) {
|
||||
repo := "test.example.com/repo/delete"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo/delete")
|
||||
_, dgst1, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||
_, dgst2, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||
var m testutil.RequestResponseMap
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "DELETE",
|
||||
Route: "/v2/" + repo + "/manifests/" + dgst1.String(),
|
||||
Route: "/v2/" + repo.Name() + "/manifests/" + dgst1.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusAccepted,
|
||||
|
@ -813,7 +808,7 @@ func TestManifestDelete(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestManifestPut(t *testing.T) {
|
||||
repo := "test.example.com/repo/delete"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo/delete")
|
||||
m1, dgst, _ := newRandomSchemaV1Manifest(repo, "other", 6)
|
||||
|
||||
_, payload, err := m1.Payload()
|
||||
|
@ -824,7 +819,7 @@ func TestManifestPut(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "PUT",
|
||||
Route: "/v2/" + repo + "/manifests/other",
|
||||
Route: "/v2/" + repo.Name() + "/manifests/other",
|
||||
Body: payload,
|
||||
},
|
||||
Response: testutil.Response{
|
||||
|
@ -857,7 +852,7 @@ func TestManifestPut(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestManifestTags(t *testing.T) {
|
||||
repo := "test.example.com/repo/tags/list"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo/tags/list")
|
||||
tagsList := []byte(strings.TrimSpace(`
|
||||
{
|
||||
"name": "test.example.com/repo/tags/list",
|
||||
|
@ -873,7 +868,7 @@ func TestManifestTags(t *testing.T) {
|
|||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "GET",
|
||||
Route: "/v2/" + repo + "/tags/list",
|
||||
Route: "/v2/" + repo.Name() + "/tags/list",
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
|
@ -919,14 +914,14 @@ func TestManifestTags(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestManifestUnauthorized(t *testing.T) {
|
||||
repo := "test.example.com/repo"
|
||||
repo, _ := reference.ParseNamed("test.example.com/repo")
|
||||
_, dgst, _ := newRandomSchemaV1Manifest(repo, "latest", 6)
|
||||
var m testutil.RequestResponseMap
|
||||
|
||||
m = append(m, testutil.RequestResponseMapping{
|
||||
Request: testutil.Request{
|
||||
Method: "GET",
|
||||
Route: "/v2/" + repo + "/manifests/" + dgst.String(),
|
||||
Route: "/v2/" + repo.Name() + "/manifests/" + dgst.String(),
|
||||
},
|
||||
Response: testutil.Response{
|
||||
StatusCode: http.StatusUnauthorized,
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
_ "github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
|
@ -251,7 +252,7 @@ func TestURLPrefix(t *testing.T) {
|
|||
}
|
||||
|
||||
type blobArgs struct {
|
||||
imageName string
|
||||
imageName reference.Named
|
||||
layerFile io.ReadSeeker
|
||||
layerDigest digest.Digest
|
||||
}
|
||||
|
@ -263,10 +264,10 @@ func makeBlobArgs(t *testing.T) blobArgs {
|
|||
}
|
||||
|
||||
args := blobArgs{
|
||||
imageName: "foo/bar",
|
||||
layerFile: layerFile,
|
||||
layerDigest: layerDigest,
|
||||
}
|
||||
args.imageName, _ = reference.ParseNamed("foo/bar")
|
||||
return args
|
||||
}
|
||||
|
||||
|
@ -609,7 +610,7 @@ func testBlobDelete(t *testing.T, env *testEnv, args blobArgs) {
|
|||
func TestDeleteDisabled(t *testing.T) {
|
||||
env := newTestEnv(t, false)
|
||||
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
// "build" our layer file
|
||||
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
||||
if err != nil {
|
||||
|
@ -634,7 +635,7 @@ func TestDeleteDisabled(t *testing.T) {
|
|||
func TestDeleteReadOnly(t *testing.T) {
|
||||
env := newTestEnv(t, true)
|
||||
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
// "build" our layer file
|
||||
layerFile, layerDigest, err := testutil.CreateRandomTarFile()
|
||||
if err != nil {
|
||||
|
@ -662,7 +663,7 @@ func TestStartPushReadOnly(t *testing.T) {
|
|||
env := newTestEnv(t, true)
|
||||
env.app.readOnly = true
|
||||
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
|
||||
layerUploadURL, err := env.builder.BuildBlobUploadURL(imageName)
|
||||
if err != nil {
|
||||
|
@ -693,42 +694,49 @@ func httpDelete(url string) (*http.Response, error) {
|
|||
}
|
||||
|
||||
type manifestArgs struct {
|
||||
imageName string
|
||||
imageName reference.Named
|
||||
mediaType string
|
||||
manifest distribution.Manifest
|
||||
dgst digest.Digest
|
||||
}
|
||||
|
||||
func TestManifestAPI(t *testing.T) {
|
||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
||||
schema2Repo, _ := reference.ParseNamed("foo/schema2")
|
||||
|
||||
deleteEnabled := false
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
testManifestAPISchema1(t, env, "foo/schema1")
|
||||
schema2Args := testManifestAPISchema2(t, env, "foo/schema2")
|
||||
testManifestAPISchema1(t, env, schema1Repo)
|
||||
schema2Args := testManifestAPISchema2(t, env, schema2Repo)
|
||||
testManifestAPIManifestList(t, env, schema2Args)
|
||||
|
||||
deleteEnabled = true
|
||||
env = newTestEnv(t, deleteEnabled)
|
||||
testManifestAPISchema1(t, env, "foo/schema1")
|
||||
schema2Args = testManifestAPISchema2(t, env, "foo/schema2")
|
||||
testManifestAPISchema1(t, env, schema1Repo)
|
||||
schema2Args = testManifestAPISchema2(t, env, schema2Repo)
|
||||
testManifestAPIManifestList(t, env, schema2Args)
|
||||
}
|
||||
|
||||
func TestManifestDelete(t *testing.T) {
|
||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
||||
schema2Repo, _ := reference.ParseNamed("foo/schema2")
|
||||
|
||||
deleteEnabled := true
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
schema1Args := testManifestAPISchema1(t, env, "foo/schema1")
|
||||
schema1Args := testManifestAPISchema1(t, env, schema1Repo)
|
||||
testManifestDelete(t, env, schema1Args)
|
||||
schema2Args := testManifestAPISchema2(t, env, "foo/schema2")
|
||||
schema2Args := testManifestAPISchema2(t, env, schema2Repo)
|
||||
testManifestDelete(t, env, schema2Args)
|
||||
}
|
||||
|
||||
func TestManifestDeleteDisabled(t *testing.T) {
|
||||
schema1Repo, _ := reference.ParseNamed("foo/schema1")
|
||||
deleteEnabled := false
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
testManifestDeleteDisabled(t, env, "foo/schema1")
|
||||
testManifestDeleteDisabled(t, env, schema1Repo)
|
||||
}
|
||||
|
||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName string) {
|
||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName reference.Named) {
|
||||
manifestURL, err := env.builder.BuildManifestURL(imageName, digest.DigestSha256EmptyTar)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||
|
@ -743,7 +751,7 @@ func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName string) {
|
|||
checkResponse(t, "status of disabled delete of manifest", resp, http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manifestArgs {
|
||||
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
||||
tag := "thetag"
|
||||
args := manifestArgs{imageName: imageName}
|
||||
|
||||
|
@ -784,7 +792,7 @@ func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manife
|
|||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: imageName,
|
||||
Name: imageName.Name(),
|
||||
Tag: tag,
|
||||
FSLayers: []schema1.FSLayer{
|
||||
{
|
||||
|
@ -1032,8 +1040,8 @@ func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manife
|
|||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName)
|
||||
if tagsResponse.Name != imageName.Name() {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName.Name())
|
||||
}
|
||||
|
||||
if len(tagsResponse.Tags) != 1 {
|
||||
|
@ -1060,7 +1068,7 @@ func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manife
|
|||
return args
|
||||
}
|
||||
|
||||
func testManifestAPISchema2(t *testing.T, env *testEnv, imageName string) manifestArgs {
|
||||
func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Named) manifestArgs {
|
||||
tag := "schema2tag"
|
||||
args := manifestArgs{
|
||||
imageName: imageName,
|
||||
|
@ -1340,7 +1348,7 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName string) manife
|
|||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName {
|
||||
if tagsResponse.Name != imageName.Name() {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName)
|
||||
}
|
||||
|
||||
|
@ -1379,7 +1387,7 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName string) manife
|
|||
if fetchedSchema1Manifest.Architecture != "amd64" {
|
||||
t.Fatal("wrong architecture")
|
||||
}
|
||||
if fetchedSchema1Manifest.Name != imageName {
|
||||
if fetchedSchema1Manifest.Name != imageName.Name() {
|
||||
t.Fatal("wrong image name")
|
||||
}
|
||||
if fetchedSchema1Manifest.Tag != tag {
|
||||
|
@ -1602,7 +1610,7 @@ func testManifestAPIManifestList(t *testing.T, env *testEnv, args manifestArgs)
|
|||
if fetchedSchema1Manifest.Architecture != "amd64" {
|
||||
t.Fatal("wrong architecture")
|
||||
}
|
||||
if fetchedSchema1Manifest.Name != imageName {
|
||||
if fetchedSchema1Manifest.Name != imageName.Name() {
|
||||
t.Fatal("wrong image name")
|
||||
}
|
||||
if fetchedSchema1Manifest.Tag != tag {
|
||||
|
@ -1715,7 +1723,7 @@ func testManifestDelete(t *testing.T, env *testEnv, args manifestArgs) {
|
|||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName {
|
||||
if tagsResponse.Name != imageName.Name() {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName)
|
||||
}
|
||||
|
||||
|
@ -1749,7 +1757,7 @@ func testManifestDelete(t *testing.T, env *testEnv, args manifestArgs) {
|
|||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName {
|
||||
if tagsResponse.Name != imageName.Name() {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName)
|
||||
}
|
||||
|
||||
|
@ -1863,7 +1871,7 @@ func putManifest(t *testing.T, msg, url, contentType string, v interface{}) *htt
|
|||
return resp
|
||||
}
|
||||
|
||||
func startPushLayer(t *testing.T, ub *v2.URLBuilder, name string) (location string, uuid string) {
|
||||
func startPushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named) (location string, uuid string) {
|
||||
layerUploadURL, err := ub.BuildBlobUploadURL(name)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error building layer upload url: %v", err)
|
||||
|
@ -1875,7 +1883,7 @@ func startPushLayer(t *testing.T, ub *v2.URLBuilder, name string) (location stri
|
|||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, fmt.Sprintf("pushing starting layer push %v", name), resp, http.StatusAccepted)
|
||||
checkResponse(t, fmt.Sprintf("pushing starting layer push %v", name.String()), resp, http.StatusAccepted)
|
||||
|
||||
u, err := url.Parse(resp.Header.Get("Location"))
|
||||
if err != nil {
|
||||
|
@ -1894,7 +1902,7 @@ func startPushLayer(t *testing.T, ub *v2.URLBuilder, name string) (location stri
|
|||
|
||||
// doPushLayer pushes the layer content returning the url on success returning
|
||||
// the response. If you're only expecting a successful response, use pushLayer.
|
||||
func doPushLayer(t *testing.T, ub *v2.URLBuilder, name string, dgst digest.Digest, uploadURLBase string, body io.Reader) (*http.Response, error) {
|
||||
func doPushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named, dgst digest.Digest, uploadURLBase string, body io.Reader) (*http.Response, error) {
|
||||
u, err := url.Parse(uploadURLBase)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error parsing pushLayer url: %v", err)
|
||||
|
@ -1918,7 +1926,7 @@ func doPushLayer(t *testing.T, ub *v2.URLBuilder, name string, dgst digest.Diges
|
|||
}
|
||||
|
||||
// pushLayer pushes the layer content returning the url on success.
|
||||
func pushLayer(t *testing.T, ub *v2.URLBuilder, name string, dgst digest.Digest, uploadURLBase string, body io.Reader) string {
|
||||
func pushLayer(t *testing.T, ub *v2.URLBuilder, name reference.Named, dgst digest.Digest, uploadURLBase string, body io.Reader) string {
|
||||
digester := digest.Canonical.New()
|
||||
|
||||
resp, err := doPushLayer(t, ub, name, dgst, uploadURLBase, io.TeeReader(body, digester.Hash()))
|
||||
|
@ -1949,7 +1957,7 @@ func pushLayer(t *testing.T, ub *v2.URLBuilder, name string, dgst digest.Digest,
|
|||
return resp.Header.Get("Location")
|
||||
}
|
||||
|
||||
func finishUpload(t *testing.T, ub *v2.URLBuilder, name string, uploadURLBase string, dgst digest.Digest) string {
|
||||
func finishUpload(t *testing.T, ub *v2.URLBuilder, name reference.Named, uploadURLBase string, dgst digest.Digest) string {
|
||||
resp, err := doPushLayer(t, ub, name, dgst, uploadURLBase, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error doing push layer request: %v", err)
|
||||
|
@ -1997,7 +2005,7 @@ func doPushChunk(t *testing.T, uploadURLBase string, body io.Reader) (*http.Resp
|
|||
return resp, digester.Digest(), err
|
||||
}
|
||||
|
||||
func pushChunk(t *testing.T, ub *v2.URLBuilder, name string, uploadURLBase string, body io.Reader, length int64) (string, digest.Digest) {
|
||||
func pushChunk(t *testing.T, ub *v2.URLBuilder, name reference.Named, uploadURLBase string, body io.Reader, length int64) (string, digest.Digest) {
|
||||
resp, dgst, err := doPushChunk(t, uploadURLBase, body)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error doing push layer request: %v", err)
|
||||
|
@ -2133,6 +2141,11 @@ func checkErr(t *testing.T, err error, msg string) {
|
|||
}
|
||||
|
||||
func createRepository(env *testEnv, t *testing.T, imageName string, tag string) digest.Digest {
|
||||
imageNameRef, err := reference.ParseNamed(imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse reference: %v", err)
|
||||
}
|
||||
|
||||
unsignedManifest := &schema1.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
|
@ -2164,8 +2177,8 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
|
|||
expectedLayers[dgst] = rs
|
||||
unsignedManifest.FSLayers[i].BlobSum = dgst
|
||||
|
||||
uploadURLBase, _ := startPushLayer(t, env.builder, imageName)
|
||||
pushLayer(t, env.builder, imageName, dgst, uploadURLBase, rs)
|
||||
uploadURLBase, _ := startPushLayer(t, env.builder, imageNameRef)
|
||||
pushLayer(t, env.builder, imageNameRef, dgst, uploadURLBase, rs)
|
||||
}
|
||||
|
||||
signedManifest, err := schema1.Sign(unsignedManifest, env.pk)
|
||||
|
@ -2176,10 +2189,10 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
|
|||
dgst := digest.FromBytes(signedManifest.Canonical)
|
||||
|
||||
// Create this repository by tag to ensure the tag mapping is made in the registry
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageName, tag)
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageNameRef, tag)
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
location, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
location, err := env.builder.BuildManifestURL(imageNameRef, dgst.String())
|
||||
checkErr(t, err, "building location URL")
|
||||
|
||||
resp := putManifest(t, "putting signed manifest", manifestDigestURL, "", signedManifest)
|
||||
|
@ -2197,7 +2210,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
|||
deleteEnabled := true
|
||||
env := newTestEnvMirror(t, deleteEnabled)
|
||||
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
tag := "latest"
|
||||
manifestURL, err := env.builder.BuildManifestURL(imageName, tag)
|
||||
if err != nil {
|
||||
|
@ -2209,7 +2222,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
|||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: imageName,
|
||||
Name: imageName.Name(),
|
||||
Tag: tag,
|
||||
FSLayers: []schema1.FSLayer{},
|
||||
History: []schema1.History{},
|
||||
|
@ -2284,12 +2297,12 @@ func TestProxyManifestGetByTag(t *testing.T) {
|
|||
}
|
||||
truthConfig.HTTP.Headers = headerConfig
|
||||
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
tag := "latest"
|
||||
|
||||
truthEnv := newTestEnvWithConfig(t, &truthConfig)
|
||||
// create a repository in the truth registry
|
||||
dgst := createRepository(truthEnv, t, imageName, tag)
|
||||
dgst := createRepository(truthEnv, t, imageName.Name(), tag)
|
||||
|
||||
proxyConfig := configuration.Configuration{
|
||||
Storage: configuration.Storage{
|
||||
|
@ -2322,7 +2335,7 @@ func TestProxyManifestGetByTag(t *testing.T) {
|
|||
})
|
||||
|
||||
// Create another manifest in the remote with the same image/tag pair
|
||||
newDigest := createRepository(truthEnv, t, imageName, tag)
|
||||
newDigest := createRepository(truthEnv, t, imageName.Name(), tag)
|
||||
if dgst == newDigest {
|
||||
t.Fatalf("non-random test data")
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/docker/distribution/health"
|
||||
"github.com/docker/distribution/health/checks"
|
||||
"github.com/docker/distribution/notifications"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/auth"
|
||||
|
@ -590,7 +591,19 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
|||
context.Context = ctxu.WithLogger(context.Context, ctxu.GetLogger(context.Context, "auth.user.name"))
|
||||
|
||||
if app.nameRequired(r) {
|
||||
repository, err := app.registry.Repository(context, getName(context))
|
||||
nameRef, err := reference.ParseNamed(getName(context))
|
||||
if err != nil {
|
||||
ctxu.GetLogger(context).Errorf("error parsing reference from context: %v", err)
|
||||
context.Errors = append(context.Errors, distribution.ErrRepositoryNameInvalid{
|
||||
Name: getName(context),
|
||||
Reason: err,
|
||||
})
|
||||
if err := errcode.ServeJSON(w, context.Errors); err != nil {
|
||||
ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors)
|
||||
}
|
||||
return
|
||||
}
|
||||
repository, err := app.registry.Repository(context, nameRef)
|
||||
|
||||
if err != nil {
|
||||
ctxu.GetLogger(context).Errorf("error resolving repository: %v", err)
|
||||
|
|
|
@ -48,7 +48,7 @@ func TestAppDispatcher(t *testing.T) {
|
|||
varCheckingDispatcher := func(expectedVars map[string]string) dispatchFunc {
|
||||
return func(ctx *Context, r *http.Request) http.Handler {
|
||||
// Always checks the same name context
|
||||
if ctx.Repository.Name() != getName(ctx) {
|
||||
if ctx.Repository.Name().Name() != getName(ctx) {
|
||||
t.Fatalf("unexpected name: %q != %q", ctx.Repository.Name(), "foo/bar")
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler {
|
|||
}
|
||||
buh.State = state
|
||||
|
||||
if state.Name != ctx.Repository.Name() {
|
||||
if state.Name != ctx.Repository.Name().Name() {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctxu.GetLogger(ctx).Infof("mismatched repository name in upload state: %q != %q", state.Name, buh.Repository.Name())
|
||||
buh.Errors = append(buh.Errors, v2.ErrorCodeBlobUploadInvalid.WithDetail(err))
|
||||
|
@ -312,7 +312,7 @@ func (buh *blobUploadHandler) blobUploadResponse(w http.ResponseWriter, r *http.
|
|||
}
|
||||
|
||||
// TODO(stevvooe): Need a better way to manage the upload state automatically.
|
||||
buh.State.Name = buh.Repository.Name()
|
||||
buh.State.Name = buh.Repository.Name().Name()
|
||||
buh.State.UUID = buh.Upload.ID()
|
||||
buh.State.Offset = offset
|
||||
buh.State.StartedAt = buh.Upload.StartedAt()
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/gorilla/handlers"
|
||||
|
@ -173,7 +174,17 @@ func (imh *imageManifestHandler) convertSchema2Manifest(schema2Manifest *schema2
|
|||
return nil, err
|
||||
}
|
||||
|
||||
builder := schema1.NewConfigManifestBuilder(imh.Repository.Blobs(imh), imh.Context.App.trustKey, imh.Repository.Name(), imh.Tag, configJSON)
|
||||
ref := imh.Repository.Name()
|
||||
|
||||
if imh.Tag != "" {
|
||||
ref, err = reference.WithTag(imh.Repository.Name(), imh.Tag)
|
||||
if err != nil {
|
||||
imh.Errors = append(imh.Errors, v2.ErrorCodeTagInvalid.WithDetail(err))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
builder := schema1.NewConfigManifestBuilder(imh.Repository.Blobs(imh), imh.Context.App.trustKey, ref, configJSON)
|
||||
for _, d := range schema2Manifest.References() {
|
||||
if err := builder.AppendReference(d); err != nil {
|
||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestInvalid.WithDetail(err))
|
||||
|
|
|
@ -40,7 +40,7 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case distribution.ErrRepositoryUnknown:
|
||||
th.Errors = append(th.Errors, v2.ErrorCodeNameUnknown.WithDetail(map[string]string{"name": th.Repository.Name()}))
|
||||
th.Errors = append(th.Errors, v2.ErrorCodeNameUnknown.WithDetail(map[string]string{"name": th.Repository.Name().Name()}))
|
||||
default:
|
||||
th.Errors = append(th.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
enc := json.NewEncoder(w)
|
||||
if err := enc.Encode(tagsAPIResponse{
|
||||
Name: th.Repository.Name(),
|
||||
Name: th.Repository.Name().Name(),
|
||||
Tags: tags,
|
||||
}); err != nil {
|
||||
th.Errors = append(th.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||
)
|
||||
|
||||
|
@ -133,7 +134,7 @@ func (pbs *proxyBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter,
|
|||
if err := pbs.storeLocal(ctx, dgst); err != nil {
|
||||
context.GetLogger(ctx).Errorf("Error committing to storage: %s", err.Error())
|
||||
}
|
||||
pbs.scheduler.AddBlob(dgst.String(), repositoryTTL)
|
||||
pbs.scheduler.AddBlob(dgst, repositoryTTL)
|
||||
}(dgst)
|
||||
|
||||
_, err = pbs.copyContent(ctx, dgst, w)
|
||||
|
@ -169,7 +170,7 @@ func (pbs *proxyBlobStore) Resume(ctx context.Context, id string) (distribution.
|
|||
return nil, distribution.ErrUnsupported
|
||||
}
|
||||
|
||||
func (pbs *proxyBlobStore) Mount(ctx context.Context, sourceRepo string, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
func (pbs *proxyBlobStore) Mount(ctx context.Context, sourceRepo reference.Named, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
return distribution.Descriptor{}, distribution.ErrUnsupported
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||
|
@ -114,6 +115,11 @@ func (te *testEnv) RemoteStats() *map[string]int {
|
|||
|
||||
// Populate remote store and record the digests
|
||||
func makeTestEnv(t *testing.T, name string) *testEnv {
|
||||
nameRef, err := reference.ParseNamed(name)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse reference: %s", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
truthDir, err := ioutil.TempDir("", "truth")
|
||||
|
@ -131,7 +137,7 @@ func makeTestEnv(t *testing.T, name string) *testEnv {
|
|||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
localRepo, err := localRegistry.Repository(ctx, name)
|
||||
localRepo, err := localRegistry.Repository(ctx, nameRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
@ -140,7 +146,7 @@ func makeTestEnv(t *testing.T, name string) *testEnv {
|
|||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
truthRepo, err := truthRegistry.Repository(ctx, name)
|
||||
truthRepo, err := truthRegistry.Repository(ctx, nameRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ type proxyManifestStore struct {
|
|||
ctx context.Context
|
||||
localManifests distribution.ManifestService
|
||||
remoteManifests distribution.ManifestService
|
||||
repositoryName string
|
||||
repositoryName reference.Named
|
||||
scheduler *scheduler.TTLExpirationScheduler
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ func (pms proxyManifestStore) Get(ctx context.Context, dgst digest.Digest, optio
|
|||
pms.scheduler.AddManifest(pms.repositoryName, repositoryTTL)
|
||||
|
||||
// Ensure the manifest blob is cleaned up
|
||||
pms.scheduler.AddBlob(dgst.String(), repositoryTTL)
|
||||
pms.scheduler.AddBlob(dgst, repositoryTTL)
|
||||
}
|
||||
|
||||
return manifest, err
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/proxy/scheduler"
|
||||
"github.com/docker/distribution/registry/storage"
|
||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||
|
@ -64,12 +65,17 @@ func (sm statsManifest) Put(ctx context.Context, manifest distribution.Manifest,
|
|||
*/
|
||||
|
||||
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
||||
nameRef, err := reference.ParseNamed(name)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse reference: %s", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
truthRepo, err := truthRegistry.Repository(ctx, name)
|
||||
truthRepo, err := truthRegistry.Repository(ctx, nameRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
@ -91,7 +97,7 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE
|
|||
if err != nil {
|
||||
t.Fatalf("error creating registry: %v", err)
|
||||
}
|
||||
localRepo, err := localRegistry.Repository(ctx, name)
|
||||
localRepo, err := localRegistry.Repository(ctx, nameRef)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting repo: %v", err)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/configuration"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
|
@ -71,9 +72,9 @@ func (pr *proxyingRegistry) Repositories(ctx context.Context, repos []string, la
|
|||
return pr.embedded.Repositories(ctx, repos, last)
|
||||
}
|
||||
|
||||
func (pr *proxyingRegistry) Repository(ctx context.Context, name string) (distribution.Repository, error) {
|
||||
func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named) (distribution.Repository, error) {
|
||||
tr := transport.NewTransport(http.DefaultTransport,
|
||||
auth.NewAuthorizer(pr.challengeManager, auth.NewTokenHandler(http.DefaultTransport, pr.credentialStore, name, "pull")))
|
||||
auth.NewAuthorizer(pr.challengeManager, auth.NewTokenHandler(http.DefaultTransport, pr.credentialStore, name.Name(), "pull")))
|
||||
|
||||
localRepo, err := pr.embedded.Repository(ctx, name)
|
||||
if err != nil {
|
||||
|
@ -121,7 +122,7 @@ func (pr *proxyingRegistry) Repository(ctx context.Context, name string) (distri
|
|||
type proxiedRepository struct {
|
||||
blobStore distribution.BlobStore
|
||||
manifests distribution.ManifestService
|
||||
name string
|
||||
name reference.Named
|
||||
tags distribution.TagService
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ func (pr *proxiedRepository) Blobs(ctx context.Context) distribution.BlobStore {
|
|||
return pr.blobStore
|
||||
}
|
||||
|
||||
func (pr *proxiedRepository) Name() string {
|
||||
func (pr *proxiedRepository) Name() reference.Named {
|
||||
return pr.name
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/storage/driver"
|
||||
)
|
||||
|
||||
|
@ -80,19 +82,19 @@ func (ttles *TTLExpirationScheduler) OnManifestExpire(f expiryFunc) {
|
|||
}
|
||||
|
||||
// AddBlob schedules a blob cleanup after ttl expires
|
||||
func (ttles *TTLExpirationScheduler) AddBlob(dgst string, ttl time.Duration) error {
|
||||
func (ttles *TTLExpirationScheduler) AddBlob(dgst digest.Digest, ttl time.Duration) error {
|
||||
ttles.Lock()
|
||||
defer ttles.Unlock()
|
||||
|
||||
if ttles.stopped {
|
||||
return fmt.Errorf("scheduler not started")
|
||||
}
|
||||
ttles.add(dgst, ttl, entryTypeBlob)
|
||||
ttles.add(dgst.String(), ttl, entryTypeBlob)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddManifest schedules a manifest cleanup after ttl expires
|
||||
func (ttles *TTLExpirationScheduler) AddManifest(repoName string, ttl time.Duration) error {
|
||||
func (ttles *TTLExpirationScheduler) AddManifest(repoName reference.Named, ttl time.Duration) error {
|
||||
ttles.Lock()
|
||||
defer ttles.Unlock()
|
||||
|
||||
|
@ -100,7 +102,7 @@ func (ttles *TTLExpirationScheduler) AddManifest(repoName string, ttl time.Durat
|
|||
return fmt.Errorf("scheduler not started")
|
||||
}
|
||||
|
||||
ttles.add(repoName, ttl, entryTypeManifest)
|
||||
ttles.add(repoName.Name(), ttl, entryTypeManifest)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||
}
|
||||
|
||||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
driver := inmemory.New()
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
|
@ -209,7 +209,7 @@ func TestSimpleBlobUpload(t *testing.T) {
|
|||
// other tests.
|
||||
func TestSimpleBlobRead(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
driver := inmemory.New()
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
|
@ -320,8 +320,8 @@ func TestBlobMount(t *testing.T) {
|
|||
}
|
||||
|
||||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
sourceImageName := "foo/source"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
sourceImageName, _ := reference.ParseNamed("foo/source")
|
||||
driver := inmemory.New()
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
|
@ -378,11 +378,7 @@ func TestBlobMount(t *testing.T) {
|
|||
t.Fatalf("unexpected non-error stating unmounted blob: %v", desc)
|
||||
}
|
||||
|
||||
namedRef, err := reference.ParseNamed(sourceRepository.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
canonicalRef, err := reference.WithDigest(namedRef, desc.Digest)
|
||||
canonicalRef, err := reference.WithDigest(sourceRepository.Name(), desc.Digest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -476,7 +472,7 @@ func TestBlobMount(t *testing.T) {
|
|||
// TestLayerUploadZeroLength uploads zero-length
|
||||
func TestLayerUploadZeroLength(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "foo/bar"
|
||||
imageName, _ := reference.ParseNamed("foo/bar")
|
||||
driver := inmemory.New()
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect)
|
||||
if err != nil {
|
||||
|
|
|
@ -326,7 +326,7 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
|
|||
// resources are already not present, no error will be returned.
|
||||
func (bw *blobWriter) removeResources(ctx context.Context) error {
|
||||
dataPath, err := pathFor(uploadDataPathSpec{
|
||||
name: bw.blobStore.repository.Name(),
|
||||
name: bw.blobStore.repository.Name().Name(),
|
||||
id: bw.id,
|
||||
})
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ type hashStateEntry struct {
|
|||
// getStoredHashStates returns a slice of hashStateEntries for this upload.
|
||||
func (bw *blobWriter) getStoredHashStates(ctx context.Context) ([]hashStateEntry, error) {
|
||||
uploadHashStatePathPrefix, err := pathFor(uploadHashStatePathSpec{
|
||||
name: bw.blobStore.repository.Name(),
|
||||
name: bw.blobStore.repository.Name().String(),
|
||||
id: bw.id,
|
||||
alg: bw.digester.Digest().Algorithm(),
|
||||
list: true,
|
||||
|
@ -159,7 +159,7 @@ func (bw *blobWriter) storeHashState(ctx context.Context) error {
|
|||
}
|
||||
|
||||
uploadHashStatePath, err := pathFor(uploadHashStatePathSpec{
|
||||
name: bw.blobStore.repository.Name(),
|
||||
name: bw.blobStore.repository.Name().String(),
|
||||
id: bw.id,
|
||||
alg: bw.digester.Digest().Algorithm(),
|
||||
offset: int64(h.Len()),
|
||||
|
|
|
@ -142,7 +142,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context, options ...distribution.
|
|||
}
|
||||
|
||||
if opts.Mount.ShouldMount {
|
||||
desc, err := lbs.mount(ctx, opts.Mount.From.Name(), opts.Mount.From.Digest())
|
||||
desc, err := lbs.mount(ctx, opts.Mount.From, opts.Mount.From.Digest())
|
||||
if err == nil {
|
||||
// Mount successful, no need to initiate an upload session
|
||||
return nil, distribution.ErrBlobMounted{From: opts.Mount.From, Descriptor: desc}
|
||||
|
@ -153,7 +153,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context, options ...distribution.
|
|||
startedAt := time.Now().UTC()
|
||||
|
||||
path, err := pathFor(uploadDataPathSpec{
|
||||
name: lbs.repository.Name(),
|
||||
name: lbs.repository.Name().Name(),
|
||||
id: uuid,
|
||||
})
|
||||
|
||||
|
@ -162,7 +162,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context, options ...distribution.
|
|||
}
|
||||
|
||||
startedAtPath, err := pathFor(uploadStartedAtPathSpec{
|
||||
name: lbs.repository.Name(),
|
||||
name: lbs.repository.Name().Name(),
|
||||
id: uuid,
|
||||
})
|
||||
|
||||
|
@ -182,7 +182,7 @@ func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution
|
|||
context.GetLogger(ctx).Debug("(*linkedBlobStore).Resume")
|
||||
|
||||
startedAtPath, err := pathFor(uploadStartedAtPathSpec{
|
||||
name: lbs.repository.Name(),
|
||||
name: lbs.repository.Name().Name(),
|
||||
id: id,
|
||||
})
|
||||
|
||||
|
@ -206,7 +206,7 @@ func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution
|
|||
}
|
||||
|
||||
path, err := pathFor(uploadDataPathSpec{
|
||||
name: lbs.repository.Name(),
|
||||
name: lbs.repository.Name().Name(),
|
||||
id: id,
|
||||
})
|
||||
|
||||
|
@ -236,7 +236,7 @@ func (lbs *linkedBlobStore) Delete(ctx context.Context, dgst digest.Digest) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
func (lbs *linkedBlobStore) mount(ctx context.Context, sourceRepo string, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
func (lbs *linkedBlobStore) mount(ctx context.Context, sourceRepo reference.Named, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
repo, err := lbs.registry.Repository(ctx, sourceRepo)
|
||||
if err != nil {
|
||||
return distribution.Descriptor{}, err
|
||||
|
@ -298,7 +298,7 @@ func (lbs *linkedBlobStore) linkBlob(ctx context.Context, canonical distribution
|
|||
}
|
||||
seenDigests[dgst] = struct{}{}
|
||||
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name().Name(), dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ func (lbs *linkedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (dis
|
|||
func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) (err error) {
|
||||
// clear any possible existence of a link described in linkPathFns
|
||||
for _, linkPathFn := range lbs.linkPathFns {
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name().Name(), dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) (er
|
|||
// linkPathFuncs to let us try a few different paths before returning not
|
||||
// found.
|
||||
func (lbs *linkedBlobStatter) resolveWithLinkFunc(ctx context.Context, dgst digest.Digest, linkPathFn linkPathFunc) (digest.Digest, error) {
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
|
||||
blobLinkPath, err := linkPathFn(lbs.repository.Name().Name(), dgst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func (ms *manifestStore) Get(ctx context.Context, dgst digest.Digest, options ..
|
|||
if err != nil {
|
||||
if err == distribution.ErrBlobUnknown {
|
||||
return nil, distribution.ErrManifestUnknownRevision{
|
||||
Name: ms.repository.Name(),
|
||||
Name: ms.repository.Name().Name(),
|
||||
Revision: dgst,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/storage/cache/memory"
|
||||
"github.com/docker/distribution/registry/storage/driver"
|
||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
|
@ -23,11 +24,11 @@ type manifestStoreTestEnv struct {
|
|||
driver driver.StorageDriver
|
||||
registry distribution.Namespace
|
||||
repository distribution.Repository
|
||||
name string
|
||||
name reference.Named
|
||||
tag string
|
||||
}
|
||||
|
||||
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
|
||||
func newManifestStoreTestEnv(t *testing.T, name reference.Named, tag string) *manifestStoreTestEnv {
|
||||
ctx := context.Background()
|
||||
driver := inmemory.New()
|
||||
registry, err := NewRegistry(ctx, driver, BlobDescriptorCacheProvider(
|
||||
|
@ -52,7 +53,8 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE
|
|||
}
|
||||
|
||||
func TestManifestStorage(t *testing.T) {
|
||||
env := newManifestStoreTestEnv(t, "foo/bar", "thetag")
|
||||
repoName, _ := reference.ParseNamed("foo/bar")
|
||||
env := newManifestStoreTestEnv(t, repoName, "thetag")
|
||||
ctx := context.Background()
|
||||
ms, err := env.repository.Manifests(ctx)
|
||||
if err != nil {
|
||||
|
@ -63,7 +65,7 @@ func TestManifestStorage(t *testing.T) {
|
|||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: env.name,
|
||||
Name: env.name.Name(),
|
||||
Tag: env.tag,
|
||||
}
|
||||
|
||||
|
|
|
@ -107,18 +107,11 @@ func (reg *registry) Scope() distribution.Scope {
|
|||
// Repository returns an instance of the repository tied to the registry.
|
||||
// Instances should not be shared between goroutines but are cheap to
|
||||
// allocate. In general, they should be request scoped.
|
||||
func (reg *registry) Repository(ctx context.Context, canonicalName string) (distribution.Repository, error) {
|
||||
if _, err := reference.ParseNamed(canonicalName); err != nil {
|
||||
return nil, distribution.ErrRepositoryNameInvalid{
|
||||
Name: canonicalName,
|
||||
Reason: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (reg *registry) Repository(ctx context.Context, canonicalName reference.Named) (distribution.Repository, error) {
|
||||
var descriptorCache distribution.BlobDescriptorService
|
||||
if reg.blobDescriptorCacheProvider != nil {
|
||||
var err error
|
||||
descriptorCache, err = reg.blobDescriptorCacheProvider.RepositoryScoped(canonicalName)
|
||||
descriptorCache, err = reg.blobDescriptorCacheProvider.RepositoryScoped(canonicalName.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -136,12 +129,12 @@ func (reg *registry) Repository(ctx context.Context, canonicalName string) (dist
|
|||
type repository struct {
|
||||
*registry
|
||||
ctx context.Context
|
||||
name string
|
||||
name reference.Named
|
||||
descriptorCache distribution.BlobDescriptorService
|
||||
}
|
||||
|
||||
// Name returns the name of the repository.
|
||||
func (repo *repository) Name() string {
|
||||
func (repo *repository) Name() reference.Named {
|
||||
return repo.name
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ type signatureStore struct {
|
|||
|
||||
func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) {
|
||||
signaturesPath, err := pathFor(manifestSignaturesPathSpec{
|
||||
name: s.repository.Name(),
|
||||
name: s.repository.Name().Name(),
|
||||
revision: dgst,
|
||||
})
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ func (ts *tagStore) All(ctx context.Context) ([]string, error) {
|
|||
var tags []string
|
||||
|
||||
pathSpec, err := pathFor(manifestTagPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
})
|
||||
if err != nil {
|
||||
return tags, err
|
||||
|
@ -36,7 +36,7 @@ func (ts *tagStore) All(ctx context.Context) ([]string, error) {
|
|||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case storagedriver.PathNotFoundError:
|
||||
return tags, distribution.ErrRepositoryUnknown{Name: ts.repository.Name()}
|
||||
return tags, distribution.ErrRepositoryUnknown{Name: ts.repository.Name().Name()}
|
||||
default:
|
||||
return tags, err
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func (ts *tagStore) All(ctx context.Context) ([]string, error) {
|
|||
// exists returns true if the specified manifest tag exists in the repository.
|
||||
func (ts *tagStore) exists(ctx context.Context, tag string) (bool, error) {
|
||||
tagPath, err := pathFor(manifestTagCurrentPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
tag: tag,
|
||||
})
|
||||
|
||||
|
@ -73,7 +73,7 @@ func (ts *tagStore) exists(ctx context.Context, tag string) (bool, error) {
|
|||
// the current tag. The digest must point to a manifest.
|
||||
func (ts *tagStore) Tag(ctx context.Context, tag string, desc distribution.Descriptor) error {
|
||||
currentPath, err := pathFor(manifestTagCurrentPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
tag: tag,
|
||||
})
|
||||
|
||||
|
@ -95,7 +95,7 @@ func (ts *tagStore) Tag(ctx context.Context, tag string, desc distribution.Descr
|
|||
// resolve the current revision for name and tag.
|
||||
func (ts *tagStore) Get(ctx context.Context, tag string) (distribution.Descriptor, error) {
|
||||
currentPath, err := pathFor(manifestTagCurrentPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
tag: tag,
|
||||
})
|
||||
|
||||
|
@ -119,7 +119,7 @@ func (ts *tagStore) Get(ctx context.Context, tag string) (distribution.Descripto
|
|||
// Untag removes the tag association
|
||||
func (ts *tagStore) Untag(ctx context.Context, tag string) error {
|
||||
tagPath, err := pathFor(manifestTagPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
tag: tag,
|
||||
})
|
||||
|
||||
|
@ -172,7 +172,7 @@ func (ts *tagStore) Lookup(ctx context.Context, desc distribution.Descriptor) ([
|
|||
var tags []string
|
||||
for _, tag := range allTags {
|
||||
tagLinkPathSpec := manifestTagCurrentPathSpec{
|
||||
name: ts.repository.Name(),
|
||||
name: ts.repository.Name().Name(),
|
||||
tag: tag,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
)
|
||||
|
||||
|
@ -21,7 +22,8 @@ func testTagStore(t *testing.T) *tagsTestEnv {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
repo, err := reg.Repository(ctx, "a/b")
|
||||
repoRef, _ := reference.ParseNamed("a/b")
|
||||
repo, err := reg.Repository(ctx, repoRef)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue