Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit c8d277d

Browse files
committed
Add schema2 push support
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
1 parent 94726f7 commit c8d277d

File tree

2 files changed

+66
-60
lines changed

2 files changed

+66
-60
lines changed

distribution/push_v2.go

+66-53
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package distribution
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"sync"
@@ -13,6 +14,7 @@ import (
1314
"github.com/docker/distribution/registry/client"
1415
"github.com/docker/docker/distribution/metadata"
1516
"github.com/docker/docker/distribution/xfer"
17+
"github.com/docker/docker/image"
1618
"github.com/docker/docker/layer"
1719
"github.com/docker/docker/pkg/ioutils"
1820
"github.com/docker/docker/pkg/progress"
@@ -73,44 +75,41 @@ func (p *v2Pusher) Push(ctx context.Context) (err error) {
7375
}
7476

7577
func (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) {
76-
var associations []reference.Association
77-
if _, isTagged := p.ref.(reference.NamedTagged); isTagged {
78+
if namedTagged, isNamedTagged := p.ref.(reference.NamedTagged); isNamedTagged {
7879
imageID, err := p.config.ReferenceStore.Get(p.ref)
7980
if err != nil {
8081
return fmt.Errorf("tag does not exist: %s", p.ref.String())
8182
}
8283

83-
associations = []reference.Association{
84-
{
85-
Ref: p.ref,
86-
ImageID: imageID,
87-
},
88-
}
89-
} else {
90-
// Pull all tags
91-
associations = p.config.ReferenceStore.ReferencesByName(p.ref)
92-
}
93-
if err != nil {
94-
return fmt.Errorf("error getting tags for %s: %s", p.repoInfo.Name(), err)
84+
return p.pushV2Tag(ctx, namedTagged, imageID)
9585
}
96-
if len(associations) == 0 {
97-
return fmt.Errorf("no tags to push for %s", p.repoInfo.Name())
86+
87+
if !reference.IsNameOnly(p.ref) {
88+
return errors.New("cannot push a digest reference")
9889
}
9990

100-
for _, association := range associations {
101-
if err := p.pushV2Tag(ctx, association); err != nil {
102-
return err
91+
// Pull all tags
92+
pushed := 0
93+
for _, association := range p.config.ReferenceStore.ReferencesByName(p.ref) {
94+
if namedTagged, isNamedTagged := association.Ref.(reference.NamedTagged); isNamedTagged {
95+
pushed++
96+
if err := p.pushV2Tag(ctx, namedTagged, association.ImageID); err != nil {
97+
return err
98+
}
10399
}
104100
}
105101

102+
if pushed == 0 {
103+
return fmt.Errorf("no tags to push for %s", p.repoInfo.Name())
104+
}
105+
106106
return nil
107107
}
108108

109-
func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Association) error {
110-
ref := association.Ref
109+
func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, imageID image.ID) error {
111110
logrus.Debugf("Pushing repository: %s", ref.String())
112111

113-
img, err := p.config.ImageStore.Get(association.ImageID)
112+
img, err := p.config.ImageStore.Get(imageID)
114113
if err != nil {
115114
return fmt.Errorf("could not find image from tag %s: %v", ref.String(), err)
116115
}
@@ -149,50 +148,64 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Associat
149148
return err
150149
}
151150

152-
var tag string
153-
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
154-
tag = tagged.Tag()
155-
}
156-
builder := schema1.NewConfigManifestBuilder(p.repo.Blobs(ctx), p.config.TrustKey, p.repo.Name(), tag, img.RawJSON())
157-
158-
// descriptors is in reverse order; iterate backwards to get references
159-
// appended in the right order.
160-
for i := len(descriptors) - 1; i >= 0; i-- {
161-
if err := builder.AppendReference(descriptors[i].(*v2PushDescriptor)); err != nil {
162-
return err
163-
}
164-
}
165-
166-
manifest, err := builder.Build(ctx)
151+
// Try schema2 first
152+
builder := schema2.NewManifestBuilder(p.repo.Blobs(ctx), img.RawJSON())
153+
manifest, err := manifestFromBuilder(ctx, builder, descriptors)
167154
if err != nil {
168155
return err
169156
}
170157

171-
manifestDigest, manifestSize, err := digestFromManifest(manifest.(*schema1.SignedManifest), ref)
158+
manSvc, err := p.repo.Manifests(ctx)
172159
if err != nil {
173160
return err
174161
}
175-
if manifestDigest != "" {
176-
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
177-
progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", tagged.Tag(), manifestDigest, manifestSize)
178-
// Signal digest to the trust client so it can sign the
179-
// push, if appropriate.
180-
progress.Aux(p.config.ProgressOutput, PushResult{Tag: tagged.Tag(), Digest: manifestDigest, Size: manifestSize})
162+
163+
putOptions := []distribution.ManifestServiceOption{client.WithTag(ref.Tag())}
164+
if _, err = manSvc.Put(ctx, manifest, putOptions...); err != nil {
165+
logrus.Warnf("failed to upload schema2 manifest: %v - falling back to schema1", err)
166+
167+
builder = schema1.NewConfigManifestBuilder(p.repo.Blobs(ctx), p.config.TrustKey, p.repo.Name(), ref.Tag(), img.RawJSON())
168+
manifest, err = manifestFromBuilder(ctx, builder, descriptors)
169+
if err != nil {
170+
return err
171+
}
172+
173+
if _, err = manSvc.Put(ctx, manifest, putOptions...); err != nil {
174+
return err
181175
}
182176
}
183177

184-
manSvc, err := p.repo.Manifests(ctx)
185-
if err != nil {
186-
return err
178+
var canonicalManifest []byte
179+
180+
switch v := manifest.(type) {
181+
case *schema1.SignedManifest:
182+
canonicalManifest = v.Canonical
183+
case *schema2.DeserializedManifest:
184+
_, canonicalManifest, err = v.Payload()
185+
if err != nil {
186+
return err
187+
}
187188
}
188189

189-
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
190-
_, err = manSvc.Put(ctx, manifest, client.WithTag(tagged.Tag()))
191-
} else {
192-
_, err = manSvc.Put(ctx, manifest)
190+
manifestDigest := digest.FromBytes(canonicalManifest)
191+
progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", ref.Tag(), manifestDigest, len(canonicalManifest))
192+
// Signal digest to the trust client so it can sign the
193+
// push, if appropriate.
194+
progress.Aux(p.config.ProgressOutput, PushResult{Tag: ref.Tag(), Digest: manifestDigest, Size: len(canonicalManifest)})
195+
196+
return nil
197+
}
198+
199+
func manifestFromBuilder(ctx context.Context, builder distribution.ManifestBuilder, descriptors []xfer.UploadDescriptor) (distribution.Manifest, error) {
200+
// descriptors is in reverse order; iterate backwards to get references
201+
// appended in the right order.
202+
for i := len(descriptors) - 1; i >= 0; i-- {
203+
if err := builder.AppendReference(descriptors[i].(*v2PushDescriptor)); err != nil {
204+
return nil, err
205+
}
193206
}
194-
// FIXME create a tag
195-
return err
207+
208+
return builder.Build(ctx)
196209
}
197210

198211
type v2PushDescriptor struct {

distribution/registry.go

-7
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@ import (
99
"time"
1010

1111
"github.com/docker/distribution"
12-
"github.com/docker/distribution/digest"
13-
"github.com/docker/distribution/manifest/schema1"
1412
"github.com/docker/distribution/registry/api/errcode"
1513
"github.com/docker/distribution/registry/client"
1614
"github.com/docker/distribution/registry/client/auth"
1715
"github.com/docker/distribution/registry/client/transport"
1816
"github.com/docker/docker/distribution/xfer"
19-
"github.com/docker/docker/reference"
2017
"github.com/docker/docker/registry"
2118
"github.com/docker/engine-api/types"
2219
"golang.org/x/net/context"
@@ -124,10 +121,6 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
124121
return repo, foundVersion, err
125122
}
126123

127-
func digestFromManifest(m *schema1.SignedManifest, name reference.Named) (digest.Digest, int, error) {
128-
return digest.FromBytes(m.Canonical), len(m.Canonical), nil
129-
}
130-
131124
type existingTokenHandler struct {
132125
token string
133126
}

0 commit comments

Comments
 (0)