1package distribution 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net/http" 9 "time" 10 11 "github.com/docker/distribution/reference" 12 "github.com/opencontainers/go-digest" 13 "github.com/opencontainers/image-spec/specs-go/v1" 14) 15 16var ( 17 // ErrBlobExists returned when blob already exists 18 ErrBlobExists = errors.New("blob exists") 19 20 // ErrBlobDigestUnsupported when blob digest is an unsupported version. 21 ErrBlobDigestUnsupported = errors.New("unsupported blob digest") 22 23 // ErrBlobUnknown when blob is not found. 24 ErrBlobUnknown = errors.New("unknown blob") 25 26 // ErrBlobUploadUnknown returned when upload is not found. 27 ErrBlobUploadUnknown = errors.New("blob upload unknown") 28 29 // ErrBlobInvalidLength returned when the blob has an expected length on 30 // commit, meaning mismatched with the descriptor or an invalid value. 31 ErrBlobInvalidLength = errors.New("blob invalid length") 32) 33 34// ErrBlobInvalidDigest returned when digest check fails. 35type ErrBlobInvalidDigest struct { 36 Digest digest.Digest 37 Reason error 38} 39 40func (err ErrBlobInvalidDigest) Error() string { 41 return fmt.Sprintf("invalid digest for referenced layer: %v, %v", 42 err.Digest, err.Reason) 43} 44 45// ErrBlobMounted returned when a blob is mounted from another repository 46// instead of initiating an upload session. 47type ErrBlobMounted struct { 48 From reference.Canonical 49 Descriptor Descriptor 50} 51 52func (err ErrBlobMounted) Error() string { 53 return fmt.Sprintf("blob mounted from: %v to: %v", 54 err.From, err.Descriptor) 55} 56 57// Descriptor describes targeted content. Used in conjunction with a blob 58// store, a descriptor can be used to fetch, store and target any kind of 59// blob. The struct also describes the wire protocol format. Fields should 60// only be added but never changed. 61type Descriptor struct { 62 // MediaType describe the type of the content. All text based formats are 63 // encoded as utf-8. 64 MediaType string `json:"mediaType,omitempty"` 65 66 // Size in bytes of content. 67 Size int64 `json:"size,omitempty"` 68 69 // Digest uniquely identifies the content. A byte stream can be verified 70 // against this digest. 71 Digest digest.Digest `json:"digest,omitempty"` 72 73 // URLs contains the source URLs of this content. 74 URLs []string `json:"urls,omitempty"` 75 76 // Annotations contains arbitrary metadata relating to the targeted content. 77 Annotations map[string]string `json:"annotations,omitempty"` 78 79 // Platform describes the platform which the image in the manifest runs on. 80 // This should only be used when referring to a manifest. 81 Platform *v1.Platform `json:"platform,omitempty"` 82 83 // NOTE: Before adding a field here, please ensure that all 84 // other options have been exhausted. Much of the type relationships 85 // depend on the simplicity of this type. 86} 87 88// Descriptor returns the descriptor, to make it satisfy the Describable 89// interface. Note that implementations of Describable are generally objects 90// which can be described, not simply descriptors; this exception is in place 91// to make it more convenient to pass actual descriptors to functions that 92// expect Describable objects. 93func (d Descriptor) Descriptor() Descriptor { 94 return d 95} 96 97// BlobStatter makes blob descriptors available by digest. The service may 98// provide a descriptor of a different digest if the provided digest is not 99// canonical. 100type BlobStatter interface { 101 // Stat provides metadata about a blob identified by the digest. If the 102 // blob is unknown to the describer, ErrBlobUnknown will be returned. 103 Stat(ctx context.Context, dgst digest.Digest) (Descriptor, error) 104} 105 106// BlobDeleter enables deleting blobs from storage. 107type BlobDeleter interface { 108 Delete(ctx context.Context, dgst digest.Digest) error 109} 110 111// BlobEnumerator enables iterating over blobs from storage 112type BlobEnumerator interface { 113 Enumerate(ctx context.Context, ingester func(dgst digest.Digest) error) error 114} 115 116// BlobDescriptorService manages metadata about a blob by digest. Most 117// implementations will not expose such an interface explicitly. Such mappings 118// should be maintained by interacting with the BlobIngester. Hence, this is 119// left off of BlobService and BlobStore. 120type BlobDescriptorService interface { 121 BlobStatter 122 123 // SetDescriptor assigns the descriptor to the digest. The provided digest and 124 // the digest in the descriptor must map to identical content but they may 125 // differ on their algorithm. The descriptor must have the canonical 126 // digest of the content and the digest algorithm must match the 127 // annotators canonical algorithm. 128 // 129 // Such a facility can be used to map blobs between digest domains, with 130 // the restriction that the algorithm of the descriptor must match the 131 // canonical algorithm (ie sha256) of the annotator. 132 SetDescriptor(ctx context.Context, dgst digest.Digest, desc Descriptor) error 133 134 // Clear enables descriptors to be unlinked 135 Clear(ctx context.Context, dgst digest.Digest) error 136} 137 138// BlobDescriptorServiceFactory creates middleware for BlobDescriptorService. 139type BlobDescriptorServiceFactory interface { 140 BlobAccessController(svc BlobDescriptorService) BlobDescriptorService 141} 142 143// ReadSeekCloser is the primary reader type for blob data, combining 144// io.ReadSeeker with io.Closer. 145type ReadSeekCloser interface { 146 io.ReadSeeker 147 io.Closer 148} 149 150// BlobProvider describes operations for getting blob data. 151type BlobProvider interface { 152 // Get returns the entire blob identified by digest along with the descriptor. 153 Get(ctx context.Context, dgst digest.Digest) ([]byte, error) 154 155 // Open provides a ReadSeekCloser to the blob identified by the provided 156 // descriptor. If the blob is not known to the service, an error will be 157 // returned. 158 Open(ctx context.Context, dgst digest.Digest) (ReadSeekCloser, error) 159} 160 161// BlobServer can serve blobs via http. 162type BlobServer interface { 163 // ServeBlob attempts to serve the blob, identified by dgst, via http. The 164 // service may decide to redirect the client elsewhere or serve the data 165 // directly. 166 // 167 // This handler only issues successful responses, such as 2xx or 3xx, 168 // meaning it serves data or issues a redirect. If the blob is not 169 // available, an error will be returned and the caller may still issue a 170 // response. 171 // 172 // The implementation may serve the same blob from a different digest 173 // domain. The appropriate headers will be set for the blob, unless they 174 // have already been set by the caller. 175 ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error 176} 177 178// BlobIngester ingests blob data. 179type BlobIngester interface { 180 // Put inserts the content p into the blob service, returning a descriptor 181 // or an error. 182 Put(ctx context.Context, mediaType string, p []byte) (Descriptor, error) 183 184 // Create allocates a new blob writer to add a blob to this service. The 185 // returned handle can be written to and later resumed using an opaque 186 // identifier. With this approach, one can Close and Resume a BlobWriter 187 // multiple times until the BlobWriter is committed or cancelled. 188 Create(ctx context.Context, options ...BlobCreateOption) (BlobWriter, error) 189 190 // Resume attempts to resume a write to a blob, identified by an id. 191 Resume(ctx context.Context, id string) (BlobWriter, error) 192} 193 194// BlobCreateOption is a general extensible function argument for blob creation 195// methods. A BlobIngester may choose to honor any or none of the given 196// BlobCreateOptions, which can be specific to the implementation of the 197// BlobIngester receiving them. 198// TODO (brianbland): unify this with ManifestServiceOption in the future 199type BlobCreateOption interface { 200 Apply(interface{}) error 201} 202 203// CreateOptions is a collection of blob creation modifiers relevant to general 204// blob storage intended to be configured by the BlobCreateOption.Apply method. 205type CreateOptions struct { 206 Mount struct { 207 ShouldMount bool 208 From reference.Canonical 209 // Stat allows to pass precalculated descriptor to link and return. 210 // Blob access check will be skipped if set. 211 Stat *Descriptor 212 } 213} 214 215// BlobWriter provides a handle for inserting data into a blob store. 216// Instances should be obtained from BlobWriteService.Writer and 217// BlobWriteService.Resume. If supported by the store, a writer can be 218// recovered with the id. 219type BlobWriter interface { 220 io.WriteCloser 221 io.ReaderFrom 222 223 // Size returns the number of bytes written to this blob. 224 Size() int64 225 226 // ID returns the identifier for this writer. The ID can be used with the 227 // Blob service to later resume the write. 228 ID() string 229 230 // StartedAt returns the time this blob write was started. 231 StartedAt() time.Time 232 233 // Commit completes the blob writer process. The content is verified 234 // against the provided provisional descriptor, which may result in an 235 // error. Depending on the implementation, written data may be validated 236 // against the provisional descriptor fields. If MediaType is not present, 237 // the implementation may reject the commit or assign "application/octet- 238 // stream" to the blob. The returned descriptor may have a different 239 // digest depending on the blob store, referred to as the canonical 240 // descriptor. 241 Commit(ctx context.Context, provisional Descriptor) (canonical Descriptor, err error) 242 243 // Cancel ends the blob write without storing any data and frees any 244 // associated resources. Any data written thus far will be lost. Cancel 245 // implementations should allow multiple calls even after a commit that 246 // result in a no-op. This allows use of Cancel in a defer statement, 247 // increasing the assurance that it is correctly called. 248 Cancel(ctx context.Context) error 249} 250 251// BlobService combines the operations to access, read and write blobs. This 252// can be used to describe remote blob services. 253type BlobService interface { 254 BlobStatter 255 BlobProvider 256 BlobIngester 257} 258 259// BlobStore represent the entire suite of blob related operations. Such an 260// implementation can access, read, write, delete and serve blobs. 261type BlobStore interface { 262 BlobService 263 BlobServer 264 BlobDeleter 265} 266