@@ -11,6 +11,10 @@ import (
11
11
"github.com/docker/distribution/uuid"
12
12
)
13
13
14
+ // linkPathFunc describes a function that can resolve a link based on the
15
+ // repository name and digest.
16
+ type linkPathFunc func (pm * pathMapper , name string , dgst digest.Digest ) (string , error )
17
+
14
18
// linkedBlobStore provides a full BlobService that namespaces the blobs to a
15
19
// given repository. Effectively, it manages the links in a given repository
16
20
// that grant access to the global blob store.
@@ -23,11 +27,13 @@ type linkedBlobStore struct {
23
27
deleteEnabled bool
24
28
resumableDigestEnabled bool
25
29
26
- // linkPath allows one to control the repository blob link set to which
27
- // the blob store dispatches. This is required because manifest and layer
28
- // blobs have not yet been fully merged. At some point, this functionality
29
- // should be removed an the blob links folder should be merged.
30
- linkPath func (pm * pathMapper , name string , dgst digest.Digest ) (string , error )
30
+ // linkPathFns specifies one or more path functions allowing one to
31
+ // control the repository blob link set to which the blob store
32
+ // dispatches. This is required because manifest and layer blobs have not
33
+ // yet been fully merged. At some point, this functionality should be
34
+ // removed an the blob links folder should be merged. The first entry is
35
+ // treated as the "canonical" link location and will be used for writes.
36
+ linkPathFns []linkPathFunc
31
37
}
32
38
33
39
var _ distribution.BlobStore = & linkedBlobStore {}
@@ -213,13 +219,16 @@ func (lbs *linkedBlobStore) linkBlob(ctx context.Context, canonical distribution
213
219
// Don't make duplicate links.
214
220
seenDigests := make (map [digest.Digest ]struct {}, len (dgsts ))
215
221
222
+ // only use the first link
223
+ linkPathFn := lbs .linkPathFns [0 ]
224
+
216
225
for _ , dgst := range dgsts {
217
226
if _ , seen := seenDigests [dgst ]; seen {
218
227
continue
219
228
}
220
229
seenDigests [dgst ] = struct {}{}
221
230
222
- blobLinkPath , err := lbs . linkPath (lbs .pm , lbs .repository .Name (), dgst )
231
+ blobLinkPath , err := linkPathFn (lbs .pm , lbs .repository .Name (), dgst )
223
232
if err != nil {
224
233
return err
225
234
}
@@ -236,33 +245,43 @@ type linkedBlobStatter struct {
236
245
* blobStore
237
246
repository distribution.Repository
238
247
239
- // linkPath allows one to control the repository blob link set to which
240
- // the blob store dispatches. This is required because manifest and layer
241
- // blobs have not yet been fully merged. At some point, this functionality
242
- // should be removed an the blob links folder should be merged.
243
- linkPath func (pm * pathMapper , name string , dgst digest.Digest ) (string , error )
248
+ // linkPathFns specifies one or more path functions allowing one to
249
+ // control the repository blob link set to which the blob store
250
+ // dispatches. This is required because manifest and layer blobs have not
251
+ // yet been fully merged. At some point, this functionality should be
252
+ // removed an the blob links folder should be merged. The first entry is
253
+ // treated as the "canonical" link location and will be used for writes.
254
+ linkPathFns []linkPathFunc
244
255
}
245
256
246
257
var _ distribution.BlobDescriptorService = & linkedBlobStatter {}
247
258
248
259
func (lbs * linkedBlobStatter ) Stat (ctx context.Context , dgst digest.Digest ) (distribution.Descriptor , error ) {
249
- blobLinkPath , err := lbs .linkPath (lbs .pm , lbs .repository .Name (), dgst )
250
- if err != nil {
251
- return distribution.Descriptor {}, err
252
- }
260
+ var (
261
+ resolveErr error
262
+ target digest.Digest
263
+ )
264
+
265
+ // try the many link path functions until we get success or an error that
266
+ // is not PathNotFoundError.
267
+ for _ , linkPathFn := range lbs .linkPathFns {
268
+ var err error
269
+ target , err = lbs .resolveWithLinkFunc (ctx , dgst , linkPathFn )
270
+
271
+ if err == nil {
272
+ break // success!
273
+ }
253
274
254
- target , err := lbs .blobStore .readlink (ctx , blobLinkPath )
255
- if err != nil {
256
275
switch err := err .(type ) {
257
276
case driver.PathNotFoundError :
258
- return distribution. Descriptor {}, distribution .ErrBlobUnknown
277
+ resolveErr = distribution .ErrBlobUnknown // move to the next linkPathFn, saving the error
259
278
default :
260
279
return distribution.Descriptor {}, err
261
280
}
281
+ }
262
282
263
- // TODO(stevvooe): For backwards compatibility with data in "_layers", we
264
- // need to hit layerLinkPath, as well. Or, somehow migrate to the new path
265
- // layout.
283
+ if resolveErr != nil {
284
+ return distribution.Descriptor {}, resolveErr
266
285
}
267
286
268
287
if target != dgst {
@@ -276,13 +295,38 @@ func (lbs *linkedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (dis
276
295
return lbs .blobStore .statter .Stat (ctx , target )
277
296
}
278
297
279
- func (lbs * linkedBlobStatter ) Clear (ctx context.Context , dgst digest.Digest ) error {
280
- blobLinkPath , err := lbs .linkPath (lbs .pm , lbs .repository .Name (), dgst )
298
+ func (lbs * linkedBlobStatter ) Clear (ctx context.Context , dgst digest.Digest ) (err error ) {
299
+ // clear any possible existence of a link described in linkPathFns
300
+ for _ , linkPathFn := range lbs .linkPathFns {
301
+ blobLinkPath , err := linkPathFn (lbs .pm , lbs .repository .Name (), dgst )
302
+ if err != nil {
303
+ return err
304
+ }
305
+
306
+ err = lbs .blobStore .driver .Delete (ctx , blobLinkPath )
307
+ if err != nil {
308
+ switch err := err .(type ) {
309
+ case driver.PathNotFoundError :
310
+ continue // just ignore this error and continue
311
+ default :
312
+ return err
313
+ }
314
+ }
315
+ }
316
+
317
+ return nil
318
+ }
319
+
320
+ // resolveTargetWithFunc allows us to read a link to a resource with different
321
+ // linkPathFuncs to let us try a few different paths before returning not
322
+ // found.
323
+ func (lbs * linkedBlobStatter ) resolveWithLinkFunc (ctx context.Context , dgst digest.Digest , linkPathFn linkPathFunc ) (digest.Digest , error ) {
324
+ blobLinkPath , err := linkPathFn (lbs .pm , lbs .repository .Name (), dgst )
281
325
if err != nil {
282
- return err
326
+ return "" , err
283
327
}
284
328
285
- return lbs .blobStore .driver . Delete (ctx , blobLinkPath )
329
+ return lbs .blobStore .readlink (ctx , blobLinkPath )
286
330
}
287
331
288
332
func (lbs * linkedBlobStatter ) SetDescriptor (ctx context.Context , dgst digest.Digest , desc distribution.Descriptor ) error {
@@ -297,5 +341,5 @@ func blobLinkPath(pm *pathMapper, name string, dgst digest.Digest) (string, erro
297
341
298
342
// manifestRevisionLinkPath provides the path to the manifest revision link.
299
343
func manifestRevisionLinkPath (pm * pathMapper , name string , dgst digest.Digest ) (string , error ) {
300
- return pm .path (layerLinkPathSpec {name : name , digest : dgst })
344
+ return pm .path (manifestRevisionLinkPathSpec {name : name , revision : dgst })
301
345
}
0 commit comments