Change some incorrect error types in proxy stores from API errors to
distribution errors. Fill in missing checks for mutations on a registry pull-through cache. Add unit tests and update documentation. Also, give v2.ErrorCodeUnsupported an HTTP status code, previously it was defaulting to 500, now its 405 Method Not Allowed. Signed-off-by: Richard Scothern <richard.scothern@gmail.com>master
							parent
							
								
									528442c015
								
							
						
					
					
						commit
						776a4ffbe8
					
				
							
								
								
									
										3
									
								
								blobs.go
								
								
								
								
							
							
						
						
									
										3
									
								
								blobs.go
								
								
								
								
							|  | @ -27,9 +27,6 @@ var ( | ||||||
| 	// ErrBlobInvalidLength returned when the blob has an expected length on
 | 	// ErrBlobInvalidLength returned when the blob has an expected length on
 | ||||||
| 	// commit, meaning mismatched with the descriptor or an invalid value.
 | 	// commit, meaning mismatched with the descriptor or an invalid value.
 | ||||||
| 	ErrBlobInvalidLength = errors.New("blob invalid length") | 	ErrBlobInvalidLength = errors.New("blob invalid length") | ||||||
| 
 |  | ||||||
| 	// ErrUnsupported returned when an unsupported operation is attempted
 |  | ||||||
| 	ErrUnsupported = errors.New("unsupported operation") |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // ErrBlobInvalidDigest returned when digest check fails.
 | // ErrBlobInvalidDigest returned when digest check fails.
 | ||||||
|  |  | ||||||
|  | @ -1731,6 +1731,24 @@ The error codes that may be included in the response body are enumerated below: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ###### On Failure: Not allowed | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 405 Method Not Allowed | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | The error codes that may be included in the response body are enumerated below: | ||||||
|  | 
 | ||||||
|  | |Code|Message|Description| | ||||||
|  | |----|-------|-----------| | ||||||
|  | | `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #### DELETE Manifest | #### DELETE Manifest | ||||||
| 
 | 
 | ||||||
|  | @ -1871,6 +1889,24 @@ The error codes that may be included in the response body are enumerated below: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ###### On Failure: Not allowed | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 405 Method Not Allowed | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Manifest delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | The error codes that may be included in the response body are enumerated below: | ||||||
|  | 
 | ||||||
|  | |Code|Message|Description| | ||||||
|  | |----|-------|-----------| | ||||||
|  | | `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### Blob | ### Blob | ||||||
|  | @ -2323,7 +2359,7 @@ Content-Type: application/json; charset=utf-8 | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Delete is not enabled on the registry | Blob delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -2456,6 +2492,24 @@ The error codes that may be included in the response body are enumerated below: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ###### On Failure: Not allowed | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 405 Method Not Allowed | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | The error codes that may be included in the response body are enumerated below: | ||||||
|  | 
 | ||||||
|  | |Code|Message|Description| | ||||||
|  | |----|-------|-----------| | ||||||
|  | | `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ##### Initiate Resumable Blob Upload | ##### Initiate Resumable Blob Upload | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
|  | @ -3129,6 +3183,7 @@ The error codes that may be included in the response body are enumerated below: | ||||||
| | `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. | | | `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. | | ||||||
| | `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. | | | `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. | | ||||||
| | `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. | | | `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. | | ||||||
|  | | `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. | | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,10 @@ import ( | ||||||
| 	"github.com/docker/distribution/digest" | 	"github.com/docker/distribution/digest" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // ErrUnsupported is returned when an unimplemented or unsupported action is
 | ||||||
|  | // performed
 | ||||||
|  | var ErrUnsupported = fmt.Errorf("operation unsupported") | ||||||
|  | 
 | ||||||
| // ErrRepositoryUnknown is returned if the named repository is not known by
 | // ErrRepositoryUnknown is returned if the named repository is not known by
 | ||||||
| // the registry.
 | // the registry.
 | ||||||
| type ErrRepositoryUnknown struct { | type ErrRepositoryUnknown struct { | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ var ( | ||||||
| 		Message: "The operation is unsupported.", | 		Message: "The operation is unsupported.", | ||||||
| 		Description: `The operation was unsupported due to a missing | 		Description: `The operation was unsupported due to a missing | ||||||
| 		implementation or invalid set of parameters.`, | 		implementation or invalid set of parameters.`, | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusMethodNotAllowed, | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	// ErrorCodeUnauthorized is returned if a request is not authorized.
 | 	// ErrorCodeUnauthorized is returned if a request is not authorized.
 | ||||||
|  |  | ||||||
|  | @ -689,6 +689,14 @@ var routeDescriptors = []RouteDescriptor{ | ||||||
| 									Format:      errorsBody, | 									Format:      errorsBody, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | 							{ | ||||||
|  | 								Name:        "Not allowed", | ||||||
|  | 								Description: "Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason", | ||||||
|  | 								StatusCode:  http.StatusMethodNotAllowed, | ||||||
|  | 								ErrorCodes: []errcode.ErrorCode{ | ||||||
|  | 									errcode.ErrorCodeUnsupported, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -757,6 +765,14 @@ var routeDescriptors = []RouteDescriptor{ | ||||||
| 									Format:      errorsBody, | 									Format:      errorsBody, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | 							{ | ||||||
|  | 								Name:        "Not allowed", | ||||||
|  | 								Description: "Manifest delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled.", | ||||||
|  | 								StatusCode:  http.StatusMethodNotAllowed, | ||||||
|  | 								ErrorCodes: []errcode.ErrorCode{ | ||||||
|  | 									errcode.ErrorCodeUnsupported, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
|  | @ -967,7 +983,7 @@ var routeDescriptors = []RouteDescriptor{ | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 							{ | 							{ | ||||||
| 								Description: "Delete is not enabled on the registry", | 								Description: "Blob delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled", | ||||||
| 								StatusCode:  http.StatusMethodNotAllowed, | 								StatusCode:  http.StatusMethodNotAllowed, | ||||||
| 								Body: BodyDescriptor{ | 								Body: BodyDescriptor{ | ||||||
| 									ContentType: "application/json; charset=utf-8", | 									ContentType: "application/json; charset=utf-8", | ||||||
|  | @ -1051,6 +1067,14 @@ var routeDescriptors = []RouteDescriptor{ | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
| 							unauthorizedResponsePush, | 							unauthorizedResponsePush, | ||||||
|  | 							{ | ||||||
|  | 								Name:        "Not allowed", | ||||||
|  | 								Description: "Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason", | ||||||
|  | 								StatusCode:  http.StatusMethodNotAllowed, | ||||||
|  | 								ErrorCodes: []errcode.ErrorCode{ | ||||||
|  | 									errcode.ErrorCodeUnsupported, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
|  | @ -1389,6 +1413,7 @@ var routeDescriptors = []RouteDescriptor{ | ||||||
| 									ErrorCodeDigestInvalid, | 									ErrorCodeDigestInvalid, | ||||||
| 									ErrorCodeNameInvalid, | 									ErrorCodeNameInvalid, | ||||||
| 									ErrorCodeBlobUploadInvalid, | 									ErrorCodeBlobUploadInvalid, | ||||||
|  | 									errcode.ErrorCodeUnsupported, | ||||||
| 								}, | 								}, | ||||||
| 								Body: BodyDescriptor{ | 								Body: BodyDescriptor{ | ||||||
| 									ContentType: "application/json; charset=utf-8", | 									ContentType: "application/json; charset=utf-8", | ||||||
|  |  | ||||||
|  | @ -1001,6 +1001,21 @@ type testEnv struct { | ||||||
| 	builder *v2.URLBuilder | 	builder *v2.URLBuilder | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func newTestEnvMirror(t *testing.T, deleteEnabled bool) *testEnv { | ||||||
|  | 	config := configuration.Configuration{ | ||||||
|  | 		Storage: configuration.Storage{ | ||||||
|  | 			"inmemory": configuration.Parameters{}, | ||||||
|  | 			"delete":   configuration.Parameters{"enabled": deleteEnabled}, | ||||||
|  | 		}, | ||||||
|  | 		Proxy: configuration.Proxy{ | ||||||
|  | 			RemoteURL: "http://example.com", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return newTestEnvWithConfig(t, &config) | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func newTestEnv(t *testing.T, deleteEnabled bool) *testEnv { | func newTestEnv(t *testing.T, deleteEnabled bool) *testEnv { | ||||||
| 	config := configuration.Configuration{ | 	config := configuration.Configuration{ | ||||||
| 		Storage: configuration.Storage{ | 		Storage: configuration.Storage{ | ||||||
|  | @ -1378,3 +1393,53 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string) | ||||||
| 		"Docker-Content-Digest": []string{dgst.String()}, | 		"Docker-Content-Digest": []string{dgst.String()}, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Test mutation operations on a registry configured as a cache.  Ensure that they return
 | ||||||
|  | // appropriate errors.
 | ||||||
|  | func TestRegistryAsCacheMutationAPIs(t *testing.T) { | ||||||
|  | 	deleteEnabled := true | ||||||
|  | 	env := newTestEnvMirror(t, deleteEnabled) | ||||||
|  | 
 | ||||||
|  | 	imageName := "foo/bar" | ||||||
|  | 	tag := "latest" | ||||||
|  | 	manifestURL, err := env.builder.BuildManifestURL(imageName, tag) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("unexpected error building base url: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Manifest upload
 | ||||||
|  | 	unsignedManifest := &manifest.Manifest{ | ||||||
|  | 		Versioned: manifest.Versioned{ | ||||||
|  | 			SchemaVersion: 1, | ||||||
|  | 		}, | ||||||
|  | 		Name:     imageName, | ||||||
|  | 		Tag:      tag, | ||||||
|  | 		FSLayers: []manifest.FSLayer{}, | ||||||
|  | 	} | ||||||
|  | 	resp := putManifest(t, "putting unsigned manifest", manifestURL, unsignedManifest) | ||||||
|  | 	checkResponse(t, "putting signed manifest to cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode) | ||||||
|  | 
 | ||||||
|  | 	// Manifest Delete
 | ||||||
|  | 	resp, err = httpDelete(manifestURL) | ||||||
|  | 	checkResponse(t, "deleting signed manifest from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode) | ||||||
|  | 
 | ||||||
|  | 	// Blob upload initialization
 | ||||||
|  | 	layerUploadURL, err := env.builder.BuildBlobUploadURL(imageName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("unexpected error building layer upload url: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	resp, err = http.Post(layerUploadURL, "", nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("unexpected error starting layer push: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  | 
 | ||||||
|  | 	checkResponse(t, fmt.Sprintf("starting layer push to cache %v", imageName), resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode) | ||||||
|  | 
 | ||||||
|  | 	// Blob Delete
 | ||||||
|  | 	blobURL, err := env.builder.BuildBlobURL(imageName, digest.DigestSha256EmptyTar) | ||||||
|  | 	resp, err = httpDelete(blobURL) | ||||||
|  | 	checkResponse(t, "deleting blob from cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode) | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -76,16 +76,17 @@ func (bh *blobHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) { | ||||||
| 	err := blobs.Delete(bh, bh.Digest) | 	err := blobs.Delete(bh, bh.Digest) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		switch err { | 		switch err { | ||||||
| 		case distribution.ErrBlobUnknown: |  | ||||||
| 			w.WriteHeader(http.StatusNotFound) |  | ||||||
| 			bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown) |  | ||||||
| 		case distribution.ErrUnsupported: | 		case distribution.ErrUnsupported: | ||||||
| 			w.WriteHeader(http.StatusMethodNotAllowed) |  | ||||||
| 			bh.Errors = append(bh.Errors, errcode.ErrorCodeUnsupported) | 			bh.Errors = append(bh.Errors, errcode.ErrorCodeUnsupported) | ||||||
|  | 			return | ||||||
|  | 		case distribution.ErrBlobUnknown: | ||||||
|  | 			bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown) | ||||||
|  | 			return | ||||||
| 		default: | 		default: | ||||||
| 			bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown) | 			bh.Errors = append(bh.Errors, err) | ||||||
|  | 			context.GetLogger(bh).Errorf("Unknown error deleting blob: %s", err.Error()) | ||||||
|  | 			return | ||||||
| 		} | 		} | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w.Header().Set("Content-Length", "0") | 	w.Header().Set("Content-Length", "0") | ||||||
|  |  | ||||||
|  | @ -117,8 +117,13 @@ type blobUploadHandler struct { | ||||||
| func (buh *blobUploadHandler) StartBlobUpload(w http.ResponseWriter, r *http.Request) { | func (buh *blobUploadHandler) StartBlobUpload(w http.ResponseWriter, r *http.Request) { | ||||||
| 	blobs := buh.Repository.Blobs(buh) | 	blobs := buh.Repository.Blobs(buh) | ||||||
| 	upload, err := blobs.Create(buh) | 	upload, err := blobs.Create(buh) | ||||||
|  | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		buh.Errors = append(buh.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) | 		if err == distribution.ErrUnsupported { | ||||||
|  | 			buh.Errors = append(buh.Errors, errcode.ErrorCodeUnsupported) | ||||||
|  | 		} else { | ||||||
|  | 			buh.Errors = append(buh.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) | ||||||
|  | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -227,6 +232,8 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht | ||||||
| 			buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail(err)) | 			buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail(err)) | ||||||
| 		default: | 		default: | ||||||
| 			switch err { | 			switch err { | ||||||
|  | 			case distribution.ErrUnsupported: | ||||||
|  | 				buh.Errors = append(buh.Errors, errcode.ErrorCodeUnsupported) | ||||||
| 			case distribution.ErrBlobInvalidLength, distribution.ErrBlobDigestUnsupported: | 			case distribution.ErrBlobInvalidLength, distribution.ErrBlobDigestUnsupported: | ||||||
| 				buh.Errors = append(buh.Errors, v2.ErrorCodeBlobUploadInvalid.WithDetail(err)) | 				buh.Errors = append(buh.Errors, v2.ErrorCodeBlobUploadInvalid.WithDetail(err)) | ||||||
| 			default: | 			default: | ||||||
|  |  | ||||||
|  | @ -154,6 +154,10 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http | ||||||
| 	if err := manifests.Put(&manifest); err != nil { | 	if err := manifests.Put(&manifest); err != nil { | ||||||
| 		// TODO(stevvooe): These error handling switches really need to be
 | 		// TODO(stevvooe): These error handling switches really need to be
 | ||||||
| 		// handled by an app global mapper.
 | 		// handled by an app global mapper.
 | ||||||
|  | 		if err == distribution.ErrUnsupported { | ||||||
|  | 			imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 		switch err := err.(type) { | 		switch err := err.(type) { | ||||||
| 		case distribution.ErrManifestVerification: | 		case distribution.ErrManifestVerification: | ||||||
| 			for _, verificationError := range err { | 			for _, verificationError := range err { | ||||||
|  | @ -210,14 +214,12 @@ func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *h | ||||||
| 			return | 			return | ||||||
| 		case distribution.ErrBlobUnknown: | 		case distribution.ErrBlobUnknown: | ||||||
| 			imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown) | 			imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown) | ||||||
| 			w.WriteHeader(http.StatusNotFound) |  | ||||||
| 			return | 			return | ||||||
| 		case distribution.ErrUnsupported: | 		case distribution.ErrUnsupported: | ||||||
| 			imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported) | 			imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported) | ||||||
| 			w.WriteHeader(http.StatusMethodNotAllowed) | 			return | ||||||
| 		default: | 		default: | ||||||
| 			imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown) | 			imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown) | ||||||
| 			w.WriteHeader(http.StatusBadRequest) |  | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ import ( | ||||||
| 	"github.com/docker/distribution/context" | 	"github.com/docker/distribution/context" | ||||||
| 	"github.com/docker/distribution/digest" | 	"github.com/docker/distribution/digest" | ||||||
| 	"github.com/docker/distribution/manifest" | 	"github.com/docker/distribution/manifest" | ||||||
| 	"github.com/docker/distribution/registry/api/errcode" |  | ||||||
| 	"github.com/docker/distribution/registry/client" | 	"github.com/docker/distribution/registry/client" | ||||||
| 	"github.com/docker/distribution/registry/proxy/scheduler" | 	"github.com/docker/distribution/registry/proxy/scheduler" | ||||||
| ) | ) | ||||||
|  | @ -147,9 +146,9 @@ func manifestDigest(sm *manifest.SignedManifest) (digest.Digest, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error { | func (pms proxyManifestStore) Put(manifest *manifest.SignedManifest) error { | ||||||
| 	return errcode.ErrorCodeUnsupported | 	return distribution.ErrUnsupported | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (pms proxyManifestStore) Delete(dgst digest.Digest) error { | func (pms proxyManifestStore) Delete(dgst digest.Digest) error { | ||||||
| 	return errcode.ErrorCodeUnsupported | 	return distribution.ErrUnsupported | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue