github.com/uber/kraken@v0.1.4/lib/dockerregistry/blobs.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package dockerregistry 15 16 import ( 17 "context" 18 "errors" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "time" 24 25 "github.com/uber/kraken/lib/dockerregistry/transfer" 26 "github.com/uber/kraken/lib/store" 27 28 storagedriver "github.com/docker/distribution/registry/storage/driver" 29 ) 30 31 // BlobStore defines cache file accessors. 32 type BlobStore interface { 33 GetCacheFileStat(name string) (os.FileInfo, error) 34 GetCacheFileReader(name string) (store.FileReader, error) 35 } 36 37 type blobs struct { 38 bs BlobStore 39 transferer transfer.ImageTransferer 40 } 41 42 func newBlobs(bs BlobStore, transferer transfer.ImageTransferer) *blobs { 43 return &blobs{bs, transferer} 44 } 45 46 // getDigest returns blob digest given a blob path. 47 func (b *blobs) getDigest(path string) ([]byte, error) { 48 digest, err := GetLayerDigest(path) 49 if err != nil { 50 return nil, err 51 } 52 53 return []byte(digest.String()), nil 54 } 55 56 func (b *blobs) stat(ctx context.Context, path string) (storagedriver.FileInfo, error) { 57 repo, err := parseRepo(ctx) 58 if err != nil { 59 return nil, fmt.Errorf("parse repo %s: %s", path, err) 60 } 61 digest, err := GetBlobDigest(path) 62 if err != nil { 63 return nil, err 64 } 65 bi, err := b.transferer.Stat(repo, digest) 66 if err != nil { 67 if err == transfer.ErrBlobNotFound { 68 return nil, storagedriver.PathNotFoundError{ 69 DriverName: "kraken", 70 Path: digest.Hex(), 71 } 72 } 73 return nil, fmt.Errorf("transferer stat: %s", err) 74 } 75 // Hacking the path, since kraken storage driver is also the consumer of this info. 76 // Instead of the relative path from root that docker registry expected, just use content hash. 77 return storagedriver.FileInfoInternal{ 78 FileInfoFields: storagedriver.FileInfoFields{ 79 Path: digest.Hex(), 80 Size: bi.Size, 81 ModTime: time.Now(), 82 IsDir: false, 83 }, 84 }, nil 85 } 86 87 func (b *blobs) reader(ctx context.Context, path string, offset int64) (io.ReadCloser, error) { 88 return b.getCacheReaderHelper(ctx, path, offset) 89 } 90 91 func (b *blobs) getContent(ctx context.Context, path string) ([]byte, error) { 92 r, err := b.getCacheReaderHelper(ctx, path, 0) 93 if err != nil { 94 return nil, err 95 } 96 defer r.Close() 97 return ioutil.ReadAll(r) 98 } 99 100 func (b *blobs) getCacheReaderHelper( 101 ctx context.Context, path string, offset int64) (io.ReadCloser, error) { 102 103 repo, err := parseRepo(ctx) 104 if err != nil { 105 return nil, fmt.Errorf("parse repo %s: %s", path, err) 106 } 107 108 digest, err := GetBlobDigest(path) 109 if err != nil { 110 return nil, fmt.Errorf("get layer digest %s: %s", path, err) 111 } 112 113 r, err := b.transferer.Download(repo, digest) 114 if err != nil { 115 if err == transfer.ErrBlobNotFound { 116 return nil, storagedriver.PathNotFoundError{ 117 DriverName: "kraken", 118 Path: digest.Hex(), 119 } 120 } 121 return nil, fmt.Errorf("transferer download: %s", err) 122 } 123 124 if _, err := r.Seek(offset, 0); err != nil { 125 return nil, fmt.Errorf("seek: %s", err) 126 } 127 return r, nil 128 } 129 130 func parseRepo(ctx context.Context) (string, error) { 131 repo, ok := ctx.Value("vars.name").(string) 132 if !ok { 133 return "", errors.New("could not parse vars.name from context") 134 } 135 if repo == "" { 136 return "", errors.New("vars.name is empty") 137 } 138 return repo, nil 139 }