github.com/uber/kraken@v0.1.4/lib/dockerregistry/uploads.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  	"bytes"
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	stdpath "path"
    22  	"time"
    23  
    24  	"github.com/uber/kraken/lib/dockerregistry/transfer"
    25  	"github.com/uber/kraken/lib/store"
    26  	"github.com/uber/kraken/lib/store/metadata"
    27  
    28  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    29  )
    30  
    31  type uploads interface {
    32  	reader(path string, subtype PathSubType, offset int64) (io.ReadCloser, error)
    33  	getContent(path string, subtype PathSubType) ([]byte, error)
    34  	putContent(path string, subtype PathSubType, content []byte) error
    35  	putBlobContent(path string, content []byte) error
    36  	writer(path string, subtype PathSubType) (store.FileReadWriter, error)
    37  	stat(path string) (storagedriver.FileInfo, error)
    38  	list(path string, subtype PathSubType) ([]string, error)
    39  	move(uploadPath, blobPath string) error
    40  }
    41  
    42  type casUploads struct {
    43  	cas        *store.CAStore
    44  	transferer transfer.ImageTransferer
    45  }
    46  
    47  func newCASUploads(cas *store.CAStore, transferer transfer.ImageTransferer) *casUploads {
    48  	return &casUploads{cas, transferer}
    49  }
    50  
    51  func (u *casUploads) getContent(path string, subtype PathSubType) ([]byte, error) {
    52  	uuid, err := GetUploadUUID(path)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	switch subtype {
    57  	case _startedat:
    58  		var s startedAtMetadata
    59  		if err := u.cas.GetUploadFileMetadata(uuid, &s); err != nil {
    60  			return nil, err
    61  		}
    62  		return s.Serialize()
    63  	case _hashstates:
    64  		algo, offset, err := GetUploadAlgoAndOffset(path)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  		hs := newHashStateMetadata(algo, offset)
    69  		if err := u.cas.GetUploadFileMetadata(uuid, hs); err != nil {
    70  			return nil, err
    71  		}
    72  		return hs.Serialize()
    73  	}
    74  	return nil, InvalidRequestError{path}
    75  }
    76  
    77  func (u *casUploads) reader(path string, subtype PathSubType, offset int64) (io.ReadCloser, error) {
    78  	switch subtype {
    79  	case _data:
    80  		uuid, err := GetUploadUUID(path)
    81  		if err != nil {
    82  			return nil, fmt.Errorf("get upload uuid: %s", err)
    83  		}
    84  		r, err := u.cas.GetUploadFileReader(uuid)
    85  		if err != nil {
    86  			return nil, fmt.Errorf("get reader: %s", err)
    87  		}
    88  		if _, err := r.Seek(offset, io.SeekStart); err != nil {
    89  			return nil, fmt.Errorf("seek: %s", err)
    90  		}
    91  		return r, nil
    92  	}
    93  	return nil, InvalidRequestError{path}
    94  }
    95  
    96  func (u *casUploads) putContent(path string, subtype PathSubType, content []byte) error {
    97  	uuid, err := GetUploadUUID(path)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	switch subtype {
   102  	case _startedat:
   103  		if err := u.cas.CreateUploadFile(uuid, 0); err != nil {
   104  			return fmt.Errorf("create upload file: %s", err)
   105  		}
   106  		s := newStartedAtMetadata(time.Now())
   107  		if err := u.cas.SetUploadFileMetadata(uuid, s); err != nil {
   108  			return fmt.Errorf("set started at: %s", err)
   109  		}
   110  		return nil
   111  	case _hashstates:
   112  		algo, offset, err := GetUploadAlgoAndOffset(path)
   113  		if err != nil {
   114  			return err
   115  		}
   116  		hs := newHashStateMetadata(algo, offset)
   117  		if err := hs.Deserialize(content); err != nil {
   118  			return fmt.Errorf("deserialize hash state: %s", err)
   119  		}
   120  		return u.cas.SetUploadFileMetadata(uuid, hs)
   121  	}
   122  	return InvalidRequestError{path}
   123  }
   124  
   125  func (u *casUploads) putBlobContent(path string, content []byte) error {
   126  	d, err := GetBlobDigest(path)
   127  	if err != nil {
   128  		return fmt.Errorf("get digest: %s", err)
   129  	}
   130  	if err := u.cas.CreateCacheFile(d.Hex(), bytes.NewReader(content)); err != nil {
   131  		return fmt.Errorf("create cache file: %s", err)
   132  	}
   133  	if err := u.transferer.Upload("TODO", d, store.NewBufferFileReader(content)); err != nil {
   134  		return fmt.Errorf("upload: %s", err)
   135  	}
   136  	return nil
   137  }
   138  
   139  func (u *casUploads) writer(path string, subtype PathSubType) (store.FileReadWriter, error) {
   140  	uuid, err := GetUploadUUID(path)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	switch subtype {
   145  	case _data:
   146  		return u.cas.GetUploadFileReadWriter(uuid)
   147  	}
   148  	return nil, InvalidRequestError{path}
   149  }
   150  
   151  func (u *casUploads) stat(path string) (storagedriver.FileInfo, error) {
   152  	uuid, err := GetUploadUUID(path)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	info, err := u.cas.GetUploadFileStat(uuid)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	// Hacking the path, since kraken storage driver is also the consumer of this info.
   161  	// Instead of the relative path from root that docker registry expected, just use uuid.
   162  	return storagedriver.FileInfoInternal{
   163  		FileInfoFields: storagedriver.FileInfoFields{
   164  			Path:    uuid,
   165  			Size:    info.Size(),
   166  			ModTime: info.ModTime(),
   167  			IsDir:   info.IsDir(),
   168  		},
   169  	}, nil
   170  }
   171  
   172  func (u *casUploads) list(path string, subtype PathSubType) ([]string, error) {
   173  	uuid, err := GetUploadUUID(path)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	switch subtype {
   178  	case _hashstates:
   179  		var paths []string
   180  		u.cas.RangeUploadMetadata(uuid, func(md metadata.Metadata) error {
   181  			if hs, ok := md.(*hashStateMetadata); ok {
   182  				p := stdpath.Join("localstore", "_uploads", uuid, hs.dockerPath())
   183  				paths = append(paths, p)
   184  			}
   185  			return nil
   186  		})
   187  		return paths, nil
   188  	}
   189  	return nil, InvalidRequestError{path}
   190  }
   191  
   192  func (u *casUploads) move(uploadPath, blobPath string) error {
   193  	uuid, err := GetUploadUUID(uploadPath)
   194  	if err != nil {
   195  		return fmt.Errorf("get upload uuid: %s", err)
   196  	}
   197  	d, err := GetBlobDigest(blobPath)
   198  	if err != nil {
   199  		return fmt.Errorf("get blob uuid: %s", err)
   200  	}
   201  	if err := u.cas.MoveUploadFileToCache(uuid, d.Hex()); err != nil {
   202  		return fmt.Errorf("move upload file to cache: %s", err)
   203  	}
   204  	f, err := u.cas.GetCacheFileReader(d.Hex())
   205  	if err != nil {
   206  		return fmt.Errorf("get cache file: %s", err)
   207  	}
   208  	if err := u.transferer.Upload("TODO", d, f); err != nil {
   209  		return fmt.Errorf("upload: %s", err)
   210  	}
   211  	return nil
   212  }
   213  
   214  var errUploadsDisabled = errors.New("uploads are disabled")
   215  
   216  type disabledUploads struct{}
   217  
   218  func (u disabledUploads) reader(path string, subtype PathSubType, offset int64) (io.ReadCloser, error) {
   219  	return nil, errUploadsDisabled
   220  }
   221  
   222  func (u disabledUploads) getContent(path string, subtype PathSubType) ([]byte, error) {
   223  	return nil, errUploadsDisabled
   224  }
   225  
   226  func (u disabledUploads) putContent(path string, subtype PathSubType, content []byte) error {
   227  	return errUploadsDisabled
   228  }
   229  
   230  func (u disabledUploads) putBlobContent(path string, content []byte) error {
   231  	return errUploadsDisabled
   232  }
   233  
   234  func (u disabledUploads) writer(path string, subtype PathSubType) (store.FileReadWriter, error) {
   235  	return nil, errUploadsDisabled
   236  }
   237  
   238  func (u disabledUploads) stat(path string) (storagedriver.FileInfo, error) {
   239  	return nil, errUploadsDisabled
   240  }
   241  
   242  func (u disabledUploads) list(path string, subtype PathSubType) ([]string, error) {
   243  	return nil, errUploadsDisabled
   244  }
   245  
   246  func (u disabledUploads) move(uploadPath, blobPath string) error {
   247  	return errUploadsDisabled
   248  }