github.com/uber/kraken@v0.1.4/lib/dockerregistry/storage_driver.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 22 "github.com/uber/kraken/lib/dockerregistry/transfer" 23 "github.com/uber/kraken/lib/store" 24 "github.com/uber/kraken/utils/log" 25 26 "github.com/docker/distribution/registry/storage/driver" 27 "github.com/docker/distribution/registry/storage/driver/factory" 28 "github.com/uber-go/tally" 29 ) 30 31 // The path layout in the storage backend is roughly as follows: 32 // 33 // <root>/v2 34 // -> repositories/ 35 // -><name>/ 36 // -> _manifests/ 37 // revisions 38 // -> <manifest digest path> 39 // -> link 40 // tags/<tag> 41 // -> current/link 42 // -> index 43 // -> <algorithm>/<hex digest>/link 44 // -> _layers/ 45 // <layer links to blob store> 46 // -> _uploads/<id> 47 // data 48 // startedat 49 // hashstates/<algorithm>/<offset> 50 // -> blobs/<algorithm> 51 // <split directory content addressable storage> 52 53 // Name of storage driver. 54 const Name = "kraken" 55 56 func init() { 57 factory.Register(Name, &krakenStorageDriverFactory{}) 58 } 59 60 // InvalidRequestError implements error and contains the path that is not supported 61 type InvalidRequestError struct { 62 path string 63 } 64 65 func (e InvalidRequestError) Error() string { 66 return fmt.Sprintf("invalid request: %s", e.path) 67 } 68 69 type krakenStorageDriverFactory struct{} 70 71 func getParam(params map[string]interface{}, name string) interface{} { 72 p, ok := params[name] 73 if !ok || p == nil { 74 log.Fatalf("Required parameter %s not found", name) 75 } 76 return p 77 } 78 79 func (factory *krakenStorageDriverFactory) Create( 80 params map[string]interface{}) (driver.StorageDriver, error) { 81 82 // Common parameters. 83 constructor := getParam(params, "constructor").(string) 84 config := getParam(params, "config").(Config) 85 transferer := getParam(params, "transferer").(transfer.ImageTransferer) 86 metrics := getParam(params, "metrics").(tally.Scope) 87 88 switch constructor { 89 case _rw: 90 castore := getParam(params, "castore").(*store.CAStore) 91 return NewReadWriteStorageDriver(config, castore, transferer, metrics), nil 92 case _ro: 93 blobstore := getParam(params, "blobstore").(BlobStore) 94 return NewReadOnlyStorageDriver(config, blobstore, transferer, metrics), nil 95 default: 96 return nil, fmt.Errorf("unknown constructor %s", constructor) 97 } 98 } 99 100 // KrakenStorageDriver is a storage driver 101 type KrakenStorageDriver struct { 102 config Config 103 transferer transfer.ImageTransferer 104 blobs *blobs 105 uploads uploads 106 manifests *manifests 107 metrics tally.Scope 108 } 109 110 // NewReadWriteStorageDriver creates a KrakenStorageDriver which can push / pull blobs. 111 func NewReadWriteStorageDriver( 112 config Config, 113 cas *store.CAStore, 114 transferer transfer.ImageTransferer, 115 metrics tally.Scope) *KrakenStorageDriver { 116 117 return &KrakenStorageDriver{ 118 config: config, 119 transferer: transferer, 120 blobs: newBlobs(cas, transferer), 121 uploads: newCASUploads(cas, transferer), 122 manifests: newManifests(transferer), 123 metrics: metrics, 124 } 125 } 126 127 // NewReadOnlyStorageDriver creates a KrakenStorageDriver which can only pull blobs. 128 func NewReadOnlyStorageDriver( 129 config Config, 130 bs BlobStore, 131 transferer transfer.ImageTransferer, 132 metrics tally.Scope) *KrakenStorageDriver { 133 134 return &KrakenStorageDriver{ 135 config: config, 136 transferer: transferer, 137 blobs: newBlobs(bs, transferer), 138 uploads: disabledUploads{}, 139 manifests: newManifests(transferer), 140 metrics: metrics, 141 } 142 } 143 144 // Name returns driver namae 145 func (d *KrakenStorageDriver) Name() string { 146 return Name 147 } 148 149 // GetContent returns content in the path 150 // sample path: /docker/registry/v2/repositories/external/ubuntu/_layers/sha256/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4/link 151 func (d *KrakenStorageDriver) GetContent(ctx context.Context, path string) (data []byte, err error) { 152 log.Debugf("(*KrakenStorageDriver).GetContent %s", path) 153 pathType, pathSubType, err := ParsePath(path) 154 if err != nil { 155 return nil, err 156 } 157 158 switch pathType { 159 case _manifests: 160 return d.manifests.getDigest(path, pathSubType) 161 case _uploads: 162 return d.uploads.getContent(path, pathSubType) 163 case _layers: 164 return d.blobs.getDigest(path) 165 case _blobs: 166 return d.blobs.getContent(ctx, path) 167 } 168 return nil, InvalidRequestError{path} 169 } 170 171 // Reader returns a reader of path at offset 172 func (d *KrakenStorageDriver) Reader(ctx context.Context, path string, offset int64) (reader io.ReadCloser, err error) { 173 log.Debugf("(*KrakenStorageDriver).Reader %s", path) 174 pathType, pathSubType, err := ParsePath(path) 175 if err != nil { 176 return nil, err 177 } 178 179 switch pathType { 180 case _uploads: 181 return d.uploads.reader(path, pathSubType, offset) 182 case _blobs: 183 return d.blobs.reader(ctx, path, offset) 184 default: 185 return nil, InvalidRequestError{path} 186 } 187 } 188 189 // PutContent writes content to path 190 func (d *KrakenStorageDriver) PutContent(ctx context.Context, path string, content []byte) error { 191 log.Debugf("(*KrakenStorageDriver).PutContent %s", path) 192 pathType, pathSubType, err := ParsePath(path) 193 if err != nil { 194 return err 195 } 196 197 switch pathType { 198 case _manifests: 199 return d.manifests.putContent(path, pathSubType) 200 case _uploads: 201 return d.uploads.putContent(path, pathSubType, content) 202 case _layers: 203 // noop 204 return nil 205 case _blobs: 206 return d.uploads.putBlobContent(path, content) 207 default: 208 return InvalidRequestError{path} 209 } 210 } 211 212 // Writer returns a writer of path 213 func (d *KrakenStorageDriver) Writer(ctx context.Context, path string, append bool) (driver.FileWriter, error) { 214 log.Debugf("(*KrakenStorageDriver).Writer %s", path) 215 pathType, pathSubType, err := ParsePath(path) 216 if err != nil { 217 return nil, err 218 } 219 220 switch pathType { 221 case _uploads: 222 w, err := d.uploads.writer(path, pathSubType) 223 if err != nil { 224 return nil, err 225 } 226 if append { 227 if _, err := w.Seek(0, io.SeekEnd); err != nil { 228 return nil, err 229 } 230 } 231 return w, nil 232 default: 233 return nil, InvalidRequestError{path} 234 } 235 } 236 237 // Stat returns fileinfo of path 238 func (d *KrakenStorageDriver) Stat(ctx context.Context, path string) (driver.FileInfo, error) { 239 log.Debugf("(*KrakenStorageDriver).Stat %s", path) 240 pathType, _, err := ParsePath(path) 241 if err != nil { 242 return nil, err 243 } 244 245 switch pathType { 246 case _uploads: 247 return d.uploads.stat(path) 248 case _blobs: 249 return d.blobs.stat(ctx, path) 250 case _manifests: 251 return d.manifests.stat(path) 252 default: 253 return nil, InvalidRequestError{path} 254 } 255 } 256 257 // List returns a list of content given path 258 func (d *KrakenStorageDriver) List(ctx context.Context, path string) ([]string, error) { 259 log.Debugf("(*KrakenStorageDriver).List %s", path) 260 pathType, pathSubType, err := ParsePath(path) 261 if err != nil { 262 return nil, err 263 } 264 265 switch pathType { 266 case _uploads: 267 return d.uploads.list(path, pathSubType) 268 case _manifests: 269 return d.manifests.list(path) 270 default: 271 return nil, InvalidRequestError{path} 272 } 273 } 274 275 // Move moves sourcePath to destPath 276 func (d *KrakenStorageDriver) Move(ctx context.Context, sourcePath string, destPath string) error { 277 log.Debugf("(*KrakenStorageDriver).Move %s %s", sourcePath, destPath) 278 pathType, _, err := ParsePath(sourcePath) 279 if err != nil { 280 return err 281 } 282 283 switch pathType { 284 case _uploads: 285 return d.uploads.move(sourcePath, destPath) 286 default: 287 return InvalidRequestError{sourcePath + " to " + destPath} 288 } 289 } 290 291 // Delete deletes path 292 func (d *KrakenStorageDriver) Delete(ctx context.Context, path string) error { 293 log.Debugf("(*KrakenStorageDriver).Delete %s", path) 294 return driver.PathNotFoundError{ 295 DriverName: "p2p", 296 Path: path, 297 } 298 } 299 300 // URLFor returns url for path 301 func (d *KrakenStorageDriver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) { 302 log.Debugf("(*KrakenStorageDriver).URLFor %s", path) 303 return "", fmt.Errorf("Not implemented") 304 } 305 306 // Walk is not implemented. 307 func (d *KrakenStorageDriver) Walk(ctx context.Context, path string, f driver.WalkFn) error { 308 return errors.New("walk not implemented") 309 }