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 }