testcontainers 7.23.2 → 8.1.1

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.
Files changed (51) hide show
  1. package/README.md +38 -12
  2. package/dist/bound-ports.d.ts +3 -0
  3. package/dist/bound-ports.js +14 -0
  4. package/dist/docker/docker-client.d.ts +9 -0
  5. package/dist/docker/docker-client.js +149 -0
  6. package/dist/docker/functions/container/create-container.d.ts +2 -2
  7. package/dist/docker/functions/container/create-container.js +11 -10
  8. package/dist/docker/functions/container/exec-container.js +16 -12
  9. package/dist/docker/functions/container/get-container.d.ts +1 -1
  10. package/dist/docker/functions/container/get-container.js +14 -2
  11. package/dist/docker/functions/container/inspect-container.d.ts +3 -4
  12. package/dist/docker/functions/container/inspect-container.js +10 -8
  13. package/dist/docker/functions/container/list-containers.js +3 -2
  14. package/dist/docker/functions/demux-stream.d.ts +1 -1
  15. package/dist/docker/functions/demux-stream.js +14 -4
  16. package/dist/docker/functions/get-info.js +3 -2
  17. package/dist/docker/functions/image/build-image.js +3 -2
  18. package/dist/docker/functions/image/list-images.js +3 -2
  19. package/dist/docker/functions/image/pull-image.js +3 -2
  20. package/dist/docker/functions/network/connect-network.js +3 -2
  21. package/dist/docker/functions/network/create-network.js +3 -2
  22. package/dist/docker/functions/network/remove-network.js +3 -2
  23. package/dist/docker/functions/run-in-container.d.ts +2 -1
  24. package/dist/docker/functions/run-in-container.js +2 -3
  25. package/dist/docker/types.d.ts +3 -0
  26. package/dist/docker-compose/default-docker-compose-options.d.ts +1 -1
  27. package/dist/docker-compose/docker-compose.d.ts +3 -0
  28. package/dist/docker-compose/docker-compose.js +10 -0
  29. package/dist/docker-compose/functions/docker-compose-down.js +1 -1
  30. package/dist/docker-compose/functions/docker-compose-stop.js +1 -1
  31. package/dist/docker-compose/functions/docker-compose-up.js +1 -1
  32. package/dist/docker-compose-environment/docker-compose-environment.d.ts +0 -1
  33. package/dist/docker-compose-environment/docker-compose-environment.js +6 -14
  34. package/dist/generic-container/generic-container.d.ts +6 -2
  35. package/dist/generic-container/generic-container.js +25 -9
  36. package/dist/log-system-diagnostics.js +2 -21
  37. package/dist/modules/kafka/kafka-container.d.ts +6 -17
  38. package/dist/modules/kafka/kafka-container.js +57 -69
  39. package/dist/port-forwarder.js +2 -2
  40. package/dist/reaper.d.ts +1 -0
  41. package/dist/reaper.js +20 -14
  42. package/dist/test-container.d.ts +2 -1
  43. package/dist/testcontainers-properties-file.d.ts +1 -0
  44. package/dist/testcontainers-properties-file.js +31 -0
  45. package/package.json +4 -2
  46. package/dist/docker/docker-host.d.ts +0 -1
  47. package/dist/docker/docker-host.js +0 -8
  48. package/dist/docker/dockerode.d.ts +0 -2
  49. package/dist/docker/dockerode.js +0 -10
  50. package/dist/docker/get-docker-host.d.ts +0 -3
  51. package/dist/docker/get-docker-host.js +0 -60
package/README.md CHANGED
@@ -5,6 +5,8 @@
5
5
  [![Node.js CI](https://github.com/testcontainers/testcontainers-node/actions/workflows/node.js.yml/badge.svg?branch=master)](https://github.com/testcontainers/testcontainers-node/actions/workflows/node.js.yml)
6
6
  [![npm version](https://badge.fury.io/js/testcontainers.svg)](https://www.npmjs.com/package/testcontainers)
7
7
  [![npm version](https://img.shields.io/npm/dm/testcontainers.svg)](https://www.npmjs.com/package/testcontainers)
8
+ [![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
9
+ [![Foresight Test Summary](https://foresight.service.thundra.us/public/api/v1/badge/test/57175ecb-d5ac-4129-957a-9dd617fd27d0)](https://foresight.thundra.live/testruns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
8
10
 
9
11
  ## Install
10
12
 
@@ -16,12 +18,18 @@ npm i -D testcontainers
16
18
 
17
19
  The following environment variables are supported:
18
20
 
19
- - `DEBUG=testcontainers` See output
20
- - `DEBUG=testcontainers:containers` See container output
21
- - `DEBUG=testcontainers*` See all output
22
- - `DOCKER_HOST=tcp://docker:2375` Daemon socket to connect to
21
+ - `DEBUG=testcontainers` See testcontainers logs
22
+ - `DEBUG=testcontainers:containers` See container logs
23
+ - `DEBUG=testcontainers*` See all logs
24
+ - `DOCKER_HOST=tcp://docker:2375` Sets the URL of the docker daemon
25
+ - `DOCKER_TLS_VERIFY=1` When set to anything other than an empty string, enables TLS communication with the docker
26
+ daemon
27
+ - `DOCKER_CERT_PATH=/some/path` Configures the path to the ca.pem, cert.pem, and key.pem files used for TLS
28
+ verification. Defaults to ~/.docker
23
29
  - `TESTCONTAINERS_HOST_OVERRIDE=docker.svc.local` Docker's host on which ports are exposed
24
- - `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock` Path to Docker's socket. Used by [ryuk](#ryuk) and other [auxiliary containers](#auxiliary-containers) that need to perform Docker actions
30
+ - `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock` Path to Docker's socket. Used by [ryuk](#ryuk) and
31
+ other [auxiliary containers](#auxiliary-containers) that need to perform Docker actions
32
+ - `TESTCONTAINERS_RYUK_PRIVILEGED=true` Run [ryuk](#ryuk) as a privileged container
25
33
  - `TESTCONTAINERS_RYUK_DISABLED=true` Disable [ryuk](#ryuk)
26
34
  - `RYUK_CONTAINER_IMAGE=registry.mycompany.com/mirror/ryuk:0.3.0` Custom image for [ryuk](#ryuk)
27
35
  - `SSHD_CONTAINER_IMAGE=registry.mycompany.com/mirror/sshd:1.0.0` Custom image for [SSHd](#SSHd)
@@ -136,7 +144,7 @@ Creating a container with a command:
136
144
  const { GenericContainer } = require("testcontainers");
137
145
 
138
146
  const container = await new GenericContainer("alpine")
139
- .withCmd(["top"])
147
+ .withCmd(["sleep", "infinity"])
140
148
  .start();
141
149
  ```
142
150
 
@@ -146,7 +154,7 @@ Execute commands inside a running container:
146
154
  const { GenericContainer } = require("testcontainers");
147
155
 
148
156
  const container = await new GenericContainer("alpine")
149
- .withCmd(["top"])
157
+ .withCmd(["sleep", "infinity"])
150
158
  .start();
151
159
 
152
160
  const { output, exitCode } = await container.exec(["echo", "hello", "world"]);
@@ -263,12 +271,12 @@ const network = await new Network()
263
271
  .start();
264
272
 
265
273
  const container = await new GenericContainer("alpine")
266
- .withCmd(["top"])
274
+ .withCmd(["sleep", "infinity"])
267
275
  .withNetworkMode(network.getName())
268
276
  .start();
269
277
 
270
278
  const fooContainer = await new GenericContainer("alpine")
271
- .withCmd(["top"])
279
+ .withCmd(["sleep", "infinity"])
272
280
  .withNetworkMode(network.getName())
273
281
  .withNetworkAliases("foo", "bar")
274
282
  .start();
@@ -276,6 +284,22 @@ const fooContainer = await new GenericContainer("alpine")
276
284
  expect((await container.exec(["nslookup", "foo"])).exitCode).toBe(0);
277
285
  ```
278
286
 
287
+ Add hostname mappings:
288
+
289
+ ```javascript
290
+ const { GenericContainer } = require("testcontainers");
291
+
292
+ const container = await new GenericContainer("alpine")
293
+ .withExtraHosts(
294
+ { host: "foo", ipAddress: "10.11.12.13" },
295
+ { host: "bar", ipAddress: "11.12.13.14" }
296
+ )
297
+ .start();
298
+
299
+ expect((await container.exec(["nslookup", "foo"])).exitCode).toBe(0);
300
+ expect((await container.exec(["nslookup", "bar"])).exitCode).toBe(0);
301
+ ```
302
+
279
303
  Specifying a pull policy. Note that if omitted will use the `DefaultPullPolicy` which will use a locally cached image
280
304
  if one already exists, this is usually the preferred option. In cases where there is a local image for a given tag
281
305
  but the remote image with the same tag may have changed (for example when using the `latest` tag), you can tell
@@ -401,7 +425,7 @@ server.listen(8000);
401
425
  await TestContainers.exposeHostPorts(8000);
402
426
 
403
427
  const container = await new GenericContainer("alpine")
404
- .withCmd(["top"])
428
+ .withCmd(["sleep", "infinity"])
405
429
  .start();
406
430
 
407
431
  const { output } = await container.exec(["curl", `http://host.testcontainers.internal:8000`]);
@@ -634,8 +658,9 @@ Once started, this container keeps track of containers/images/networks/volumes c
634
658
  automatically clean them up 10s after connectivity with testcontainers is lost. This is useful for example if a test
635
659
  starts a container and then terminates unexpectedly, as it will be automatically removed.
636
660
 
637
- ryuk must be run with privileged mode; in CI environments such as Bit Bucket where this isn't supported, ryuk can be
638
- disabled by setting the environment variable `TESTCONTAINERS_RYUK_DISABLED` to `true`.
661
+ ryuk by default does not run privileged, if necessary this can be overridden by setting the environment variable
662
+ `TESTCONTAINERS_RYUK_PRIVILEGED` to `true`. If necessary, ryuk can be disabled enirely by setting the environment
663
+ variable `TESTCONTAINERS_RYUK_DISABLED` to `true`.
639
664
 
640
665
  ### SSHd
641
666
 
@@ -665,3 +690,4 @@ depending on file sizes and network constraints. It's unlikely that the default
665
690
  timeouts set by test frameworks are sufficient.
666
691
 
667
692
  - Increase the test timeout via the methods provided by the testing framework.
693
+
@@ -1,7 +1,10 @@
1
1
  import { Port } from "./port";
2
+ import { InspectResult } from "./docker/functions/container/inspect-container";
2
3
  export declare class BoundPorts {
3
4
  private readonly ports;
4
5
  getBinding(port: Port): Port;
5
6
  setBinding(key: Port, value: Port): void;
6
7
  iterator(): Iterable<[Port, Port]>;
8
+ filter(ports: Port[]): BoundPorts;
9
+ static fromInspectResult(inspectResult: InspectResult): BoundPorts;
7
10
  }
@@ -18,5 +18,19 @@ class BoundPorts {
18
18
  iterator() {
19
19
  return this.ports;
20
20
  }
21
+ filter(ports) {
22
+ const boundPorts = new BoundPorts();
23
+ for (const [internalPort, hostPort] of this.iterator()) {
24
+ if (ports.includes(internalPort)) {
25
+ boundPorts.setBinding(internalPort, hostPort);
26
+ }
27
+ }
28
+ return boundPorts;
29
+ }
30
+ static fromInspectResult(inspectResult) {
31
+ const boundPorts = new BoundPorts();
32
+ Object.entries(inspectResult.ports).forEach(([internalPort, hostPort]) => boundPorts.setBinding(parseInt(internalPort), hostPort));
33
+ return boundPorts;
34
+ }
21
35
  }
22
36
  exports.BoundPorts = BoundPorts;
@@ -0,0 +1,9 @@
1
+ import Dockerode from "dockerode";
2
+ import { Host } from "./types";
3
+ import "../testcontainers-properties-file";
4
+ declare type DockerClient = {
5
+ host: Host;
6
+ dockerode: Dockerode;
7
+ };
8
+ export declare const dockerClient: Promise<DockerClient>;
9
+ export {};
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.dockerClient = void 0;
16
+ const dockerode_1 = __importDefault(require("dockerode"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const logger_1 = require("../logger");
19
+ const url_1 = require("url");
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const run_in_container_1 = require("./functions/run-in-container");
22
+ const log_system_diagnostics_1 = require("../log-system-diagnostics");
23
+ require("../testcontainers-properties-file");
24
+ const getDockerClient = () => __awaiter(void 0, void 0, void 0, function* () {
25
+ const strategies = [
26
+ new ConfigurationStrategy(),
27
+ new UnixSocketStrategy(),
28
+ new NpipeSocketStrategy(),
29
+ ];
30
+ for (const strategy of strategies) {
31
+ if (strategy.isApplicable()) {
32
+ logger_1.log.debug(`Found applicable Docker client strategy: ${strategy.getName()}`);
33
+ const dockerConfig = strategy.getDockerConfig();
34
+ const dockerode = new dockerode_1.default(createDockerodeOptions(dockerConfig));
35
+ logger_1.log.debug(`Testing Docker client strategy URI: ${dockerConfig.uri}`);
36
+ if (yield isDockerDaemonReachable(dockerode)) {
37
+ const host = yield resolveHost(dockerode, dockerConfig.uri);
38
+ logger_1.log.info(`Using Docker client strategy: ${strategy.getName()}, Docker host: ${host}`);
39
+ log_system_diagnostics_1.logSystemDiagnostics();
40
+ return { host, dockerode };
41
+ }
42
+ else {
43
+ logger_1.log.warn(`Docker client strategy ${strategy.getName()} is not reachable`);
44
+ }
45
+ }
46
+ }
47
+ throw new Error("No Docker client strategy found");
48
+ });
49
+ const createDockerodeOptions = (dockerConfig) => {
50
+ const dockerOptions = {};
51
+ if (dockerConfig.socketPath) {
52
+ dockerOptions.socketPath = dockerConfig.socketPath;
53
+ }
54
+ else {
55
+ dockerOptions.host = dockerConfig.uri;
56
+ }
57
+ if (dockerConfig.ssl) {
58
+ dockerOptions.ca = dockerConfig.ssl.ca;
59
+ dockerOptions.cert = dockerConfig.ssl.cert;
60
+ dockerOptions.key = dockerConfig.ssl.key;
61
+ }
62
+ return dockerOptions;
63
+ };
64
+ const isDockerDaemonReachable = (dockerode) => __awaiter(void 0, void 0, void 0, function* () { return (yield dockerode.ping()).toString() === "OK"; });
65
+ class ConfigurationStrategy {
66
+ getDockerConfig() {
67
+ const { DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH } = process.env;
68
+ return {
69
+ uri: DOCKER_HOST,
70
+ ssl: DOCKER_TLS_VERIFY === "1" && DOCKER_CERT_PATH !== undefined
71
+ ? {
72
+ ca: path_1.default.resolve(DOCKER_CERT_PATH, "ca.pem"),
73
+ cert: path_1.default.resolve(DOCKER_CERT_PATH, "cert.pem"),
74
+ key: path_1.default.resolve(DOCKER_CERT_PATH, "key.pem"),
75
+ }
76
+ : undefined,
77
+ };
78
+ }
79
+ isApplicable() {
80
+ return process.env.DOCKER_HOST !== undefined;
81
+ }
82
+ getName() {
83
+ return "ConfigurationStrategy";
84
+ }
85
+ }
86
+ class UnixSocketStrategy {
87
+ getDockerConfig() {
88
+ return {
89
+ uri: "unix:///var/run/docker.sock",
90
+ socketPath: "/var/run/docker.sock",
91
+ };
92
+ }
93
+ isApplicable() {
94
+ return process.platform === "linux" || process.platform === "darwin";
95
+ }
96
+ getName() {
97
+ return "UnixSocketStrategy";
98
+ }
99
+ }
100
+ class NpipeSocketStrategy {
101
+ getDockerConfig() {
102
+ return {
103
+ uri: "npipe:////./pipe/docker_engine",
104
+ socketPath: "//./pipe/docker_engine",
105
+ };
106
+ }
107
+ isApplicable() {
108
+ return process.platform === "win32";
109
+ }
110
+ getName() {
111
+ return "NpipeSocketStrategy";
112
+ }
113
+ }
114
+ const resolveHost = (dockerode, uri) => __awaiter(void 0, void 0, void 0, function* () {
115
+ if (process.env.TESTCONTAINERS_HOST_OVERRIDE !== undefined) {
116
+ return process.env.TESTCONTAINERS_HOST_OVERRIDE;
117
+ }
118
+ const { protocol, hostname } = new url_1.URL(uri);
119
+ switch (protocol) {
120
+ case "http:":
121
+ case "https:":
122
+ case "tcp:":
123
+ return hostname;
124
+ case "unix:":
125
+ case "npipe:": {
126
+ if (isInContainer()) {
127
+ const gateway = yield findGateway(dockerode);
128
+ if (gateway !== undefined) {
129
+ return gateway;
130
+ }
131
+ const defaultGateway = yield findDefaultGateway(dockerode);
132
+ if (defaultGateway !== undefined) {
133
+ return defaultGateway;
134
+ }
135
+ }
136
+ return "localhost";
137
+ }
138
+ default:
139
+ throw new Error(`Unsupported protocol: ${protocol}`);
140
+ }
141
+ });
142
+ const findGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
143
+ var _a, _b, _c;
144
+ const inspectResult = yield dockerode.getNetwork("bridge").inspect();
145
+ return (_c = (_b = (_a = inspectResult === null || inspectResult === void 0 ? void 0 : inspectResult.IPAM) === null || _a === void 0 ? void 0 : _a.Config) === null || _b === void 0 ? void 0 : _b.find((config) => config.Gateway !== undefined)) === null || _c === void 0 ? void 0 : _c.Gateway;
146
+ });
147
+ const findDefaultGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () { return run_in_container_1.runInContainer(dockerode, "alpine:3.5", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]); });
148
+ const isInContainer = () => fs_1.default.existsSync("/.dockerenv");
149
+ exports.dockerClient = getDockerClient();
@@ -1,6 +1,6 @@
1
1
  import { DockerImageName } from "../../../docker-image-name";
2
- import { BoundPorts } from "../../../bound-ports";
3
2
  import Dockerode from "dockerode";
3
+ import { Port } from "../../../port";
4
4
  import { BindMount, Command, ContainerName, Env, ExtraHost, HealthCheck, NetworkMode, TmpFs } from "../../types";
5
5
  export declare type CreateContainerOptions = {
6
6
  imageName: DockerImageName;
@@ -8,7 +8,7 @@ export declare type CreateContainerOptions = {
8
8
  cmd: Command[];
9
9
  bindMounts: BindMount[];
10
10
  tmpFs: TmpFs;
11
- boundPorts: BoundPorts;
11
+ exposedPorts: Port[];
12
12
  name?: ContainerName;
13
13
  networkMode?: NetworkMode;
14
14
  healthCheck?: HealthCheck;
@@ -11,17 +11,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.createContainer = void 0;
13
13
  const logger_1 = require("../../../logger");
14
- const dockerode_1 = require("../../dockerode");
14
+ const docker_client_1 = require("../../docker-client");
15
15
  const create_labels_1 = require("../create-labels");
16
16
  const createContainer = (options) => __awaiter(void 0, void 0, void 0, function* () {
17
17
  try {
18
18
  logger_1.log.info(`Creating container for image: ${options.imageName}`);
19
- return yield dockerode_1.dockerode.createContainer({
19
+ const { dockerode } = yield docker_client_1.dockerClient;
20
+ return yield dockerode.createContainer({
20
21
  name: options.name,
21
22
  User: options.user,
22
23
  Image: options.imageName.toString(),
23
24
  Env: getEnv(options.env),
24
- ExposedPorts: getExposedPorts(options.boundPorts),
25
+ ExposedPorts: getExposedPorts(options.exposedPorts),
25
26
  Cmd: options.cmd,
26
27
  Labels: create_labels_1.createLabels(options.imageName),
27
28
  // @ts-ignore
@@ -31,7 +32,7 @@ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function*
31
32
  ExtraHosts: getExtraHosts(options.extraHosts),
32
33
  AutoRemove: options.autoRemove,
33
34
  NetworkMode: options.networkMode,
34
- PortBindings: getPortBindings(options.boundPorts),
35
+ PortBindings: getPortBindings(options.exposedPorts),
35
36
  Binds: getBindMounts(options.bindMounts),
36
37
  Tmpfs: options.tmpFs,
37
38
  LogConfig: getLogConfig(options.useDefaultLogDriver),
@@ -46,20 +47,20 @@ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function*
46
47
  });
47
48
  exports.createContainer = createContainer;
48
49
  const getEnv = (env) => Object.entries(env).reduce((dockerodeEnvironment, [key, value]) => [...dockerodeEnvironment, `${key}=${value}`], []);
49
- const getExposedPorts = (boundPorts) => {
50
+ const getExposedPorts = (exposedPorts) => {
50
51
  const dockerodeExposedPorts = {};
51
- for (const [internalPort] of boundPorts.iterator()) {
52
- dockerodeExposedPorts[internalPort.toString()] = {};
52
+ for (const exposedPort of exposedPorts) {
53
+ dockerodeExposedPorts[exposedPort.toString()] = {};
53
54
  }
54
55
  return dockerodeExposedPorts;
55
56
  };
56
57
  const getExtraHosts = (extraHosts) => {
57
58
  return extraHosts.map((extraHost) => `${extraHost.host}:${extraHost.ipAddress}`);
58
59
  };
59
- const getPortBindings = (boundPorts) => {
60
+ const getPortBindings = (exposedPorts) => {
60
61
  const dockerodePortBindings = {};
61
- for (const [internalPort, hostPort] of boundPorts.iterator()) {
62
- dockerodePortBindings[internalPort.toString()] = [{ HostPort: hostPort.toString() }];
62
+ for (const exposedPort of exposedPorts) {
63
+ dockerodePortBindings[exposedPort] = [{ HostPort: "0" }];
63
64
  }
64
65
  return dockerodePortBindings;
65
66
  };
@@ -19,18 +19,11 @@ const execContainer = (container, command) => __awaiter(void 0, void 0, void 0,
19
19
  AttachStderr: true,
20
20
  });
21
21
  const stream = yield startExec(exec);
22
- return yield new Promise((resolve) => {
23
- const chunks = [];
24
- stream.on("data", (chunk) => chunks.push(chunk));
25
- const interval = setInterval(() => __awaiter(void 0, void 0, void 0, function* () {
26
- const { running, exitCode } = yield inspectExec(exec);
27
- if (!running) {
28
- clearInterval(interval);
29
- stream.destroy();
30
- resolve({ output: chunks.join(""), exitCode });
31
- }
32
- }), 100);
33
- });
22
+ const chunks = [];
23
+ stream.on("data", (chunk) => chunks.push(chunk));
24
+ const exitCode = yield waitForExec(exec);
25
+ stream.destroy();
26
+ return { output: chunks.join(""), exitCode };
34
27
  }
35
28
  catch (err) {
36
29
  logger_1.log.error(`Failed to exec container ${container.id} with command "${command.join(" ")}": ${err}`);
@@ -72,3 +65,14 @@ const inspectExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
72
65
  throw err;
73
66
  }
74
67
  });
68
+ const waitForExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
69
+ return new Promise((resolve) => {
70
+ const interval = setInterval(() => __awaiter(void 0, void 0, void 0, function* () {
71
+ const { running, exitCode } = yield inspectExec(exec);
72
+ if (!running) {
73
+ clearInterval(interval);
74
+ resolve(exitCode);
75
+ }
76
+ }), 100);
77
+ });
78
+ });
@@ -1,3 +1,3 @@
1
1
  import Dockerode from "dockerode";
2
2
  import { Id } from "../../types";
3
- export declare const getContainerById: (id: Id) => Dockerode.Container;
3
+ export declare const getContainerById: (id: Id) => Promise<Dockerode.Container>;
@@ -1,6 +1,18 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.getContainerById = void 0;
4
- const dockerode_1 = require("../../dockerode");
5
- const getContainerById = (id) => dockerode_1.dockerode.getContainer(id);
13
+ const docker_client_1 = require("../../docker-client");
14
+ const getContainerById = (id) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const { dockerode } = yield docker_client_1.dockerClient;
16
+ return dockerode.getContainer(id);
17
+ });
6
18
  exports.getContainerById = getContainerById;
@@ -1,10 +1,9 @@
1
- import { ContainerName, HealthCheckStatus, NetworkSettings } from "../../types";
2
- import { Port } from "../../../port";
1
+ import { ContainerName, HealthCheckStatus, NetworkSettings, Ports } from "../../types";
3
2
  import Dockerode from "dockerode";
4
3
  export declare type InspectResult = {
5
4
  name: ContainerName;
6
- internalPorts: Port[];
7
- hostPorts: Port[];
5
+ hostname: string;
6
+ ports: Ports;
8
7
  healthCheckStatus: HealthCheckStatus;
9
8
  networkSettings: {
10
9
  [networkName: string]: NetworkSettings;
@@ -15,9 +15,9 @@ const inspectContainer = (container) => __awaiter(void 0, void 0, void 0, functi
15
15
  try {
16
16
  const inspectResult = yield container.inspect();
17
17
  return {
18
- hostPorts: getHostPorts(inspectResult),
19
- internalPorts: getInternalPorts(inspectResult),
20
- name: getName(inspectResult),
18
+ name: inspectResult.Name,
19
+ hostname: inspectResult.Config.Hostname,
20
+ ports: getPorts(inspectResult),
21
21
  healthCheckStatus: getHealthCheckStatus(inspectResult),
22
22
  networkSettings: getNetworkSettings(inspectResult),
23
23
  state: { status: inspectResult.State.Status, running: inspectResult.State.Running },
@@ -29,11 +29,13 @@ const inspectContainer = (container) => __awaiter(void 0, void 0, void 0, functi
29
29
  }
30
30
  });
31
31
  exports.inspectContainer = inspectContainer;
32
- const getHostPorts = (inspectInfo) => Object.values(inspectInfo.NetworkSettings.Ports)
33
- .filter((portsArray) => portsArray !== null)
34
- .map((portsArray) => Number(portsArray[0].HostPort));
35
- const getInternalPorts = (inspectInfo) => Object.keys(inspectInfo.NetworkSettings.Ports).map((port) => Number(port.split("/")[0]));
36
- const getName = (inspectInfo) => inspectInfo.Name;
32
+ const getPorts = (inspectInfo) => Object.entries(inspectInfo.NetworkSettings.Ports)
33
+ .filter(([, hostPorts]) => hostPorts !== null)
34
+ .map(([internalPort, hostPorts]) => {
35
+ const hostPort = hostPorts[0].HostPort;
36
+ return { [parseInt(internalPort.split("/")[0])]: parseInt(hostPort) };
37
+ })
38
+ .reduce((acc, curr) => (Object.assign(Object.assign({}, acc), curr)), {});
37
39
  const getHealthCheckStatus = (inspectResult) => {
38
40
  const health = inspectResult.State.Health;
39
41
  if (health === undefined) {
@@ -10,11 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.listContainers = void 0;
13
- const dockerode_1 = require("../../dockerode");
13
+ const docker_client_1 = require("../../docker-client");
14
14
  const logger_1 = require("../../../logger");
15
15
  const listContainers = () => __awaiter(void 0, void 0, void 0, function* () {
16
16
  try {
17
- return yield dockerode_1.dockerode.listContainers();
17
+ const { dockerode } = yield docker_client_1.dockerClient;
18
+ return yield dockerode.listContainers();
18
19
  }
19
20
  catch (err) {
20
21
  logger_1.log.error(`Failed to list containers: ${err}`);
@@ -1,2 +1,2 @@
1
1
  import { Readable } from "stream";
2
- export declare const demuxStream: (stream: Readable) => Readable;
2
+ export declare const demuxStream: (stream: Readable) => Promise<Readable>;
@@ -1,13 +1,23 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.demuxStream = void 0;
4
13
  const stream_1 = require("stream");
5
14
  const logger_1 = require("../../logger");
6
- const dockerode_1 = require("../dockerode");
7
- const demuxStream = (stream) => {
15
+ const docker_client_1 = require("../docker-client");
16
+ const demuxStream = (stream) => __awaiter(void 0, void 0, void 0, function* () {
8
17
  try {
9
18
  const demuxedStream = new stream_1.PassThrough({ autoDestroy: true, encoding: "utf-8" });
10
- dockerode_1.dockerode.modem.demuxStream(stream, demuxedStream, demuxedStream);
19
+ const { dockerode } = yield docker_client_1.dockerClient;
20
+ dockerode.modem.demuxStream(stream, demuxedStream, demuxedStream);
11
21
  stream.on("end", () => demuxedStream.end());
12
22
  demuxedStream.on("close", () => {
13
23
  if (!stream.destroyed) {
@@ -20,5 +30,5 @@ const demuxStream = (stream) => {
20
30
  logger_1.log.error(`Failed to demux stream: ${err}`);
21
31
  throw err;
22
32
  }
23
- };
33
+ });
24
34
  exports.demuxStream = demuxStream;
@@ -10,9 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getDockerInfo = void 0;
13
- const dockerode_1 = require("../dockerode");
13
+ const docker_client_1 = require("../docker-client");
14
14
  const getDockerInfo = () => __awaiter(void 0, void 0, void 0, function* () {
15
- const info = yield dockerode_1.dockerode.info();
15
+ const { dockerode } = yield docker_client_1.dockerClient;
16
+ const info = yield dockerode.info();
16
17
  return {
17
18
  serverVersion: info.ServerVersion,
18
19
  operatingSystem: info.OperatingSystem,
@@ -18,14 +18,15 @@ const docker_ignore_1 = require("../../../docker-ignore");
18
18
  const tar_fs_1 = __importDefault(require("tar-fs"));
19
19
  const slash_1 = __importDefault(require("slash"));
20
20
  const byline_1 = __importDefault(require("byline"));
21
- const dockerode_1 = require("../../dockerode");
21
+ const docker_client_1 = require("../../docker-client");
22
22
  const create_labels_1 = require("../create-labels");
23
23
  const buildImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
24
24
  try {
25
25
  logger_1.log.info(`Building image '${options.imageName.toString()}' with context '${options.context}'`);
26
26
  const dockerIgnoreFiles = yield docker_ignore_1.findDockerIgnoreFiles(options.context, options.dockerfileName);
27
27
  const tarStream = tar_fs_1.default.pack(options.context, { ignore: (name) => dockerIgnoreFiles.has(slash_1.default(name)) });
28
- return new Promise((resolve) => dockerode_1.dockerode
28
+ const { dockerode } = yield docker_client_1.dockerClient;
29
+ return new Promise((resolve) => dockerode
29
30
  .buildImage(tarStream, {
30
31
  dockerfile: options.dockerfileName,
31
32
  buildargs: options.buildArgs,
@@ -11,11 +11,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.listImages = void 0;
13
13
  const docker_image_name_1 = require("../../../docker-image-name");
14
- const dockerode_1 = require("../../dockerode");
14
+ const docker_client_1 = require("../../docker-client");
15
15
  const logger_1 = require("../../../logger");
16
16
  const listImages = () => __awaiter(void 0, void 0, void 0, function* () {
17
17
  try {
18
- const images = yield dockerode_1.dockerode.listImages();
18
+ const { dockerode } = yield docker_client_1.dockerClient;
19
+ const images = yield dockerode.listImages();
19
20
  return images.reduce((dockerImageNames, image) => {
20
21
  if (isDanglingImage(image)) {
21
22
  return dockerImageNames;
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.pullImage = void 0;
13
13
  const logger_1 = require("../../../logger");
14
14
  const pull_stream_parser_1 = require("../../pull-stream-parser");
15
- const dockerode_1 = require("../../dockerode");
15
+ const docker_client_1 = require("../../docker-client");
16
16
  const image_exists_1 = require("./image-exists");
17
17
  const pullImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
18
18
  try {
@@ -21,7 +21,8 @@ const pullImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
21
21
  return;
22
22
  }
23
23
  logger_1.log.info(`Pulling image: ${options.imageName}`);
24
- const stream = yield dockerode_1.dockerode.pull(options.imageName.toString(), { authconfig: options.authConfig });
24
+ const { dockerode } = yield docker_client_1.dockerClient;
25
+ const stream = yield dockerode.pull(options.imageName.toString(), { authconfig: options.authConfig });
25
26
  yield new pull_stream_parser_1.PullStreamParser(options.imageName, logger_1.log).consume(stream);
26
27
  }
27
28
  catch (err) {
@@ -11,11 +11,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.connectNetwork = void 0;
13
13
  const logger_1 = require("../../../logger");
14
- const dockerode_1 = require("../../dockerode");
14
+ const docker_client_1 = require("../../docker-client");
15
15
  const connectNetwork = (options) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  try {
17
17
  logger_1.log.info(`Connecting container ${options.containerId} to network ${options.networkId}`);
18
- const network = dockerode_1.dockerode.getNetwork(options.networkId);
18
+ const { dockerode } = yield docker_client_1.dockerClient;
19
+ const network = dockerode.getNetwork(options.networkId);
19
20
  yield network.connect({ Container: options.containerId, EndpointConfig: { Aliases: options.networkAliases } });
20
21
  }
21
22
  catch (err) {