node-docker-registry-client
A Docker Registry API client for node.js.
Limitations: Currently only support for Registry API v1 (https://docs.docker.com/v1.6/reference/api/registry_api/) pull support (i.e. excluding API endpoints for push) and Registry API v2 pull support. Support for v2 push endpoints is coming.
Install
npm install docker-registry-client
Overview
Most usage of this package involves creating a Registry API client for a specific repository and calling its methods.
A Registry client requires a repository name (called a repo
in the code):
[INDEX/]NAME # a "repo name"
Examples:
mongo # implies default index (docker.io) and namespace (library)
docker.io/mongo # same thing
docker.io/library/mongo # same thing
myreg.example.com:5000/busybox # a "busybox" repo on a private registry
quay.io/trentm/foo # trentm's "foo" repo on the quay.io service
The parseRepo
function is used to parse these. See "examples/parseRepo.js"
to see how they are parsed:
$ node examples/parseRepo.js mongo
{
"index": {
"name": "docker.io",
"official": true
},
"official": true,
"remoteName": "library/mongo",
"localName": "mongo",
"canonicalName": "docker.io/mongo"
}
Commonly, a "repo name and tag" string is used for working with a Docker
registry, e.g. docker pull busybox:latest
. The v2 API adds support for using
"repo name and digest" to stably identify images, e.g. docker pull alpine@sha256:fb9f16730ac6316afa4d97caa5130219927bfcecf0b0ce35c01dcb612f449739
.
This package provides a parseRepoAndRef
(and the synonym parseRepoAndTag
)
for that, e.g.:
$ node examples/parseRepoAndRef.js myreg.example.com:5000/busybox:foo
{
"index": {
"name": "myreg.example.com:5000",
"official": false
},
"official": false,
"remoteName": "busybox",
"localName": "myreg.example.com:5000/busybox",
"canonicalName": "myreg.example.com:5000/busybox",
"tag": "foo"
}
Slightly different than docker.git's parsing, this package allows the scheme to be given on the index:
$ node examples/parseRepoAndRef.js https://quay.io/trentm/foo
{
"index": {
"scheme": "https", // <--- scheme
"name": "quay.io",
"official": false
},
"official": false,
"remoteName": "trentm/foo",
"localName": "quay.io/trentm/foo",
"canonicalName": "quay.io/trentm/foo",
"tag": "latest" // <--- default to 'latest' tag
}
If a scheme isn't given, then "https" is assumed.
Usage
If you know, for example, that you are only dealing with a v2 Docker Registry, then simple usage will look like this:
var drc = require('docker-registry-client');
var REPO = 'alpine';
var client = drc.createClientV2({name: REPO});
client.listTags(function (err, tags) {
// ...
console.log(JSON.stringify(tags, null, 4));
/*
* Because the client is typically using Keep-Alive, it will maintain
* open connections. Therefore you should call `.close()` to close
* those when finished.
*/
client.close();
});
A more complete example (showing logging, auth, etc.):
var bunyan = require('bunyan');
var drc = require('docker-registry-client');
// This package uses https://github.com/trentm/node-bunyan for logging.
var log = bunyan.createLogger({
name: 'regplay',
// TRACE-level logging will show you all request/response activity
// with the registry. This isn't suggested for production usage.
level: 'trace'
});
var REPO = 'alpine';
var client = drc.createClientV2({
name: REPO,
log: log,
// Optional basic auth to the registry
username: <username>,
password: <password>,
// Optional, for a registry without a signed TLS certificate.
insecure: <true|false>,
// ... see the source code for other options
});
This package also supports the nominal technique for pinging the registry to see if it supports v2, otherwise falling back to v1:
var drc = require('docker-registry-client');
var REPO = 'alpine';
drc.createClient({name: REPO, /* ... */}, function (err, client) {
console.log('Got a Docker Registry API v%d client', client.version);
// ...
});
v2 API
A mapping of the Docker Registry API v2 endpoints to the API equivalents in this client lib. "NYI" means the endpoint is not yet implemented by this client lib.
Name | Endpoint | Description |
---|---|---|
ping | GET /v2/ |
Check that the endpoint implements Docker Registry API V2. |
listTags | GET /v2/<name>/tags/list |
Fetch the tags under the repository identified by name . |
getManifest | GET /v2/<name>/manifests/<reference> |
Fetch the manifest identified by name and reference where reference can be a tag or digest. |
putManifest | PUT /v2/<name>/manifests/<reference> |
NYI. Put the manifest identified by name and reference where reference can be a tag or digest. |
deleteManifest | DELETE /v2/<name>/manifests/<reference> |
NYI. Delete the manifest identified by name and reference where reference can be a tag or digest. |
createBlobReadStream | GET /v2/<name>/blobs/<digest> |
Retrieve the blob from the registry identified by digest . |
headBlob | HEAD /v2/<name>/blobs/<digest> |
Retrieve the blob from the registry identified by digest -- just the headers. |
startBlobUpload | POST /v2/<name>/blobs/uploads/ |
NYI. 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. |
getBlobUploadStatus | GET /v2/<name>/blobs/uploads/<uuid> |
NYI. Retrieve status of upload identified by uuid . The primary purpose of this endpoint is to resolve the current status of a resumable upload. |
uploadBlobChunk | PATCH /v2/<name>/blobs/uploads/<uuid> |
NYI. Upload a chunk of data for the specified upload. |
completeBlobUpload | PUT /v2/<name>/blobs/uploads/<uuid> |
NYI. Complete the upload specified by uuid , optionally appending the body as the final chunk. |
cancelBlobUpload | DELETE /v2/<name>/blobs/uploads/<uuid> |
NYI. Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout. |
deleteBlob | DELETE /v2/<name>/blobs/<digest> |
NYI. Delete the blob identified by name and digest . Warning: From the Docker spec I'm not sure that deleteBlob doesn't corrupt images if you delete a shared blob. |
listRepositories | GET /v2/_catalog/ |
NYI List all repositories in this registry. Spec. |
See "examples/v2/*.js" for short code examples one can run from the CLI for each API endpoint. E.g.:
$ npm install # install dependencies for this module
$ node examples/v2/listTags.js busybox
{
"name": "library/busybox",
"tags": [
"buildroot-2013.08.1",
"buildroot-2014.02",
"latest",
"ubuntu-12.04",
"ubuntu-14.04"
]
}
You can also get logging on processing and HTTP requests/responses via the
-v
option to the example scripts. This library uses
Bunyan for logging, so you'll
want to pipe the log output (on stderr) through the bunyan
command for
pretty output:
$ node examples/v2/listTags.js -v busybox 2>&1 | ./node_modules/.bin/bunyan
[2015-06-01T22:26:44.065Z] TRACE: v2.listTags/registry/23400 on grape.local: request sent
GET /v2/ HTTP/1.1
Host: registry-1.docker.io
accept: application/json
user-agent: node-docker-registry-client/2.0.0 (x64-darwin; node/0.10.28)
date: Mon, 01 Jun 2015 22:26:44 GMT
[2015-06-01T22:26:44.480Z] TRACE: v2.listTags/registry/23400 on grape.local: Response received (client_res={})
HTTP/1.1 401 Unauthorized
content-type: application/json; charset=utf-8
docker-distribution-api-version: registry/2.0
www-authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io"
date: Mon, 01 Jun 2015 22:26:44 GMT
content-length: 114
connection: close
strict-transport-security: max-age=3153600
[2015-06-01T22:26:44.482Z] TRACE: v2.listTags/registry/23400 on grape.local:
body received:
{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":null}]}
[2015-06-01T22:26:44.485Z] TRACE: v2.listTags/registry/23400 on grape.local: login
[2015-06-01T22:26:44.487Z] DEBUG: v2.listTags/registry/23400 on grape.local: login: get Bearer auth token
...
[2015-06-01T22:26:45.680Z] TRACE: v2.listTags/registry/23400 on grape.local:
body received:
{"name":"library/busybox","tags":["buildroot-2013.08.1","buildroot-2014.02","latest","ubuntu-12.04","ubuntu-14.04"]}
{
"name": "library/busybox",
"tags": [
"buildroot-2013.08.1",
"buildroot-2014.02",
"latest",
"ubuntu-12.04",
"ubuntu-14.04"
]
}
v1 API
A mapping of the Docker Registry API v1 endpoints to the API equivalents in this client lib.
Limitation: Only the read endpoints of the v1 API are implement. I.e. putting layers, deleting repositories, setting/deleting tags are all not implemented.
Name | Endpoint | Description |
---|---|---|
ping | GET /v1/_ping |
Check status of the registry. |
search | GET /v1/search |
Search the index. |
listRepoImgs | GET /v1/repositories/$repo/images |
List all images in this repo. This is actually against the "Index API" (aka "Hub API"). |
listRepoTags | GET /v1/repositories/$repo/tags |
List all tags for a repo. |
getImgAncestry | GET /v1/images/$imgId/ancestry |
Get the ancestry of an image. |
getImgJson | GET /v1/images/$imgId/json |
Get the metadata (sometimes called the "image JSON") for an image. |
getImgLayerStream | GET /v1/images/$imgId/layer |
Download the image layer file. |
- | PUT /v1/images/$imgId/layer |
Not implemented. Put image layer. |
- | DELETE /v1/repositories/$repo/tags/$tag |
Not implemented. Delete a repo tag. |
- | PUT /v1/repositories/$repo/tags/$tag |
Not implemented. Set a repo tag. |
- | DELETE /v1/repositories/$repo |
Not implemented. Delete a repo. |
See "examples/v1/*.js" for short code examples one can run from the CLI for each API endpoint. E.g.:
$ npm install # install dependencies for this module
$ node examples/v1/listRepoTags.js busybox
{
"buildroot-2013.08.1": "3dba22db9896eb5f020691e1f8cda46735de533ca7b6b1b3b072272752935bad",
"buildroot-2014.02": "8c2e06607696bd4afb3d03b687e361cc43cf8ec1a4a725bc96e39f05ba97dd55",
"latest": "8c2e06607696bd4afb3d03b687e361cc43cf8ec1a4a725bc96e39f05ba97dd55",
"ubuntu-12.04": "faf804f0e07b2936e84c9fe4ca7c60a6246cc669cf2ff70969f14a9eab6efb48",
"ubuntu-14.04": "32e97f5f5d6bd15b9cc293b38a5102a7ddac736852811110043992b20553177a"
}
You can also get logging on processing and HTTP requests/responses via the
-v
option to the example scripts. This library uses
Bunyan for logging, so you'll
want to pipe the log output (on stderr) through the bunyan
command for
pretty output:
$ node listRepoTags.js -v busybox 2>&1 | bunyan
[2015-09-02T22:14:35.790Z] TRACE: listRepoTags/registry/13388 on danger0.local: get session token/cookie
[2015-09-02T22:14:35.836Z] TRACE: listRepoTags/registry/13388 on danger0.local: request sent
GET /v1/repositories/library/busybox/images HTTP/1.1
Host: index.docker.io
X-Docker-Token: true
accept: application/json
user-agent: node-docker-registry-client/2.0.0 (x64-darwin; node/0.10.40)
date: Wed, 02 Sep 2015 22:14:35 GMT
[2015-09-02T22:14:36.374Z] TRACE: listRepoTags/registry/13388 on danger0.local: Response received (client_res={})
HTTP/1.1 200 OK
server: nginx/1.6.2
date: Wed, 02 Sep 2015 22:14:36 GMT
...
[2015-09-02T22:14:37.888Z] TRACE: listRepoTags/registry/13388 on danger0.local:
body received:
{"buildroot-2013.08.1": "3dba22db9...
[2015-09-02T22:14:37.888Z] TRACE: listRepoTags/registry/13388 on danger0.local: close http client (host=index.docker.io)
[2015-09-02T22:14:37.889Z] TRACE: listRepoTags/registry/13388 on danger0.local: close http client (host=registry-1.docker.io)
{
"buildroot-2013.08.1": "3dba22db9896eb5f020691e1f8cda46735de533ca7b6b1b3b072272752935bad",
"buildroot-2014.02": "8c2e06607696bd4afb3d03b687e361cc43cf8ec1a4a725bc96e39f05ba97dd55",
"latest": "8c2e06607696bd4afb3d03b687e361cc43cf8ec1a4a725bc96e39f05ba97dd55",
"ubuntu-12.04": "faf804f0e07b2936e84c9fe4ca7c60a6246cc669cf2ff70969f14a9eab6efb48",
"ubuntu-14.04": "32e97f5f5d6bd15b9cc293b38a5102a7ddac736852811110043992b20553177a"
}
V1 client usage:
var repo = 'alpine';
var client = drc.createClientV1({
name: repo,
// ...
});
client.listRepoTags(function (err, repoTags) {
client.close();
if (err) {
console.log(err);
process.exit(1);
}
console.log(JSON.stringify(repoTags, null, 4));
});
Development
Naming convensions
For naming this package attempts to consistently use repo
for repository,
img
for image, etc.
Commits
Before commit, ensure that the following checks are clean:
make prepush
Also see the note at the top that cr.joyent.us is used for code review for this repo.
Releases
Changes with possible user impact should:
-
Add a note to the changelog (CHANGES.md).
-
Bump the package version appropriately.
-
Once merged to master, the new version should be tagged and published to npm via:
make cutarelease
To list to npm accounts that have publish access:
npm owner ls docker-registry-client
The desire is that users of this package use published versions in their
package.json dependencies
, rather than depending on git shas.