1
1
package distribution
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
5
6
"io"
6
7
"sync"
@@ -13,6 +14,7 @@ import (
13
14
"github.com/docker/distribution/registry/client"
14
15
"github.com/docker/docker/distribution/metadata"
15
16
"github.com/docker/docker/distribution/xfer"
17
+ "github.com/docker/docker/image"
16
18
"github.com/docker/docker/layer"
17
19
"github.com/docker/docker/pkg/ioutils"
18
20
"github.com/docker/docker/pkg/progress"
@@ -73,44 +75,41 @@ func (p *v2Pusher) Push(ctx context.Context) (err error) {
73
75
}
74
76
75
77
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 {
78
79
imageID , err := p .config .ReferenceStore .Get (p .ref )
79
80
if err != nil {
80
81
return fmt .Errorf ("tag does not exist: %s" , p .ref .String ())
81
82
}
82
83
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 )
95
85
}
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" )
98
89
}
99
90
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
+ }
103
99
}
104
100
}
105
101
102
+ if pushed == 0 {
103
+ return fmt .Errorf ("no tags to push for %s" , p .repoInfo .Name ())
104
+ }
105
+
106
106
return nil
107
107
}
108
108
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 {
111
110
logrus .Debugf ("Pushing repository: %s" , ref .String ())
112
111
113
- img , err := p .config .ImageStore .Get (association . ImageID )
112
+ img , err := p .config .ImageStore .Get (imageID )
114
113
if err != nil {
115
114
return fmt .Errorf ("could not find image from tag %s: %v" , ref .String (), err )
116
115
}
@@ -149,50 +148,64 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Associat
149
148
return err
150
149
}
151
150
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 )
167
154
if err != nil {
168
155
return err
169
156
}
170
157
171
- manifestDigest , manifestSize , err := digestFromManifest ( manifest .( * schema1. SignedManifest ), ref )
158
+ manSvc , err := p . repo . Manifests ( ctx )
172
159
if err != nil {
173
160
return err
174
161
}
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
181
175
}
182
176
}
183
177
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
+ }
187
188
}
188
189
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
+ }
193
206
}
194
- // FIXME create a tag
195
- return err
207
+
208
+ return builder . Build ( ctx )
196
209
}
197
210
198
211
type v2PushDescriptor struct {
0 commit comments