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  }