...

Source file src/github.com/docker/distribution/registry/storage/driver/base/base.go

Documentation: github.com/docker/distribution/registry/storage/driver/base

     1  // Package base provides a base implementation of the storage driver that can
     2  // be used to implement common checks. The goal is to increase the amount of
     3  // code sharing.
     4  //
     5  // The canonical approach to use this class is to embed in the exported driver
     6  // struct such that calls are proxied through this implementation. First,
     7  // declare the internal driver, as follows:
     8  //
     9  //	type driver struct { ... internal ...}
    10  //
    11  // The resulting type should implement StorageDriver such that it can be the
    12  // target of a Base struct. The exported type can then be declared as follows:
    13  //
    14  //	type Driver struct {
    15  //		Base
    16  //	}
    17  //
    18  // Because Driver embeds Base, it effectively implements Base. If the driver
    19  // needs to intercept a call, before going to base, Driver should implement
    20  // that method. Effectively, Driver can intercept calls before coming in and
    21  // driver implements the actual logic.
    22  //
    23  // To further shield the embed from other packages, it is recommended to
    24  // employ a private embed struct:
    25  //
    26  //	type baseEmbed struct {
    27  //		base.Base
    28  //	}
    29  //
    30  // Then, declare driver to embed baseEmbed, rather than Base directly:
    31  //
    32  //	type Driver struct {
    33  //		baseEmbed
    34  //	}
    35  //
    36  // The type now implements StorageDriver, proxying through Base, without
    37  // exporting an unnecessary field.
    38  package base
    39  
    40  import (
    41  	"context"
    42  	"io"
    43  	"time"
    44  
    45  	dcontext "github.com/docker/distribution/context"
    46  	prometheus "github.com/docker/distribution/metrics"
    47  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    48  	"github.com/docker/go-metrics"
    49  )
    50  
    51  var (
    52  	// storageAction is the metrics of blob related operations
    53  	storageAction = prometheus.StorageNamespace.NewLabeledTimer("action", "The number of seconds that the storage action takes", "driver", "action")
    54  )
    55  
    56  func init() {
    57  	metrics.Register(prometheus.StorageNamespace)
    58  }
    59  
    60  // Base provides a wrapper around a storagedriver implementation that provides
    61  // common path and bounds checking.
    62  type Base struct {
    63  	storagedriver.StorageDriver
    64  }
    65  
    66  // Format errors received from the storage driver
    67  func (base *Base) setDriverName(e error) error {
    68  	switch actual := e.(type) {
    69  	case nil:
    70  		return nil
    71  	case storagedriver.ErrUnsupportedMethod:
    72  		actual.DriverName = base.StorageDriver.Name()
    73  		return actual
    74  	case storagedriver.PathNotFoundError:
    75  		actual.DriverName = base.StorageDriver.Name()
    76  		return actual
    77  	case storagedriver.InvalidPathError:
    78  		actual.DriverName = base.StorageDriver.Name()
    79  		return actual
    80  	case storagedriver.InvalidOffsetError:
    81  		actual.DriverName = base.StorageDriver.Name()
    82  		return actual
    83  	default:
    84  		storageError := storagedriver.Error{
    85  			DriverName: base.StorageDriver.Name(),
    86  			Enclosed:   e,
    87  		}
    88  
    89  		return storageError
    90  	}
    91  }
    92  
    93  // GetContent wraps GetContent of underlying storage driver.
    94  func (base *Base) GetContent(ctx context.Context, path string) ([]byte, error) {
    95  	ctx, done := dcontext.WithTrace(ctx)
    96  	defer done("%s.GetContent(%q)", base.Name(), path)
    97  
    98  	if !storagedriver.PathRegexp.MatchString(path) {
    99  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   100  	}
   101  
   102  	start := time.Now()
   103  	b, e := base.StorageDriver.GetContent(ctx, path)
   104  	storageAction.WithValues(base.Name(), "GetContent").UpdateSince(start)
   105  	return b, base.setDriverName(e)
   106  }
   107  
   108  // PutContent wraps PutContent of underlying storage driver.
   109  func (base *Base) PutContent(ctx context.Context, path string, content []byte) error {
   110  	ctx, done := dcontext.WithTrace(ctx)
   111  	defer done("%s.PutContent(%q)", base.Name(), path)
   112  
   113  	if !storagedriver.PathRegexp.MatchString(path) {
   114  		return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   115  	}
   116  
   117  	start := time.Now()
   118  	err := base.setDriverName(base.StorageDriver.PutContent(ctx, path, content))
   119  	storageAction.WithValues(base.Name(), "PutContent").UpdateSince(start)
   120  	return err
   121  }
   122  
   123  // Reader wraps Reader of underlying storage driver.
   124  func (base *Base) Reader(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
   125  	ctx, done := dcontext.WithTrace(ctx)
   126  	defer done("%s.Reader(%q, %d)", base.Name(), path, offset)
   127  
   128  	if offset < 0 {
   129  		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset, DriverName: base.StorageDriver.Name()}
   130  	}
   131  
   132  	if !storagedriver.PathRegexp.MatchString(path) {
   133  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   134  	}
   135  
   136  	rc, e := base.StorageDriver.Reader(ctx, path, offset)
   137  	return rc, base.setDriverName(e)
   138  }
   139  
   140  // Writer wraps Writer of underlying storage driver.
   141  func (base *Base) Writer(ctx context.Context, path string, append bool) (storagedriver.FileWriter, error) {
   142  	ctx, done := dcontext.WithTrace(ctx)
   143  	defer done("%s.Writer(%q, %v)", base.Name(), path, append)
   144  
   145  	if !storagedriver.PathRegexp.MatchString(path) {
   146  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   147  	}
   148  
   149  	writer, e := base.StorageDriver.Writer(ctx, path, append)
   150  	return writer, base.setDriverName(e)
   151  }
   152  
   153  // Stat wraps Stat of underlying storage driver.
   154  func (base *Base) Stat(ctx context.Context, path string) (storagedriver.FileInfo, error) {
   155  	ctx, done := dcontext.WithTrace(ctx)
   156  	defer done("%s.Stat(%q)", base.Name(), path)
   157  
   158  	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
   159  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   160  	}
   161  
   162  	start := time.Now()
   163  	fi, e := base.StorageDriver.Stat(ctx, path)
   164  	storageAction.WithValues(base.Name(), "Stat").UpdateSince(start)
   165  	return fi, base.setDriverName(e)
   166  }
   167  
   168  // List wraps List of underlying storage driver.
   169  func (base *Base) List(ctx context.Context, path string) ([]string, error) {
   170  	ctx, done := dcontext.WithTrace(ctx)
   171  	defer done("%s.List(%q)", base.Name(), path)
   172  
   173  	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
   174  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   175  	}
   176  
   177  	start := time.Now()
   178  	str, e := base.StorageDriver.List(ctx, path)
   179  	storageAction.WithValues(base.Name(), "List").UpdateSince(start)
   180  	return str, base.setDriverName(e)
   181  }
   182  
   183  // Move wraps Move of underlying storage driver.
   184  func (base *Base) Move(ctx context.Context, sourcePath string, destPath string) error {
   185  	ctx, done := dcontext.WithTrace(ctx)
   186  	defer done("%s.Move(%q, %q", base.Name(), sourcePath, destPath)
   187  
   188  	if !storagedriver.PathRegexp.MatchString(sourcePath) {
   189  		return storagedriver.InvalidPathError{Path: sourcePath, DriverName: base.StorageDriver.Name()}
   190  	} else if !storagedriver.PathRegexp.MatchString(destPath) {
   191  		return storagedriver.InvalidPathError{Path: destPath, DriverName: base.StorageDriver.Name()}
   192  	}
   193  
   194  	start := time.Now()
   195  	err := base.setDriverName(base.StorageDriver.Move(ctx, sourcePath, destPath))
   196  	storageAction.WithValues(base.Name(), "Move").UpdateSince(start)
   197  	return err
   198  }
   199  
   200  // Delete wraps Delete of underlying storage driver.
   201  func (base *Base) Delete(ctx context.Context, path string) error {
   202  	ctx, done := dcontext.WithTrace(ctx)
   203  	defer done("%s.Delete(%q)", base.Name(), path)
   204  
   205  	if !storagedriver.PathRegexp.MatchString(path) {
   206  		return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   207  	}
   208  
   209  	start := time.Now()
   210  	err := base.setDriverName(base.StorageDriver.Delete(ctx, path))
   211  	storageAction.WithValues(base.Name(), "Delete").UpdateSince(start)
   212  	return err
   213  }
   214  
   215  // URLFor wraps URLFor of underlying storage driver.
   216  func (base *Base) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) {
   217  	ctx, done := dcontext.WithTrace(ctx)
   218  	defer done("%s.URLFor(%q)", base.Name(), path)
   219  
   220  	if !storagedriver.PathRegexp.MatchString(path) {
   221  		return "", storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   222  	}
   223  
   224  	start := time.Now()
   225  	str, e := base.StorageDriver.URLFor(ctx, path, options)
   226  	storageAction.WithValues(base.Name(), "URLFor").UpdateSince(start)
   227  	return str, base.setDriverName(e)
   228  }
   229  
   230  // Walk wraps Walk of underlying storage driver.
   231  func (base *Base) Walk(ctx context.Context, path string, f storagedriver.WalkFn) error {
   232  	ctx, done := dcontext.WithTrace(ctx)
   233  	defer done("%s.Walk(%q)", base.Name(), path)
   234  
   235  	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
   236  		return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   237  	}
   238  
   239  	return base.setDriverName(base.StorageDriver.Walk(ctx, path, f))
   240  }
   241  

View as plain text