@lakutata/docker 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +309 -0
- package/THIRD_PARTY_NOTICES.md +299 -0
- package/dist/cjs/client/BuildContext.d.ts +22 -0
- package/dist/cjs/client/BuildContext.js +76 -0
- package/dist/cjs/client/BuildKitProgress.d.ts +81 -0
- package/dist/cjs/client/BuildKitProgress.js +195 -0
- package/dist/cjs/client/DockerClient.d.ts +196 -0
- package/dist/cjs/client/DockerClient.js +312 -0
- package/dist/cjs/client/DockerConnection.d.ts +154 -0
- package/dist/cjs/client/DockerConnection.js +397 -0
- package/dist/cjs/client/DockerIgnore.d.ts +44 -0
- package/dist/cjs/client/DockerIgnore.js +186 -0
- package/dist/cjs/client/DockerRequestError.d.ts +17 -0
- package/dist/cjs/client/DockerRequestError.js +24 -0
- package/dist/cjs/client/DockerStreams.d.ts +35 -0
- package/dist/cjs/client/DockerStreams.js +117 -0
- package/dist/cjs/client/types/ContainerCreateResponse.d.ts +7 -0
- package/dist/cjs/client/types/ContainerCreateResponse.js +2 -0
- package/dist/cjs/client/types/ContainerStopQuery.d.ts +13 -0
- package/dist/cjs/client/types/ContainerStopQuery.js +2 -0
- package/dist/cjs/client/types/DeviceMapping.d.ts +8 -0
- package/dist/cjs/client/types/DeviceMapping.js +2 -0
- package/dist/cjs/client/types/IdResponse.d.ts +6 -0
- package/dist/cjs/client/types/IdResponse.js +2 -0
- package/dist/cjs/client/types/NetworkCreateResponse.d.ts +7 -0
- package/dist/cjs/client/types/NetworkCreateResponse.js +2 -0
- package/dist/cjs/client/types/PortBinding.d.ts +10 -0
- package/dist/cjs/client/types/PortBinding.js +2 -0
- package/dist/cjs/docker/ConnectionOptionsBuilder.d.ts +128 -0
- package/dist/cjs/docker/ConnectionOptionsBuilder.js +150 -0
- package/dist/cjs/docker/Docker.d.ts +301 -0
- package/dist/cjs/docker/Docker.js +703 -0
- package/dist/cjs/docker/exceptions/DockerConnectionException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerConnectionException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerContainerNotFoundException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerContainerNotFoundException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerImageBuildException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerImageBuildException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerImageImportException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerImageImportException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerImageNotFoundException.d.ts +10 -0
- package/dist/cjs/docker/exceptions/DockerImageNotFoundException.js +17 -0
- package/dist/cjs/docker/exceptions/DockerImagePullException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerImagePullException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerImagePushException.d.ts +8 -0
- package/dist/cjs/docker/exceptions/DockerImagePushException.js +15 -0
- package/dist/cjs/docker/exceptions/DockerImageRepoTagNotFoundException.d.ts +8 -0
- package/dist/cjs/docker/exceptions/DockerImageRepoTagNotFoundException.js +15 -0
- package/dist/cjs/docker/exceptions/DockerNetworkNotFoundException.d.ts +9 -0
- package/dist/cjs/docker/exceptions/DockerNetworkNotFoundException.js +16 -0
- package/dist/cjs/docker/exceptions/DockerRequestException.d.ts +22 -0
- package/dist/cjs/docker/exceptions/DockerRequestException.js +24 -0
- package/dist/cjs/docker/interfaces/IDockerConnectionOptions.d.ts +75 -0
- package/dist/cjs/docker/interfaces/IDockerConnectionOptions.js +2 -0
- package/dist/cjs/docker/interfaces/IDockerHttpConnectionOptions.d.ts +16 -0
- package/dist/cjs/docker/interfaces/IDockerHttpConnectionOptions.js +2 -0
- package/dist/cjs/docker/interfaces/IDockerHttpsConnectionOptions.d.ts +16 -0
- package/dist/cjs/docker/interfaces/IDockerHttpsConnectionOptions.js +2 -0
- package/dist/cjs/docker/interfaces/IDockerKeyObject.d.ts +14 -0
- package/dist/cjs/docker/interfaces/IDockerKeyObject.js +2 -0
- package/dist/cjs/docker/interfaces/IDockerSSHConnectionOptions.d.ts +16 -0
- package/dist/cjs/docker/interfaces/IDockerSSHConnectionOptions.js +2 -0
- package/dist/cjs/docker/interfaces/IDockerSocketConnectionOptions.d.ts +7 -0
- package/dist/cjs/docker/interfaces/IDockerSocketConnectionOptions.js +2 -0
- package/dist/cjs/docker/lib/DockerContainer.d.ts +315 -0
- package/dist/cjs/docker/lib/DockerContainer.js +742 -0
- package/dist/cjs/docker/lib/DockerContainerTTY.d.ts +99 -0
- package/dist/cjs/docker/lib/DockerContainerTTY.js +157 -0
- package/dist/cjs/docker/lib/DockerImage.d.ts +153 -0
- package/dist/cjs/docker/lib/DockerImage.js +273 -0
- package/dist/cjs/docker/lib/EngineSettings.d.ts +41 -0
- package/dist/cjs/docker/lib/EngineSettings.js +86 -0
- package/dist/cjs/docker/lib/ParseBaseImages.d.ts +9 -0
- package/dist/cjs/docker/lib/ParseBaseImages.js +50 -0
- package/dist/cjs/docker/lib/ParseEnvToRecord.d.ts +14 -0
- package/dist/cjs/docker/lib/ParseEnvToRecord.js +25 -0
- package/dist/cjs/docker/lib/ParseRepositoryTag.d.ts +17 -0
- package/dist/cjs/docker/lib/ParseRepositoryTag.js +48 -0
- package/dist/cjs/docker/lib/RegistryAuth.d.ts +8 -0
- package/dist/cjs/docker/lib/RegistryAuth.js +15 -0
- package/dist/cjs/docker/options/DockerPruneOptions.d.ts +38 -0
- package/dist/cjs/docker/options/DockerPruneOptions.js +47 -0
- package/dist/cjs/docker/options/auth/DockerAuthOptions.d.ts +46 -0
- package/dist/cjs/docker/options/auth/DockerAuthOptions.js +59 -0
- package/dist/cjs/docker/options/container/ContainerCommitOptions.d.ts +28 -0
- package/dist/cjs/docker/options/container/ContainerCommitOptions.js +39 -0
- package/dist/cjs/docker/options/container/ContainerCreateTTYOptions.d.ts +32 -0
- package/dist/cjs/docker/options/container/ContainerCreateTTYOptions.js +43 -0
- package/dist/cjs/docker/options/container/ContainerExecOptions.d.ts +26 -0
- package/dist/cjs/docker/options/container/ContainerExecOptions.js +38 -0
- package/dist/cjs/docker/options/container/ContainerExportDirectoryOptions.d.ts +27 -0
- package/dist/cjs/docker/options/container/ContainerExportDirectoryOptions.js +39 -0
- package/dist/cjs/docker/options/container/ContainerKillOptions.d.ts +25 -0
- package/dist/cjs/docker/options/container/ContainerKillOptions.js +36 -0
- package/dist/cjs/docker/options/container/ContainerLogsOptions.d.ts +48 -0
- package/dist/cjs/docker/options/container/ContainerLogsOptions.js +56 -0
- package/dist/cjs/docker/options/container/ContainerRemoveOptions.d.ts +22 -0
- package/dist/cjs/docker/options/container/ContainerRemoveOptions.js +34 -0
- package/dist/cjs/docker/options/container/ContainerSettingOptions.d.ts +137 -0
- package/dist/cjs/docker/options/container/ContainerSettingOptions.js +136 -0
- package/dist/cjs/docker/options/container/ContainerStopOptions.d.ts +28 -0
- package/dist/cjs/docker/options/container/ContainerStopOptions.js +40 -0
- package/dist/cjs/docker/options/container/ContainerTTYConsoleSizeOptions.d.ts +26 -0
- package/dist/cjs/docker/options/container/ContainerTTYConsoleSizeOptions.js +40 -0
- package/dist/cjs/docker/options/image/ImageBuildOptions.d.ts +117 -0
- package/dist/cjs/docker/options/image/ImageBuildOptions.js +111 -0
- package/dist/cjs/docker/options/image/ImageExportOptions.d.ts +33 -0
- package/dist/cjs/docker/options/image/ImageExportOptions.js +44 -0
- package/dist/cjs/docker/options/image/ImageImportOptions.d.ts +28 -0
- package/dist/cjs/docker/options/image/ImageImportOptions.js +42 -0
- package/dist/cjs/docker/options/image/ImagePullOptions.d.ts +49 -0
- package/dist/cjs/docker/options/image/ImagePullOptions.js +63 -0
- package/dist/cjs/docker/options/image/ImagePushOptions.d.ts +41 -0
- package/dist/cjs/docker/options/image/ImagePushOptions.js +56 -0
- package/dist/cjs/docker/options/image/ImageRemoveOptions.d.ts +26 -0
- package/dist/cjs/docker/options/image/ImageRemoveOptions.js +38 -0
- package/dist/cjs/docker/options/image/ImageTagOptions.d.ts +25 -0
- package/dist/cjs/docker/options/image/ImageTagOptions.js +38 -0
- package/dist/cjs/docker/options/network/NetworkCreateOptions.d.ts +54 -0
- package/dist/cjs/docker/options/network/NetworkCreateOptions.js +63 -0
- package/dist/cjs/docker/types/ContainerBind.d.ts +19 -0
- package/dist/cjs/docker/types/ContainerBind.js +2 -0
- package/dist/cjs/docker/types/ContainerCapability.d.ts +286 -0
- package/dist/cjs/docker/types/ContainerCapability.js +290 -0
- package/dist/cjs/docker/types/ContainerConfig.d.ts +67 -0
- package/dist/cjs/docker/types/ContainerConfig.js +2 -0
- package/dist/cjs/docker/types/ContainerDevice.d.ts +19 -0
- package/dist/cjs/docker/types/ContainerDevice.js +2 -0
- package/dist/cjs/docker/types/ContainerExecResult.d.ts +20 -0
- package/dist/cjs/docker/types/ContainerExecResult.js +2 -0
- package/dist/cjs/docker/types/ContainerNetwork.d.ts +46 -0
- package/dist/cjs/docker/types/ContainerNetwork.js +2 -0
- package/dist/cjs/docker/types/ContainerPort.d.ts +25 -0
- package/dist/cjs/docker/types/ContainerPort.js +2 -0
- package/dist/cjs/docker/types/ContainerRestartPolicy.d.ts +11 -0
- package/dist/cjs/docker/types/ContainerRestartPolicy.js +2 -0
- package/dist/cjs/docker/types/ContainerState.d.ts +48 -0
- package/dist/cjs/docker/types/ContainerState.js +2 -0
- package/dist/cjs/docker/types/ContainerStats.d.ts +408 -0
- package/dist/cjs/docker/types/ContainerStats.js +2 -0
- package/dist/cjs/docker/types/DockerOutputCallback.d.ts +8 -0
- package/dist/cjs/docker/types/DockerOutputCallback.js +2 -0
- package/dist/cjs/docker/types/ImageConfig.d.ts +34 -0
- package/dist/cjs/docker/types/ImageConfig.js +2 -0
- package/dist/cjs/docker/types/ImageExposePort.d.ts +17 -0
- package/dist/cjs/docker/types/ImageExposePort.js +2 -0
- package/dist/cjs/docker/types/NetworkInfo.d.ts +59 -0
- package/dist/cjs/docker/types/NetworkInfo.js +2 -0
- package/dist/cjs/docker/types/RepositoryTag.d.ts +15 -0
- package/dist/cjs/docker/types/RepositoryTag.js +2 -0
- package/dist/cjs/exports/Docker.d.ts +73 -0
- package/dist/cjs/exports/Docker.js +92 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/client/BuildContext.js +70 -0
- package/dist/esm/client/BuildKitProgress.js +190 -0
- package/dist/esm/client/DockerClient.js +307 -0
- package/dist/esm/client/DockerConnection.js +355 -0
- package/dist/esm/client/DockerIgnore.js +179 -0
- package/dist/esm/client/DockerRequestError.js +20 -0
- package/dist/esm/client/DockerStreams.js +111 -0
- package/dist/esm/client/types/ContainerCreateResponse.js +1 -0
- package/dist/esm/client/types/ContainerStopQuery.js +1 -0
- package/dist/esm/client/types/DeviceMapping.js +1 -0
- package/dist/esm/client/types/IdResponse.js +1 -0
- package/dist/esm/client/types/NetworkCreateResponse.js +1 -0
- package/dist/esm/client/types/PortBinding.js +1 -0
- package/dist/esm/docker/ConnectionOptionsBuilder.js +142 -0
- package/dist/esm/docker/Docker.js +697 -0
- package/dist/esm/docker/exceptions/DockerConnectionException.js +12 -0
- package/dist/esm/docker/exceptions/DockerContainerNotFoundException.js +12 -0
- package/dist/esm/docker/exceptions/DockerImageBuildException.js +12 -0
- package/dist/esm/docker/exceptions/DockerImageImportException.js +12 -0
- package/dist/esm/docker/exceptions/DockerImageNotFoundException.js +13 -0
- package/dist/esm/docker/exceptions/DockerImagePullException.js +12 -0
- package/dist/esm/docker/exceptions/DockerImagePushException.js +11 -0
- package/dist/esm/docker/exceptions/DockerImageRepoTagNotFoundException.js +11 -0
- package/dist/esm/docker/exceptions/DockerNetworkNotFoundException.js +12 -0
- package/dist/esm/docker/exceptions/DockerRequestException.js +20 -0
- package/dist/esm/docker/interfaces/IDockerConnectionOptions.js +1 -0
- package/dist/esm/docker/interfaces/IDockerHttpConnectionOptions.js +1 -0
- package/dist/esm/docker/interfaces/IDockerHttpsConnectionOptions.js +1 -0
- package/dist/esm/docker/interfaces/IDockerKeyObject.js +1 -0
- package/dist/esm/docker/interfaces/IDockerSSHConnectionOptions.js +1 -0
- package/dist/esm/docker/interfaces/IDockerSocketConnectionOptions.js +1 -0
- package/dist/esm/docker/lib/DockerContainer.js +739 -0
- package/dist/esm/docker/lib/DockerContainerTTY.js +154 -0
- package/dist/esm/docker/lib/DockerImage.js +270 -0
- package/dist/esm/docker/lib/EngineSettings.js +78 -0
- package/dist/esm/docker/lib/ParseBaseImages.js +47 -0
- package/dist/esm/docker/lib/ParseEnvToRecord.js +22 -0
- package/dist/esm/docker/lib/ParseRepositoryTag.js +45 -0
- package/dist/esm/docker/lib/RegistryAuth.js +12 -0
- package/dist/esm/docker/options/DockerPruneOptions.js +43 -0
- package/dist/esm/docker/options/auth/DockerAuthOptions.js +55 -0
- package/dist/esm/docker/options/container/ContainerCommitOptions.js +35 -0
- package/dist/esm/docker/options/container/ContainerCreateTTYOptions.js +39 -0
- package/dist/esm/docker/options/container/ContainerExecOptions.js +34 -0
- package/dist/esm/docker/options/container/ContainerExportDirectoryOptions.js +35 -0
- package/dist/esm/docker/options/container/ContainerKillOptions.js +32 -0
- package/dist/esm/docker/options/container/ContainerLogsOptions.js +52 -0
- package/dist/esm/docker/options/container/ContainerRemoveOptions.js +30 -0
- package/dist/esm/docker/options/container/ContainerSettingOptions.js +132 -0
- package/dist/esm/docker/options/container/ContainerStopOptions.js +36 -0
- package/dist/esm/docker/options/container/ContainerTTYConsoleSizeOptions.js +36 -0
- package/dist/esm/docker/options/image/ImageBuildOptions.js +107 -0
- package/dist/esm/docker/options/image/ImageExportOptions.js +40 -0
- package/dist/esm/docker/options/image/ImageImportOptions.js +38 -0
- package/dist/esm/docker/options/image/ImagePullOptions.js +59 -0
- package/dist/esm/docker/options/image/ImagePushOptions.js +52 -0
- package/dist/esm/docker/options/image/ImageRemoveOptions.js +34 -0
- package/dist/esm/docker/options/image/ImageTagOptions.js +34 -0
- package/dist/esm/docker/options/network/NetworkCreateOptions.js +59 -0
- package/dist/esm/docker/types/ContainerBind.js +1 -0
- package/dist/esm/docker/types/ContainerCapability.js +287 -0
- package/dist/esm/docker/types/ContainerConfig.js +1 -0
- package/dist/esm/docker/types/ContainerDevice.js +1 -0
- package/dist/esm/docker/types/ContainerExecResult.js +1 -0
- package/dist/esm/docker/types/ContainerNetwork.js +1 -0
- package/dist/esm/docker/types/ContainerPort.js +1 -0
- package/dist/esm/docker/types/ContainerRestartPolicy.js +1 -0
- package/dist/esm/docker/types/ContainerState.js +1 -0
- package/dist/esm/docker/types/ContainerStats.js +1 -0
- package/dist/esm/docker/types/DockerOutputCallback.js +1 -0
- package/dist/esm/docker/types/ImageConfig.js +1 -0
- package/dist/esm/docker/types/ImageExposePort.js +1 -0
- package/dist/esm/docker/types/NetworkInfo.js +1 -0
- package/dist/esm/docker/types/RepositoryTag.js +1 -0
- package/dist/esm/exports/Docker.js +73 -0
- package/dist/types/client/BuildContext.d.ts +22 -0
- package/dist/types/client/BuildKitProgress.d.ts +81 -0
- package/dist/types/client/DockerClient.d.ts +196 -0
- package/dist/types/client/DockerConnection.d.ts +154 -0
- package/dist/types/client/DockerIgnore.d.ts +44 -0
- package/dist/types/client/DockerRequestError.d.ts +17 -0
- package/dist/types/client/DockerStreams.d.ts +35 -0
- package/dist/types/client/types/ContainerCreateResponse.d.ts +7 -0
- package/dist/types/client/types/ContainerStopQuery.d.ts +13 -0
- package/dist/types/client/types/DeviceMapping.d.ts +8 -0
- package/dist/types/client/types/IdResponse.d.ts +6 -0
- package/dist/types/client/types/NetworkCreateResponse.d.ts +7 -0
- package/dist/types/client/types/PortBinding.d.ts +10 -0
- package/dist/types/docker/ConnectionOptionsBuilder.d.ts +128 -0
- package/dist/types/docker/Docker.d.ts +301 -0
- package/dist/types/docker/exceptions/DockerConnectionException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerContainerNotFoundException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerImageBuildException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerImageImportException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerImageNotFoundException.d.ts +10 -0
- package/dist/types/docker/exceptions/DockerImagePullException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerImagePushException.d.ts +8 -0
- package/dist/types/docker/exceptions/DockerImageRepoTagNotFoundException.d.ts +8 -0
- package/dist/types/docker/exceptions/DockerNetworkNotFoundException.d.ts +9 -0
- package/dist/types/docker/exceptions/DockerRequestException.d.ts +22 -0
- package/dist/types/docker/interfaces/IDockerConnectionOptions.d.ts +75 -0
- package/dist/types/docker/interfaces/IDockerHttpConnectionOptions.d.ts +16 -0
- package/dist/types/docker/interfaces/IDockerHttpsConnectionOptions.d.ts +16 -0
- package/dist/types/docker/interfaces/IDockerKeyObject.d.ts +14 -0
- package/dist/types/docker/interfaces/IDockerSSHConnectionOptions.d.ts +16 -0
- package/dist/types/docker/interfaces/IDockerSocketConnectionOptions.d.ts +7 -0
- package/dist/types/docker/lib/DockerContainer.d.ts +315 -0
- package/dist/types/docker/lib/DockerContainerTTY.d.ts +99 -0
- package/dist/types/docker/lib/DockerImage.d.ts +153 -0
- package/dist/types/docker/lib/EngineSettings.d.ts +41 -0
- package/dist/types/docker/lib/ParseBaseImages.d.ts +9 -0
- package/dist/types/docker/lib/ParseEnvToRecord.d.ts +14 -0
- package/dist/types/docker/lib/ParseRepositoryTag.d.ts +17 -0
- package/dist/types/docker/lib/RegistryAuth.d.ts +8 -0
- package/dist/types/docker/options/DockerPruneOptions.d.ts +38 -0
- package/dist/types/docker/options/auth/DockerAuthOptions.d.ts +46 -0
- package/dist/types/docker/options/container/ContainerCommitOptions.d.ts +28 -0
- package/dist/types/docker/options/container/ContainerCreateTTYOptions.d.ts +32 -0
- package/dist/types/docker/options/container/ContainerExecOptions.d.ts +26 -0
- package/dist/types/docker/options/container/ContainerExportDirectoryOptions.d.ts +27 -0
- package/dist/types/docker/options/container/ContainerKillOptions.d.ts +25 -0
- package/dist/types/docker/options/container/ContainerLogsOptions.d.ts +48 -0
- package/dist/types/docker/options/container/ContainerRemoveOptions.d.ts +22 -0
- package/dist/types/docker/options/container/ContainerSettingOptions.d.ts +137 -0
- package/dist/types/docker/options/container/ContainerStopOptions.d.ts +28 -0
- package/dist/types/docker/options/container/ContainerTTYConsoleSizeOptions.d.ts +26 -0
- package/dist/types/docker/options/image/ImageBuildOptions.d.ts +117 -0
- package/dist/types/docker/options/image/ImageExportOptions.d.ts +33 -0
- package/dist/types/docker/options/image/ImageImportOptions.d.ts +28 -0
- package/dist/types/docker/options/image/ImagePullOptions.d.ts +49 -0
- package/dist/types/docker/options/image/ImagePushOptions.d.ts +41 -0
- package/dist/types/docker/options/image/ImageRemoveOptions.d.ts +26 -0
- package/dist/types/docker/options/image/ImageTagOptions.d.ts +25 -0
- package/dist/types/docker/options/network/NetworkCreateOptions.d.ts +54 -0
- package/dist/types/docker/types/ContainerBind.d.ts +19 -0
- package/dist/types/docker/types/ContainerCapability.d.ts +286 -0
- package/dist/types/docker/types/ContainerConfig.d.ts +67 -0
- package/dist/types/docker/types/ContainerDevice.d.ts +19 -0
- package/dist/types/docker/types/ContainerExecResult.d.ts +20 -0
- package/dist/types/docker/types/ContainerNetwork.d.ts +46 -0
- package/dist/types/docker/types/ContainerPort.d.ts +25 -0
- package/dist/types/docker/types/ContainerRestartPolicy.d.ts +11 -0
- package/dist/types/docker/types/ContainerState.d.ts +48 -0
- package/dist/types/docker/types/ContainerStats.d.ts +408 -0
- package/dist/types/docker/types/DockerOutputCallback.d.ts +8 -0
- package/dist/types/docker/types/ImageConfig.d.ts +34 -0
- package/dist/types/docker/types/ImageExposePort.d.ts +17 -0
- package/dist/types/docker/types/NetworkInfo.d.ts +59 -0
- package/dist/types/docker/types/RepositoryTag.d.ts +15 -0
- package/dist/types/exports/Docker.d.ts +73 -0
- package/package.json +57 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { DockerConnection } from './DockerConnection.js';
|
|
2
|
+
import { DockerRequestError } from './DockerRequestError.js';
|
|
3
|
+
import { DockerContainerNotFoundException } from '../docker/exceptions/DockerContainerNotFoundException.js';
|
|
4
|
+
import { DockerImageNotFoundException } from '../docker/exceptions/DockerImageNotFoundException.js';
|
|
5
|
+
import { DockerNetworkNotFoundException } from '../docker/exceptions/DockerNetworkNotFoundException.js';
|
|
6
|
+
import { DockerRequestException } from '../docker/exceptions/DockerRequestException.js';
|
|
7
|
+
/**
|
|
8
|
+
* The status codes of the requests: the successes, and the reasons of the failures
|
|
9
|
+
*/
|
|
10
|
+
const SERVER_ERROR = { 500: 'server error' };
|
|
11
|
+
const OK = { 200: true, 204: true };
|
|
12
|
+
const NO_SUCH_IMAGE = { 404: 'no such image' };
|
|
13
|
+
const NO_SUCH_CONTAINER = { 404: 'no such container' };
|
|
14
|
+
const NO_SUCH_EXEC = { 404: 'no such exec' };
|
|
15
|
+
const NO_SUCH_NETWORK = { 404: 'no such network' };
|
|
16
|
+
/**
|
|
17
|
+
* The exception of a request the daemon refused: the not found exception of the resource missing (told by the daemon's
|
|
18
|
+
* message, else by the meaning of the status for the request), a DockerRequestException otherwise. The other errors
|
|
19
|
+
* (the network errors, the aborts) are given as they are
|
|
20
|
+
* @param error
|
|
21
|
+
*/
|
|
22
|
+
export function dockerException(error) {
|
|
23
|
+
if (!(error instanceof DockerRequestError))
|
|
24
|
+
return error;
|
|
25
|
+
if (error.statusCode === 404) {
|
|
26
|
+
//"No such container: x", "No such image: x", "network x not found" (also in the failure of a start)
|
|
27
|
+
const kind = /no such container/i.test(error.detail) ? 'container'
|
|
28
|
+
: /no such image/i.test(error.detail) ? 'image'
|
|
29
|
+
: /no such network|network \S+ not found/i.test(error.detail) ? 'network'
|
|
30
|
+
: error.reason.replace(/^no such /, '');
|
|
31
|
+
if (kind === 'container')
|
|
32
|
+
return new DockerContainerNotFoundException(error.detail);
|
|
33
|
+
if (kind === 'image')
|
|
34
|
+
return new DockerImageNotFoundException(error.detail);
|
|
35
|
+
if (kind === 'network')
|
|
36
|
+
return new DockerNetworkNotFoundException(error.detail);
|
|
37
|
+
}
|
|
38
|
+
return new DockerRequestException(error.statusCode, error.detail || error.message);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The client of the Docker Engine API
|
|
42
|
+
*/
|
|
43
|
+
export class DockerClient {
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
this.connection = new DockerConnection(options);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A request whose response is JSON, its failure as the exception of the component
|
|
49
|
+
* @param request
|
|
50
|
+
*/
|
|
51
|
+
async #request(request) {
|
|
52
|
+
try {
|
|
53
|
+
return await this.connection.request(request);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
throw dockerException(e);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A request whose response is a stream, its failure as the exception of the component
|
|
61
|
+
* @param request
|
|
62
|
+
*/
|
|
63
|
+
async #stream(request) {
|
|
64
|
+
try {
|
|
65
|
+
return await this.connection.stream(request);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
throw dockerException(e);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A request upgraded to a raw stream, its failure as the exception of the component
|
|
73
|
+
* @param request
|
|
74
|
+
*/
|
|
75
|
+
async #hijack(request) {
|
|
76
|
+
try {
|
|
77
|
+
return await this.connection.hijack(request);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
throw dockerException(e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether the daemon answers
|
|
85
|
+
* @param signal
|
|
86
|
+
*/
|
|
87
|
+
async ping(signal) {
|
|
88
|
+
return await this.#request({ method: 'GET', path: '/_ping', statusCodes: { 200: true, ...SERVER_ERROR }, signal: signal });
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The versions of the daemon
|
|
92
|
+
*/
|
|
93
|
+
async version() {
|
|
94
|
+
return await this.#request({ method: 'GET', path: '/version', statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check registry credentials (docker login)
|
|
98
|
+
* @param auth
|
|
99
|
+
*/
|
|
100
|
+
async checkAuth(auth) {
|
|
101
|
+
return await this.#request({ method: 'POST', path: '/auth', body: auth, statusCodes: { ...OK, ...SERVER_ERROR } });
|
|
102
|
+
}
|
|
103
|
+
/** Images **/
|
|
104
|
+
async listImages(query, signal) {
|
|
105
|
+
return await this.#request({ method: 'GET', path: '/images/json', query: query, statusCodes: { 200: true, 400: 'bad parameter', ...SERVER_ERROR }, signal: signal });
|
|
106
|
+
}
|
|
107
|
+
async inspectImage(name, signal) {
|
|
108
|
+
return await this.#request({ method: 'GET', path: `/images/${name}/json`, statusCodes: { 200: true, ...NO_SUCH_IMAGE, ...SERVER_ERROR }, signal: signal });
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Pull an image: the stream of the progress (docker pull)
|
|
112
|
+
* @param query fromImage, tag, platform
|
|
113
|
+
* @param auth
|
|
114
|
+
* @param signal
|
|
115
|
+
*/
|
|
116
|
+
async pullImage(query, auth, signal) {
|
|
117
|
+
return await this.#stream({ method: 'POST', path: '/images/create', query: query, auth: auth, statusCodes: { 200: true, ...SERVER_ERROR }, signal: signal });
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build an image: the stream of the progress
|
|
121
|
+
* @param context the gzipped tar archive of the context
|
|
122
|
+
* @param query dockerfile, t, platform, version...
|
|
123
|
+
* @param registryConfig the credentials of the registries, by server
|
|
124
|
+
* @param signal
|
|
125
|
+
*/
|
|
126
|
+
async buildImage(context, query, registryConfig, signal) {
|
|
127
|
+
return await this.#stream({ method: 'POST', path: '/build', query: query, body: context, registryConfig: registryConfig, statusCodes: { 200: true, ...SERVER_ERROR }, signal: signal });
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Load the images of a tar archive (docker load): the stream of the progress
|
|
131
|
+
* @param archive
|
|
132
|
+
* @param query quiet
|
|
133
|
+
*/
|
|
134
|
+
async loadImage(archive, query) {
|
|
135
|
+
return await this.#stream({ method: 'POST', path: '/images/load', query: query, body: archive, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The tar archive of an image (docker save)
|
|
139
|
+
* @param name
|
|
140
|
+
*/
|
|
141
|
+
async exportImage(name) {
|
|
142
|
+
return await this.#stream({ method: 'GET', path: `/images/${name}/get`, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
143
|
+
}
|
|
144
|
+
async tagImage(name, query) {
|
|
145
|
+
await this.#request({ method: 'POST', path: `/images/${name}/tag`, query: query, statusCodes: { 200: true, 201: true, 400: 'bad parameter', ...NO_SUCH_IMAGE, 409: 'conflict', ...SERVER_ERROR } });
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Push an image: the stream of the progress
|
|
149
|
+
* @param name
|
|
150
|
+
* @param query tag, platform
|
|
151
|
+
* @param auth
|
|
152
|
+
*/
|
|
153
|
+
async pushImage(name, query, auth) {
|
|
154
|
+
return await this.#stream({ method: 'POST', path: `/images/${name}/push`, query: query, auth: (auth ?? {}), statusCodes: { 200: true, ...NO_SUCH_IMAGE, ...SERVER_ERROR } });
|
|
155
|
+
}
|
|
156
|
+
async removeImage(name, query) {
|
|
157
|
+
return await this.#request({ method: 'DELETE', path: `/images/${name}`, query: query, statusCodes: { 200: true, ...NO_SUCH_IMAGE, 409: 'conflict', ...SERVER_ERROR } });
|
|
158
|
+
}
|
|
159
|
+
async pruneImages(query) {
|
|
160
|
+
return await this.#request({ method: 'POST', path: '/images/prune', query: query, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
161
|
+
}
|
|
162
|
+
/** Containers **/
|
|
163
|
+
async listContainers(query, signal) {
|
|
164
|
+
return await this.#request({ method: 'GET', path: '/containers/json', query: query, statusCodes: { 200: true, 400: 'bad parameter', ...SERVER_ERROR }, signal: signal });
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a container
|
|
168
|
+
* @param body its configuration
|
|
169
|
+
* @param query name, platform
|
|
170
|
+
*/
|
|
171
|
+
async createContainer(body, query) {
|
|
172
|
+
return await this.#request({ method: 'POST', path: '/containers/create', query: query, body: body, statusCodes: { 200: true, 201: true, 400: 'bad parameter', ...NO_SUCH_IMAGE, 409: 'conflict', ...SERVER_ERROR } });
|
|
173
|
+
}
|
|
174
|
+
async inspectContainer(id, signal) {
|
|
175
|
+
return await this.#request({ method: 'GET', path: `/containers/${id}/json`, statusCodes: { 200: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR }, signal: signal });
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Start a container: one already started is done (HTTP 304), as the Docker CLI does
|
|
179
|
+
* @param id
|
|
180
|
+
* @param signal
|
|
181
|
+
*/
|
|
182
|
+
async startContainer(id, signal) {
|
|
183
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/start`, statusCodes: { ...OK, 304: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR }, signal: signal });
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Stop a container: one already stopped is done (HTTP 304), as the Docker CLI does
|
|
187
|
+
* @param id
|
|
188
|
+
* @param query
|
|
189
|
+
* @param signal
|
|
190
|
+
*/
|
|
191
|
+
async stopContainer(id, query, signal) {
|
|
192
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/stop`, query: query, statusCodes: { ...OK, 304: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR }, signal: signal });
|
|
193
|
+
}
|
|
194
|
+
async restartContainer(id, query, signal) {
|
|
195
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/restart`, query: query, statusCodes: { ...OK, ...NO_SUCH_CONTAINER, ...SERVER_ERROR }, signal: signal });
|
|
196
|
+
}
|
|
197
|
+
async pauseContainer(id) {
|
|
198
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/pause`, statusCodes: { ...OK, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
199
|
+
}
|
|
200
|
+
async unpauseContainer(id) {
|
|
201
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/unpause`, statusCodes: { ...OK, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
202
|
+
}
|
|
203
|
+
async killContainer(id, query) {
|
|
204
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/kill`, query: query, statusCodes: { ...OK, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
205
|
+
}
|
|
206
|
+
async removeContainer(id, query) {
|
|
207
|
+
await this.#request({ method: 'DELETE', path: `/containers/${id}`, query: query, statusCodes: { ...OK, 400: 'bad parameter', ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Rename a container
|
|
211
|
+
* @param id
|
|
212
|
+
* @param name
|
|
213
|
+
*/
|
|
214
|
+
async renameContainer(id, name) {
|
|
215
|
+
await this.#request({ method: 'POST', path: `/containers/${id}/rename`, query: { name: name }, statusCodes: { ...OK, ...NO_SUCH_CONTAINER, 409: 'name already in use', ...SERVER_ERROR } });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Update the resources and the restart policy of a container, live (docker update)
|
|
219
|
+
* @param id
|
|
220
|
+
* @param body
|
|
221
|
+
*/
|
|
222
|
+
async updateContainer(id, body) {
|
|
223
|
+
return await this.#request({ method: 'POST', path: `/containers/${id}/update`, body: body, statusCodes: { ...OK, 400: 'bad parameter', ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create an image of a container (docker commit)
|
|
227
|
+
* @param id
|
|
228
|
+
* @param query repo, tag, comment, author, pause, changes
|
|
229
|
+
*/
|
|
230
|
+
async commitContainer(id, query) {
|
|
231
|
+
return await this.#request({ method: 'POST', path: '/commit', query: { ...query, container: id }, statusCodes: { 200: true, 201: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The logs of a container: multiplexed when it has no TTY
|
|
235
|
+
* @param id
|
|
236
|
+
* @param query follow, stdout, stderr, since, until, timestamps, tail
|
|
237
|
+
*/
|
|
238
|
+
async containerLogs(id, query) {
|
|
239
|
+
return await this.#stream({ method: 'GET', path: `/containers/${id}/logs`, query: query, statusCodes: { 200: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The statistics of a container, once
|
|
243
|
+
* @param id
|
|
244
|
+
*/
|
|
245
|
+
async containerStats(id) {
|
|
246
|
+
return await this.#request({ method: 'GET', path: `/containers/${id}/stats`, query: { 'stream': false, 'one-shot': true }, statusCodes: { 200: true, ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The tar archive of a path of a container
|
|
250
|
+
* @param id
|
|
251
|
+
* @param query path
|
|
252
|
+
*/
|
|
253
|
+
async getArchive(id, query) {
|
|
254
|
+
return await this.#stream({ method: 'GET', path: `/containers/${id}/archive`, query: query, statusCodes: { 200: true, 400: 'client error, bad parameters', ...NO_SUCH_CONTAINER, ...SERVER_ERROR } });
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Create an execution in a container
|
|
258
|
+
* @param id
|
|
259
|
+
* @param body Cmd, AttachStdin, AttachStdout, AttachStderr, Tty, ConsoleSize...
|
|
260
|
+
*/
|
|
261
|
+
async createExec(id, body) {
|
|
262
|
+
return await this.#request({ method: 'POST', path: `/containers/${id}/exec`, body: body, statusCodes: { 200: true, 201: true, ...NO_SUCH_CONTAINER, 409: 'container stopped/paused', ...SERVER_ERROR } });
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Start an execution, attached: its stream, read (its output, multiplexed without TTY) and written (its input)
|
|
266
|
+
* @param execId
|
|
267
|
+
* @param body Detach, Tty
|
|
268
|
+
*/
|
|
269
|
+
async startExec(execId, body) {
|
|
270
|
+
return await this.#hijack({ method: 'POST', path: `/exec/${execId}/start`, body: body, statusCodes: { ...OK, ...NO_SUCH_EXEC, 409: 'container stopped/paused', 500: 'container not running' } });
|
|
271
|
+
}
|
|
272
|
+
async resizeExec(execId, query) {
|
|
273
|
+
await this.#request({ method: 'POST', path: `/exec/${execId}/resize`, query: query, statusCodes: { ...OK, ...NO_SUCH_EXEC, 500: 'container not running' } });
|
|
274
|
+
}
|
|
275
|
+
async inspectExec(execId) {
|
|
276
|
+
return await this.#request({ method: 'GET', path: `/exec/${execId}/json`, statusCodes: { 200: true, ...NO_SUCH_EXEC, ...SERVER_ERROR } });
|
|
277
|
+
}
|
|
278
|
+
async pruneContainers(query) {
|
|
279
|
+
return await this.#request({ method: 'POST', path: '/containers/prune', query: query, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
280
|
+
}
|
|
281
|
+
/** Networks **/
|
|
282
|
+
async listNetworks(query, signal) {
|
|
283
|
+
return await this.#request({ method: 'GET', path: '/networks', query: query, statusCodes: { 200: true, 400: 'bad parameter', ...SERVER_ERROR }, signal: signal });
|
|
284
|
+
}
|
|
285
|
+
async createNetwork(body) {
|
|
286
|
+
return await this.#request({ method: 'POST', path: '/networks/create', body: body, statusCodes: { 200: true, 201: true, 404: 'driver not found', ...SERVER_ERROR } });
|
|
287
|
+
}
|
|
288
|
+
async inspectNetwork(id) {
|
|
289
|
+
return await this.#request({ method: 'GET', path: `/networks/${id}`, statusCodes: { 200: true, ...NO_SUCH_NETWORK, ...SERVER_ERROR } });
|
|
290
|
+
}
|
|
291
|
+
async removeNetwork(id) {
|
|
292
|
+
await this.#request({ method: 'DELETE', path: `/networks/${id}`, statusCodes: { ...OK, ...NO_SUCH_NETWORK, 409: 'conflict', ...SERVER_ERROR } });
|
|
293
|
+
}
|
|
294
|
+
async pruneNetworks(query) {
|
|
295
|
+
return await this.#request({ method: 'POST', path: '/networks/prune', query: query, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
296
|
+
}
|
|
297
|
+
/** Volumes **/
|
|
298
|
+
async pruneVolumes(query) {
|
|
299
|
+
return await this.#request({ method: 'POST', path: '/volumes/prune', query: query, statusCodes: { 200: true, ...SERVER_ERROR } });
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Close the connections kept alive
|
|
303
|
+
*/
|
|
304
|
+
close() {
|
|
305
|
+
this.connection.close();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The connection to the Docker Engine API, rewritten from docker-modem (Copyright Pedro Dias, Apache License 2.0,
|
|
3
|
+
* see THIRD_PARTY_NOTICES.md), modified: the requests are promises, the API version is negotiated, and the requests
|
|
4
|
+
* streaming a body close their connection (see Request)
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import http from 'node:http';
|
|
8
|
+
import https from 'node:https';
|
|
9
|
+
import { homedir, platform } from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { Duplex, Writable } from 'node:stream';
|
|
12
|
+
import { DockerRequestError } from './DockerRequestError.js';
|
|
13
|
+
/**
|
|
14
|
+
* The newest API version this client is tested with (Docker 29.8): the one negotiated when the daemon supports it, so that
|
|
15
|
+
* a newer daemon answers as the tested one. An older daemon answers with its version: the fields a version does not have
|
|
16
|
+
* are missing or null
|
|
17
|
+
*/
|
|
18
|
+
export const DOCKER_API_VERSION = '1.56';
|
|
19
|
+
/**
|
|
20
|
+
* The oldest API version this client works with
|
|
21
|
+
*/
|
|
22
|
+
export const DOCKER_MIN_API_VERSION = '1.41';
|
|
23
|
+
/**
|
|
24
|
+
* Compare two API versions
|
|
25
|
+
* @param a
|
|
26
|
+
* @param b
|
|
27
|
+
*/
|
|
28
|
+
export function compareAPIVersions(a, b) {
|
|
29
|
+
const [x, y] = [a, b].map((version) => version.replace(/^v/, '').split('.').map(Number));
|
|
30
|
+
return (x[0] - y[0]) || ((x[1] ?? 0) - (y[1] ?? 0));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The certificates of a CA file, split (a file may have several)
|
|
34
|
+
* @param file
|
|
35
|
+
*/
|
|
36
|
+
function splitCA(file) {
|
|
37
|
+
return readFileSync(file, 'utf8').split(/(?<=-----END CERTIFICATE-----)\s*/).map((certificate) => certificate.trim()).filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The connection options given by the environment (DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH,
|
|
41
|
+
* DOCKER_CLIENT_TIMEOUT), else the socket of the platform: the named pipe on Windows, the socket of the user (Docker
|
|
42
|
+
* Desktop) or /var/run/docker.sock
|
|
43
|
+
*/
|
|
44
|
+
export function defaultConnectionOptions() {
|
|
45
|
+
const dockerHost = process.env.DOCKER_HOST;
|
|
46
|
+
if (!dockerHost) {
|
|
47
|
+
if (platform() === 'win32')
|
|
48
|
+
return { socketPath: '//./pipe/docker_engine' };
|
|
49
|
+
const userSocket = path.join(homedir(), '.docker', 'run', 'docker.sock');
|
|
50
|
+
return { socketPath: existsSync(userSocket) ? userSocket : '/var/run/docker.sock' };
|
|
51
|
+
}
|
|
52
|
+
if (dockerHost.startsWith('unix://'))
|
|
53
|
+
return { socketPath: dockerHost.slice(7) || '/var/run/docker.sock' };
|
|
54
|
+
if (dockerHost.startsWith('npipe://'))
|
|
55
|
+
return { socketPath: dockerHost.slice(8) || '//./pipe/docker_engine' };
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(dockerHost.includes('//') ? dockerHost : `tcp://${dockerHost}`);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new Error('DOCKER_HOST should be something like tcp://localhost:2375');
|
|
62
|
+
}
|
|
63
|
+
const options = { host: url.hostname, port: url.port };
|
|
64
|
+
if (url.protocol === 'ssh:') {
|
|
65
|
+
options.protocol = 'ssh';
|
|
66
|
+
options.username = url.username || undefined;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
options.protocol = process.env.DOCKER_TLS_VERIFY === '1' || url.port === '2376' ? 'https' : 'http';
|
|
70
|
+
}
|
|
71
|
+
const certPath = process.env.DOCKER_CERT_PATH;
|
|
72
|
+
if (certPath) {
|
|
73
|
+
options.ca = splitCA(path.join(certPath, 'ca.pem'));
|
|
74
|
+
options.cert = readFileSync(path.join(certPath, 'cert.pem'));
|
|
75
|
+
options.key = readFileSync(path.join(certPath, 'key.pem'));
|
|
76
|
+
}
|
|
77
|
+
if (process.env.DOCKER_CLIENT_TIMEOUT)
|
|
78
|
+
options.timeout = Number.parseInt(process.env.DOCKER_CLIENT_TIMEOUT, 10);
|
|
79
|
+
return options;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The query string of the parameters of a request
|
|
83
|
+
* @param query
|
|
84
|
+
*/
|
|
85
|
+
function queryString(query = {}) {
|
|
86
|
+
const parameters = new URLSearchParams();
|
|
87
|
+
for (const [key, value] of Object.entries(query)) {
|
|
88
|
+
if (value === undefined || value === null)
|
|
89
|
+
continue;
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
value.forEach((item) => parameters.append(key, String(item)));
|
|
92
|
+
}
|
|
93
|
+
else if (typeof value === 'object') {
|
|
94
|
+
parameters.append(key, JSON.stringify(value));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
parameters.append(key, String(value));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const text = parameters.toString();
|
|
101
|
+
return text ? `?${text}` : '';
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Whether a body is a stream
|
|
105
|
+
* @param body
|
|
106
|
+
*/
|
|
107
|
+
function isStream(body) {
|
|
108
|
+
return !!body && typeof body.pipe === 'function';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The connection to a Docker daemon
|
|
112
|
+
*/
|
|
113
|
+
export class DockerConnection {
|
|
114
|
+
#options;
|
|
115
|
+
#protocol;
|
|
116
|
+
/**
|
|
117
|
+
* The agent of the requests: the connections are kept alive
|
|
118
|
+
*/
|
|
119
|
+
#agent;
|
|
120
|
+
/**
|
|
121
|
+
* The agent of the requests streaming their body: their connections are closed after them. Docker answers a build
|
|
122
|
+
* while it reads its context: on a kept alive connection, its HTTP server discards a part of the unread body when it
|
|
123
|
+
* answers, which corrupts the context ("unpigz: corrupted -- invalid deflate data")
|
|
124
|
+
*/
|
|
125
|
+
#closingAgent;
|
|
126
|
+
/**
|
|
127
|
+
* The negotiated API version
|
|
128
|
+
*/
|
|
129
|
+
#version;
|
|
130
|
+
#sshAgent;
|
|
131
|
+
constructor(options = {}) {
|
|
132
|
+
//The options given (a timeout, headers…) apply over the ones of the environment, the ones not given keep them
|
|
133
|
+
const given = Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined));
|
|
134
|
+
this.#options = given.socketPath || given.host ? given : { ...defaultConnectionOptions(), ...given };
|
|
135
|
+
this.#protocol = this.#options.protocol ?? (this.#options.key && this.#options.cert && this.#options.ca ? 'https' : 'http');
|
|
136
|
+
if (this.#options.version)
|
|
137
|
+
this.#version = this.#options.version.replace(/^v/, '');
|
|
138
|
+
if (this.#protocol !== 'ssh') {
|
|
139
|
+
const module = this.#protocol === 'https' ? https : http;
|
|
140
|
+
this.#agent = new module.Agent({ keepAlive: true });
|
|
141
|
+
this.#closingAgent = new module.Agent({ keepAlive: false });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The API version of the requests, once negotiated
|
|
146
|
+
*/
|
|
147
|
+
get version() {
|
|
148
|
+
return this.#version;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Negotiate the API version with the daemon: the newest one both support
|
|
152
|
+
*/
|
|
153
|
+
async negotiate() {
|
|
154
|
+
if (this.#version)
|
|
155
|
+
return this.#version;
|
|
156
|
+
const version = await this.request({ method: 'GET', path: '/version', statusCodes: { 200: true, 500: 'server error' } });
|
|
157
|
+
const daemon = version.ApiVersion ?? DOCKER_MIN_API_VERSION;
|
|
158
|
+
let negotiated = compareAPIVersions(daemon, DOCKER_API_VERSION) < 0 ? daemon : DOCKER_API_VERSION;
|
|
159
|
+
//The daemon no longer supports the version of the client
|
|
160
|
+
if (version.MinAPIVersion && compareAPIVersions(negotiated, version.MinAPIVersion) < 0)
|
|
161
|
+
negotiated = version.MinAPIVersion;
|
|
162
|
+
this.#version = negotiated;
|
|
163
|
+
return negotiated;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The agent of an SSH connection: the requests are sent to "docker system dial-stdio" (ssh2, an optional dependency)
|
|
167
|
+
*/
|
|
168
|
+
sshAgent() {
|
|
169
|
+
return this.#sshAgent ??= (async () => {
|
|
170
|
+
let ssh2;
|
|
171
|
+
try {
|
|
172
|
+
//An optional dependency, loaded where it is installed
|
|
173
|
+
const ssh2Module = 'ssh2';
|
|
174
|
+
ssh2 = await import(ssh2Module);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
throw new Error('The SSH connections to Docker need the package ssh2: npm install ssh2');
|
|
178
|
+
}
|
|
179
|
+
const Client = ssh2.Client ?? ssh2.default?.Client;
|
|
180
|
+
const agent = new http.Agent();
|
|
181
|
+
const options = this.#options;
|
|
182
|
+
agent.createConnection = ((_, callback) => {
|
|
183
|
+
const client = new Client();
|
|
184
|
+
const fail = (error) => {
|
|
185
|
+
client.end();
|
|
186
|
+
callback(error);
|
|
187
|
+
};
|
|
188
|
+
client.once('ready', () => {
|
|
189
|
+
client.exec('docker system dial-stdio', (error, stream) => {
|
|
190
|
+
if (error)
|
|
191
|
+
return fail(error);
|
|
192
|
+
callback(null, stream);
|
|
193
|
+
stream.once('close', () => client.end());
|
|
194
|
+
});
|
|
195
|
+
}).once('error', fail).connect({
|
|
196
|
+
host: options.host,
|
|
197
|
+
port: Number(options.port ?? 22),
|
|
198
|
+
username: options.username,
|
|
199
|
+
password: options.password,
|
|
200
|
+
agent: options.sshAuthAgent ?? process.env.SSH_AUTH_SOCK
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
return agent;
|
|
204
|
+
})();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The options of a request
|
|
208
|
+
* @param request
|
|
209
|
+
* @param streamingBody
|
|
210
|
+
*/
|
|
211
|
+
async requestOptions(request, streamingBody) {
|
|
212
|
+
const headers = { ...this.#options.headers, ...request.headers };
|
|
213
|
+
if (request.auth)
|
|
214
|
+
headers['X-Registry-Auth'] = Buffer.from(JSON.stringify(request.auth)).toString('base64url');
|
|
215
|
+
if (request.registryConfig)
|
|
216
|
+
headers['X-Registry-Config'] = Buffer.from(JSON.stringify(request.registryConfig)).toString('base64');
|
|
217
|
+
const versioned = this.#version ? `/v${this.#version}${request.path}` : request.path;
|
|
218
|
+
const options = {
|
|
219
|
+
method: request.method,
|
|
220
|
+
path: `${versioned}${queryString(request.query)}`,
|
|
221
|
+
headers: headers,
|
|
222
|
+
signal: request.signal,
|
|
223
|
+
timeout: this.#options.timeout
|
|
224
|
+
};
|
|
225
|
+
if (this.#protocol === 'ssh') {
|
|
226
|
+
options.agent = await this.sshAgent();
|
|
227
|
+
options.host = 'localhost';
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
options.agent = streamingBody ? this.#closingAgent : this.#agent;
|
|
231
|
+
if (this.#options.socketPath) {
|
|
232
|
+
options.socketPath = this.#options.socketPath;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
options.host = this.#options.host;
|
|
236
|
+
options.port = this.#options.port;
|
|
237
|
+
}
|
|
238
|
+
if (this.#protocol === 'https')
|
|
239
|
+
Object.assign(options, { ca: this.#options.ca, cert: this.#options.cert, key: this.#options.key });
|
|
240
|
+
}
|
|
241
|
+
return options;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Send a request: the response, once its status is known
|
|
245
|
+
* @param request
|
|
246
|
+
* @param hijack upgrade the connection to a raw stream (the TTYs, the attached executions)
|
|
247
|
+
*/
|
|
248
|
+
async send(request, hijack = false) {
|
|
249
|
+
const streamingBody = isStream(request.body);
|
|
250
|
+
const options = await this.requestOptions(request, streamingBody);
|
|
251
|
+
const headers = options.headers;
|
|
252
|
+
let payload;
|
|
253
|
+
if (request.body !== undefined && !streamingBody) {
|
|
254
|
+
payload = JSON.stringify(request.body);
|
|
255
|
+
headers['Content-Type'] = 'application/json';
|
|
256
|
+
headers['Content-Length'] = String(Buffer.byteLength(payload));
|
|
257
|
+
}
|
|
258
|
+
else if (streamingBody) {
|
|
259
|
+
headers['Content-Type'] = 'application/x-tar';
|
|
260
|
+
}
|
|
261
|
+
if (hijack) {
|
|
262
|
+
headers.Connection = 'Upgrade';
|
|
263
|
+
headers.Upgrade = 'tcp';
|
|
264
|
+
}
|
|
265
|
+
const module = this.#protocol === 'https' ? https : http;
|
|
266
|
+
return new Promise((resolve, reject) => {
|
|
267
|
+
const req = module.request(options);
|
|
268
|
+
req.once('error', reject);
|
|
269
|
+
req.once('timeout', () => req.destroy(new Error(`Timeout of ${this.#options.timeout} ms exceeded`)));
|
|
270
|
+
if (hijack) {
|
|
271
|
+
req.once('upgrade', (response, socket, head) => {
|
|
272
|
+
if (head.length)
|
|
273
|
+
socket.unshift(head);
|
|
274
|
+
resolve({ response: response, socket: socket, request: req });
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
req.once('response', (response) => resolve({ response: response, request: req }));
|
|
278
|
+
if (streamingBody) {
|
|
279
|
+
const body = request.body;
|
|
280
|
+
//An error of the body (the packing of a build context) fails the request, instead of ending its stream
|
|
281
|
+
body.once('error', (error) => req.destroy(error));
|
|
282
|
+
body.pipe(req);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
req.end(payload);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The error of a failed response
|
|
291
|
+
* @param request
|
|
292
|
+
* @param response
|
|
293
|
+
*/
|
|
294
|
+
async failure(request, response) {
|
|
295
|
+
const text = Buffer.concat(await response.toArray()).toString();
|
|
296
|
+
let json;
|
|
297
|
+
try {
|
|
298
|
+
json = JSON.parse(text);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
json = undefined;
|
|
302
|
+
}
|
|
303
|
+
const reason = typeof request.statusCodes[response.statusCode] === 'string' ? request.statusCodes[response.statusCode] : 'unexpected';
|
|
304
|
+
return new DockerRequestError(response.statusCode, reason, json?.message ?? text.trim(), json);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* A request whose response is JSON (or nothing)
|
|
308
|
+
* @param request
|
|
309
|
+
*/
|
|
310
|
+
async request(request) {
|
|
311
|
+
const { response } = await this.send(request);
|
|
312
|
+
if (request.statusCodes[response.statusCode] !== true)
|
|
313
|
+
throw await this.failure(request, response);
|
|
314
|
+
const text = Buffer.concat(await response.toArray()).toString();
|
|
315
|
+
if (!text)
|
|
316
|
+
return undefined;
|
|
317
|
+
try {
|
|
318
|
+
return JSON.parse(text);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return text;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* A request whose response is a stream (the progress of a pull, the logs, an archive)
|
|
326
|
+
* @param request
|
|
327
|
+
*/
|
|
328
|
+
async stream(request) {
|
|
329
|
+
const { response } = await this.send(request);
|
|
330
|
+
if (request.statusCodes[response.statusCode] !== true)
|
|
331
|
+
throw await this.failure(request, response);
|
|
332
|
+
return response;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* A request upgraded to a raw stream, read and written (the TTYs, the attached executions)
|
|
336
|
+
* @param request
|
|
337
|
+
*/
|
|
338
|
+
async hijack(request) {
|
|
339
|
+
const { response, socket } = await this.send(request, true);
|
|
340
|
+
if (socket)
|
|
341
|
+
return socket;
|
|
342
|
+
if (request.statusCodes[response.statusCode] !== true)
|
|
343
|
+
throw await this.failure(request, response);
|
|
344
|
+
//A daemon answering without upgrading: its response is the output, what is written is discarded
|
|
345
|
+
return Duplex.from({ readable: response, writable: new Writable({ write: (_chunk, _encoding, callback) => callback() }) });
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Close the kept alive connections
|
|
349
|
+
*/
|
|
350
|
+
close() {
|
|
351
|
+
this.#agent?.destroy();
|
|
352
|
+
this.#closingAgent?.destroy();
|
|
353
|
+
this.#sshAgent?.then((agent) => agent.destroy()).catch(() => undefined);
|
|
354
|
+
}
|
|
355
|
+
}
|