github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/layerstore.go (about)

     1  package storage
     2  
     3  import (
     4  	"time"
     5  
     6  	"code.google.com/p/go-uuid/uuid"
     7  	"github.com/docker/distribution"
     8  	ctxu "github.com/docker/distribution/context"
     9  	"github.com/docker/distribution/digest"
    10  	"github.com/docker/distribution/manifest"
    11  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    12  )
    13  
    14  type layerStore struct {
    15  	repository *repository
    16  }
    17  
    18  func (ls *layerStore) Exists(digest digest.Digest) (bool, error) {
    19  	ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Exists")
    20  
    21  	// Because this implementation just follows blob links, an existence check
    22  	// is pretty cheap by starting and closing a fetch.
    23  	_, err := ls.Fetch(digest)
    24  
    25  	if err != nil {
    26  		switch err.(type) {
    27  		case distribution.ErrUnknownLayer:
    28  			return false, nil
    29  		}
    30  
    31  		return false, err
    32  	}
    33  
    34  	return true, nil
    35  }
    36  
    37  func (ls *layerStore) Fetch(dgst digest.Digest) (distribution.Layer, error) {
    38  	ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Fetch")
    39  	bp, err := ls.path(dgst)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	fr, err := newFileReader(ls.repository.driver, bp)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	return &layerReader{
    50  		fileReader: *fr,
    51  		digest:     dgst,
    52  	}, nil
    53  }
    54  
    55  // Upload begins a layer upload, returning a handle. If the layer upload
    56  // is already in progress or the layer has already been uploaded, this
    57  // will return an error.
    58  func (ls *layerStore) Upload() (distribution.LayerUpload, error) {
    59  	ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Upload")
    60  
    61  	// NOTE(stevvooe): Consider the issues with allowing concurrent upload of
    62  	// the same two layers. Should it be disallowed? For now, we allow both
    63  	// parties to proceed and the the first one uploads the layer.
    64  
    65  	uuid := uuid.New()
    66  	startedAt := time.Now().UTC()
    67  
    68  	path, err := ls.repository.pm.path(uploadDataPathSpec{
    69  		name: ls.repository.Name(),
    70  		uuid: uuid,
    71  	})
    72  
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	startedAtPath, err := ls.repository.pm.path(uploadStartedAtPathSpec{
    78  		name: ls.repository.Name(),
    79  		uuid: uuid,
    80  	})
    81  
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	// Write a startedat file for this upload
    87  	if err := ls.repository.driver.PutContent(startedAtPath, []byte(startedAt.Format(time.RFC3339))); err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return ls.newLayerUpload(uuid, path, startedAt)
    92  }
    93  
    94  // Resume continues an in progress layer upload, returning the current
    95  // state of the upload.
    96  func (ls *layerStore) Resume(uuid string) (distribution.LayerUpload, error) {
    97  	ctxu.GetLogger(ls.repository.ctx).Debug("(*layerStore).Resume")
    98  	startedAtPath, err := ls.repository.pm.path(uploadStartedAtPathSpec{
    99  		name: ls.repository.Name(),
   100  		uuid: uuid,
   101  	})
   102  
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	startedAtBytes, err := ls.repository.driver.GetContent(startedAtPath)
   108  	if err != nil {
   109  		switch err := err.(type) {
   110  		case storagedriver.PathNotFoundError:
   111  			return nil, distribution.ErrLayerUploadUnknown
   112  		default:
   113  			return nil, err
   114  		}
   115  	}
   116  
   117  	startedAt, err := time.Parse(time.RFC3339, string(startedAtBytes))
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	path, err := ls.repository.pm.path(uploadDataPathSpec{
   123  		name: ls.repository.Name(),
   124  		uuid: uuid,
   125  	})
   126  
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	return ls.newLayerUpload(uuid, path, startedAt)
   132  }
   133  
   134  // newLayerUpload allocates a new upload controller with the given state.
   135  func (ls *layerStore) newLayerUpload(uuid, path string, startedAt time.Time) (distribution.LayerUpload, error) {
   136  	fw, err := newFileWriter(ls.repository.driver, path)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	lw := &layerWriter{
   142  		layerStore:         ls,
   143  		uuid:               uuid,
   144  		startedAt:          startedAt,
   145  		bufferedFileWriter: *fw,
   146  	}
   147  
   148  	lw.setupResumableDigester()
   149  
   150  	return lw, nil
   151  }
   152  
   153  func (ls *layerStore) path(dgst digest.Digest) (string, error) {
   154  	// We must traverse this path through the link to enforce ownership.
   155  	layerLinkPath, err := ls.repository.pm.path(layerLinkPathSpec{name: ls.repository.Name(), digest: dgst})
   156  	if err != nil {
   157  		return "", err
   158  	}
   159  
   160  	blobPath, err := ls.repository.blobStore.resolve(layerLinkPath)
   161  
   162  	if err != nil {
   163  		switch err := err.(type) {
   164  		case storagedriver.PathNotFoundError:
   165  			return "", distribution.ErrUnknownLayer{
   166  				FSLayer: manifest.FSLayer{BlobSum: dgst},
   167  			}
   168  		default:
   169  			return "", err
   170  		}
   171  	}
   172  
   173  	return blobPath, nil
   174  }