init project

This commit is contained in:
root
2026-07-31 13:12:54 -04:00
parent 0da92d5e02
commit f3863f760c
7215 changed files with 1860260 additions and 1 deletions
+2
View File
@@ -0,0 +1,2 @@
# 3rd-party files
node_modules
+35
View File
@@ -0,0 +1,35 @@
{
"env": {
"mocha": true,
"node": true
},
"rules": {
/* Possible Errors */
"no-extra-parens": 2,
"valid-jsdoc": 2,
/* Best Practices */
"block-scoped-var": 2,
"complexity": [1, 3],
"default-case": 2,
"dot-notation": [2],
"guard-for-in": 2,
"no-div-regex": 2,
"no-else-return": 2,
"no-eq-null": 2,
"no-floating-decimal": 2,
"no-process-env": 2,
"no-self-compare": 2,
"no-void": 2,
"no-warning-comments": 2,
"radix": 2,
"vars-on-top": 2,
"wrap-iife": 2,
/* Variables */
"no-catch-shadow": 2,
/* Node.JS */
"no-sync": 2,
/* Stylistic Issues */
"no-mixed-spaces-and-tabs": 2,
"no-underscore-dangle": 2,
"quotes": [1, "single", "avoid-escape"]
}}
+1
View File
@@ -0,0 +1 @@
github: apocas
+20
View File
@@ -0,0 +1,20 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 550
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- question
- bug
- enhancement
- "needs love"
- "needs inspection"
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Open a new issue if needed.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
+35
View File
@@ -0,0 +1,35 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
build_nodejs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Provisioning
run: |
docker --version
node -v
docker pull ubuntu
- name: NPM install
run: npm install
- name: NPM test
run: npm test
+24
View File
@@ -0,0 +1,24 @@
sudo: required
language: node_js
node_js:
- "8"
before_script:
- docker pull ubuntu
services:
- docker
before_install:
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update
- sudo apt-get -y install docker-ce
install:
- npm install
script:
- npm test
+25
View File
@@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"args": [
"--colors",
"${workspaceFolder}/test",
"-R",
"spec",
"--exit"
],
"internalConsoleOptions": "openOnSessionStart",
"name": "Mocha Tests",
"program": "./node_modules/mocha/bin/mocha.js",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
}
]
}
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+530
View File
@@ -0,0 +1,530 @@
# dockerode
Not another Node.js Docker Remote API module.
`dockerode` objectives:
* **streams** - `dockerode` does NOT break any stream, it passes them to you allowing for some stream voodoo.
* **stream demux** - Supports optional [stream demultiplexing](https://github.com/apocas/dockerode#helper-functions).
* **entities** - containers, images and execs are defined entities and not random static methods.
* **run** - `dockerode` allow you to seamless run commands in a container aka `docker run`.
* **tests** - `dockerode` really aims to have a good test set, allowing to follow `Docker` changes easily, quickly and painlessly.
* **feature-rich** - There's a real effort in keeping **All** `Docker` Remote API features implemented and tested.
* **interfaces** - Features **callback** and **promise** based interfaces, making everyone happy :)
## Ecosystem
* docker-modem [https://github.com/apocas/docker-modem](https://github.com/apocas/docker-modem) - Docker's API network stack
* dockerode-compose [https://github.com/apocas/dockerode-compose](https://github.com/apocas/dockerode-compose) - docker-compose in Node.js
## Installation
`npm install dockerode`
## Usage
* Input options are directly passed to Docker. Check [Docker API documentation](https://docs.docker.com/engine/api/latest/) for more details.
* Return values are unchanged from Docker, official Docker documentation will also apply to them.
* Check the tests and examples folder for more examples.
### Getting started
To use `dockerode` first you need to instantiate it:
``` js
var Docker = require('dockerode');
var docker = new Docker({socketPath: '/var/run/docker.sock'});
var docker1 = new Docker(); //defaults to above if env variables are not used
var docker2 = new Docker({host: 'http://192.168.1.10', port: 3000});
var docker3 = new Docker({protocol:'http', host: '127.0.0.1', port: 3000});
var docker4 = new Docker({host: '127.0.0.1', port: 3000}); //defaults to http
//protocol http vs https is automatically detected
var docker5 = new Docker({
host: '192.168.1.10',
port: process.env.DOCKER_PORT || 2375,
ca: fs.readFileSync('ca.pem'),
cert: fs.readFileSync('cert.pem'),
key: fs.readFileSync('key.pem'),
version: 'v1.25' // required when Docker >= v1.13, https://docs.docker.com/engine/api/version-history/
});
var docker6 = new Docker({
protocol: 'https', //you can enforce a protocol
host: '192.168.1.10',
port: process.env.DOCKER_PORT || 2375,
ca: fs.readFileSync('ca.pem'),
cert: fs.readFileSync('cert.pem'),
key: fs.readFileSync('key.pem')
});
//using a different promise library (default is the native one)
var docker7 = new Docker({
Promise: require('bluebird')
//...
});
//...
```
### Manipulating a container:
``` js
// create a container entity. does not query API
var container = docker.getContainer('71501a8ab0f8');
// query API for container info
container.inspect(function (err, data) {
console.log(data);
});
container.start(function (err, data) {
console.log(data);
});
container.remove(function (err, data) {
console.log(data);
});
// promises are supported
var auxContainer;
docker.createContainer({
Image: 'ubuntu',
AttachStdin: false,
AttachStdout: true,
AttachStderr: true,
Tty: true,
Cmd: ['/bin/bash', '-c', 'tail -f /var/log/dmesg'],
OpenStdin: false,
StdinOnce: false
}).then(function(container) {
auxContainer = container;
return auxContainer.start();
}).then(function(data) {
return auxContainer.resize({
h: process.stdout.rows,
w: process.stdout.columns
});
}).then(function(data) {
return auxContainer.stop();
}).then(function(data) {
return auxContainer.remove();
}).then(function(data) {
console.log('container removed');
}).catch(function(err) {
console.log(err);
});
```
You may also specify default options for each container's operations, which will always be used for the specified container and operation.
``` js
container.defaultOptions.start.Binds = ["/tmp:/tmp:rw"];
```
### Stopping all containers on a host
``` js
docker.listContainers(function (err, containers) {
containers.forEach(function (containerInfo) {
docker.getContainer(containerInfo.Id).stop(cb);
});
});
```
### Building an Image
Context: provides the path to the Dockerfile. Additionaly files that are involved in the build *must* be explicitly mentioned in src array, since they are sent to a temp env to build. Example: file for COPY command are extracted from that temporary environment.
``` js
docker.buildImage('archive.tar', {t: imageName}, function (err, response){
//...
});
docker.buildImage({
context: __dirname,
src: ['Dockerfile', 'file1', 'file2']
}, {t: imageName}, function (err, response) {
//...
});
```
`buildImage` returns a Promise of NodeJS stream. In case you want to find out when the build has finished, you must follow the progress of the build with the `modem` instance in dockerode:
``` js
let dockerode = new Dockerode();
let stream = await dockerode.buildImage(...);
await new Promise((resolve, reject) => {
dockerode.modem.followProgress(stream, (err, res) => err ? reject(err) : resolve(res));
});
// Build has finished
```
### Creating a container:
``` js
docker.createContainer({Image: 'ubuntu', Cmd: ['/bin/bash'], name: 'ubuntu-test'}, function (err, container) {
container.start(function (err, data) {
//...
});
});
//...
```
### Streams goodness:
``` js
//tty:true
docker.createContainer({ /*...*/ Tty: true /*...*/ }, function(err, container) {
/* ... */
container.attach({stream: true, stdout: true, stderr: true}, function (err, stream) {
stream.pipe(process.stdout);
});
/* ... */
});
//tty:false
docker.createContainer({ /*...*/ Tty: false /*...*/ }, function(err, container) {
/* ... */
container.attach({stream: true, stdout: true, stderr: true}, function (err, stream) {
//dockerode may demultiplex attach streams for you :)
container.modem.demuxStream(stream, process.stdout, process.stderr);
});
/* ... */
});
docker.createImage({fromImage: 'ubuntu'}, function (err, stream) {
stream.pipe(process.stdout);
});
//...
```
There is also support for [HTTP connection hijacking](https://docs.docker.com/engine/api/v1.45/#tag/Container/operation/ContainerAttach),
which allows for cleaner interactions with commands that work with stdin and stdout separately.
```js
docker.createContainer({Tty: false, /*... other options */}, function(err, container) {
container.start(function(err) {
container.exec({Cmd: ['shasum', '-'], AttachStdin: true, AttachStdout: true}, function(err, exec) {
exec.start({hijack: true, stdin: true}, function(err, stream) {
// shasum can't finish until after its stdin has been closed, telling it that it has
// read all the bytes it needs to sum. Without a socket upgrade, there is no way to
// close the write-side of the stream without also closing the read-side!
fs.createReadStream('node-v5.1.0.tgz', 'binary').pipe(stream);
// Fortunately, we have a regular TCP socket now, so when the readstream finishes and closes our
// stream, it is still open for reading and we will still get our results :-)
docker.modem.demuxStream(stream, process.stdout, process.stderr);
});
});
});
});
```
### Equivalent of `docker run` in `dockerode`:
* `image` - container image
* `cmd` - command to be executed
* `stream` - stream(s) which will be used for execution output.
* `create_options` - (optional) Options used for container creation. Refer to the [DockerEngine ContainerCreate documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerCreate) for the possible values
* `start_options` - (optional) Options used for container start. Refer to the [DockerEngine ContainerStart documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerStart) for the possible values
* `callback` - callback called when execution ends (optional, promise will be returned if not used).
``` js
//callback
docker.run('ubuntu', ['bash', '-c', 'uname -a'], process.stdout, function (err, data, container) {
console.log(data.StatusCode);
});
//promise
docker.run(testImage, ['bash', '-c', 'uname -a'], process.stdout).then(function(data) {
var output = data[0];
var container = data[1];
console.log(output.StatusCode);
return container.remove();
}).then(function(data) {
console.log('container removed');
}).catch(function(err) {
console.log(err);
});
```
or, if you want to split stdout and stderr (you must to pass `Tty:false` as an option for this to work)
``` js
docker.run('ubuntu', ['bash', '-c', 'uname -a'], [process.stdout, process.stderr], {Tty:false}, function (err, data, container) {
console.log(data.StatusCode);
});
```
If you provide a callback, `run` will return an EventEmitter supporting the following events: container, stream, data.
If a callback isn't provided a promise will be returned.
``` js
docker.run('ubuntu', ['bash', '-c', 'uname -a'], [process.stdout, process.stderr], {Tty:false}, function (err, data, container) {
//...
}).on('container', function (container) {
//...
});
```
And here is one more complex example using auto-remove and Docker network.
``` js
docker.run('some-python-image', ['python', 'main.py', arg], process.stdout, {name: 'my-python-container', HostConfig: { AutoRemove: true, NetworkMode: 'my_network'}}, function(err, data, container) {
// Do stuff
});
```
### Equivalent of `docker pull` in `dockerode`:
* `repoTag` - container image name (optionally with tag)
`myrepo/myname:withtag`
* `options` - extra options passed to create image.
* `callback` - callback called when execution ends.
``` js
docker.pull('myrepo/myname:tag', function (err, stream) {
// streaming output from pull...
});
```
#### Pull from private repos
`docker-modem` already base64 encodes the necessary auth object for you.
``` js
var auth = {
username: 'username',
password: 'password',
auth: '',
email: 'your@email.email',
serveraddress: 'https://index.docker.io/v1'
};
docker.pull('tag', {'authconfig': auth}, function (err, stream) {
//...
});
```
If you already have a base64 encoded auth object, you can use it directly:
```js
var auth = { key: 'yJ1J2ZXJhZGRyZXNzIjoitZSI6Im4OCIsImF1dGgiOiIiLCJlbWFpbCI6ImZvbGllLmFkcmc2VybmF0iLCJzZX5jb2aHR0cHM6Ly9pbmRleC5kb2NrZXIuaW8vdZvbGllYSIsInBhc3N3b3JkIjoiRGVjZW1icmUjEvIn0=' }
```
## Helper functions
* `followProgress` - allows to fire a callback only in the end of a stream based process. (build, pull, ...)
``` js
//followProgress(stream, onFinished, [onProgress])
docker.pull(repoTag, function(err, stream) {
//...
docker.modem.followProgress(stream, onFinished, onProgress);
function onFinished(err, output) {
//output is an array with output json parsed objects
//...
}
function onProgress(event) {
//...
}
});
```
* `demuxStream` - demux stdout and stderr
``` js
//demuxStream(stream, stdout, stderr)
container.attach({
stream: true,
stdout: true,
stderr: true
}, function handler(err, stream) {
//...
container.modem.demuxStream(stream, process.stdout, process.stderr);
//...
});
```
## Sponsors
Amazing entities that [sponsor](https://github.com/sponsors/apocas) my open-source work. Check them out!
[![HTTP Toolkit](https://avatars.githubusercontent.com/u/39777515?s=100)](https://github.com/httptoolkit)
[![OOMOL - Oomol AI Studio](https://avatars.githubusercontent.com/u/146153906?s=100)](https://oomol.com)
## Documentation
### Docker
- docker.createContainer(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Container/operation/ContainerCreate)
- docker.createImage([auth], options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image/operation/ImageCreate)
- docker.loadImage(file, options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image/operation/ImageLoad)
- docker.importImage(file, options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image/operation/ImageCreate)
- docker.buildImage(file, options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image/operation/ImageBuild)
- docker.checkAuth(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/System/operation/SystemAuth)
- docker.getContainer(id) - Returns a Container object.
- docker.getImage(name) - Returns an Image object.
- docker.getVolume(name) - Returns a Volume object.
- docker.getPlugin(name) - Returns a Plugin object.
- docker.getService(id) - Returns a Service object.
- docker.getTask(id) - Returns a Task object.
- docker.getNode(id) - Returns a Node object.
- docker.getNetwork(id) - Returns a Network object.
- docker.getSecret(id) - Returns a Secret object.
- docker.getConfig(id) - Returns a Config object.
- docker.getExec(id) - Returns a Exec object.
- docker.listContainers(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Container/operation/ContainerList)
- docker.listImages(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image/operation/ImageList)
- docker.listServices(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Service/operation/ServiceList)
- docker.listNodes(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Node/operation/NodeList)
- docker.listTasks(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Task/operation/TaskList)
- docker.listSecrets(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Secret/operation/SecretList)
- docker.listConfigs(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Config/operation/ConfigList)
- docker.listPlugins(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Plugin/operation/PluginList)
- docker.listVolumes(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Volume/operation/VolumeList)
- docker.listNetworks(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Network/operation/NetworkList)
- docker.createSecret(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Secret/operation/SecretCreate)
- docker.createConfig(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Config/operation/ConfigCreate)
- docker.createPlugin(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Plugin/operation/PluginCreate)
- docker.createVolume(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Volume/operation/VolumeCreate)
- docker.createService(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ServiceCreate)
- docker.createNetwork(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkCreate)
- docker.pruneImages(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImagePrune)
- docker.pruneBuilder() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/BuildPrune)
- docker.pruneContainers(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerPrune)
- docker.pruneVolumes(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/VolumePrune)
- docker.pruneNetworks(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkPrune)
- docker.searchImages(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageSearch)
- docker.info() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SystemInfo)
- docker.version() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SystemVersion)
- docker.ping() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SystemPing)
- docker.df() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SystemDataUsage)
- docker.getEvents(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SystemEvents)
- docker.swarmInit(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SwarmInit)
- docker.swarmJoin(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SwarmJoin)
- docker.swarmLeave(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SwarmLeave)
- docker.swarmUpdate(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SwarmUpdate)
- docker.swarmInspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SwarmInspect)
- docker.pull(repoTag, options, callback, auth) - Like Docker's CLI pull
- docker.pullAll(repoTag, options, callback, auth) - Like Docker's CLI pull with "-a"
- docker.run(image, cmd, stream, createOptions, startOptions) - Like Docker's CLI run
### Container
- container.inspect(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerInspect)
- container.rename(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerRename)
- container.update(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerUpdate)
- container.top(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerTop)
- container.changes() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerChanges)
- container.export() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerExport)
- container.start(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerStart)
- container.stop(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerStop)
- container.pause(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerPause)
- container.unpause(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerUnpause)
- container.exec(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerExec)
- container.commit(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageCommit)
- container.restart(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerRestart)
- container.kill(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerKill)
- container.resize(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerResize)
- container.attach(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerAttach)
- container.wait(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerWait)
- container.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerDelete)
- container.getArchive(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerArchive)
- container.infoArchive(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerArchiveInfo)
- container.putArchive(file, options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PutContainerArchive)
- container.logs(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerLogs)
- container.stats(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerStats)
### Exec
- exec.start(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ExecStart)
- exec.resize(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ExecResize)
- exec.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ExecInspect)
### Image
- image.inspect(options) - [Docker API Endpoint](https://docs.docker.com/engine/api/v1.48/#tag/Image/operation/ImageInspect)
- image.history() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageHistory)
- image.push(options, callback, auth) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImagePush)
- image.tag(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageTag)
- image.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageDelete)
- image.get() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ImageGet)
### Network
- network.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkInspect)
- network.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkDelete)
- network.connect(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkConnect)
- network.disconnect(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NetworkDisconnect)
### Node
- node.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NodeInspect)
- node.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NodeDelete)
- node.update(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/NodeUpdate)
### Plugin
- plugin.privileges() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/GetPluginPrivileges)
- plugin.pull(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginPull)
- plugin.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginInspect)
- plugin.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginDelete)
- plugin.enable(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginEnable)
- plugin.disable(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginDisable)
- plugin.update([auth], options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginUpgrade)
- plugin.push(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginPush)
- plugin.configure(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/PluginSet)
### Secret
- secret.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SecretInspect)
- secret.remove() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SecretDelete)
- secret.update(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/SecretUpdate)
### Service
- service.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ServiceInspect)
- service.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ServiceDelete)
- service.update(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ServiceUpdate)
- service.logs(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ServiceLogs)
### Task
- task.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/TaskInspect)
- task.logs(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/Session)
### Volume
- volume.inspect() - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/VolumeInspect)
- volume.remove(options) - [Docker API Endpoint](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/VolumeDelete)
## Tests
* `docker pull ubuntu:latest` to prepare your system for the tests.
* Tests are implemented using `mocha` and `chai`. Run them with `npm test`.
## Examples
Check the examples folder for more specific use cases examples.
## License
Pedro Dias - [@pedromdias](https://twitter.com/pedromdias)
Licensed under the Apache license, version 2.0 (the "license"); You may not use this file except in compliance with the license. You may obtain a copy of the license at:
http://www.apache.org/licenses/LICENSE-2.0.html
Unless required by applicable law or agreed to in writing, software distributed under the license is distributed on an "as is" basis, without warranties or conditions of any kind, either express or implied. See the license for the specific language governing permissions and limitations under the license.
+242
View File
@@ -0,0 +1,242 @@
var protobuf = require("protobufjs");
var path = require("path");
// Constants
var BUILDKIT_TRACE_ID = "moby.buildkit.trace";
var BUILDKIT_IMAGE_ID = "moby.image.id";
var PROTO_TYPE = "moby.buildkit.v1.StatusResponse";
var ENCODING_UTF8 = "utf8";
var ENCODING_BASE64 = "base64";
var StatusResponse;
// Load the protobuf schema
function loadProto() {
if (StatusResponse) return StatusResponse;
var root = protobuf.loadSync(
path.resolve(__dirname, "proto", "buildkit_status.proto")
);
StatusResponse = root.lookupType(PROTO_TYPE);
return StatusResponse;
}
/**
* Decodes a BuildKit trace message
* @param {string} base64Data - Base64-encoded protobuf data from aux field
* @returns {Object} Decoded status response with vertexes, logs, etc.
*/
function decodeBuildKitStatus(base64Data) {
var StatusResponse = loadProto();
// Handle empty messages
if (!base64Data || base64Data.length === 0) {
return {
vertexes: [],
statuses: [],
logs: [],
warnings: []
};
}
var buffer = Buffer.from(base64Data, ENCODING_BASE64);
var message = StatusResponse.decode(buffer);
return StatusResponse.toObject(message, {
longs: String,
enums: String,
bytes: String,
defaults: true
});
}
/**
* Formats BuildKit status into human-readable text
* @param {Object} status - Decoded status response
* @returns {string[]} Array of human-readable log lines
*/
function formatBuildKitStatus(status) {
var lines = [];
// Process vertexes (build steps)
if (status.vertexes && status.vertexes.length > 0) {
status.vertexes.forEach(function(vertex) {
if (vertex.name && vertex.started && !vertex.completed) {
lines.push("[" + vertex.digest.substring(0, 12) + "] " + vertex.name);
}
if (vertex.error) {
lines.push("ERROR: " + vertex.error);
}
if (vertex.completed && vertex.cached) {
lines.push("CACHED: " + vertex.name);
}
});
}
// Process logs (command output)
if (status.logs && status.logs.length > 0) {
status.logs.forEach(function(log) {
var msg = Buffer.from(log.msg).toString(ENCODING_UTF8);
if (msg.trim()) {
lines.push(msg.trimEnd());
}
});
}
// Process status updates (progress)
if (status.statuses && status.statuses.length > 0) {
status.statuses.forEach(function(s) {
if (s.name && s.total > 0) {
var percent = Math.floor((s.current / s.total) * 100);
lines.push(s.name + ": " + percent + "% (" + s.current + "/" + s.total + ")");
}
});
}
// Process warnings
if (status.warnings && status.warnings.length > 0) {
status.warnings.forEach(function(warning) {
var msg = Buffer.from(warning.short).toString(ENCODING_UTF8);
lines.push("WARNING: " + msg);
});
}
return lines;
}
/**
* Parse a BuildKit stream line and extract human-readable logs
* @param {string} line - JSON line from build stream
* @returns {Object} { isBuildKit: boolean, logs: string[], raw: Object }
*/
function parseBuildKitLine(line) {
try {
var json = JSON.parse(line);
// Check if it's a BuildKit trace message
if (json.id === BUILDKIT_TRACE_ID && json.aux !== undefined) {
var status = decodeBuildKitStatus(json.aux);
var logs = formatBuildKitStatus(status);
return {
isBuildKit: true,
logs: logs,
raw: status
};
}
// Check if it's the final image ID
if (json.id === BUILDKIT_IMAGE_ID && json.aux && json.aux.ID) {
return {
isBuildKit: true,
logs: ["Built image: " + json.aux.ID],
raw: json.aux
};
}
// Not a BuildKit message
return {
isBuildKit: false,
logs: [],
raw: json
};
} catch (e) {
return {
isBuildKit: false,
logs: [],
raw: null,
error: e.message
};
}
}
/**
* Follow progress of a stream, automatically handling both BuildKit and regular output.
* This provides the same ergonomics as modem.followProgress but decodes BuildKit logs.
*
* @param {Stream} stream - Stream from buildImage(), pull(), push(), etc.
* @param {Function} onFinished - Called when stream ends: (err, output) => void
* @param {Function} onProgress - Called for each log event: (event) => void
* @returns {void}
*/
function followProgress(stream, onFinished, onProgress) {
var buffer = '';
var output = [];
var finished = false;
stream.on('data', onStreamEvent);
stream.on('error', onStreamError);
stream.on('end', onStreamEnd);
stream.on('close', onStreamEnd);
function onStreamEvent(data) {
buffer += data.toString();
// Process complete lines
var lines = buffer.split('\n');
buffer = lines.pop(); // Save incomplete line
lines.forEach(function(line) {
if (!line.trim()) return;
processLine(line);
});
}
function processLine(line) {
try {
// Try to parse as BuildKit or regular Docker output
var result = parseBuildKitLine(line);
if (result.isBuildKit) {
// BuildKit message - create events from decoded logs
result.logs.forEach(function(log) {
var event = { stream: log + '\n' };
output.push(event);
if (onProgress) onProgress(event);
});
} else if (result.raw) {
// Regular Docker message
output.push(result.raw);
if (onProgress) onProgress(result.raw);
}
} catch (e) {
// If parsing fails, try plain JSON
try {
var json = JSON.parse(line);
output.push(json);
if (onProgress) onProgress(json);
} catch (e2) {
// Ignore parse errors
}
}
}
function onStreamError(err) {
finished = true;
stream.removeListener('data', onStreamEvent);
stream.removeListener('error', onStreamError);
stream.removeListener('end', onStreamEnd);
stream.removeListener('close', onStreamEnd);
if (onFinished) onFinished(err, output);
}
function onStreamEnd() {
if (finished) return;
finished = true;
// Process any remaining data in buffer
if (buffer.trim()) {
processLine(buffer);
}
stream.removeListener('data', onStreamEvent);
stream.removeListener('error', onStreamError);
stream.removeListener('end', onStreamEnd);
stream.removeListener('close', onStreamEnd);
if (onFinished) onFinished(null, output);
}
}
module.exports = {
followProgress: followProgress
};
+135
View File
@@ -0,0 +1,135 @@
var util = require('./util');
/**
* Represents a config
* @param {Object} modem docker-modem
* @param {String} id Config's id
*/
var Config = function(modem, id) {
this.modem = modem;
this.id = id;
};
Config.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
*
* @param {Object} opts Options (optional)
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Config.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/configs/' + this.id,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'config not found',
500: 'server error',
503: 'node is not part of a swarm'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Update a config.
*
* @param {object} opts
* @param {function} callback
*/
Config.prototype.update = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/configs/' + this.id + '/update?',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'config not found',
500: 'server error',
503: 'node is not part of a swarm'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Removes the config
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Config.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/configs/' + this.id,
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'config not found',
500: 'server error',
503: 'node is not part of a swarm'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Config;
+1085
View File
File diff suppressed because it is too large Load Diff
+1903
View File
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
var util = require('./util');
/**
* Represents an Exec
* @param {Object} modem docker-modem
* @param {String} id Exec's ID
*/
var Exec = function(modem, id) {
this.modem = modem;
this.id = id;
};
Exec.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Start the exec call that was setup.
*
* @param {object} opts
* @param {function} callback
*/
Exec.prototype.start = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/exec/' + this.id + '/start',
method: 'POST',
abortSignal: args.opts.abortSignal,
isStream: true,
allowEmpty: true,
hijack: args.opts.hijack,
openStdin: args.opts.stdin,
statusCodes: {
200: true,
204: true,
404: 'no such exec',
409: 'container stopped/paused',
500: 'container not running'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
/**
* Resize the exec call that was setup.
*
* @param {object} opts
* @param {function} callback
*/
Exec.prototype.resize = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/exec/' + this.id + '/resize?',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such exec',
500: 'container not running'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
/**
* Get low-level information about the exec call.
*
* @param {Object} opts Options (optional)
* @param {function} callback
*/
Exec.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/exec/' + this.id + '/json',
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such exec',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
module.exports = Exec;
+279
View File
@@ -0,0 +1,279 @@
var util = require('./util');
/**
* Represents an image
* @param {Object} modem docker-modem
* @param {String} name Image's name
*/
var Image = function(modem, name) {
this.modem = modem;
this.name = name;
};
Image.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
* @param {Object} opts Inspect options, only 'manifests' (optional)
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Image.prototype.inspect = function(opts, callback) {
var args = util.processArgs(opts, callback);
var self = this;
var opts = {
path: '/images/' + this.name + '/json',
method: 'GET',
options: args.opts,
statusCodes: {
200: true,
404: 'no such image',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(opts, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(opts, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
/**
* Distribution
* @param {Object} opts
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Image.prototype.distribution = function(opts, callback) {
var args = util.processArgs(opts, callback);
var self = this;
var fopts = {
path: '/distribution/' + this.name + '/json',
method: 'GET',
statusCodes: {
200: true,
401: 'no such image',
500: 'server error'
},
authconfig: (args.opts) ? args.opts.authconfig : undefined
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(fopts, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(fopts, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
/**
* History
* @param {Function} callback Callback
*/
Image.prototype.history = function(callback) {
var self = this;
var opts = {
path: '/images/' + this.name + '/history',
method: 'GET',
statusCodes: {
200: true,
404: 'no such image',
500: 'server error'
}
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(opts, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(opts, function(err, data) {
if (err) return callback(err, data);
callback(err, data);
});
}
};
/**
* Get
* @param {Function} callback Callback with data stream.
*/
Image.prototype.get = function(callback) {
var self = this;
var opts = {
path: '/images/' + this.name + '/get',
method: 'GET',
isStream: true,
statusCodes: {
200: true,
500: 'server error'
}
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(opts, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(opts, function(err, data) {
if (err) return callback(err, data);
callback(err, data);
});
}
};
/**
* Push
* @param {Object} opts Push options, like 'registry' (optional)
* @param {Function} callback Callback with stream.
* @param {Object} auth Registry authentication
*/
Image.prototype.push = function(opts, callback, auth) {
var self = this;
var args = util.processArgs(opts, callback);
var isStream = true;
if (args.opts.stream === false) {
isStream = false;
}
var optsf = {
path: '/images/' + this.name + '/push?',
method: 'POST',
options: args.opts,
authconfig: args.opts.authconfig || auth,
abortSignal: args.opts.abortSignal,
isStream: isStream,
statusCodes: {
200: true,
404: 'no such image',
500: 'server error'
}
};
delete optsf.options.authconfig;
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
/**
* Tag
* @param {Object} opts Tag options, like 'repo' (optional)
* @param {Function} callback Callback
*/
Image.prototype.tag = function(opts, callback) {
var self = this;
var optsf = {
path: '/images/' + this.name + '/tag?',
method: 'POST',
options: opts,
abortSignal: opts && opts.abortSignal,
statusCodes: {
200: true, // unofficial, but proxies may return it
201: true,
400: 'bad parameter',
404: 'no such image',
409: 'conflict',
500: 'server error'
}
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
/**
* Removes the image
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Image.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/images/' + this.name + '?',
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such image',
409: 'conflict',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Image;
+171
View File
@@ -0,0 +1,171 @@
var util = require('./util');
/**
* Represents an network
* @param {Object} modem docker-modem
* @param {String} id Network's id
*/
var Network = function(modem, id) {
this.modem = modem;
this.id = id;
};
Network.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Id only if callback isn't specified.
*/
Network.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var opts = {
path: '/networks/' + this.id + '?',
method: 'GET',
statusCodes: {
200: true,
404: 'no such network',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(opts, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(opts, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Removes the network
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Network.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/networks/' + this.id,
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'no such network',
409: 'conflict',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Connects a container to a network
* @param {[Object]} opts Connect options (optional)
* @param {Function} callback Callback
*/
Network.prototype.connect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/networks/' + this.id + '/connect',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
201: true,
404: 'network or container is not found',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Disconnects a container from a network
* @param {[Object]} opts Disconnect options (optional)
* @param {Function} callback Callback
*/
Network.prototype.disconnect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/networks/' + this.id + '/disconnect',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
201: true,
404: 'network or container is not found',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Network;
+135
View File
@@ -0,0 +1,135 @@
var util = require('./util');
/**
* Represents an Node
* @param {Object} modem docker-modem
* @param {String} id Node's ID
*/
var Node = function(modem, id) {
this.modem = modem;
this.id = id;
};
Node.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Query Docker for Node details.
*
* @param {Object} opts Options (optional)
* @param {function} callback
*/
Node.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/nodes/' + this.id,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such node',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Update a node.
*
* @param {object} opts
* @param {function} callback
*/
Node.prototype.update = function(opts, callback) {
var self = this;
if (!callback && typeof opts === 'function') {
callback = opts;
}
var optsf = {
path: '/nodes/' + this.id + '/update?',
method: 'POST',
abortSignal: opts && opts.abortSignal,
statusCodes: {
200: true,
404: 'no such node',
406: 'node is not part of a swarm',
500: 'server error'
},
options: opts
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
/**
* Remove a Node.
* Warning: This method is not documented in the API.
*
* @param {object} opts
* @param {function} callback
*/
Node.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/nodes/' + this.id + '?',
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such node',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Node;
+372
View File
@@ -0,0 +1,372 @@
var util = require('./util');
/**
* Represents a plugin
* @param {Object} modem docker-modem
* @param {String} name Plugin's name
*/
var Plugin = function(modem, name, remote) {
this.modem = modem;
this.name = name;
this.remote = remote || name;
};
Plugin.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
*
* @param {Object} opts Options (optional)
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Plugin.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '/json',
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'plugin is not installed',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Removes the plugin
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Plugin.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '?',
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'plugin is not installed',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
if (err) return args.callback(err, data);
args.callback(err, data);
});
}
};
/**
* get privileges
* @param {Object} opts Options (optional)
* @param {Function} callback Callback
* @return {Object} Name only if callback isn't specified.
*/
Plugin.prototype.privileges = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/privileges?',
method: 'GET',
options: {
'remote': this.remote
},
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Installs a new plugin
* @param {Object} opts Create options
* @param {Function} callback Callback
*/
Plugin.prototype.pull = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
if(args.opts._query && !args.opts._query.name) {
args.opts._query.name = this.name;
}
if(args.opts._query && !args.opts._query.remote) {
args.opts._query.remote = this.remote;
}
var optsf = {
path: '/plugins/pull?',
method: 'POST',
abortSignal: args.opts.abortSignal,
isStream: true,
options: args.opts,
statusCodes: {
200: true, // unofficial, but proxies may return it
204: true,
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Enable
* @param {Object} opts Plugin enable options (optional)
* @param {Function} callback Callback
*/
Plugin.prototype.enable = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '/enable?',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Disable
* @param {Object} opts Plugin disable options (optional)
* @param {Function} callback Callback
*/
Plugin.prototype.disable = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '/disable',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Push
* @param {Object} opts Plugin push options (optional)
* @param {Function} callback Callback
*/
Plugin.prototype.push = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '/push',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'plugin not installed',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* COnfigure
* @param {Object} opts Plugin configure options (optional)
* @param {Function} callback Callback
*/
Plugin.prototype.configure = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/plugins/' + this.name + '/set',
method: 'POST',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'plugin not installed',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Upgrade plugin
*
* @param {object} auth
* @param {object} opts
* @param {function} callback
*/
Plugin.prototype.upgrade = function(auth, opts, callback) {
var self = this;
if (!callback && typeof opts === 'function') {
callback = opts;
opts = auth;
auth = opts.authconfig || undefined;
}
var optsf = {
path: '/plugins/' + this.name + '/upgrade?',
method: 'POST',
abortSignal: opts && opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'plugin not installed',
500: 'server error'
},
authconfig: auth,
options: opts
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
module.exports = Plugin;
+54
View File
@@ -0,0 +1,54 @@
syntax = "proto3";
package moby.filesync.v1;
option go_package = "auth";
service Auth{
rpc Credentials(CredentialsRequest) returns (CredentialsResponse);
rpc FetchToken(FetchTokenRequest) returns (FetchTokenResponse);
rpc GetTokenAuthority(GetTokenAuthorityRequest) returns (GetTokenAuthorityResponse);
rpc VerifyTokenAuthority(VerifyTokenAuthorityRequest) returns (VerifyTokenAuthorityResponse);
}
message CredentialsRequest {
string Host = 1;
}
message CredentialsResponse {
string Username = 1;
string Secret = 2;
}
message FetchTokenRequest {
string ClientID = 1;
string Host = 2;
string Realm = 3;
string Service = 4;
repeated string Scopes = 5;
}
message FetchTokenResponse {
string Token = 1;
int64 ExpiresIn = 2; // seconds
int64 IssuedAt = 3; // timestamp
}
message GetTokenAuthorityRequest {
string Host = 1;
bytes Salt = 2;
}
message GetTokenAuthorityResponse {
bytes PublicKey = 1;
}
message VerifyTokenAuthorityRequest {
string Host = 1;
bytes Payload = 2;
bytes Salt = 3;
}
message VerifyTokenAuthorityResponse {
bytes Signed = 1;
}
+81
View File
@@ -0,0 +1,81 @@
syntax = "proto3";
package moby.buildkit.v1;
// Minimal definitions for decoding BuildKit status messages
// Based on https://github.com/moby/buildkit/blob/master/api/services/control/control.proto
// Related to https://github.com/moby/buildkit/blob/master/solver/pb/ops.proto (vertices map to the solver op DAG)
message StatusResponse {
repeated Vertex vertexes = 1;
repeated VertexStatus statuses = 2;
repeated VertexLog logs = 3;
repeated VertexWarning warnings = 4;
}
message Vertex {
string digest = 1;
repeated string inputs = 2;
string name = 3;
bool cached = 4;
Timestamp started = 5;
Timestamp completed = 6;
string error = 7;
ProgressGroup progressGroup = 8;
}
message VertexStatus {
string ID = 1;
string vertex = 2;
string name = 3;
int64 current = 4;
int64 total = 5;
Timestamp timestamp = 6;
Timestamp started = 7;
Timestamp completed = 8;
}
message VertexLog {
string vertex = 1;
Timestamp timestamp = 2;
int64 stream = 3;
bytes msg = 4;
}
message VertexWarning {
string vertex = 1;
int64 level = 2;
bytes short = 3;
repeated bytes detail = 4;
string url = 5;
SourceInfo info = 6;
repeated Range ranges = 7;
}
message ProgressGroup {
string id = 1;
string name = 2;
bool weak = 3;
}
// Simplified Timestamp to match google.protobuf.Timestamp wire format
message Timestamp {
int64 seconds = 1;
int32 nanos = 2;
}
message SourceInfo {
string filename = 1;
bytes data = 2;
// definition and language fields omitted - not needed for log decoding
}
message Range {
Position start = 1;
Position end = 2;
}
message Position {
int32 line = 1;
int32 character = 2;
}
+134
View File
@@ -0,0 +1,134 @@
var util = require('./util');
/**
* Represents a secret
* @param {Object} modem docker-modem
* @param {String} id Secret's id
*/
var Secret = function(modem, id) {
this.modem = modem;
this.id = id;
};
Secret.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
* @param {Object} opts Options (optional)
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Secret.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/secrets/' + this.id,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'secret not found',
406: 'node is not part of a swarm',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Update a secret.
*
* @param {object} opts
* @param {function} callback
*/
Secret.prototype.update = function(opts, callback) {
var self = this;
if (!callback && typeof opts === 'function') {
callback = opts;
}
var optsf = {
path: '/secrets/' + this.id + '/update?',
method: 'POST',
abortSignal: opts && opts.abortSignal,
statusCodes: {
200: true,
404: 'secret not found',
500: 'server error'
},
options: opts
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
/**
* Removes the secret
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Secret.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/secrets/' + this.id,
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'secret not found',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Secret;
+183
View File
@@ -0,0 +1,183 @@
var util = require('./util');
/**
* Represents an Service
* @param {Object} modem docker-modem
* @param {String} id Service's ID
*/
var Service = function(modem, id) {
this.modem = modem;
this.id = id;
};
Service.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Query Docker for service details.
*
* @param {Object} opts Options (optional)
* @param {function} callback
*/
Service.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/services/' + this.id,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such service',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Delete Service
*
* @param {Object} opts Options (optional)
* @param {function} callback
*/
Service.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/services/' + this.id,
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
204: true,
404: 'no such service',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Update service
*
* @param {object} auth
* @param {object} opts
* @param {function} callback
*/
Service.prototype.update = function(auth, opts, callback) {
var self = this;
if (!callback) {
var t = typeof opts;
if(t === 'function'){
callback = opts;
opts = auth;
auth = opts.authconfig || undefined;
} else if (t === 'undefined'){
opts = auth;
auth = opts.authconfig || undefined;
}
}
var optsf = {
path: '/services/' + this.id + '/update?',
method: 'POST',
abortSignal: opts && opts.abortSignal,
statusCodes: {
200: true,
404: 'no such service',
500: 'server error'
},
authconfig: auth,
options: opts
};
if(callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
callback(err, data);
});
}
};
/**
* Service logs
* @param {Object} opts Logs options. (optional)
* @param {Function} callback Callback with data
*/
Service.prototype.logs = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback, {});
var optsf = {
path: '/services/' + this.id + '/logs?',
method: 'GET',
abortSignal: args.opts.abortSignal,
isStream: args.opts.follow || false,
statusCodes: {
200: true,
404: 'no such service',
500: 'server error',
503: 'node is not part of a swarm'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Service;
+63
View File
@@ -0,0 +1,63 @@
var grpc = require("@grpc/grpc-js"),
protoLoader = require("@grpc/proto-loader"),
path = require("path"),
uuid = require("uuid").v4;
function withSession(docker, auth, handler) {
const sessionId = uuid();
const opts = {
method: "POST",
path: "/session",
hijack: true,
headers: {
Upgrade: "h2c",
"X-Docker-Expose-Session-Uuid": sessionId,
"X-Docker-Expose-Session-Name": "testcontainers",
},
statusCodes: {
200: true,
500: "server error",
},
};
docker.modem.dial(opts, function (err, socket) {
if (err) {
return handler(err, null, () => undefined);
}
const server = new grpc.Server();
const creds = grpc.ServerCredentials.createInsecure();
const injector = server.createConnectionInjector(creds);
injector.injectConnection(socket);
const pkg = protoLoader.loadSync(
path.resolve(__dirname, "proto", "auth.proto")
);
const service = grpc.loadPackageDefinition(pkg);
server.addService(service.moby.filesync.v1.Auth.service, {
Credentials({ request }, callback) {
// We probably want to have the possibility to pass credentials per
// hots. The correct one could be returned based on `request.Host`
if (auth) {
callback(null, {
Username: auth.username,
Secret: auth.password,
});
} else {
callback(null, {});
}
},
});
function done() {
server.forceShutdown();
socket.end();
}
handler(null, sessionId, done);
});
}
module.exports = withSession;
+97
View File
@@ -0,0 +1,97 @@
var util = require('./util');
/**
* Represents an Task
* @param {Object} modem docker-modem
* @param {String} id Task's ID
*/
var Task = function(modem, id) {
this.modem = modem;
this.id = id;
this.defaultOptions = {
log: {}
};
};
Task.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Query Docker for Task details.
*
* @param {Object} opts Options (optional)
* @param {function} callback
*/
Task.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/tasks/' + this.id,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'unknown task',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Task logs
* @param {Object} opts Logs options. (optional)
* @param {Function} callback Callback with data
*/
Task.prototype.logs = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback, this.defaultOptions.log);
var optsf = {
path: '/tasks/' + this.id + '/logs?',
method: 'GET',
abortSignal: args.opts.abortSignal,
isStream: args.opts.follow || false,
statusCodes: {
101: true,
200: true,
404: 'no such container',
500: 'server error',
503: 'node is not part of a swarm'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Task;
+106
View File
@@ -0,0 +1,106 @@
var DockerIgnore = require('@balena/dockerignore');
var fs = require('fs');
var path = require('path');
var tar = require('tar-fs');
var zlib = require('zlib');
// https://github.com/HenrikJoreteg/extend-object/blob/v0.1.0/extend-object.js
var arr = [];
var each = arr.forEach;
var slice = arr.slice;
module.exports.extend = function(obj) {
each.call(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
obj[prop] = source[prop];
}
}
});
return obj;
};
module.exports.processArgs = function(opts, callback, defaultOpts) {
if (!callback && typeof opts === 'function') {
callback = opts;
opts = null;
}
return {
callback: callback,
opts: module.exports.extend({}, defaultOpts, opts)
};
};
/**
* Parse the given repo tag name (as a string) and break it out into repo/tag pair.
* // if given the input http://localhost:8080/woot:latest
* {
* repository: 'http://localhost:8080/woot',
* tag: 'latest'
* }
* @param {String} input Input e.g: 'repo/foo', 'ubuntu', 'ubuntu:latest'
* @return {Object} input parsed into the repo and tag.
*/
module.exports.parseRepositoryTag = function(input) {
var separatorPos;
var digestPos = input.indexOf('@');
var colonPos = input.lastIndexOf(':');
// @ symbol is more important
if (digestPos >= 0) {
separatorPos = digestPos;
} else if (colonPos >= 0) {
separatorPos = colonPos;
} else {
// no colon nor @
return {
repository: input
};
}
// last colon is either the tag (or part of a port designation)
var tag = input.slice(separatorPos + 1);
// if it contains a / its not a tag and is part of the url
if (tag.indexOf('/') === -1) {
return {
repository: input.slice(0, separatorPos),
tag: tag
};
}
return {
repository: input
};
};
module.exports.prepareBuildContext = function(file, next) {
if (file && file.context) {
fs.readFile(path.join(file.context, '.dockerignore'), (err, data) => {
let ignoreFn;
let filterFn;
if (!err) {
const dockerIgnore = DockerIgnore({ ignorecase: false }).add(data.toString());
filterFn = dockerIgnore.createFilter();
ignoreFn = (path) => {
return !filterFn(path);
}
}
const entries = file.src.slice() || []
const pack = tar.pack(file.context, {
entries: filterFn ? entries.filter(filterFn) : entries,
ignore: ignoreFn // Only works on directories
});
next(pack.pipe(zlib.createGzip()));
})
} else {
next(file);
}
}
+90
View File
@@ -0,0 +1,90 @@
var util = require('./util');
/**
* Represents a volume
* @param {Object} modem docker-modem
* @param {String} name Volume's name
*/
var Volume = function(modem, name) {
this.modem = modem;
this.name = name;
};
Volume.prototype[require('util').inspect.custom] = function() { return this; };
/**
* Inspect
* @param {Object} opts Options (optional)
* @param {Function} callback Callback, if specified Docker will be queried.
* @return {Object} Name only if callback isn't specified.
*/
Volume.prototype.inspect = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/volumes/' + this.name,
method: 'GET',
abortSignal: args.opts.abortSignal,
statusCodes: {
200: true,
404: 'no such volume',
500: 'server error'
}
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
/**
* Removes the volume
* @param {[Object]} opts Remove options (optional)
* @param {Function} callback Callback
*/
Volume.prototype.remove = function(opts, callback) {
var self = this;
var args = util.processArgs(opts, callback);
var optsf = {
path: '/volumes/' + this.name,
method: 'DELETE',
abortSignal: args.opts.abortSignal,
statusCodes: {
204: true,
404: 'no such volume',
409: 'conflict',
500: 'server error'
},
options: args.opts
};
if(args.callback === undefined) {
return new this.modem.Promise(function(resolve, reject) {
self.modem.dial(optsf, function(err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
} else {
this.modem.dial(optsf, function(err, data) {
args.callback(err, data);
});
}
};
module.exports = Volume;
+40
View File
@@ -0,0 +1,40 @@
{
"name": "dockerode",
"description": "Docker Remote API module.",
"version": "4.0.12",
"author": "Pedro Dias <petermdias@gmail.com>",
"maintainers": [
"apocas <petermdias@gmail.com>"
],
"repository": {
"type": "git",
"url": "http://github.com/apocas/dockerode.git"
},
"keywords": [
"docker",
"docker.io"
],
"dependencies": {
"@balena/dockerignore": "^1.0.2",
"@grpc/grpc-js": "^1.11.1",
"@grpc/proto-loader": "^0.7.13",
"docker-modem": "^5.0.7",
"protobufjs": "^7.3.2",
"tar-fs": "^2.1.4",
"uuid": "^10.0.0"
},
"devDependencies": {
"bluebird": "^3.7.0",
"chai": "~4.2.0",
"memorystream": "~0.3.0",
"mocha": "^10.2.0"
},
"main": "./lib/docker",
"scripts": {
"test": "./node_modules/mocha/bin/mocha.js -R spec --exit"
},
"license": "Apache-2.0",
"engines": {
"node": ">= 8.0"
}
}