diff --git a/docs/spec/api.md b/docs/spec/api.md
index c573178ae..9b56b6c5e 100644
--- a/docs/spec/api.md
+++ b/docs/spec/api.md
@@ -175,7 +175,6 @@ identify a set of modifications.
Added error code for unsupported operations.
-
## Overview
@@ -727,7 +726,8 @@ delete may be issued with the following request format:
DELETE /v2//blobs/
-If the blob exists and has been successfully deleted, the following response will be issued:
+If the blob exists and has been successfully deleted, the following response
+will be issued:
202 Accepted
Content-Length: None
@@ -735,6 +735,8 @@ If the blob exists and has been successfully deleted, the following response wil
If the blob had already been deleted or did not exist, a `404 Not Found`
response will be issued instead.
+If a layer is deleted which is referenced by a manifest in the registry,
+then the complete images will not be resolvable.
#### Pushing an Image Manifest
@@ -1016,13 +1018,13 @@ A list of methods and URIs are covered in the table below:
| PUT | `/v2//manifests/` | Manifest | Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest. |
| DELETE | `/v2//manifests/` | Manifest | Delete the manifest identified by `name` and `reference`. Note that a manifest can _only_ be deleted by `digest`. |
| GET | `/v2//blobs/` | Blob | Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data. |
+| DELETE | `/v2//blobs/` | Blob | Delete the blob identified by `name` and `digest` |
| POST | `/v2//blobs/uploads/` | Initiate Blob Upload | Initiate a resumable blob upload. If successful, an upload location will be provided to complete the upload. Optionally, if the `digest` parameter is present, the request body will be used to complete the upload in a single request. |
| GET | `/v2//blobs/uploads/` | Blob Upload | Retrieve status of upload identified by `uuid`. The primary purpose of this endpoint is to resolve the current status of a resumable upload. |
| PATCH | `/v2//blobs/uploads/` | Blob Upload | Upload a chunk of data for the specified upload. |
| PUT | `/v2//blobs/uploads/` | Blob Upload | Complete the upload specified by `uuid`, optionally appending the body as the final chunk. |
| DELETE | `/v2//blobs/uploads/` | Blob Upload | Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout. |
| GET | `/v2/_catalog` | Catalog | Retrieve a sorted, json list of repositories available in the registry. |
-| DELETE | `/v2//blobs/` | Blob delete | Delete the blob identified by `name` and `digest`|
The detail for each endpoint is covered in the following sections.
@@ -1374,7 +1376,7 @@ The error codes that may be included in the response body are enumerated below:
### Manifest
-Create, update and retrieve manifests.
+Create, update, delete and retrieve manifests.
@@ -1732,7 +1734,6 @@ The error codes that may be included in the response body are enumerated below:
#### DELETE Manifest
-
Delete the manifest identified by `name` and `reference`. Note that a manifest can _only_ be deleted by `digest`.
@@ -1874,7 +1875,7 @@ The error codes that may be included in the response body are enumerated below:
### Blob
-Fetch the blob identified by `name` and `digest`. Used to fetch layers by digest.
+Operations on blobs identified by `name` and `digest`. Used to fetch or delete layers by digest.
@@ -2207,6 +2208,134 @@ The range specification cannot be satisfied for the requested content. This can
+#### DELETE Blob
+
+Delete the blob identified by `name` and `digest`
+
+
+
+```
+DELETE /v2//blobs/
+Host:
+Authorization:
+```
+
+
+
+
+The following parameters should be specified on the request:
+
+|Name|Kind|Description|
+|----|----|-----------|
+|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
+|`Authorization`|header|An RFC7235 compliant authorization header.|
+|`name`|path|Name of the target repository.|
+|`digest`|path|Digest of desired blob.|
+
+
+
+
+###### On Success: Accepted
+
+```
+202 Accepted
+Content-Length: 0
+Docker-Content-Digest:
+```
+
+
+
+The following headers will be returned with the response:
+
+|Name|Description|
+|----|-----------|
+|`Content-Length`|Zero|
+|`Docker-Content-Digest`|Digest of the targeted content for the request.|
+
+
+
+
+###### On Failure: Invalid Name or Digest
+
+```
+400 Bad Request
+```
+
+
+
+
+
+The error codes that may be included in the response body are enumerated below:
+
+|Code|Message|Description|
+|----|-------|-----------|
+| `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. |
+
+
+
+###### On Failure: Not Found
+
+```
+404 Not Found
+Content-Type: application/json; charset=utf-8
+
+{
+ "errors:" [
+ {
+ "code": ,
+ "message": "",
+ "detail": ...
+ },
+ ...
+ ]
+}
+```
+
+The blob, identified by `name` and `digest`, is unknown to the registry.
+
+
+
+The error codes that may be included in the response body are enumerated below:
+
+|Code|Message|Description|
+|----|-------|-----------|
+| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |
+| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |
+
+
+
+###### On Failure: Method Not Allowed
+
+```
+405 Method Not Allowed
+Content-Type: application/json; charset=utf-8
+
+{
+ "errors:" [
+ {
+ "code": ,
+ "message": "",
+ "detail": ...
+ },
+ ...
+ ]
+}
+```
+
+Delete is not enabled on the registry
+
+
+
+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 Blob Upload
diff --git a/docs/spec/api.md.tmpl b/docs/spec/api.md.tmpl
index de2f5a90e..cc6bd7c53 100644
--- a/docs/spec/api.md.tmpl
+++ b/docs/spec/api.md.tmpl
@@ -277,7 +277,7 @@ API. When this header is omitted, clients may fallback to an older API version.
This API design is driven heavily by [content addressability](http://en.wikipedia.org/wiki/Content-addressable_storage).
The core of this design is the concept of a content addressable identifier. It
-uniquely identifies content by taking a collision-resistent hash of the bytes.
+uniquely identifies content by taking a collision-resistant hash of the bytes.
Such an identifier can be independently calculated and verified by selection
of a common _algorithm_. If such an identifier can be communicated in a secure
manner, one can retrieve the content from an insecure source, calculate it
@@ -791,7 +791,7 @@ Images are stored in collections, known as a _repository_, which is keyed by a
contain several repositories. The list of available repositories is made
available through the _catalog_.
-The catalog for a given registry can be retrived with the following request:
+The catalog for a given registry can be retrieved with the following request:
```
GET /v2/_catalog
@@ -875,7 +875,7 @@ To get the next result set, a client would issue the request as follows, using
the URL encoded in the described `Link` header:
```
-GET /v2/_catalog?n=&last=
+GET /v2/_catalog?n=&last=
```
The above process should then be repeated until the `Link` header is no longer
diff --git a/registry/api/v2/descriptors.go b/registry/api/v2/descriptors.go
index 74bdb9f2e..0ef64f88b 100644
--- a/registry/api/v2/descriptors.go
+++ b/registry/api/v2/descriptors.go
@@ -519,7 +519,7 @@ var routeDescriptors = []RouteDescriptor{
Name: RouteNameManifest,
Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/manifests/{reference:" + TagNameRegexp.String() + "|" + digest.DigestRegexp.String() + "}",
Entity: "Manifest",
- Description: "Create, update and retrieve manifests.",
+ Description: "Create, update, delete and retrieve manifests.",
Methods: []MethodDescriptor{
{
Method: "GET",
@@ -536,7 +536,7 @@ var routeDescriptors = []RouteDescriptor{
},
Successes: []ResponseDescriptor{
{
- Description: "The manifest idenfied by `name` and `reference`. The contents can be used to identify and resolve resources required to run the specified image.",
+ Description: "The manifest identified by `name` and `reference`. The contents can be used to identify and resolve resources required to run the specified image.",
StatusCode: http.StatusOK,
Headers: []ParameterDescriptor{
digestHeader,
@@ -768,9 +768,8 @@ var routeDescriptors = []RouteDescriptor{
Name: RouteNameBlob,
Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/{digest:" + digest.DigestRegexp.String() + "}",
Entity: "Blob",
- Description: "Fetch the blob identified by `name` and `digest`. Used to fetch layers by digest.",
+ Description: "Operations on blobs identified by `name` and `digest`. Used to fetch or delete layers by digest.",
Methods: []MethodDescriptor{
-
{
Method: "GET",
Description: "Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.",
@@ -919,6 +918,70 @@ var routeDescriptors = []RouteDescriptor{
},
},
},
+ {
+ Method: "DELETE",
+ Description: "Delete the blob identified by `name` and `digest`",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ digestPathParameter,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ StatusCode: http.StatusAccepted,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "0",
+ Format: "0",
+ },
+ digestHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Name: "Invalid Name or Digest",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []errcode.ErrorCode{
+ ErrorCodeDigestInvalid,
+ ErrorCodeNameInvalid,
+ },
+ },
+ {
+ Description: "The blob, identified by `name` and `digest`, is unknown to the registry.",
+ StatusCode: http.StatusNotFound,
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []errcode.ErrorCode{
+ ErrorCodeNameUnknown,
+ ErrorCodeBlobUnknown,
+ },
+ },
+ {
+ Description: "Delete is not enabled on the registry",
+ StatusCode: http.StatusMethodNotAllowed,
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []errcode.ErrorCode{
+ ErrorCodeUnsupported,
+ },
+ },
+ },
+ },
+ },
+ },
+
// TODO(stevvooe): We may want to add a PUT request here to
// kickoff an upload of a blob, integrated with the blob upload
// API.
@@ -928,7 +991,7 @@ var routeDescriptors = []RouteDescriptor{
{
Name: RouteNameBlobUpload,
Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/",
- Entity: "Intiate Blob Upload",
+ Entity: "Initiate Blob Upload",
Description: "Initiate a blob upload. This endpoint can be used to create resumable uploads or monolithic uploads.",
Methods: []MethodDescriptor{
{